Programmers can talk all about their craft here
Programmers
Programming links
Game creation tools
- Game Maker
http://www.gamemaker.nl/
Game Programming links
- GameDev.net
http://www.gamedev.net/ - flipcode
http://www.flipcode.com/ - Gamasutra
http://www.gamasutra.com/
General Programming links
- Boost C++ Libraries
http://www.boost.org - SGI's STL documentation
http://www.sgi.com/tech/stl - cplusplus resources
http://www.cplusplus.com/ - C/C++ Users Journal
http://cuj.com/ - Guru of the week
http://www.gotw.ca/
Advanced Programming links
- General-Purpose computation on GPUs
http://gpgpu.org/ - Calling conventions for different C++ compilers and operating systems
http://www.agner.org/assem/calling_conventions.pdf - A Taxonomy for "Bad Code Smells"
http://www.soberit.hut.fi/mmantyla/BadCodeSmellsTaxonomy.htm - Handle Exceptions Gracefully
http://www.ftponline.com/vsm/2003_05/online/wagner/ - Go To Statement Considered Harmful
http://www.acm.org/classics/oct95/ - Exception Handling Best Practices in .NET
http://www.codeproject.com/dotnet/exceptionbestpractices.asp
Game Programming links
- Networking
- Graphics
- BabelShader {Designed to convert between DirectX HLSL output, pixelshader 2.0 and OpenGL's low level shading languages}
http://graphics.stanford.edu/~danielrh/babelshader.html
- BabelShader {Designed to convert between DirectX HLSL output, pixelshader 2.0 and OpenGL's low level shading languages}
Windows CE, Pockect PC and Mobile
- Game API
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/APISP/…
[*] Windows Mobile Game Programming
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/devgui…
Unsorted:
http://icculus.org/
If you think something should be added to this list, post in this thread. I will delete the post when I add the links to keep it clean.
To be honest, I had totally forgotten about them, and it took me 10 minutes to find them (for those of you playing at home, "essential links" to the right in the coder section). I don't think they've been touched since they were added how many years ago...
So I'll work on this list and if Souri wants to improve the links section they can go there :)
I only test with Firefox and IE6, and maybe sometimes with Opera, but only if I'm asking for a headache. I don't know if I can save my sanity trying to support another browser [:X]
It's not that my css code is that sloppy (well, I don't think it is), but it's hard to make it compatible with all the browsers out there which interpret css differently from each other. Firefox seems to have the least problems though.
Everything else I've tried on sumea works fine in Konqueror. I hope CSS with MSIE 6 is better than C++ with MSVC 6 [:)]
It just decided to work btw, though it looks a little strange:
[img]icon_paperclip.gif[/img] Download Attachment: [url="http://www.sumea.com.au/forum/attached/lorien/200542924951_coder1.jpg"]coder1.jpg[/url]
135.92 KB
Let's not talk about CSS with MSIE6, shall we. Thanks. [:D]
I'm guessing the reason why the page was blank for you before was that the old style sheet was still stuck in your browsers cache, so nothing was being seen until the new style sheet explaining where things go kicked in. If there's one thing I've learnt about css's is that they can be stubborn getting out of the cache or refreshed. If you want to upload a screenshot of what's happening in the sumea website related section, I'd appreciate it!
Ahh, ok , I see you've attached it. It's the same problem with the opera browser. It's not recognising the code for transparent background with iframes. The three listings in the page (thumbnails, memberslisting, and the list on the left) shouldn't be having white backgrounds..
Anyway, back to Redwyre's thread of progammer links - please do post your links here. I will add them to the essential links in the programmers section as well.
Here are a few then:
http://icculus.org/ (run by a former Loki programmer Ryan C Gordon)
http://enet.cubik.org/ (the enet game networking library)
http://gpgpu.org/ (general purpose programming of GPUs)
hi..
i have been using this tool called GAME MAKER v6.1 and i love it :)
it is mainly a 2D tool, but it can do 3D stuff.. and a good user can make almost ANYTHING with it? (people have made MMORPG's, chat tools, audio players etc)
the best part is that is has drag and drop interface for beginners to make stuff with (very, very simple and a huge active web community) along with its own code / scripting areas for advanced users.. check out the site for more info..
it is a fre download, but a registered version will unlock advanced features.. (but the free version is 99% of the thing anyway!)
Ok, I'm unstickying this thread, and moving the links across to Sumea Wiki. You can update and modify the list at: http://www.sumea.com.au/sumeawiki/owbase/ow.asp?ProgrammerLinks
exporting templates from dlls
http://support.microsoft.com/default.aspx?scid=kb;EN-US;168958
Bloody windoze... You have to force an explicit instantiation with a __declspec(dllexport) inside the dll, a __declspec(dllimport) when using the dll, and an "extern" in front of the template keyword when using the dll...
Might as well sacrifice a chicken to Bill while you're at it.
Well templates are really generated at compile time, the compile time of where they are used to be more precise. Therefore in order to have a templated class of some sort (say std::vector) in a library of yours you need to tell it to generate the code for that class. Thus requiring an explicit instantiation, otherwise the template will be compiled when it gets actually used in some other program.
I'm not sure about mingw, I know Borland does automatically export because there is a commandline option to tell it to do so.
But if mingw wasn't exporting/importing, then iterating over a a vector full of strings returned from a method inside a dll wouldn't work, and it does.
No idea on other OSs, and don't really care, what I do care about is it working.
It wouldn't surprise me if it was re-compiling, but then throwing away the rendundant template instatiations. The whole shared library thing is much better on unixish platforms (though loading plugins is a little strange on MacOSX)- it defaults to every symbol in a .so file being exported by default, and whilst the ability to hide symbols is part of the ELF specification, it hasn't been properly supported by pre GCC 4.0 compilers (the only way you could hide something was by declaring it as static in a cpp file, or putting it in an anonymous namespace).
It hasn't mattered, on unixish platforms shared objects just work without hassle. No import libraries are needed either.
I think BeOS needed identical __declspec stuff to windows, but BeOS is dead.
Returning a std::vector from a DLL would still work even if the instantiated template code was not exported from the DLL. This would be because a copy of the code would be created inside the executable and another in the DLL, and all that would be passed would be the data that they use.
I wouldn't be too surprised if it did the same thing in shared libraries on unix platorms too. Because to you still need to compile against the library's header files when you want to use it. Therefore your code knows that it needs to instantiate a std::vector etc, and it would compile that code into the binary. I guess you'd have to inspect the symbols stored and the code generated for the shared library to be able to tell for sure.
The data types still have to be exported, and this is not a normal string (I know std::string is exported from msvcrt).
It is a std::basic_string, MyMetapoolAllocator > i.e. a string that uses an allocator that uses my memory pool system.
Even then this is a nebulous point: msvc throws out a million warning messages about returning vectors from a function in a dll, it says that it will not work.
I'll try removing my exports and running a test in msvc. Another test would be making a public map member variables in an exported class, and try using it in an exe.
__declspec question with intel c++
I've got 3 wrapper functions for dealing with thread local storage (to make it cross-platform):
void* LDK_API threadLocalGet(TLSKey key);
TLSKey LDK_API threadLocalCreateKey(ThreadLocalDtor dtor=NULL);
void LDK_API threadLocalSet(TLSKey key, void* data);
Intel C++ 7.1 tells me "#warning 903: __declspec attributes ignored void* LDK_API threadLocalGet(TLSKey key)"
It doesn't complain about either of the other functions, and none of them are inlines. This is during the building of the dll, so LDK_API resolves to __declspec(dllexport).
When I try to link with my dll it cannot find the threadLocalGet() symbol.
Anyone got a solution? Google isn't helping at all [:(]
Thanks
Is it meant to be returning a void pointer?
My suggestion would be to make the void* return value into a parameter that gets passed into the function, and possibly return int or bool from it to indicate a level of success etc.
The other thing to check out would be what you have before that function. Since it could be a parse error from some other section of code that's making the parser confused somewhat.
generic singleton and windows dlls solution
This will help anyone who has ever been frustrated by trying to export a template singleton from a dll on windows...
[code]
#define Singleton(api,klass,name)class api name {protected: static api klass* mInstance; inline name() {} inline name(const name&) {} inline ~name() {} inline void operator=(const name&) {} inline static void dtor() { if(mInstance) delete mInstance; }public: static klass& instance() { if(!mInstance) { mInstance = new klass; atexit(dtor); } return *mInstance; }}
#define SINGLETON_DATA(name) klass* name::mInstance = NULL
[/code]
You declare a singleton in your code with
[code]
//in a header somewhere
#ifdef MY_DLL_EXPORT
#define MY_DLL_API __declspec(dllexport)
#else
#define MY_DLL_API __declspec(dllimport)
#endif
//also in a header somewhere
Singleton(MY_DLL_API,MyClass,MySingleton);
//probably in MyClass.cpp
SINGLETON_DATA(MySingleton);
[/code]
You then use it with
[code]
MySingleton::instance().myMethod();
[/code]
The bottom line is it is (imho) impossible to use template singletons inside dlls on windows then use those singletons in other dlls or exes. Even partial template specialisation doesn't work:
[code]
template
class Singleton;
template
class Singleton
{
...
};
template
class Singleton
{
...
};
[/code]
fails because Singleton and Singleton are completely different types.
Hence my preprocessor hacking.
Hope it is useful
That static variable doesn't need "api" in front of it (it seemed as though it did with mingw, but that was a misunderstanding on my part). The reson why this thing has to be a macro is because you may want to create Singletons in multiple dlls and exes, so the normal preprocessor trick for handling __declspec is useless.
Windows Mobile Woes
Has anyone done any development for Windows Mobile 2003 (or Pocket PC 2003)? I'm having trouble getting eVC to deploy to my mobile.
Right now I'm doing development on Windows CE 5.0 using eVc 4 SP4 at work, although its not the same thing, I do know how much trouble these things can be. My questions would be:
What kind of transports in the Platform manager have you tried?
What cable is connecting your phone to your workstation?
Are you trying to upload your application through eVC itself?
I know that the Microsoft embedded stuff can be a pain to use and get right, even with the emulator and that, so good luck to you getting it working.
quote:What kind of transports in the Platform manager have you tried?
Every possible permutation. If I select the Windows CE device, it connects successfully but I can't select that as the platform.
quote:What cable is connecting your phone to your workstation?
USB that came with the phone, works fine for syncing and browsing the phone.
quote:Are you trying to upload your application through eVC itself?
Yeah, eVC++ SP4 fails as well as VS2003.
Odd thing is that I can't connect to the emulator either, so I dunno what's going on.
Next step
Ok, I've got a degree. The average grade was a distinction (high-end).
You've seen a screenshot my crappy game engine demo (it's on here
somewhere). I'm working on basic animation and AI but nothing in
stone yet, also I'm messing around with writing a campaign for NWN,
which might be good practice with using a toolset (debatable). I'm
waiting for my visa to processed, which should complete soon,
then write up a proper CV. I'll be looking for entry-level
game-programming/designing work.
I'm wondering if any gurus out there might have any advice as
to my first step into the world of professional game programming.
Dean knows code! [:O] man thats 2 'revelations' this week.
Wiffle: Pump out those demos man. Just keepem coming add new functionality to your existing demos or write something new. Start ripping apart every engine and every 'builder' program you can. Read books - programming gems series / game design series. Overall push your skills and absorb as much information as you can on what you want to be and start pushing yourself toward your goals.
yay, nice code Malus hehe.
Hazard: the project so far does bsp-based collision detection as
you walk around a level. My final yr project was a CSG language,
which used flex/bison to parse the language - which are quite
difficult creatures to tame under Win32. There are better parsers
out there now for Win32. Animation is the next step, I just
bought "Advanced Animation Techniques", Jim Adams. I'll start
making a seperate animation project soon before integrating it
with the bsp project. Whether this will be done in time for my
CV I'm not sure yet, but steady, regular progress is the best way.
Comments Please
I am interested to see the comments of some other people in relation to this program: http://www.smcmillan.net/scenerenderer.html .
Suggestions as to any additions or changes to the web site would also be welcomed. I guess it's a bit rough at the moment.
The program is not actually a game, just a simple scene viewing/editing system using a library I've made. Most of the library features have been designed to allow implementation of a game I want to make, but there are still a few more features to implement (and then the actual game to make) so I've been progressively updating this scene renderer program to use for testing purposes. The program primarily allows me to easily produce scenes that you can then watch.
I try to make it sound good on the web site, but I'd like to know what other people think I need to change or add, given that I would like to use this in my CV.
If I had to point out bad features at the moment (given the requirements and purpose of the scene renderer application) I'd probably say:
-The content needs to be upgraded in a major fashion. The two included scenes were just the most reasonable looking of those I was using for testing. The graphics quality should get a major boost when I finish creating this new content. There are also changes required to things such as some fragment shader code. E.g., tangent space normal mapped items with specular highlights are not ever "fogged".
-The menu system used was designed for a game. It's only really used because I wanted to test the game code library progressively during development. A standard MFC interface would have been a lot better (and a LOT easier). How bad does it seem? I'm used to it by now.
-If you want to create a new scene you need to add an XML file to the correct directory, not just choose a "New" menu item or something. There are also simple XML files that need to be configured to get other data into the program (e.g., models). I.e., adding new scenes or new content to place in the scenes requires some amount of knowledge, though reasonably small. This hasn't really bothered me because it's far quicker to add in a few small files and do the important editing operations in the program rather than spend the time writing and debugging import/export/new functions. Again this feature is also not required in the game code library. I guess it's a bit dodgy though.
Thanks to anyone who goes to the effort of looking at this program. If it crashes (noooooooooo!) please press "Yes" when it asks you if you want to send me an error log. The minidump file it sends could be very helpful in getting rid of a bug. Any other bugs you notice I would like to hear about too (they are lurking around somewhere in there I'm sure).
I updated the program a bit recently. I would appreciate any small comments what-so-ever. You don't even need to download the program if 6.5 MB is too much, just visit http://www.smcmillan.net/scenerenderer.html and click on the link to go to the Read Me file. A quick browse of that will give you a fair idea. I mainly just want to know what it looks like I've done right/wrong, whether the program looks advanced or basic, etc.
Thanks for any replies,
Scott McMillan.
PS: here's a picture.
[img]http://www.smcmillan.net/programming_page_files/scenerenderer3.jpg[/img]
Thanks for the feedback.
I have found the code style to be quite good actually, it seems quite neat and easy to follow to me. It's consistent throughout the entire program. The guidelines are documented here http://www.smcmillan.net/programming/scenerenderer/0.9.2/nongenerateddo… . I am open to any suggestions for improvements. So far as I know it's pretty standard though, generally following the style guidelines I picked up in textbooks at university. I figure that the generally accepted conventions have evolved since before I was born and would have reached a pretty good state by now.
There were a couple of things that I learnt the importance of due to this being the largest program I've written though:
- prefixing member variables with m_ is extremely useful when you come back to some code you haven't been working on for a few months. It's even more useful when you don't have the luxury of a nice IDE like Visual C++.
- you need to have standard conventions for naming things such as enum values. If I know a MaterialVertexData enum is going to contain values prefixed with MVD_, I can just type that and press control+space to get a list. Sometimes you can't choose the names you want due to clashes, but it's a lot better than nothing.
Those were the only two things I changed.
A template metaprogrammed memory pool allocator
As I said elsewhere I've been trying to make heap allocation almost as fast as stack allocation for a realtime scripting language I'm making. Here is the allocator code.
I was going to make this a tutorial, but instead I'm going to try and get something about this published in somewhere like the C++ Users Journal.
For some info on metaprogramming have a look at http://osl.iu.edu/~tveldhui/papers/Template-Metaprograms/meta-art.html and/or do some googling. There is a fair amount of info out there for such an exotic technique, and there are even some libraries like the boost mpl.
Enjoy [:)]
[code]
#ifndef __METAPOOL_HH__
#define __METAPOOL_HH__
/********************************************************************************
** A cross-platform template metaprogrammed memory pool allocation system. **
** **
** Copyright (C) 2003-2005 Lorien Dunn and The Applied Computing Research **
** Institute, La Trobe University. **
** **
** Released at http://sumea.com.au/forum/topic.asp?TOPIC_ID=2716 under **
** the Boost license (repreoduced below) on the 7th of Feb 2005. The API for **
** normal use is at the end of this file. **
** **
** In addition to the boost license I ask that bug fixes, optimisations **
** and other improvements be posted on sumea at the URL given above. **
** And if you use this and meet me perhaps you could buy me a beer :) **
** **
** This system manages a variable number of pools, each of which caters for **
** a different size allocation. The metaprogramming is used to find which **
** pool bests fits a particular size allocation request at compile time. **
** A runtime search is also provided (for when a size can't be known at **
** compile time). **
** **
** Pool chunkSizes are arranged like this: **
** 16 24 32 48 64 96 128 192 or **
** 24 32 48 64 96 128 192 256 **
** depending on whether the value defined by METAPOOL_MIN_CHUNK_SIZE **
** is a power of two or a power of two + 1/2 times the same power of two. **
** **
** Compared to previous versions this release vastly improves memory **
** wastage and scalability. METAPOOL_HEAP_SIZE_IN_K can be set to 4 **
** megs and METAPOOL_MAX_CHUNK_SIZE to 2 megs without problem. There is a **
** small runtime penalty for this scalabilty, and synthetic benchmarks that **
** allocate tons of memory probably won't perform hugely better than malloc. **
** It will perform much better in real programs. **
** **
** It should be 64-bit clean, providing you change one macro, but I've not **
** been able to verify this yet. It will not work on 16-bit CPUs. **
** **
** Note pools with a chunkSizes that are multiples of 16 bytes will return **
** 16 byte allocations, making them suitable for use with SSE vector **
** operations. **
** **
** Normal use API appears at the end of this file. It is very similar to **
** the c standard library: **
** **
** void* alloc(); **
** void* alloc(); **
** void* alloc(size_t size); **
** void* realloc(void* mem); **
** void* realloc(void* mem, size_t newSize); **
** void free(void* mem); **
** **
** The Allocator classes from the previous versions are gone, but a base **
** class allocator for use with the "curiously recursive template pattern" **
** is provided, as are preprocessor macros. **
** **
** Forget about using this with MSVC 6.0 (even with SP 5). 6.0 is way too **
** broken (particularly in templates), and the headers are missing the memory **
** alignment functions. AFAIK the only version of MSVC this code will compile **
** with is .net 2003 because it requires partial template specialisation. **
** If you are using MinGW make sure it is >= 3.4.0 because the memory **
** alignment functions are missing from the headers in 3.3.x **
** Works fine with Intel C++ 7.1 on win32 with MSVC6 headers, but have to hak **
** alignedAlloc and alignedFree to use normal malloc/free :( **
** I have no idea if it works with Borland compilers, and to be honest I **
** don't care- I've had nothing but trouble with them. **
** **
********************************************************************************/
/********************************************************************************
** Boost Software License - Version 1.0 - August 17th, 2003 **
** **
** Permission is hereby granted, free of charge, to any person or organization **
** obtaining a copy of the software and accompanying documentation covered by **
** this license (the "Software") to use, reproduce, display, distribute, **
** execute, and transmit the Software, and to prepare derivative works of the **
** Software, and to permit third-parties to whom the Software is furnished to **
** do so, all subject to the following: **
** **
** The copyright notices in the Software and this entire statement, including **
** the above license grant, this restriction and the following disclaimer, **
** must be included in all copies of the Software, in whole or in part, and **
** all derivative works of the Software, unless such copies or derivative **
** works are solely in the form of machine-executable object code generated by **
** a source language processor. **
** **
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR **
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, **
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT **
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE **
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, **
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER **
** DEALINGS IN THE SOFTWARE. **
********************************************************************************/
#include
#include //for std::bad_alloc
//not using headers because they causes
//compatibility issues when including c header files.
#include //for memcpy,
#include
//Re-implimentation of the Loki library static assert.
//Makes a compile error if the condition is false.
template struct CTAssert;
template <> struct CTAssert {};
#define CTASSERT(expr,msg) CTAssert<((expr) != false)> ERROR_##msg;
//All memory will be aligned on 16 byte boundaries. Do not change.
#define BYTE_ALIGNMENT 16
#ifdef METAPOOL_USE_MALLOC
#warning "METAPOOL_USE_MALLOC overridden"
#else
#define METAPOOL_USE_MALLOC
#endif //METAPOOL_USE_MALLOC
//change this to 0 on a 64 bit system (untested atm). I wish
//sizeof would work in the preprocessor!
#ifdef THIRTY_TWO_BIT
#warning "THIRTY_TWO_BIT overridden"
#else
#define THIRTY_TWO_BIT 1
#endif //THIRTY_TWO_BIT
//You might want to change these according to your needs.
//Chunk sizes should be be powers of two or memory alignment
//will likely be completely wrong, and smaller than 16 bytes
//on 32-bit systems and 32 bytes on 64-bit systems
//will mean more space wasted than allocated for the Pools
//with the smaller chunkSizes.
//add warnings if overidden
#ifdef METAPOOL_MAX_SPARE_HEAPS
#warning "METAPOOL_MAX_SPARE_HEAPS overridden"
#else
#define METAPOOL_MAX_SPARE_HEAPS 20
#endif //METAPOOL_MAX_SPARE_HEAPS
#if THIRTY_TWO_BIT == 1
#ifdef METAPOOL_HEAP_SIZE_IN_K
#warning "METAPOOL_HEAP_SIZE_IN_K overridden"
#else
#define METAPOOL_HEAP_SIZE_IN_K 1024
#endif //METAPOOL_HEAP_SIZE_IN_K
#ifdef METAPOOL_MIN_CHUNK_SIZE
#warning "METAPOOL_MIN_CHUNK_SIZE overridden"
#else
#define METAPOOL_MIN_CHUNK_SIZE 16
#endif //METAPOOL_MIN_CHUNK_SIZE
#else //64-bit
#ifdef METAPOOL_HEAP_SIZE_IN_K
#warning "METAPOOL_HEAP_SIZE_IN_K overridden"
#else
#define METAPOOL_HEAP_SIZE_IN_K 2048
#endif //METAPOOL_HEAP_SIZE_IN_K
#ifdef METAPOOL_MIN_CHUNK_SIZE
#warning "METAPOOL_MIN_CHUNK_SIZE overridden"
#else
#define METAPOOL_MIN_CHUNK_SIZE 32
#endif //METAPOOL_MIN_CHUNK_SIZE
#endif //THIRTY_TWO_BIT == 1
#ifdef METAPOOL_MAX_CHUNK_SIZE
#warning "METAPOOL_MIN_CHUNK_SIZE overridden"
#else
#define METAPOOL_MAX_CHUNK_SIZE ((METAPOOL_HEAP_SIZE_IN_K*1024)/2)
#endif //METAPOOL_MAX_CHUNK_SIZE
//do a little preprocessor sanity checking.
//Real power-of-2 and power-of-2 + 1/2-power-of-2 sanity
//checking is done with a template metaprogram.
#if METAPOOL_HEAP_SIZE_IN_K % 2 != 0
#error "METAPOOL_HEAP_SIZE_IN_K must be even"
#endif //METAPOOL_HEAP_SIZE_IN_K % 2 == 0
#if METAPOOL_MAX_CHUNK_SIZE < METAPOOL_MIN_CHUNK_SIZE
#error "METAPOOL_MAX_CHUNK_SIZE < METAPOOL_MIN_CHUNK_SIZE"
#endif //METAPOOL_MAX_CHUNK_SIZE < METAPOOL_MIN_CHUNK_SIZE
#if METAPOOL_MIN_CHUNK_SIZE % 2 != 0
#error "METAPOOL_MIN_CHUNK_SIZE must be even"
#endif //METAPOOL_MIN_CHUNK_SIZE % 2 != 0
#if METAPOOL_MAX_CHUNK_SIZE % 2 != 0
#warning "METAPOOL_MAX_CHUNK_SIZE must be even"
#endif //METAPOOL_MAX_CHUNK_SIZE % 2 != 0
#if METAPOOL_MAX_CHUNK_SIZE / 1024 > METAPOOL_HEAP_SIZE_IN_K
#error "METAPOOL_MAX_CHUNK_SIZE / 1024 > HEAP_SIZE"
#endif //METAPOOL_MAX_CHUNK_SIZE / 1024 > METAPOOL_HEAP_SIZE_IN_K
#if THIRTY_TWO_BIT == 1
#if METAPOOL_MIN_CHUNK_SIZE < 16
#warning "minimum chunk size is less than housekeeping size"
#endif //METAPOOL_MIN_CHUNK_SIZE < 16
#else //64 bit
#if METAPOOL_MIN_CHUNK_SIZE < 32
#warning "minimum chunk size is less than housekeeping size"
#endif //METAPOOL_MIN_CHUNK_SIZE < 32
#endif //THIRTY_TWO_BIT
#define MAX_CHUNKS_PER_HEAP (METAPOOL_HEAP_SIZE_IN_K/ METAPOOL_MIN_CHUNK_SIZE)
//You should probably get rid of this and use a
//better Singleton class beacuse static storage
//is rather slow to access.
//I plan on using a thread local storage singleton,
//so each thread gets it's own MetaPool. This will
//make everything threadsafe without using any
//mutexes. Providing the same thread that allocates
//a given piece of memory also frees it...
template
class Singleton
{
public:
inline static T* instance()
{
static T instance;
return &instance;
}
};
//Portability functions for allocating memory aligned on a
//particular bytes boundary. This allocation system always
//uses 16-byte alignment.
#ifdef unix
#include //cstdlib doesn't have posix_memalign!
//WARNING: arg order reversed from prev versions
inline void* alignedAlloc(size_t bytes, size_t align=BYTE_ALIGNMENT)
{
void *rtn = NULL;
#ifdef METAPOOL_USE_MALLOC
posix_memalign(&rtn,align,bytes);
#else
rtn = malloc(bytes);
#endif
if(!rtn) throw std::bad_alloc();
return rtn;
}
inline void alignedFree(void *mem)
{
assert(mem);
free(mem);
}
#elif defined WIN32
#include
//WARNING: arg order reversed from prev versions
inline void* alignedAlloc(size_t bytes,size_t align=BYTE_ALIGNMENT)
{
#ifdef METAPOOL_USE_MALLOC
void* rtn = malloc(bytes);
#else
void* rtn = _aligned_malloc(bytes,align);
#endif
if(!rtn) throw std::bad_alloc();
return rtn;
}
inline void alignedFree(void *mem)
{
assert(mem);
#ifdef METAPOOL_USE_MALLOC
free(mem);
#else
_aligned_free(mem);
#endif
}
#else
#error "Either unix or WIN32 was not defined, or you have an unsupported system"
#endif //unix
namespace Memory
{
class MetaPool;
namespace Details
{
class Heap;
////////////////////////////////////////////////////////////////////////
// //
// Struct Node. A header for a chunk and also a linked //
// list node. The list structure eliminates searching for //
// free chunks. //
// //
////////////////////////////////////////////////////////////////////////
struct Node
{
//Holds the actual size of the allocation to speed up realloc
//and test if free
size_t mAllocSize;
//next node in this heap
Node* mNext;
//heap that owns this node (BIG freeChunk speedup)
Heap* mHeap;
//To be used for reference counted smart pointers.
//Also ensures sizeof(Node) is 16 (32 on 64-bit systems) bytes to
//eliminate memory alignment issues
size_t mRefCount;
};
CTASSERT(sizeof(char)==1,CharSizeIsNot1Byte);
#if THIRTY_TWO_BIT == 1
CTASSERT(sizeof(Node)==16,NodeSizeIsNot16Bytes)
#else
CTASSERT(sizeof(Node)==32,NodeSizeIsNot32Bytes);
#endif //THIRTY_TWO_BIT
/*
** NB I use c-style casts in places because it is much
** easier to read. IMHO the reinterpret_cast syntax
** was never designed for such crazy casting.
*/
//Finds the mHeap member in the node that this memory
//belongs to.
inline Heap* getOwnerHeap(void* mem)
{
// *(Heap**) (((char*)mem) - HeapOffsetIntoNodeInBytes);
return *(Heap**) (((char*)mem) - sizeof(size_t) - sizeof(Heap*));
}
//returns the Node that owns this memory.
inline Node* getNode(void* mem)
{
return (Node*)(((char*)mem) - sizeof(Node));
}
class Pool;
////////////////////////////////////////////////////////////////////////
// //
// Class Heap. Uses a very strange and (eventually) tangled //
// linked list of nodes and chunks that get allocated as //
// one block of ram, arranged like this: //
// //
// |--------------| The tangle comes from nodes and chunks //
// | Node | being reused, and the linked list means //
// |--------------| there is no searching through the heap //
// | Allocated | for a free node/chunk combination. //
// | chunk | The nodes are headers for the chunks //
// |--------------| //
// | Next Node | Strangely this class becomes much slower //
// |--------------| if I make this block of memory part of //
// |Next Allocated| the instance rather than dynamically //
// | chunk | allocating it. //
// |--------------| //
// //
////////////////////////////////////////////////////////////////////////
class Heap
{
friend class Pool;
//the mem that gets split into Nodes and chunks
void* mMemory;
//sizeof(Node) + chunkSize
size_t mNodeSize;
//the next unused node
Node* mNextFree;
//the last node in the heap
Node* mLastNode;
//the size of the mem chunks this heap contains
size_t mChunkSize;
//the noOfChunks in this heap that have been allocated
size_t mAllocCount;
//the max allocs this heap can hold
size_t mMaxAllocs;
//used in cleanup phase
Pool* mParent;
//the requested heapSize
const size_t mSizeInBytes;
//size of the heap + sizeof the max possible no of nodes
const size_t mRealSize;
inline void setup(Pool* parent, size_t chunkSize)
{
mParent = parent;
mChunkSize = chunkSize;
mNodeSize = chunkSize + sizeof(Node);
mMaxAllocs = mRealSize / mNodeSize;
mAllocCount = 0;
//Set all the pointers. This loop will cause a little
//lag for small chunkSize heaps, but it can't be avoided :(
Node *n;
for(int i=0;imHeap = this;
n->mNext = (*this)[i+1]; //this will go past the end, but it gets
//set to NULL on the last Node below
n->mAllocSize = 0;
}
// set pointer to first free node.
mNextFree = reinterpret_cast(mMemory);
// set pointer to last free Node.
mLastNode = (*this)[mMaxAllocs-1];
mLastNode->mAllocSize = 0;
mLastNode->mHeap = this;
mLastNode->mNext = NULL;
}
public:
//make absolutely sure this thing throws bad_alloc
//independent of compiler stupidities
inline void* operator new(size_t size)
{
void* mem = malloc(size);
if(!mem)
throw std::bad_alloc();
return mem;
}
inline void operator delete(void* mem)
{
assert(mem);
::free(mem);
}
inline Heap(Pool* parent, size_t chunkSize, size_t size) :
mChunkSize(chunkSize),
mMemory(NULL),
mSizeInBytes(size),
mRealSize(size+(MAX_CHUNKS_PER_HEAP*sizeof(Node)))
{
mMemory = alignedAlloc(mRealSize);
setup(parent, chunkSize);
}
inline ~Heap()
{
if(mMemory)
alignedFree(mMemory);
}
//makes a node and chunk appear as one block of memory,
//and a heap as an array of them. mNodeSize is sizeof(Node)
//plus the size of the chunk.
inline Node* operator[](size_t idx) const
{
return reinterpret_cast((char*)mMemory + (idx*mNodeSize));
}
inline size_t chunkSize() const { return mChunkSize; }
inline size_t sizeInBytes() const { return mSizeInBytes; }
inline size_t allocCount() const { return mAllocCount; }
inline size_t maxAllocs() const { return mMaxAllocs; }
inline bool full() const { return !mNextFree; }
inline bool empty() const { return mAllocCount == 0; }
//Returns a free chunk from this heap and sets up the next
//allocation. This method will never be called if mNextFree
//is NULL
inline void* allocChunk(size_t allocSize)
{
void *chunk = NULL;
mNextFree->mAllocSize = allocSize;
mNextFree->mRefCount = 0;
chunk = (void*)(((char*)mNextFree) + sizeof(Node));
mNextFree = mNextFree->mNext;
mAllocCount++;
return chunk;
}
//Frees a chunk of memory and sets up all the pointers so no
//searching for free chunks is needed. This is what causes
//the tangles in the list. When the heap this belongs to is
//empty it gets passed to the parent pool for re-use.
//Implemented after Pool because it needs to call a Pool method.
inline void freeChunk(void *mem);
};
//A wrapper function for alignedAlloc that places a Node structure
//prior to the usable memory. Used when the requested allocation
//size will not fit in a Pool. The Node structure makes the allocation
//able to be freed and realloced by Memory::free and Memory::realloc.
inline void* bigAlloc(size_t size)
{
void* mem = alignedAlloc(size+sizeof(Details::Node));
Details::Node* n = reinterpret_cast(mem);
n->mAllocSize = size;
n->mNext = NULL;
n->mHeap = NULL;
n->mRefCount = 0;
return (void*)((char*)mem+sizeof(Details::Node));
}
////////////////////////////////////////////////////////////////////////
// //
// Class Pool. Manages a vector of (equal chunkSize) heaps //
// for allocation, also facilitates recycling of heaps both //
// within itself and though MetaPool. //
// //
////////////////////////////////////////////////////////////////////////
class Pool
{
protected:
friend class Heap;
friend class MetaPool;
Heap* mCurrentHeap;
Heap* mSpareHeap; //to avoid calling Heap::setup when there is no need
size_t mChunkSize;
MetaPool* mParent;
const size_t mDefaultHeapSize;
typedef std::vector HeapVector;
HeapVector mHeaps;
//When a heap is completely empty try putting it in the
//mSpareHeap member (so setup doesn't have to be called).
//If mSpareHeap is already used, add the heap to a LIFO
//in MetaPool for re-use elsewhere.
void cleanup(Heap* h);
public:
inline Pool(MetaPool* parent, size_t chunkSize, size_t defaultHeapSize) :
mCurrentHeap(NULL),
mSpareHeap(NULL),
mChunkSize(chunkSize),
mParent(parent),
mDefaultHeapSize(defaultHeapSize)
{
mHeaps.reserve(100);
}
inline ~Pool()
{
HeapVector::iterator i;
for(i=mHeaps.begin();i!=mHeaps.end();i++)
{
delete *i;
}
}
//Find a heap with a reasonable numer of free slots. If none
//are free allocates a new heap as a last resort, hence could
//throw std::bad_alloc. Implemented after MetaPool.
void findHeap();
//Returns a free chunk. Can throw std::bad_alloc.
//Contains the only branch I can't remove in mempry present conditions.
//Will trigger plenty more branches if mCurrentHeap is full though.
inline void *allocChunk(size_t allocSize)
{
if(!mCurrentHeap || mCurrentHeap->full())
findHeap();
return mCurrentHeap->allocChunk(allocSize);
}
inline size_t chunkSize() const { return mChunkSize; }
inline size_t noOfHeaps() const { return mHeaps.size(); }
inline size_t defaultHeapSize() const { return mDefaultHeapSize; }
};
/*
** This Heap method is here because it has to call a Pool
** method.
*/
//Frees a chunk of memory and sets up all the pointers so no
//searching for free chunks is needed. This is what causes
//the tangles in the list. When the heap this belongs to is
//empty it gets passed to the parent pool for re-use.
inline void Heap::freeChunk(void *mem)
{
Node* n = getNode(mem);
n->mRefCount = 0;
n->mAllocSize = 0;
//set up the pointers
Node* prevLast = mLastNode;
mLastNode = n;
prevLast->mNext = mLastNode;
mLastNode->mNext = NULL;
if(!mNextFree)
mNextFree = mLastNode;
mAllocCount--;
if(mAllocCount == 0)
mParent->cleanup(this);
}
/***********************************************************************
** **
** Begin template metaprogramming **
** **
***********************************************************************/
//////////////////////////////////////////////////////////////////////
// A compile-time loop to test if a number is a power of 2 //
//////////////////////////////////////////////////////////////////////
template
struct PowerOf2Test
{
enum
{
value = !(N%2) ? PowerOf2Test<(int)((N/2.0)+0.5)>::value : false
};
};
//it is a power of two
template <>
struct PowerOf2Test<2>
{
enum { value = true };
};
//it is not a power of two
template <>
struct PowerOf2Test<0>
{
enum { value = false };
};
//////////////////////////////////////////////////////////////////////
// A compile-time test to if a number is a power of 2 plus //
// (itself divided by two). This figures of that the next power //
// of two from 48 is 64 for example. //
//////////////////////////////////////////////////////////////////////
template
struct HalfwayTest
{
enum
{
//perhaps this first PowerOf2Test is redundant, but icc
//complains without it
value = PowerOf2Test::value ? false : PowerOf2Test<(int)(Size+((Size/3.0)+0.5))>::value
};
};
//////////////////////////////////////////////////////////////////////
// A metaprog "if" statement //
//////////////////////////////////////////////////////////////////////
template struct If;
//the true case
template
struct If
{
typedef TCase result;
};
//the false case
template
struct If
{
typedef FCase result;
};
//////////////////////////////////////////////////////////////////////
// True and False boolean wrapper types //
//////////////////////////////////////////////////////////////////////
struct True
{
enum { value = 1 };
};
struct False
{
enum { value = 0 };
};
#define MIN_CHUNKSIZE METAPOOL_MIN_CHUNK_SIZE
#define MAX_CHUNKSIZE METAPOOL_MAX_CHUNK_SIZE
///////////////////////////////////////////////////////////////////////
//Compile time sanity checks for heapSize, and min and max chunkSizes//
///////////////////////////////////////////////////////////////////////
typedef If::value,
True, HalfwayTest >::result HeapSizeCondition;
CTASSERT(HeapSizeCondition::value, BadHeapSize);
typedef If::value,
True, HalfwayTest >::result MinChunkCondition;
CTASSERT(MinChunkCondition::value, BadMinChunkSize);
typedef If::value,
True,HalfwayTest >::result MaxChunkCondition;
CTASSERT(MaxChunkCondition::value, BadMaxChunkSize);
//////////////////////////////////////////////////////////////////////
// Calculate (compile time) the number of pools required //
//////////////////////////////////////////////////////////////////////
template
struct PoolCount
{
enum
{
value = PoolCount::value + 1
};
};
//These terminates the above loop
template <>
struct PoolCount
{
enum { value = 1 };
};
template <>
struct PoolCount<(MIN_CHUNKSIZE+(MIN_CHUNKSIZE/2))>
{
enum { value = 1 };
};
template <>
struct PoolCount<(MIN_CHUNKSIZE+(MIN_CHUNKSIZE/3))>
{
enum { value = 1 };
};
//provides easy acces to the compile time calculated number of
//pools
struct NoOfPools
{
enum
{
max = MAX_CHUNKSIZE,
maxIsPowerOf2 = PowerOf2Test::value,
pwrOf2 = PoolCount<(maxIsPowerOf2 ? max : (max-(max/3)))>::value,
notPwrOf2 = PoolCount<(maxIsPowerOf2 ? (max-(max/4)) : max)>::value,
value = pwrOf2 + notPwrOf2
};
};
///////////////////////////////////////////////////////////////////////
// Calculate (compile time) the chunkSize of the pool at Idx //
///////////////////////////////////////////////////////////////////////
template
class ChunkSize
{
struct MinChunkPowerOf2
{
enum
{
powerOf2 = !(Idx%2),
value = powerOf2 ? ChunkSize::value - ChunkSize::value/3 : ChunkSize::value - ChunkSize::value/4
};
};
struct MinChunkNotPowerOf2
{
enum
{
powerOf2 = Idx%2,
value = powerOf2 ? ChunkSize::value - ChunkSize::value/3 : ChunkSize::value - ChunkSize::value/4
};
};
public:
enum
{
value = If::value, MinChunkPowerOf2, MinChunkNotPowerOf2>::result::value
};
};
//This terminates the above loop
template<>
class ChunkSize
{
struct MaxChunkPowerOf2
{
enum { value = MAX_CHUNKSIZE + (MAX_CHUNKSIZE/2) };
};
struct MaxChunkNotPowerOf2
{
enum { value = MAX_CHUNKSIZE + (MAX_CHUNKSIZE/3) };
};
public:
enum
{
value = If::value, MaxChunkPowerOf2, MaxChunkNotPowerOf2>::result::value
};
};
///////////////////////////////////////////////////////////////////////
// Calculate (compile time) the best pool Idx to allocate Size bytes //
///////////////////////////////////////////////////////////////////////
template
struct PoolIdxSearch
{
enum
{
//will the requested alloc fit in a chunk?
inRange = Size <= MAX_CHUNKSIZE? true : false,
//does the alloc fit in a pool, and it will fit in the current pool?
fitsHereToo = (inRange && (Size < ChunkSize::value)) ? true : false,
//if it does return the current index, otherwise keep recursing
value = fitsHereToo ? Idx : PoolIdxSearch::value
};
};
//terminate the loop at NoOfPools::value, which means we have to use
//the run-time allocator because there isn't a pool large enough
template
struct PoolIdxSearch
{
enum { value = -1 };
};
#undef MIN_CHUNKSIZE
#undef MAX_CHUNKSIZE
/***********************************************************************
** **
** End template metaprogramming **
** **
***********************************************************************/
} //namespace Details
////////////////////////////////////////////////////////////////////////
// //
// Class MetaPool. Encapsulates multiple pools of different //
// chunkSizes, handles runtime searching for the best size //
// pool for an alloc, and manages recylcling of heaps between //
// pools with different chunkSizes. //
// //
////////////////////////////////////////////////////////////////////////
class MetaPool
{
friend class Details::Pool;
typedef Details::NoOfPools NoOfPools;
//holds all the pools
Details::Pool* mPools[NoOfPools::value];
//some space to store empty heaps for re-use between
//pools. Using a vector as a LIFO because of constant-time
//pop_back() and ability to reserve space (which deque can't)
typedef std::vector HeapVector;
HeapVector mSpareHeaps;
inline void addSpareHeap(Details::Heap* h)
{
if(mSpareHeaps.size() > METAPOOL_MAX_SPARE_HEAPS)
{
delete h;
return;
}
mSpareHeaps.push_back(h);
}
inline Details::Heap* findSpareHeap(size_t chunkSize)
{
Details::Heap* h = NULL;
if(mSpareHeaps.empty())
{
for(int i=0;imSpareHeap && (mPools[i]->mSpareHeap->sizeInBytes() % chunkSize))
{
h = mPools[i]->mSpareHeap;
mPools[i]->mSpareHeap = NULL;
return h;
}
}
return NULL;
}
HeapVector::iterator it = mSpareHeaps.begin();
for(;it!=mSpareHeaps.end();it++)
{
if(!((*it)->sizeInBytes() % chunkSize))
{
h = (*it);
mSpareHeaps.erase(it);
return h;
}
}
return NULL;
}
public:
inline Details::Pool* pool(int idx)
{
return mPools[idx];
}
MetaPool()
{
const size_t heapSizeInK = METAPOOL_HEAP_SIZE_IN_K;
const size_t minChunkSize = METAPOOL_MIN_CHUNK_SIZE;
const size_t maxChunkSize = METAPOOL_MAX_CHUNK_SIZE;
//make sure there is plenty of room so the vector
//doesn't have to realloc
mSpareHeaps.reserve(METAPOOL_MAX_SPARE_HEAPS);
bool minChunkPwrOf2 = Details::PowerOf2Test::value;
bool maxChunkPwrOf2 = Details::PowerOf2Test::value;
bool heapSizePwrOf2 = Details::PowerOf2Test::value;
size_t pwrOf2HeapSize = heapSizePwrOf2 ? heapSizeInK : heapSizeInK-(heapSizeInK/3);
size_t notPwrOf2HeapSize = heapSizePwrOf2 ? heapSizeInK-(heapSizeInK/4) : heapSizeInK;
pwrOf2HeapSize *= 1024;
notPwrOf2HeapSize *= 1024;
size_t currentSize = minChunkSize;
if(minChunkPwrOf2)
{
int i;
int j = 0;
for(i=0;i METAPOOL_MAX_CHUNK_SIZE)
return Details::bigAlloc(size);
for(int i=0;ichunkSize())
return mPools[i]->allocChunk(size);
}
throw std::bad_alloc();
return NULL;
}
//Copies an allocation to a larger one and frees the old alloc.
//Can throw std::bad_alloc.
inline void* realloc(void *mem, size_t newSize)
{
assert(mem);
void* newMem = NULL;
Details::Node* n = Details::getNode(mem);
Details::Heap* h = n->mHeap;
if(!h)
{
if(newSize > n->mAllocSize || newSize < (n->mAllocSize/2))
{
newMem = alloc(newSize);
memcpy(newMem,mem,n->mAllocSize);
h->freeChunk(mem);
return newMem;
}
return mem;
}
if(newSize > h->chunkSize() || newSize < (h->chunkSize()/2))
{
void *newChunk = alloc(newSize);
memcpy(newChunk,mem,n->mAllocSize);
h->freeChunk(mem);
return newChunk;
}
return mem;
}
//Free an allocation. This WILL crash if you pass it memory
//that was not allocated through this allocation system.
inline void free(void *mem)
{
assert(mem);
Details::Heap *h = Details::getOwnerHeap(mem);
if(!h)
{
alignedFree(Details::getNode(mem));
return;
}
h->freeChunk(mem);
}
};
/*
** These Pool methods are here because they rely on calling
** MetaPool methods
*/
//When a heap is completely empty try putting it in the
//mSpareHeap member (so setup doesn't have to be called).
//If mSpareHeap is already used, add the heap to a list
//in MetaPool for re-use elsewhere (though setup will
//have to be called).
void Details::Pool::cleanup(Details::Heap* h)
{
if(h==mCurrentHeap && !mSpareHeap)
{
mSpareHeap = h;
mCurrentHeap = NULL;
return;
}
if(h!=mCurrentHeap)
{
mParent->addSpareHeap(h);
//need to remove h from mHeaps!!!
assert(!mHeaps.empty());
HeapVector::iterator it = mHeaps.end();
it--;
while(it!=mHeaps.begin())
{
if((*it) == h)
{
mHeaps.erase(it);
return;
}
it--;
}
assert(mHeaps[0]==h);
mHeaps.erase(it);
}
}
//Find a heap with reasonable number of free chunks. If none are suitable
//allocates a new heap, hence could throw std::bad_alloc.
void Details::Pool::findHeap()
{
if(mCurrentHeap)
{
mHeaps.push_back(mCurrentHeap);
mCurrentHeap = NULL;
}
if(mSpareHeap)
{
mCurrentHeap = mSpareHeap;
mSpareHeap = NULL;
return;
}
//Fallback to looking for a recent Heap with at least threshhold free chunks.
//Looping backwards to exploit any short-lived objects
//that have been freed.
int size = mHeaps.size();
int threshhold = 1;
int stopAt = 0;
if(size)
{
Heap* h;
stopAt = size > 5 ? 5 : size;
for(int i=size-1;i>=stopAt;i--)
{
h = mHeaps[i];
threshhold = h->maxAllocs() - (h->maxAllocs() / 4);
if(mHeaps[i]->allocCount() <= threshhold)
{
mCurrentHeap = mHeaps[i];
return;
}
}
}
//Fallback to asking MetaPool for a spare Heap and calling setup if found
Heap* fallback = mParent->findSpareHeap(mChunkSize);
if(fallback)
{
fallback->setup(this,mChunkSize);
mCurrentHeap = fallback;
return;
}
//Fallback to allocating a new one
mCurrentHeap = new Heap(this,mChunkSize,mDefaultHeapSize);
}
typedef Singleton MetaSingleton;
//This struct will be the result of an If template if the
//requested size will fit in a pool.
template
struct CTAllocHelper
{
inline static void* alloc(size_t size)
{
return MetaSingleton::instance()->pool(Idx)->allocChunk(size);
}
};
//This struct will be the result of an If template if the
//requested size will not fit in a pool.
template
struct RTAllocHelper
{
inline static void* alloc()
{
return Details::bigAlloc(Size);
}
};
/*
** Normal use API follows
*/
template
inline void* alloc()
{
const int idx = Details::PoolIdxSearch::value;
return Details::If, RTAllocHelper >::result::alloc(Size);
}
template
inline void* alloc()
{
return alloc();
};
//Allocate size bytes (from a pool if possible). Throws std::bad_alloc
//if the request cannot be fulfilled. Uses a runtime search for the
//best pool.
inline void* alloc(size_t size)
{
return MetaSingleton::instance()->alloc(size);
}
template
inline void* realloc(void* mem)
{
void* newMem = NULL;
Details::Node* n = Details::getNode(mem);
Details::Heap* h = n->mHeap;
if(!h)
{
if(Size > n->mAllocSize || Size < (n->mAllocSize/2))
{
newMem = alloc();
memcpy(newMem,mem,n->mAllocSize);
Memory::free(mem);
return newMem;
}
return mem;
}
if(Size > h->chunkSize() || Size < (h->chunkSize()/2))
{
newMem = alloc();
memcpy(newMem,mem,n->mAllocSize);
Memory::free(mem);
return newMem;
}
return mem;
}
//Copies an allocation to a larger one and frees the old alloc.
//Will never shrink an allocation. Uses pools if possible.
//Throws std::bad_alloc if the request cannot be fulfilled.
//Uses a runtime search for the best pool.
inline void* realloc(void *mem, size_t newSize)
{
return MetaSingleton::instance()->realloc(mem, newSize);
}
//Free memory allocated with this system only. Will crash if used on
//memory allocated with malloc/calloc/realloc or the default new
//operators.
inline void free(void* mem)
{
MetaSingleton::instance()->free(mem);
}
//class Test : public AddAllocator
template
struct AddAllocator
{
inline void* operator new(size_t rtSize)
{
assert(sizeof(T)==rtSize);
return Memory::alloc();
}
inline void operator delete(void* mem)
{
Memory::free(mem);
}
inline void* operator new[](size_t size)
{
return Memory::alloc(size);
}
inline void operator delete[](void* mem)
{
Memory::free(mem);
}
};
#define METAPOOL_CT_SINGLE_NEW(klass) inline void* operator new(size_t rtSize){ assert(sizeof(klass)==rtSize); return Memory::alloc::alloc();}
#define METAPOOL_RT_SINGLE_NEW inline void* operator new(size_t size){ return Memory::alloc(size);}
#define METAPOOL_SINGLE_DELETE inline void operator delete(void* mem){ Memory::free(mem);}
#define METAPOOL_ARRAY_NEW inline void* operator new[](size_t size){ return Memory::alloc(size);}
#define METAPOOL_ARRAY_DELETE inline void operator delete[](void* mem){ Memory::free(mem);}
#define METAPOOL_CT_ALLOCATORS(klass) METAPOOL_CT_SINGLE_NEW(klass) METAPOOL_SINGLE_DELETE METAPOOL_ARRAY_NEW METAPOOL_ARRAY_DELETE
#define METAPOOL_RT_ALLOCATORS METAPOOL_RT_SINGLE_NEW METAPOOL_SINGLE_DELETE METAPOOL_ARRAY_NEW METAPOOL_ARRAY_DELETE
}//namespace Memory
//clean up the macros
#undef CTASSERT
#undef BYTE_ALIGNMENT
#undef MAX_CHUNKS_PER_HEAP
#endif //__METAPOOL_HH__
[/code]
And here is a completely stupid and synthetic little benchmark prog
[code]
#define _XOPEN_SOURCE 600
#include
#include "MetaPool.h"
/*
** millisecond accurate timer code for win32
*/
#ifdef WIN32
#include
#ifdef __GNUC__
#ifndef INT64
#define INT64 long long
#endif //INT64
#endif //__GNUC__
#include
#include
#define LARGE_INTEGER_PTR LARGE_INTEGER*
#ifdef _MSC_VER
#define LARGE_INTEGER_PTR LARGE_INTEGER*
#endif //_MSC_VER
static INT64 gDivision;
static INT64 gStartTime;
size_t time()
{
INT64 time;
QueryPerformanceCounter((LARGE_INTEGER_PTR)&time);
time -= gStartTime;
time /= gDivision;
return (unsigned) time;
}
#endif //WIN32
/*
** millisecond accurate timer code for unix
** on x86 Linux gettimeofday is as accurate as
** QueryPerformanceCounter on win32.
*/
#ifdef unix
#include
#include
#include
#include
timeval gStartTime;
timeval gSleepTime;
size_t time()
{
size_t time;
struct timeval tv;
gettimeofday(&tv,NULL);
time = (tv.tv_sec - gStartTime.tv_sec) * 1000;
time += ((tv.tv_usec - gStartTime.tv_usec) / 1000);
return time;
}
#endif //unix
void alignedAllocTest(const int runs, int size)
{
size_t start = time();
void** test = (void**)Memory::alloc(runs*sizeof(void*));
for(int repeats=0;repeats<10;repeats++)
{
int i;
for(i=0;i
void ctPoolTest(const int runs)
{
void** test = (void**)Memory::alloc(runs*sizeof(void*));
size_t start = time();
for(int repeats=0;repeats<10;repeats++)
{
int i;
for(i=0;i();
}
for(i=0;i(t1Runs);
std::cout<<"
";
const int t2Runs=100000;
const int t2Size=10;
std::cout<<"Test2: runs "<(t2Runs);
std::cout<<"
";
const int t3Runs=50000;
const int t3Size=1023;
std::cout<<"Test3: runs "<(t3Runs);
std::cout<<"
";
const int tvRuns=3000;
const int tvLower=16;
const int tvUpper=1024;
std::cout<<"Var size test: runs "<
What are you guys (Hazard and Barry) doing in the programmer discussion area then? [:)] This thing will increase framerates.
I'm just fixing a bug btw: the alignedAlloc function for windows doesn't throw a std::bad_alloc if an allocation fails (doh!)
And another Doh!, an "#include " made in in somehow. Both these things are fixed now.
...so there's a sanity check that the MIN_CHUNK_SIZE and MAX_CHUNK_SIZE are even (your error message saying "must be power of two"), but what actually happens at compile time if they're not powers of two? Do we simply end up with one of those unreadable template error messages, or does it infinitely recurse?
It certainly looks funky - but I'm still confused as to how Pools, Heaps and Chunks really work together. If I'm reading it right, You have 'n' pools, each managing a set of Heaps, and each Heap manages a number of fixed size block of memory (Chunks) ranging from MIN_CHUNK_SIZE to MAX_CHUNK_SIZE in powers of two.
Why the level of indirection using Heaps? What benefit does that give over simply a number of pools of chunks? Perhaps a nice high-level disagram of the data structure would explain what it's achieving...
If they are not powers of two everything should still work (I'll do some destructive testing, thanks), but the 16-byte alignment of every allocation will be thrown off, making it useless for vector operations (I'm doing audio synthesis using SSE intrinsics, and the realtime scripting language, whilst general purpose and pure OO, is designed for audio). The next chunksize will still be calculated by 2* currentChunkSize. Also power of two is a good idea because (on the x86) double precision floats are very slow if not aligned on 8-byte boundaries, and some other architectures just crash without things being aligned properly.
I could do a real compile-time test for power-of-two-ness using another metaprogrammed loop. I probably will if it goes boom when they aren't.
I'm afraid I'm going to have to save the nice diagrams for an academic journal- I need to try to properly publish this because it is very close to a solution to an "impossible" problem of computer science (avoiding the runtime search in memory allocators). I wish I could make it work with languages other than C++ too [:)]
The relation is:
* Heaps manage Nodes, which are headers for chunks. Chunks are where you put your data and they don't exist as a class- they are just ram waiting to be used. Heaps have a fixed chunksize, and by making all Heaps equal in size they can be easily re-used by different Pools when they are empty. This is why the Heap class exists: to pass unused memory around between Pools.
* Pools manage Heaps. Pools also have a fixed chunksize. The Pool class also can ask MetaPool for a spare heap or allocate a new one if the current Heap is full.
* MetaPool manages an array of Pools, each of which has different size chunks.
The goal with this arrangement is to avoid calling malloc or new like the plague. They can have highly variable latency, which is a Bad Thing (tm) for realtime software.
I'm just posting another update, this one has some improved comments, and my CTAssert class was stuffed, it just compiled whether or not the condition was false. Now it prints nice errors. Also I #undef the macros I've defined now.
One more thing, malloc and alignedAlloc functions seem to perform much better on AMD CPUs, it's on P4s that I've seen well over 10 fold performance increase. I suspect it's the stupidly long pipelines in P4s and failed branch predictions. On Athlons the max increase I've seen is around 6x.
Happy me [:D] I've got the only relevent google link to "metaprogrammed memory allocator"
http://www.google.com/search?q=metaprogrammed%20memory%20allocator&ie=U…
Update done, changes are the copyright (apparently I share it with the uni, despite much of this code being written in early 2003 before I started), a typo (CTAssert instead of CTASSERT in a 64-bit section), replaced #errors with #warnings if the chunkSizes are not powers of two, replaced #warn (an invalid preprocessor instruction) with #warning, and a few little code style and comment cleanups.
mcdrewski: it does work with non-power of two chunkSizes, but as I said above it's probably a bad idea to use them.
The Heap class serves another purpose btw: it allows Pools to expand without having to realloc. Without the Heap class a Pool would have to hold one big chunk of contiguous memory, and the whole thing would probably need to be copied during a realloc when it filled up. Instead another Heap* is added to a vector inside Pool, and the vector already has a fair bit of space (for Heap*s) reserved to avoid calling realloc or whatever your STL allocator does to resize a vector.
David: I find this code pretty brain bending too, and I find template metaprogramming a little perverse...
Thats pretty damn handy stuff lorien.
I have seen similarly developed ideas for console memory allocation, however none of which cater for the runtime new/alloc problem.
I have seen solutions in Game Programming Gems which use a couple of differing methods, but again, none that cover general purpose use - really great stuff.
I would imagine this would be especially useful for consoles, where their alloc routines are very slow - PS2 is an example I can think of. I'll also try it out on NGage and GBA, and see how it goes.
Another update with a little more metaprogramming. It's documented in the comments. It goes faster :)
Thanks Grover, and thanks Souri for making it sticky.
I actually didn't think it would be good for consoles because of wasted memory because of the pools. Though of course if a near constant frame-rate is important this should be great.
I don't think I can optimise it much more with my current knowledge of c++ and hardware, so further updates are likely to be bug fixes. If you port it to another platform and are not prevented from doing so by an evil NDA please post those ports here and I'll add them to the main code- providing they don't break it for normal computers.
BTW the only "normal" textbook I've seen that mentions template metaprogramming and similar high end techniques is the 2nd edition of Thinking In C++ by Bruce Eckel. It is available for free in electronic form from http://mindview.net/Books
I'm not sure exactly what you mean by 'normal' textbook, but
two good metaprogramming books come to mind;
Modern C++ Design, by Alexei Alexandrescu.
C++ Template Metaprogramming, by David Abrahams and Aleksey Gurtovoy.
Modern C++ design takes alot of traditional design patterns, and
using heavy template code, makes them very safe, flexible, and
easy to use. Alexandrescu's code has problems with alot of compilers
though, it's just too much for them.
C++ Template Metaprogramming is generally a walk-through of the
Boost.MPL library, and showing ways to use it, and how it works.
It's probably good to get a fundamental understanding on how to
actually use metaprogramming techniques. Also, the Boost.MPL library
is quite well supported by a range of compilers, despite it's
complexity. (Quite a feat!)
[edit]
Also, the Boost.Pool library may be of interest in this thread.
http://www.boost.org/libs/pool/doc/index.html
I don't call either of those books "normal", I call them "crazy", but only in the nicest of ways [:)]. Loki (the norse god of mischief) is a perfect name for Alexei's library...
The Boost Metaprogramming library has to be the most complex and innovative library I've ever seen, and I don't even pretend to have anything other than the barest glimmering of understanding of what can be done with it. I've got the book on order.
Be careful asking questions about David Abrahams work on the boost mailing list, I haven't dared for years after copping a real flaming from him- in front of many of the most full-on c++ gurus in the world. I was just asking questions which the docs to his boost::python library didn't make clear.
*****
Sigh, I was completely blind in that update yesterday... There were two conditional branches the instruction stream for a compile time searched allocation when memory was available.
I have reduced it to one, and I simply can't get rid of it :(
These branches are important because they are slow if the CPU's prediction algorithm fails.
Fortunately this one should be quite predictable. It is in Pool::allocChunk().
Malloc/free (which is the same as new/delete) algorithms will commonly have hundreds of branches, many of which are not at all easy to predict. My synthetic benchmark should be showing close to best case for malloc (and the alignedAlloc functions use the same algorithms).
Just posting the update.
I dug out my copy of Modern C++ Design again, and found the author's name to be Andrei, not Alexei. There seems to be some confusion here, I was sure Alexei was wrong previously, but a google search returned Alexei so that is what I wrote above.
The cover of the book has Andrei printed on it.
I'll post a fix to a nasty bug shortly: having the Singleton::instance method inlined could lead to multiple instances of MetaPool in different translation units :(
I'll have to do some research on the implications of static local variables in inline functions to be sure. The problem could still be there if the compiler decides to inline the method anyway.
The issue code is:
[code]
template
class Singleton
{
public:
static T* instance();
};
template
T* Singleton::instance()
{
static T instance;
return &instance
}
[/code]
Alexei, oops. I guess I was tired that day, I had the name printed on a book no more than 40cm from me. -_-
As for the static variables and inline functions.. I don't think it would ever be a problem. Since the object is in static-storage space, it would be impossible to compile the program if it generated a seperate additional copy per call, because it would break the ODR (One definition rule) for the linker. (Any workarounds would just be an impossible nightmare - what would their mangled link-names be?)
Local statics in inline functions are a problem when using DLL's. It will create one copy inside the DLL, and another copy for any access outside of the DLL. I don't think it's a problem anytime you are using normal static (early?) binding. So static libs and just compiling into your executable should be fine.
CYer, Blitz
Just posted a huge update. Please use this one because there was a showstopper crash bug in all previous versions.
Docs in this major revision will improve with time.
Perhaps I should make a custom non-template Singleton for this- having seperate memory management between dlls will really stink.
Updated the little stupid and synthetic benchmark too.
This version of the allocator is not designed to give fantastic results in stupid benchmarks. It is designed for much better efficiency in real-world progs.
Just made a very minor update: it didn't build with msvc.net because I'd left out one "template<>" befor a full specialisation. Both g++ and icc didn't complain.
Apparently the msvc.net preprocessor doesn't support "#warning", it tells me "invalid preprocessor command". This means my macro overloading stuff doesn't work on msvc.
lorien, please elaborate on how your memory allocator is better than the boost pool libraries.
I once wrote a custom memory allocator class based on the bulk allocator of Bartosz Milewski's 1997 classic C++ In Action. [url]http://www.relisoft.com/book/tech/9new.html[/url]
I can't provide the code as it's owned by my previous employer, but it's basically a single class encapsulating the described behaviour and templatized with an integer which tells it which size objects it can allocate.
The classes which you want to allocate space in bulk for are then provided with an overloaded operator new and delete which calls into the allocator class. This way no other code had to be changed in the 600k line code base.
However, since Boost has come up with a pool allocator library, I'd be likely to check that one before writing my own again. Particularly since it's thread safe and portable.
It's different to the boost pools. I think it's better in the ways that are important to my projects, but I'm not going to say "my code is better than boost", I'm not so stupid :)
quote:
Boost C++ Libraries
#8220;...one of the most highly regarded and expertly designed C++ library projects in the world.#8221;#8212; Herb Sutter and Andrei Alexandrescu, C++ Coding Standards
This is off the top of my head, please correct anything about boost if I'm mistaken...
The boost pools are single pools. They are not a generic allocation system like this.
The boost pools have a very roughly similar linked list structure to the one I'm using in my Heap class. The difference is the boost pools header structure for an alloc, and the alloc itself are different pieces of memory. Have a look at my Heap and Node class, the Heap allocates a single block of memory, which it splits into Nodes and Chunks (chunks are what I call the actual memory you use) using some nutty pointer maths.
The boost pools let you choose your own memory alignment. Mine is pretty well set to 16-bytes, though it can be hacked.
This allocator is designed to be an insanely fast and reasonably memory efficient full replacement for new and delete, that takes advantage of the compilers innate knowledge of the sizes of all your classes (the metaprogramming). The number of conditional branches in the allocation path is absolutely minimised.
The boost pools are designed to be special purpose allocators for particular types of objects.
My code has changed somewhat since the posts above, I think the above might have a nasty crash bug still... Will release on sourceforge when I'm good and ready, though just ask if anyone want a pre-release. It's part of a much larger low level library with a bunch of smart pointers, STL allocators, singletons, lockless queues etc, etc. Some of the guts of a realtime (low latency audio), multithreaded scripting language split out into a shared library.
One of the big differences between the code above and my current code is I'm using a thread-local singleton to hold the MetaPool class (a thread-local singleton means one instance per-thread).
Making it into a per-thread allocator means there is not a single mutex in the allocation path, and it's completely threadsafe. But you can't allocate memory in 1 thread then free it in another. This condition is asserted for. A gather a lot of JVMs use this optimisation.
This allocator puts a whole bunch of pools together in a vector. The run-time search involves iterating over the vector until the best-fit pool is found. The metaprogramming does this at compile time.
For anyone at a uni here, if you're interested in memory allocators, go to your libraries website and find the database collection. Look for IEEE XPlore and start seaching. It will bring back full journal papers talking about the issues involved in memory allocators. Maybe add "real-time" to the search too.
As far as I've been able to find this is a unique memory allocator.
The library is under the ZLib license, which is basically "do want you want with this, except don't claim you own it". Sourceforge doesn't have the boost license as an option.
Just ask if you'd like more detail, and I'm going to be talking about this at the thing La Trobe runs instead of the AGDC, which is also on Dec the 2nd. Send me a PM if you'd like an invite, and we feed you too [:)] We don't claim it's a conference, it's a chance to see some postgrad and undergrad student work and (if you want) hire some graduates. There will be people from other unis there too.
Edit: it may be dec 3, I'll check tomorrow, though plenty have invites.
Is this any good?
G'day, long time reader first time poster. I have knocked up a demo to be the core of my CV. It is 3DS viewer called GLoadX that can be found here: http://www.skullbonez.com/gloadx/gloadx.htm I would really appreciate any feedback you might have, particularly if you think it is good enough to gain employment. Not sure if it is relavent but I am in Canberra and am looking locally.
Apologies if this should have been posted in the looking for work section but I wanted the opinion of fellow programmers.
Cheers
-A-
It definately looks pretty schmik.
Though without puting it through it's paces (or reviewing code style) I dunno if it'll win you work.
To help exstoll its virtues maybe a table of feature comparison with some other viewers would help it stand out. Or maybe a set of benchmark-type results which show that this viewer handles (fixes?) 3ds files which other exporters/importers/viewers don't.
Some notes on the software design might be helpful too. If I were recruiting coders and I checked it out. I'd be looking for evidence of skill aside from functionality (who's to say u didn't just cut & paste the viewer/importer code from a couple of SDKs (like I would [:P]).
(your link has attached the '.' which has broken it).
But all in all. Cool to have something that you can use to put DX & OGL side-by-side!
gametutorials now charging
I just noticed that game tutorials are now charging $5 (us i'm guessing) a tutorial. I'm sure glad i downloaded most of them a few weeks ago [:D] They were a good start to game programming but i'm not sure they really offer that much for their money compared to what you could find for free elsewhere or even better in a book.
$5 for a win32 hello world :-/
$5 for a tutorial which will init directx and draw a triangle and another $5 if you want to color that triangle.
Not sure if you guys know that there is an archive of the tutorials maybe go get them while you can:
http://web.archive.org/web/20040109222147/www.gametutorials.com/Tutoria…
Cheers
Sam
I know what you mean, those compile errors from template meta-programming are not nice :(
What I'm working on atm is a meta-programmed memory pool based allocator- it's a container of pools, each of which is specialised for a particular size chunk of memory, and using compile time calculations to find the most appropriate pool to allocate an instance from i.e. getting rid of the run-time search.
So you get something like this
class MyType
{
public:
void* operator new(size_t size)
{
return Allocator::alloc(); //size arg not used
}
};
Of course this means that you would be in BIG trouble if you didn't overload new on every derived class. Still pondering. The pool allocator is done, it's the best way of doing the meta-programming that's taking some time.
The result should be dynamic allocation as fast as stack allocation, and I'm doing it because I'm developing a realtime scripting language where every object lives on the heap.
These accidental features are what keeps c++ interesting [:)]
Compile time polymorphism I might as well do now:
template
class Furniture
{
public:
inline void drawFurniture()
{
reinterpret_cast(this)->draw();
}
};
class Chair : public Furniture
{
public:
inline draw()
{
//actually do the stuff
}
};
How it works:
this Chair : public Furniture strangeness is called the "curiously recursive template pattern". In this case the only thing I'm using the template parameter "Chair" for is so I know in the base class that this class is actually a chair, which makes it safe to reinterpret_cast the this pointer to a Chair pointer, and call methods that are inlined in Chair.
Why would you do this sort of crazy stuff? Performance- virtual functions (and calls through function pointers) can defeat the branch prediction algorithms in CPUs, and the Prescott has around a 30 stage pipline. That means a virtual function call can be expensive. Virtual calls and function pointer calls also present problems for optimisers.
The problems with this technique are:
*Bigger code size caused by more inlining- but caches are only getting bigger
*You can't have an STL container full of Funiture pointers, because each becomes a different type due to the template parameter.
Comments please (and if someone knows how to stop sumea mangling code that would be great)
You can do lots of neat stuff with templates. A personal favorite is this,
used to allow a single base type to be used for derived templatized
types that are passed from the constructor of an object.
[code]
struct DelegateBase
{
virtual void Exec() = 0;
};
template
MethodBase : DelegateBase
{
typedef ReturnT (Object::*MethodType)();
MethodBase(ObjectT& o, MethodType ptr); // Stores method and object.
virtual void Exec() { if (m_Method) m_Object.*m_Method)(); }
};
struct Method
{
template
Method(ObjectT& o, ReturnT (ObjectT::*ptr))
: m_pBase(new MethodBase(o. ptr))
{ }
virtual void Exec() { m_pBase->Exec(); }
};
[/code]
So, this allows us to store:
[code]std::vector methods;[/code]
And still gain the benefits of having the types available when we use the
object.
These extracts from a C#-like delegate, (source available if interested)
and the interface is along the lines of:
[code]
typedef Event MessageEvent; // Takes a string.
MessageEvent OnSomething;
OnSomething += MessageEvent::Function(&PrintMessage);
OnSomething += MessageEvent::Method(Foo::GetSingleton(), &Foo::PrintMessage);
OnSomething(); // Calls Function(string), and Foo::GetSingleton().PrintMessage().
[/code]
Using the above method was required to store a list of the attached
methods and functions bound to the event, and allowing each to have
a seperate return type that is ignored. I'm sure there are many more
cases like this where the technique can be used.
I presseded the complile buttons and the compilers says mean things to me about the C++.
[edit]
But really, there are some errors/omissions in the above post.
Method's Exec() is should not be virtual.
'm_pBase' is of type boost::shared_ptr
Probably numerous that I didn't notice, the actual source works,
that's just a snip anyway. ;)
Well the meta-program is up and running, hopefully I should have the whole mempool thing working next week sometime. The meta programming has crazy stuff like this small sample:
[code]
//////////////////////////////////////////////////////////////////////
// Calculate (compile time) the number of pools required //
//////////////////////////////////////////////////////////////////////
template
struct PoolCount
{
enum { value = 1 + PoolCount::value }; //will hold the number of recursions
};
//This terminates the above loop at Size==MinChunkSize
template <>
struct PoolCount
{
enum { value = 1 };
};
//provides easy access to the compile time calculated number of
//pools with noOfPools::value
typedef PoolCount noOfPools;
[/code]
And the syntax used to allocate will be void* mem = Allocator::alloc() , and memory gets freed by an overloaded delete operator. I'll post the full code with detailed explanations (including the runtime pool) in a thread when done.
Anyone got any ideas why the "code" formatter isn't working for me?
Yeah, I wouldn't use templates all over the place normally, but in some cases (where an increase in compile time means a decrease in runtime in a subsystem that's used all the time) I think it is worth it.
Another example is the scripting language I'm making- it's completely full of template code, primarily to make it really easy to extend with new types, and to automate much of the wrapping and type conversion.
Very, very cool and free version control
Hi all,
about a month ago I discovered DARCS http://darcs.net and I've been using it solidly ever since. It blows every VCS I've used out of the water except for BitKeeper, and BitKeeper is EXPENSIVE.
DARCS is changeset based, has atomic commits, has good merging capabilities, can work over SSH, works on unix and win32, etc, etc, etc. It is also very simple- despite the being command-line driven.
Every time you check out a working copy you actually get your own copy of the repository, meaning you can commit broken things to your local copy and they won't affect anyone else. You can then merge this local repository with a central repos to give others access to your changes. Every checkout creates a branch.
If you are using CVS, Subversion, SourceSafe or Perforce I suggest give it a go, I think you won't want to go back :)
The only issue I have with it is it isn't so great for binaries: it doesn't store binary diffs, but the whole binary every time :( So not so great for art asset management.
I have nothing to do with DARCS development, I've just been using it.
Binaries for lots of platforms are available from here http://www.scannedinavian.org/DarcsWiki/CategoryBinaries
Sounds interesting, might give it a looksee - reading the manual of features, it looks alot like subversion though (subversion has true atomic commits.. and such.)
The local commit sounds promising though, both possibly a benefit and a bane - Not having consistant versions across multiple clients and server could get a bit nasty when commits start to occur - how does the merging get handled with multiple clients committing their largely changed local copies (yes each is atomic, but resolving merges on large local changes would be a little nightmarish)? Would this mean youd have a list of client based branches that would now be in the repository?
That would be my only problem, Im a big fan of subversion with its more strict client/server design. But, I like the idea of a local repository - local versioning control would be handy. Would also be nice to have binary diffs too, currently we have all our projects data and source together in the one repository.
It is nothing like subversion (or CVS). It's much more like BitKeeper or GNU Arch.
How you avoid that sort of mess is by updateting you local copy regularly from a central repository, but I haven't looked into that side of it (yet), I've only been using it on my own.
However BitKeeper manages to handle all the crazy amount of work the thousand-odd Linux kernel developers throw at it, and it uses the same "everyone gets a local repository" model. It just takes really smart merging.
The branches are very different to normal too, every checkout creates one. A commit is a patch against the whole repository, and they are identified by what I think is a 128-bit random number.
You can also pull in changes from other people's local repositories, and because the repository is made up of uniquely identified patch files it won't cause too many problems.
The ataomic commits in darcs come about because of this "commit == single patch file" system.
All I can suggest is try it out. I keep a repository on my home machine, on a master server at home, on my USB key drive, on my work/study machine at uni, and on a master server at uni, and I've had no problems at all keeping them all in sync.
I don't think I'm about to loose any work with that many backups [:D]
BitKeeper is free for open-source projects btw, though it seems a little too much like spyware for my taste.
Hey lorien - big thanks. I have been using darcs for serving / controlling our current game project to my lappy (my main repository now works on darcs and cvs - cvs is required because thats what the US people require). So I have been able to do a darcs get from my home server and do a push we needed to update, and it works flawlessly. The only problems I had with it, was when initially setting up the repository. Some of the binaries I had lying around in some folders caused it to bawk badly - once I found them and commited only what I needed, it has worked flawlessly since.I also realise too, that the binary thing was my fault, since the docs state you should specify binary types in the binary file in the repository.
The plusses over subversion are great - the local patching idea works so well. I also like the autopatch generation and emailing (very handy for team projects). Even the checking and repairing worked quite well (I intentionally damaged some of the repository to see whether it was intelligent enough to fix it :-) ).
Im also working on a specific front end for window for darcs - why? Well, I figure this is an _ideal_ system for art, design and code versioning. The only problem is getting a designer or artist to use another command line tool :-) .. so a pretty interface will hopefully help it get some decent usage with people who dont have time to learn new command line tools. I will post it when it gets completed, might be useful - it is intended to be pretty transparent to use (think alienbrain usage).
I have now switched the majority of my gear over to darcs, and wish to thank you lorien - this is a gem.
Yes, my own cross platform gear (since a simple lightweight UI with the components I wanted just isnt available :-) ). Will be using LuaGL that I have posted on Adelindie. Its just Lua+OpenGL + a little UI system I am building - being script its all nice rapid dev, and easy to modify (personalise?). I was even thinking of using a html/xml style display system - thus people can use their fave web builder to make a UI component - will see, the base set of gadgets are nearly complete, then its a matter of data... All operations for darcs will be through script, thus completely adjustable to suit the deployment.
Oh, and it all runs in OpenGL because I wanted something that had a completely consistant interface across platforms, without the hassle of various libraries (like the various toolkits available) and maintaining them and their compatibility. Also, there is an advantage in game development too :-), I plan to build an RPG type D&D game starting sometime in June...
My demo screenshot!
Hi,
I've only recently noticed much of the functionality of
Sumea since before now it was a trip to the cybercafe.
This is a screenshot of my game demo featuring BSP,
collision detection and texture mapping. There is no
animation yet, and it is a test scene so Artists feel
free to snort at the graphics!
I'm not sure of how the rules go with pixeltown, but
I'd quite like to design a little plot there [8D]
[img]icon_paperclip.gif[/img] Download Attachment: [url="http://www.sumea.com.au/forum/attached/WiffleCube/2004122072938_screens…"]screenshot.JPG[/url]
48.27 KB
Your screenshot looks interesting. BSP can be a difficult beast to master! So I?m guessing that your loading bounding boxes and getting successful collision detection?
So what engine are you using (or writing your own)?
Anyway, pixel town is now full, but the current activity is pixel class: [url]http://www.sumea.com.au/forum/topic.asp?TOPIC_ID=2211&whichpage=1[/url]
quote:Originally posted by palantir
Your screenshot looks interesting. BSP can be a difficult beast to master!
I had particular trouble to start with by setting tolerance
values too high, resulting in non-terminating BSP division.
It works fine now.
quote:
So I?m guessing that your loading bounding boxes and getting successful collision detection?
The player avatar has an ellipsoidal bounding volume checked
using a simple distance to player origin. This is checked
against the BSP tree of the scene. Collision detection works
great, and even has a 'bounce back' feature.[8D]
quote:
So what engine are you using (or writing your own)?
It's written from the ground up using C++ and DirectX. My
rationale is that once I've written a game from the ground
up, only then will I be entitled to use 3rd party engines.[:p]
I'm currently working on animation and there is scant
documentation to be found. I'm waiting on a book to
come from Amazon called 'Advanced Animation with DirectX',
which might help demystify skeletal animation with bones.
In the meantime there is a bitmap library to be written
for putting up consoles etc.
I've also written a rough UML for message parsing:
MessageUser and MessageQueue. This is the 'observer'
pattern I think.
An agent inherits from MessageUser and has a Brain
and an AnimationDatabase.
More to follow. [:p]
A Simple Framework for Animated Models
I'm trying to work out a simple structure for holding and sending
animation frames i.e. a mob - mobile object.
Here's what I've come up with so far, any ideas would be appreciated:
Basic animation with perhaps interpolation of vertices would be a good start.
The docs seem scant on the .x animation format but I'm persevering. The
idea is that the scenery is BSP (implemented), then movable and mobile
objects are not.
The mobile objects need to be animated. Here is my plan:
Frame: 0 1 2 3 4 5 6 7 8 9 10
Say do <0,1,2,3> for state: walking.
<4,5,6,7> state: melee fighting.
<8,9,10> state: firing gun.
Each set would loop around. I'm not sure of how interpolation features
are accessed yet, but it would be good to interpolate between frames.
Skeletal animation would be good, but as this is my first venture into
3D games perhaps I'll leave it for the future. My main obstacle at the
moment is digging the animation information out of the .x format.
the text mode of .x format with animation enable in the export (and frames/bones enabled) was just a matrix for each frame/node per keyframe... (when i wanted to read this, a simple text parser was sufficeint)
for what you are describing (a series of 'statue' animations) you could just have a .x file of the geometry for each frame, and 'lerp' between two of these geometries for the current animation. perhaps having a custom vertex format with seperate vert_translation into which you can place the 'lerped' vert pos (the uv info wouldn't change, and would be tempted not to change the normals either, just leave them in the original object space, since if it is animating, you may not notice them not reorientate--- movement covers a lot of things)
hope some of that made sence
quote:Originally posted by davidcoen
the text mode of .x format with animation enable in the export (and frames/bones enabled) was just a matrix for each frame/node per keyframe... (when i wanted to read this, a simple text parser was sufficeint)
for what you are describing (a series of 'statue' animations) you could just have a .x file of the geometry for each frame, and 'lerp' between two of these geometries for the current animation. perhaps having a custom vertex format with seperate vert_translation into which you can place the 'lerped' vert pos (the uv info wouldn't change, and would be tempted not to change the normals either, just leave them in the original object space, since if it is animating, you may not notice them not reorientate--- movement covers a lot of things)
hope some of that made sence
Yes it did, and thank you.[:)]
I've been haranguing people on flipcode for close to a month for that info. So I'll make a new vertex structure with a 'scratch' vertex which is constantly changing according to where it is in the lerp. Great. And I'll be able to get the frames from the .x file.
The animation framework for DirectX is there, but docs are scant (I've been searching everywhere). I'm not sure how to access the lerping functions (although I know they exist). I'm hoping the animation using this method will emulate Thief I, using ellipsoid collision objects for humanoids. If that would require more than this method (e.g. skeletal anim.) then i'll stick with this.
EDIT: There is a screenshot of the demo in General Discussion.
Best Regards,
WiffleCube/Heddwyn
Half-Life 2 Mod - Looking For Programmers
Blades of Blood: The Foretold Ninja is looking for more programmers currently I am the only one.
Any experience with mods or experience in C/C++/C#/Java are the types of coders I am looking for.
Thanks
I have experience in some java and c/c++ most of my experience is in Visual Basic .NET and C# .NET. I have not currently been in any mods that stayed alive sadly each one I have joined have had horrible leaders. Now I am the leader and I don't plan on stopping the mod for any reasons.
There is about 10 or more people that are currently on the mod.
We should have our website complete this weekend I have yet to hear more news on it.
The Story is still in the works but it's based in Feudal Japan with traditional Samurai and Ninja.
If you would like to read basicly our whole rough layout of the mod then go to:
http://halflife2.filefront.com/news/;10349
Thanks for your interest
hmm read into your mod, found it quite interesting as i was considering writing a thief-style game with more complex swordfighting recently using openquartz or something.. dont have any experience with HL/HL2 modding myself, but have done quite a lot with openquartz, tribes, tribes2, etc.. will look into it sometime once i bother to get my hands on a copy of HL2
normals
I'm using the left handed system here
----2
---/---/----/-----1_______0
When creating the vectors from the vertices my sketchy research has found two different ways.
(p1-p0) x (p2-p1) This produces a normal -z (guess)
or
(p1-p0) x (p2-p0) This produces a normal +z (guess)
Hmmm ok, so i guess my question is what are normals used for? And do i want +z or -z.. or would you use both +z and -z for different things? Also, are either of the above equations right or wrong?
I really don't know what i'm talking about here so any help is appreciated.
a normal vector is the vector that is perpendicular to a surface. so, it basically describes which way a surface is pointing, which as davidcoen mentioned is very useful for lighting, especially when used something like normal mapping, can give the illusion of a complex surface from a simple surface. (basically, you have a texture with all the normal information, which can be applied to a surface)
Yea i'm pretty sure i understand the concept behind it but i was having trouble choosing the right vertices to create the vectors. I was getting confused with the "winding order". Tutorials were saying it's important which order you choose your vectors, but i think it's the order which you set your vertices, clockwise counter-clockwise (at least with the example i was working with).
One tutorial i read from gametutorials.com said
quote:The winding order of the vertices determines how you want to create your vectors. If you winding order is clockwise, you want to create your vectors so that the head of the first vector touches the tail of the second vector with a clockwise turn and then cross the second vector with the first.
And then subtracted like this, p1-p0 and p2-p1. From what i gather it seemed to work. Yet everywhere else that i've read they subtracted from the one point e.g p1-p2 p3-p2.
I guess that's where i was getting confused, i think i've got it sorted now.
Thanks for the help though [:)]
quote:Originally posted by Daemin
It just depends where you want the normal to "face". As if you create the normal with the reverse winding order it will point in the opposite direction. Therefore it's just a matter of figuring out which direction you want to be the front face for the triangle.
...and then keeping that consistent throughout the whole world data.
quote:Originally posted by Triton
[code]
----2
---/---/----/-----1_______0
[/code]
When creating the vectors from the vertices my sketchy research has found two different ways.
(p1-p0) x (p2-p1) This produces a normal -z (guess)
or
(p1-p0) x (p2-p0) This produces a normal +z (guess)
Hmmm ok, so i guess my question is what are normals used for?
Sorry for the kindy tute to all the gurus, but hopefully it'll explain something useful.
Well, in nice, simple cartesian (x,y,z) space, the cross product gives you a vector orthogonal to (at 90deg to) the two crossed vectors. If the two crossed vectors are already orthogonal, then the cross product gives you what's called an "orthogonal set" of vectors - ie: they're all orthogonal to each other. An 'n'-dimensional space requires 'n' orthogonal vectors to identify any point in it.
Now, any two vectors (*except two collinear ones) define a plane. The 'normal' to the plane (defined by the two vectors) is the cross product of those vectors.
This means that the normal is just the vector orthogonal to the two vectors you've chosen. In a triangle (the bread-and-butter of 3d graphics for this very reason) you have three vertices (0,1,2 in your diagram), hence three vectors clockwise (p1-p0 , p2-p1 , p0-p2), or three vectors anti-clockwise (p2-p0 , p0-p1 , p1-p2). However, the very concept of clockwise or anti-clockwise means that the triangle/poly you're talking about has a 'front'. The convention is that the normal should also point toward the 'front'.
So, two very simple cases in which it's used:
1) Flat shading. Take the normal generated by the two vectors attached to any vertex, and use that to work out how much light from our light source is reaching that face. Change your colour accordingly (i'm white, but 50% of red light is reaching me, I'll look pink)
2) Backface culling. If i'm looking at a polygon, and the normal is pointing 'away' from me, then I'm looking at the back of the polygon. In most cases, models are built so that backfaces can't be seen (ie: they're inside the sphere/helmet/orc), meaning that there's always a corresponding front-face which will be drawn over the back face. Hence, it makes your rendering faster because you don't need to do all the lighting calculations for back-faces.
Now, "normal maps" and the like are simply ways of saying "you think the normal here is blah, based on the polys, but I want you to pretend that the normal is actually like this. ie: pretend this nice big flat bit is actually pitted like a dried lemon skin. This affects the lighting, and hence the cool facter that we all want.
Please, feel free to correct me gurus :)
Mini coding competition
Yes, it's time for a mini coding comp, and for this one there is a prize! I have an unopened copy of Full Spectrum Warrior for the Xbox (you can trade it if you don't have an Xbox), which will go to the winner. Watch this space for more details!
Ok, here's the challenge: Demonstrate the best use of the STL. This will be in the form of a simple program that does a small task while taking advantage of the STL. Here is an example that reads white-space delimed input into a vector:
[code]
#include
#include
#include
#include
using namespace std;
int main(int argc, char** argv)
{
// variables used
vector output;
// push back strings from cin, splits on whitespace
copy(istream_iterator(cin), istream_iterator(), back_inserter(output));
// output to screen
copy(output.begin(), output.end(), ostream_iterator(cout, "
"));
// wait for user to hit enter before closing
cin.clear(); cin.get();
}
[/code]
Programs will be judged on code size (smaller is better), code elegance (keep it clean), and functionality (more bang for your buck). Entries close midnight 31st of December. You may have up to 2 entries. At this point, it will just be me judging. What I say goes.
I put a thread up in the competition section for entries.
http://www.sumea.com.au/forum/topic.asp?TOPIC_ID=2575
It was mentioned that it's not actually a programmer challenge,
but I don't know how to delete the thread. Oops!
Here's a quick one to get the ball rolling, a simple replacement for the standard STL sort algorithm:
[code]#include
#include
#include
#include
using namespace std;
template void merge_sort(T &data, P predicate)
{
T::size_type size = data.size();
if(size == 2)
{
// A single pair, put them in order
T::iterator a = data.begin();
T::iterator b = data.begin() + 1;
if(predicate(*b, *a)) swap(*a, *b);
}
else if(size > 2)
{
T::size_type mid = size / 2;
// Split the data into two halves
T a(data.begin(), data.begin() + mid);
T b(data.begin() + mid, data.end());
// Sort each half individually
merge_sort(a, predicate);
merge_sort(b, predicate);
// Combine the two sorted halves
merge(a.begin(), a.end(), b.begin(), b.end(), data.begin(), predicate);
}
}
int get_random_int()
{
return rand() % 100;
}
int main(int argc, char **argv)
{
static const int size = 20;
// Generate a random unordered data set
vector data(size);
generate_n(data.begin(), size, get_random_int);
// Test our Merge Sort
merge_sort(data, less());
// Display
copy(data.begin(), data.end(), ostream_iterator(cout, " "));
cout << endl;
return 0;
}[/code]
To me the best thing about STL is that it gives you a reliable base on which you can easily experiment with different ideas. It abstracts you just enough that you can concentrate on optimising what's really important, the algorithms rather than individual lines of code. I went for easy to read but my first performance modification would be to make it sort in place to reduce the amount of array copying going on in each recursion. After that I suggest changing to a different algorithm, haha!
- Clean easy to read code.
- All trivial tasks covered by standard STL components.
- Works with any container providing random access iterators.
- Works with any type your predicate can compare.
I tested this briefly on VC++ .Net, apologies for any bugs or incompatibilites.
quote:Originally posted by kalin
I put a thread up in the competition section for entries.
http://www.sumea.com.au/forum/topic.asp?TOPIC_ID=2575
It was mentioned that it's not actually a programmer challenge,
but I don't know how to delete the thread. Oops!
BALETED!
Here is an example that reads words from a file into a set (which is sorted) and outputs them to the screen.
[code]
#include
#include
#include
#include
#include
#include
using namespace std;
class Word
{
private:
string chars;
public:
friend istream& operator>> (istream& is, Word& ch );
operator const string& ()
{
return chars;
}
bool operator < (const Word& rhs) const
{
return chars < rhs.chars;
}
};
istream& operator>> (istream& is, Word& w )
{
w.chars.clear();
// dump non-alpha chars at the begining
while (is.good() && !isalpha(is.peek()))
{
is.get();
}
// get all the alpha chars
while (is.good() && isalpha(is.peek()))
{
w.chars += is.get();
}
return is;
}
int main(int argc, char** argv)
{
// variables used
set output;
ifstream fin((argc > 1) ? argv[1] : "input.txt");
// insert Words from file stream
copy(istream_iterator(fin), istream_iterator(), inserter(output, output.begin()));
// output to screen
copy(output.begin(), output.end(), ostream_iterator(cout, "
"));
// wait for user to hit enter before closing
cin.clear(); cin.get();
}
[/code]
edited:
BALETED!
...I mean fixed closing code tag
Here is a simple file copying program.
Usage: "copy output.ext input.ext"
I'll probably try and think up something more complicated later,
but this is a nice simple example of how nice STL is to work with. :)
[code]
#include
#include
int main(int argc, char** argv)
{
if (argc >= 3)
std::ofstream(argv[2]) << std::ios::binary << (std::ifstream(argv[1]));
return 0;
}
[/code]
Okay, here's one. It does a search and replace on a given text file:
[code]
#include
#include
#include
#include
#include
using namespace std;
/*
redwyre's mini coding contest
Usage:
replace
Replaces all occurances of with in
*/
ofstream fout;
void putwords(string s)
{
// Put words into file
fout << s + " ";
}
int main(int argc, char **argv)
{
list words;
ifstream fin;
string s;
if (argc < 4)
{
cout << "Usage: replace " << endl;
return -1;
}
// Open file
fin.open(argv[1]);
if(!fin)
{
cout << "Couldn't open file " << argv[1] << endl;
return -1;
}
// Read all words into list
while(!fin.eof())
{
getline(fin, s, ' ');
words.push_back(s);
}
// Close input file stream and open output file stream
fin.close();
fout.open(argv[1]);
if (!fout)
{
cout << "Couldn't open file " << argv[1] << endl;
return -1;
}
// Replace oldstring with newstring
replace_copy(words.begin(), words.end(), words.begin(), string(argv[2]), string(argv[3]));
for_each(words.begin(), words.end(), putwords);
fout.close();
return 0;
}
[/code]
To submit your entries, feel…
To submit your entries, feel free to post them here, but make sure you send them to me via email: xxx with the subject starting with "[Sumea]" I'll try and get everything sorted and announce the winner before the end of January.
[code]
//cache invert sqrt class and testbed
#include
#include
#include
#include
typedef float real;
typedef signed int s32;
typedef unsigned char u8;
struct TCommonCache_InverseSqrt
{
bool operator()(const float lhs, const float rhs) const
{
return (lhs < rhs);
}
};
class CCommonCache_InverseSqrt
{
public:
~CCommonCache_InverseSqrt(void);
bool Clear(void);
bool GetInverseSqrt( const real in_square, real & out_root);
private:
typedef std::map< real, real, TCommonCache_InverseSqrt> TRealRootMap;
private:
TRealRootMap m_root_map;
};
CCommonCache_InverseSqrt::~CCommonCache_InverseSqrt(void)
{
Clear();
return;
}
bool CCommonCache_InverseSqrt::Clear(void)
{
m_root_map.clear();
return true;
}
bool CCommonCache_InverseSqrt::GetInverseSqrt(const real in_square, real & out_invert_root)
{
TRealRootMap::const_iterator iterate;
real root;
bool ok;
ok = true;
if (ok)
{
ok = (0.0F <= in_square);
}
if (ok)
{
iterate = m_root_map.find(in_square);
if (iterate == m_root_map.end())
{
if (in_square == 0.0F)
{
root = 0.0F;
}
else
{
root = sqrt(in_square);
}
if (root != 0.0F)
{
out_invert_root = (real)(1.0F / root);
}
else
{
out_invert_root = 0.0F;
}
m_root_map[in_square] = out_invert_root;
}
else
{
out_invert_root = iterate->second;
}
}
assert(ok);
return ok;
}
s32 main(s32 argc, u8 ** argv)
{
CCommonCache_InverseSqrt invert_sqrt_cache;
real input_number;
real invert_sqrt;
bool loop;
printf("CCommonCache_InverseSqrt testbed: David Coen 041230
");
loop = true;
while (loop == true)
{
input_number = 0.0F;
printf(" please input a number (zero to exit)
");
scanf("%f", &input_number);
if (input_number != 0.0F)
{
invert_sqrt_cache.GetInverseSqrt(input_number, invert_sqrt);
printf(" invert square root is %f
", invert_sqrt);
}
else
{
loop = false;
}
}
return 0;
}
[/code]
quote:Originally posted by davidcoen
[code]
bool CCommonCache_InverseSqrt::GetInverseSqrt(const real in_square, real & out_invert_root)
{
TRealRootMap::const_iterator iterate;
real root;
bool ok;
ok = true;
if (ok)
{
ok = (0.0F <= in_square);
}
if (ok)
{
iterate = m_root_map.find(in_square);
if (iterate == m_root_map.end())
{
if (in_square == 0.0F)
{
root = 0.0F;
}
else
{
root = sqrt(in_square);
}
if (root != 0.0F)
{
out_invert_root = (real)(1.0F / root);
}
else
{
out_invert_root = 0.0F;
}
m_root_map[in_square] = out_invert_root;
}
else
{
out_invert_root = iterate->second;
}
}
assert(ok);
return ok;
}
[/code]
A little constructive criticism. There are a few ways that I think you can improve your code.[;)]
After performing the following steps:
- remove unnecessary variables and redundant checks
- use ternary operators where appropriate
- use a tolerance value (EPSILON) when comparing floating point numbers to avoid precision errors
- a little re-ordering
- recognise that it always returns true and make the function void
- add comments!!!
The code above appears to reduce to:
[code]
void CCommonCache_InverseSqrt::GetInverseSqrt(const real in_square, real & out_invert_root)
{
TRealRootMap::const_iterator iterate;
// assert that a real root exists
assert(in_square > EPSILON);
// some comment
iterate = m_root_map.find(in_square);
// some comment
if (iterate != m_root_map.end())
{
// some comment
out_invert_root = iterate->second;
}
else // some comment
{
// output inverse of root
out_invert_root = (real)(1.0F / sqrt(in_square)));
// set inverse value of root in map
m_root_map[in_square] = out_invert_root;
}
}
[/code]
The EPSILON checks may be unnecessary if the "real" class (template?) handles precision checks (I wasn't sure, I usually code in C).
Update: I got rid of a ternary operator and the check that the root is valid. If in_square is greater than a well-conditioned threshold (EPSILON), the root should be valid... I think that this is a reasonable assumption...
Tell me whatcha think
Hey guys, new to the forum and only discoverd it yesterday, looks like ive been missing out on the fun. SO rather than posting asking for help or something. i've decided to share my first born
[url]www.crapagotchi.cjb.net[/url]
hope you enjoy. and btw ive just finished first year(of 2) in diploma in software engineering corse in NZ, this was one of my final projects.
im trying/learning to be a geek. i promise [8D]
~ cheers
p.s it is writtin in C so dont bust my balls 2 hard :P
DirectInput Questions
Just a quick question about DirectInput.
Has it changed much since DirectX 8? The reason I ask is I am unsure whether to learn from a book I have that uses DirectX 8 or from newer Internet based tutorials.
Help! How to make application programming demo?
I have applied for a job at Torus, and Wendy is asking me to send her a Demo of my Programming work
HOW DO I DO THIS?
I have only worked on Mod Projects before, and have just started to lead the ZHLT 3.0 team - www.ammahls.com - how ever i have complted the Dip Of Software dev (Java) at north sydney TAFE
Any tips?
I have made mapping demos before, but this was basicly a rip of my website on cd-rom
Adam
Ludumdare 48 on again
Im sure most of you already know.. but if you didnt:
http://www.mechanicalcat.net/tech/ld48/
Come join in :)
Its on the 15th - wich according to the front page is Jacanas bday ;-) (happy 28th!)
Timing that code!
Yet another 'Steptoe and Son' shoestring-budget software tip:
Remember programming the Z80/6502 where you could time code easily by changing the border colour when your code was executing?
Well, there is an instruction on pentium+ class processors that can be used to count how many cycles your code takes; RDTSC. It's pretty good
alternative to using an expensive profiler, although it doesn't take into account things like graphics cards that process concurrently.
Here is the general idea, you can find code on the net:
__int64 gstart, gend; // 64 bit integers i.e. LONG LONG
int gcycles;
void StartTimer()
{
_asm
{ do a cpuid to reset processor.
rdtsc
store result in gstart;
}
}
void StopTimer()
{
_asm
{ do a cpuid to reset processor.
rdtsc.
store result in gend.
}
gcycles=(int)(gend-gstart);
}
void main()
{
StartTimer();
....yourcode
StopTimer();
cout<<"Cycles taken"<
Forgot to mention.. you may get slightly different results each time you take a measurement... this is due to other processes being executed.
As an aside, the MVC++ inline keyword is not just syntactic sugar. During
disassembly I found that taking it out causes a function to be 'called' whereas leaving it in puts it straight in the execution flow.
For timing code on Windows computers just use the built in high resolution timer, it's that simple. And you're using __int64 there which is IIRC a Visual Studio keyword, not a GCC one.
It might be useful for Linux and other operating systems running on x86 hardware. However generally now I try to stay away from doing assembly stuff in my programming, it really isn't worth the effort for anything more than a consoles.
Yeah, you can just use QueryPerformanceCounter etc. on win32 systems and that way you don't even need to do any checks to see what the CPU is, the Query function will just fail if the CPU doesn't support it.
But anyway, the benefit of using expensive profilers is not the timing, but they usually give you nice information on a function by function basis for the entire program, without having to insert any additional code in your program. At least thats what i read/hear :P
"As an aside, the MVC++ inline keyword is not just syntactic sugar. During
disassembly I found that taking it out causes a function to be 'called' whereas leaving it in puts it straight in the execution flow."
Yup, thats what it's supposed to do :P
And "inline" is a C++ keyword, not MSVC++ specific...
CYer, Blitz
It's good that you can do that wrapped up in a call. Didn't know it existed, or how it's implemented. If it clears the pipeline beforehand it'd be useful for measurement, but if it
leaves stuff there then the code your trying to tighten up might be measured inaccurately.
I wouldn't advocate writing everything in assembler, but timing allows different C++ approaches
to be compared for e.g. cache coherency etc.
On the subject of the 'inline' keyword, of course it's a standard C++ command, as is 'reg', but depending on your compiler they may or may not do anything. In MVC++ with optimisation turned on forgetting to inline code sometimes still results in a call-which is quite surprising. Probably some flag settings I missed.
There are compiler options in vc++ to turn inlining on/off (should be under c/c++->optimisation->inline function expansion). The inline keyword itself is only a hint to the compiler anyway, the compiler can still choose to not inline code that you have specified as such.
"In MVC++ with optimisation turned on forgetting to inline code sometimes still results in a call-which is quite surprising. "
Are you talking about code that you have implicitly inlined by defining it inside the class declaration? If so, then it's probably a case of what i stated above, compiler decided the function wasn't worth inlining. If it's a function defined outside the class, then afaik VC++ will never inline that code unless you give it the inline hint...
You can use the MSVC++ specific "__force_inline" directive to give the compiler a very strong hint that you want certain code inline.
CYer, Blitz
There is one case I know of where inlining actually made the code go slower :) It was under the BeOS, running on a bebox with 2xPowerPC 603e processors - the L1 cache was something like 16K for instructions. It turned out that what was happening was that by inlining this particular function (which was (A) long and (B) had been used in many other parts of the code) it forced a loop to bloat to well over what would fit in cache, hence lots of cache misses :) (The program was calculating Pi or some equally nerdly pursuit...)
Ah now there was a cool case mod that was ahead of its time (the LEDs on either side of the case showed the processor load):
Regarding the RDTSC instruction, you need to remember that it might not work as intended in multi-processor environment. For that you'll need to keep track which CPU is executing the RDTSC instruction. Also, there is a chance that some OS' don't allow the execution or RDTSC, which causes the CPU to triggering an exception.
Novadex Rocket physics demo download
This was mentioned in the [url="http://www.sumea.com.au/forum/topic.asp?TOPIC_ID=897"]Games Engine listing[/url] a while ago but I've noticed that the Novadex Rocket demo has just been available as a download for just over a week.
I'm sure everyone loves watching examples of funky physics simulations, but this demo takes the cake! 45 physics demos, with tonnes of other knobs and gadgets to push... Building blocks made up of hundreds (or thousands!) of pieces collapsing or exploding, throwing objects onto grass, tonnes of ragdoll bodies falling down steps, cars running over ragdolls, animal and insect ragdoll, gears, cloth and matresses, dominoes etc.. You can throw objects at the scene at any time, and pick most things up and swing them around.. it's great! Check it out! [url="http://www.novodex.com/downloads.html"]NovodeX Rocket[/url]
Text Based Adventure Games
Hi people,
I've made a concsious decision now to get into games development as a career path. Im currently doing a TAFE Diploma of Software Engineering and after this i'll hopefully get int a Uni/AIE course for games.
Unfortunately my course only covers java, VB6, Javascript, Asp and DHTML programming/scripting.
So last night i decided to start teaching myself C++
Luckily its not too diff from java, in concepts anyway, i like it a lot better so far too. ANyway, i've decided my first decent C++ project will be a text based adventure game, like one of my old fav's, THGTTG (hitchikers guide).
Has anyone here completed a game like this?
Im interested in knowing
a) How long it took you to complete the game, inc details about design stage, code stage, debug stage, etc
b) how experienced you were when you wrote it
c) What langauge you wrote it in
d)Some good online resources for this kind of thing
e)Any tips, information, etc you would like to share with me
Thank you !
The longest part of writing a text-based adventure, is going to be creating the game data, not the engine.
Provided you design the "engine" to be generic enough from the beginning, you should be able to code it early on, and spend the remainder of your time creating game data (without the need to go back to the code and add features etc).
You could easily code this game in C++, although I can't see there being too many levels of abstraction / classes etc in a text-based adventure.
I haven't played THGTTG, so I'm not sure what that was like. What sort of "feel" are you going to give this text-based adventure? Will it be the classic "room"-style adventure, where each room has a description, a number of exits, some items etc? That system becomes quite easy to represent: Have a class for a room, which contains a linked list of exits, a linked list of items, a linked list of opponents etc. You'd probably create classes for each of those things, too (exits, items, opponents - exits could simply be a pointer, though).
It wouldn't be unrealistic to store the entire world in memory, along with each item etc.
There's bound to be quite a bit available on the web - if you're going with the room-based system, MUD's (Multi-User Dungeons) are on a similar path, although their source is likely to be overly complex dealing with the multiplayer issues.
Advice for a simple runtime please
I'd very much appreciate any advice from programmers to help me out with the following...
I had an enquiry from a person involved in Formula One sponsorship. This person would like to use a simple application to show potential sponsors how their cars will look painted in different combinations of liveries etc.
Does anyone know of an easy to use off-the-shelf runtime that would be suited for this purpose, basically all that's required is that the 3D model can be loaded and then rotated and zoomed.
Thanks,
Chris
What file format is the model saved in?
I'd love to help but unfortunately any simple run-time I could create at the moment would only be able to read my own custom xml format. Haven't gotten to looking at supporting 3rd party formats yet.
Also another downer is that my engine can only render triangle strips with a single opengl material, no texture's as of yet.
That's probably a bit limiting for you.
Thanks,
Stephen
Hi Stephen,
Thanks for the input, I would prefer something that could use .xsi format if possible.
Something like ATI's normal map viewer is the type of thing I'm after, it'd probably do the job if it supported environment mapping.
Edit: I just found this http://www.quick3d.com/index.html and tried it out, looks like the type of app I was looking for.
quote:Originally posted by Souri
Are they using lightwave objects/scenes by any chance?
I think the site said that Lightwave file support was currently in the works.
I downloaded the 4x4 model to try and I wasn't too impressed with the framerate after bumping up the texture resolution, (I ran it on a high spec machine) especially since the model was only 12k tri's.
oops, I meant are you/your client using lightwave. And I just missed the bit where you said .xsi [:)]
Hemiware had adjusted their serenity engine into a viewer for a client. It loads a lightwave scene (animations and all) and renders it in realtime. So if your scene was a camera fly through or whatever, that's what the engine would render. I had a look and it's pretty cool, and it would seem perfect for you, apart from the fact that I don't think SoftImage files are supported.
Well, as a matter of fact my current system does already do alot of what you need. Could also easily add UI to select between the different decals and such. All of it runs in script, so there is no need to recompile or build the exe to add features. I dont support XSI at the moment, but I think I can provide it (I have an old XSI exporter I worked on a few years ago) if you really need it - would only be a day or two to add. I would however, obviously charge for use of the engine.
If you are looking for a free option - try out Nebula 2 or Nebula. Its totally free, and there are viewer scritps already available for it. It shouldnt take more than an hour to get a car doing what you want in it.
Hope this helps.
cylinders from planes
i had an idea, not sure if its been implemented yet but it goes much the same way as using a sprite to represend a sphere,,
using a rectangular plane that always faces the camera with a normal map to represent its roundness and a scrolling texture if needed.
you could represent all sorts of cylinders with this kind of technique,, ie hundreds of lamp poles in cities, tree's, etc, anything cylindrical..
if this has already been done then im behind the times,, has anyone the knowledge as to whether this is more or less ecenomical?
That's a pretty good idea, I haven't heard of it being used like that before, but someone else has probably thought of it :)
I'm not sure if it would be worth it though... you only need ~6 triangles to make a thin cylinder, vs the extra overhead of normal mapping and processing to work out the 4 points based off the 2 end points (which would probably need special casing, adding bloat to the pipeline).
It would probably be easier just to create the lamp post using ~50 polygons with a texture or two rather than making a sprite (which it is). That is on current/newish PC technology, however on the consoles this still might be a good idea, however I don't know how expensive normal/bump/displacement mapping is on them. I would imagine quite expensive on the PS2.
i would love to be goon enough to make a simple test to benchmark this,.
i guess the construction of the plane per frame would be a bit much. esp for multiple adjoining segments. even so !! i love the thought.
even if its not good computational wise i would still like to see if it has any benefits over regular cylinders, beauty wise.
Just throwing thoughts around, but you could probably make it so you didn't have to do any re-calc per frame. Instead, you'd write a tool to pre-calc it all before hand, and store it in you map file (etc). Anyhow, if you were to create the normal and displacement maps so that the one image contained the pixel information for the full 360 degrees, you could apply it to the plane in an environment-mapping sort of way (heh, real bad explanation there).
Basically what I'm getting at, is that only a portion of the entire texture would be mapped onto the plane at one time, and this portion would differ, dependent upon the direction of the vector from the camera to the plane. That way there'd be no major per-frame calculations, and the effect could be pulled off quite effectively (I think).
This would only work for objects that are uniform around one or more axes, but then it would break down if we were looking at it from above or below...
Also I don't know how well it would blend from polygonal geometry to this sprite based one...
Although using a displacement mapping technique like this could be applied to make voxel type landscapes in games now I reckon. I think the game Perimiter does something like this...
you couldnt use a sprite for this as looking at it from above or below hanges the shape of the object
it would be a polygon rectangle that rotates around 1 axis so that it is always perpendicular to the viewer
there would also be the overhead of making the algorithm connect the edge vertices of a multiple segmented cylinder ie something that isnt straight like a lightpole or a torus
This is kind of similar to what Phong shading does. The reason Phong shading isn't widely
used for real-time graphics is because it's computationally expensive to recompute so many
normals; one of the reasons polygonal/boundary representations (B-Rep) are used is because
it is relatively cheap to fling them onto the screen.
Theoretically you could make a set of stairs out of a single rectangle using bump-mapping,
but it would be a lot neater and computationally cheaper to use a bunch of different sized
boxes welded together instead.
The two main things (apart from hubris and opportunities for laziness)to be at the front
of the mind of a programmer when designing algorithms are 'How much does it cost in terms
of time/storage compared to another method?'. Most algorithms courses will leave you with
these notions firmly burnt into your mind!
Don't we already have something like this in the coder section of Sumea?
Why not add the links there instead, or haven't you found that feature yet?