Ok, I've been distracted by several things:
-3d: I have been goofing around with the mandelbox. This is not helping 2d graphics, lol.
- ham radio. A new hobby to compete with my time.
-Christmas: Yes it is Christmas time. Haha.
This project isn't dead. It's just been 'paused' for a little while.
Wednesday, December 15, 2010
Thursday, November 4, 2010
back to 2d and memory management
I am jumping back into the 2D graphics world by adding a key function. I had very basic sprite rendering. I've now added 'rotozoom' support; when drawing a sprite onto the screen, it can be rotated about an arbitrary point and scaled.
Another thing I am dealing with is memory management. Currently my 'malloc wrapper' is a little unusual: every single invocation of the allocation function takes a function pointer to use as a destructor. That way anytime any string, struct, tree or whatever is just 'freed', any other cleanup that needs to happen happens too.
So, what's next? Reference counting. I'm adding one new function to the memory allocator: addref. It looks like this:
void* alloc( size, function* destructor): creates a memory block of 'size' bytes, and binds to the provided destructor. The returned memory block has a reference count of 1.
void free(void* block); decrements the reference count of the given block. If the reference count is decremented to 0, the destructor provided at creation is called.
void* addref(void* block); adds one to the reference count of the given block. Returns the given block as the argument.
Additionally, the realloc function should be modified to only succeed when the reference count of the resized block is one; Think about it: If the reference count is 2, and you're resizing the block, if the block moves how will the other pointer to it be updated?
How do you use this? To simplify memory management, just follow a few simple rules:
1. When storing a pointer into another object, use the addref function. If x is a struct, and y is a pointer to something, instead of:
x->thing=y;
write:
x->thing=addref(y);
2. Free things when they go out of scope. Don't be afraid to free things going out of scope in YOUR function even if you think some other struct is hanging on to them; if something else has the reference count will keep the object alive.
Because this reference counting occurs at the 'malloc level' of the application, ANYTHING can now reference counted, even simple strings. A version of strdup that uses this allocator can do stuff like this:
x = strdup("hello");
y= addref(x);
z= addref(x);
free(x);
free(y);
free(z);
Note that reference counting is still not a magic panacea to your memory problems. There is still the problem of reference cycles. For my current application, this issue is easy to get around.
Another thing I am dealing with is memory management. Currently my 'malloc wrapper' is a little unusual: every single invocation of the allocation function takes a function pointer to use as a destructor. That way anytime any string, struct, tree or whatever is just 'freed', any other cleanup that needs to happen happens too.
So, what's next? Reference counting. I'm adding one new function to the memory allocator: addref. It looks like this:
void* alloc( size, function* destructor): creates a memory block of 'size' bytes, and binds to the provided destructor. The returned memory block has a reference count of 1.
void free(void* block); decrements the reference count of the given block. If the reference count is decremented to 0, the destructor provided at creation is called.
void* addref(void* block); adds one to the reference count of the given block. Returns the given block as the argument.
Additionally, the realloc function should be modified to only succeed when the reference count of the resized block is one; Think about it: If the reference count is 2, and you're resizing the block, if the block moves how will the other pointer to it be updated?
How do you use this? To simplify memory management, just follow a few simple rules:
1. When storing a pointer into another object, use the addref function. If x is a struct, and y is a pointer to something, instead of:
x->thing=y;
write:
x->thing=addref(y);
2. Free things when they go out of scope. Don't be afraid to free things going out of scope in YOUR function even if you think some other struct is hanging on to them; if something else has the reference count will keep the object alive.
Because this reference counting occurs at the 'malloc level' of the application, ANYTHING can now reference counted, even simple strings. A version of strdup that uses this allocator can do stuff like this:
x = strdup("hello");
y= addref(x);
z= addref(x);
free(x);
free(y);
free(z);
Note that reference counting is still not a magic panacea to your memory problems. There is still the problem of reference cycles. For my current application, this issue is easy to get around.
Saturday, September 11, 2010
3d stuff so far
So, continuing on the Quest to create the rendering portion of a 3d game engine from scratch in plain C, this is where I am at now:
-Load Targa image files (1, 3, and 4-channel)
2d:
-Specify rectangular regions of images to use as sprite
-User-specified coordinate mapping of screen
-rendering sprites using GL hardware acceleration
3d:
-Create VBOs and populate with vertices/texcoords
-Multitexturing (currently alpha-blend from layer to layer: To do 'fancy stuff', specify a shader.)
-Convert Targa heightfield images into meshes.
-6 DOF Camera control ( up/down, left-right, forward-back, yaw, pitch, roll)
-VBO sharing: multiple small meshes can reside in the same VBO
-Mesh segmentation: Large meshes can be broken into multiple VBOs
Next on the list:
Rooms: A Room is an axis-aligned box populated with meshes for floor,ceiling, walls, and any other static objects.
Portals: A portal is a 'magic' polygon drawn in a room, that leads to another room. If a portal is visible, then the room it leads to is drawn. If a portal is not visible, then the room is ignored. Portals are key to breaking the world up into small pieces, and to allow the renderer to only render parts of the world that can be seen.
-load GLSL shader files and apply to meshes (relatively low priority: Fixed Function pipeline is currently sufficient to proof-of-concept the mesh and scenegraph data structures)
-Load Targa image files (1, 3, and 4-channel)
2d:
-Specify rectangular regions of images to use as sprite
-User-specified coordinate mapping of screen
-rendering sprites using GL hardware acceleration
3d:
-Create VBOs and populate with vertices/texcoords
-Multitexturing (currently alpha-blend from layer to layer: To do 'fancy stuff', specify a shader.)
-Convert Targa heightfield images into meshes.
-6 DOF Camera control ( up/down, left-right, forward-back, yaw, pitch, roll)
-VBO sharing: multiple small meshes can reside in the same VBO
-Mesh segmentation: Large meshes can be broken into multiple VBOs
Next on the list:
Rooms: A Room is an axis-aligned box populated with meshes for floor,ceiling, walls, and any other static objects.
Portals: A portal is a 'magic' polygon drawn in a room, that leads to another room. If a portal is visible, then the room it leads to is drawn. If a portal is not visible, then the room is ignored. Portals are key to breaking the world up into small pieces, and to allow the renderer to only render parts of the world that can be seen.
-load GLSL shader files and apply to meshes (relatively low priority: Fixed Function pipeline is currently sufficient to proof-of-concept the mesh and scenegraph data structures)
Wednesday, August 25, 2010
Project back on track
Hi! I've been busy with a lot of stuff lately, but this project is not dead! I have started going through some old OpenGL code, and am creating a simple graphics layer for projectZ. I have a lot of 3d code, but I think that for now, the best approach is to get simple 2D rendering off the ground. I need to get something on-the-screen otherwise the project will never get off the ground. I can't spend all my time designing and tweaking Vectors or Hashtables, etc, because then I would loose sight of the large picture of the project.
So, where am I at now? I've worked-over the Targa image loader and opengl texture loading code, so now a projectZ-based app can now load an image from disk and display it on the screen! The short-term goal is to compose a useful 2D rendering API, allowing rotation, scale and shear transformations to be applied to image tiles rendered to the screen. All hardware-accelerated.
So, where am I at now? I've worked-over the Targa image loader and opengl texture loading code, so now a projectZ-based app can now load an image from disk and display it on the screen! The short-term goal is to compose a useful 2D rendering API, allowing rotation, scale and shear transformations to be applied to image tiles rendered to the screen. All hardware-accelerated.
Saturday, June 19, 2010
Working out the more boring parts of the project like memory, linked lists, etc
This week I'm working on the more mundane parts of the project. I am choosing the 'best' version of hashtable, list and vector implementations and:
Then once i got vector.c, hashtable.c and linkedlist.c working at least enough to start using them:
Why am I jumping into graphics right away? Motivation. It is hard for me to stay motivated on a project that is not producing results. Once I can allocate opengl graphics buffers and get something on the screen, and see that the app does something interesting, I can stay motivated on the project. Trying to build the 'perfect hashtable' or 'perfect malloc wrapper' implementation can take a long time, and there is no clear definition of how to perfect I would like to get. Without an application, I don't know how simple or complex the API has to be; what's the point of implementing a feature that is not going to be used very often?
Once I can cleanly allocate memory, define destructors to free that memory, and can perform basic vector manipulation (which is basically just create vector, add item, remove item, and access/iterate/index those items), I can jump into graphics. I will probably not need hashtables for basic graphics; I usually don't use those until much higher level coding. (Usually to assign string names to objects, and look them up later.) Linked lists will also probably be used by graphics.
- convert them over to use the newly created malloc wrapper (zmem.c), specifically utilizing the automatic destructor-on-free callback mechanism
- clean them up with consistent naming
- test for memory leaks
Then once i got vector.c, hashtable.c and linkedlist.c working at least enough to start using them:
- Take my latest opengl based project, and separate out the GL init and basic 'raw' rendering parts from the functionality of the app.
- Convert it over to use zmem and my new structures.
- Begin packaging up the basic functionality into a simple graphics library
Why am I jumping into graphics right away? Motivation. It is hard for me to stay motivated on a project that is not producing results. Once I can allocate opengl graphics buffers and get something on the screen, and see that the app does something interesting, I can stay motivated on the project. Trying to build the 'perfect hashtable' or 'perfect malloc wrapper' implementation can take a long time, and there is no clear definition of how to perfect I would like to get. Without an application, I don't know how simple or complex the API has to be; what's the point of implementing a feature that is not going to be used very often?
Once I can cleanly allocate memory, define destructors to free that memory, and can perform basic vector manipulation (which is basically just create vector, add item, remove item, and access/iterate/index those items), I can jump into graphics. I will probably not need hashtables for basic graphics; I usually don't use those until much higher level coding. (Usually to assign string names to objects, and look them up later.) Linked lists will also probably be used by graphics.
Tuesday, June 15, 2010
Started work on Project Z
I have started my latest project, which, for lack of a better name, I am now calling project Z. (There are too many Project X's on github.)
What is Project Z? This is an attempt to take several years worth of writing random graphics or sound related programs I've written, and attempting to extract the useful bits out of them and create a working game development / game engine library.
The project is 'on' github here: http://wiki.github.com/carangil/ProjectZ/ However no code has yet been posted, only a couple of wiki pages.
This project seems huge... Where do you start? Well, many of my projects end up recreating some of the classic structures, such as linked lists, hashtables or vectors. Also, many of them also utilize some kind of thin wrapper on top of malloc, with various stupid names such as xmalloc. These usually end up being a call to malloc, followed by a NULL check, with the program exiting if allocation failed. So, I will begin there. I am currently working on a simple malloc wrapper, which has better options than just 'die on fail.' I am also selecting my 'best linked list', 'best vector', and 'best hashtable' implementations from the code I have, and cleaning them up.
You may be wondering how a professional's personal code base can become so disorganized. Well, the code has been around since before I went 'pro'... I started playing around with OpenGL in high school. In college, a lot of my time was spent on school projects. In both H.S. and college, I didn't want to 'waste' my time with writing design docs and doing actual 'engineering;' I just wanted to jump into some code and see what happens. Now that I have been developing software professionally for a couple of years, I find most of my old designs rather gross. However, I would not go back and change anything; I am very glad that I have recklessly jumped into coding. If I had spent the time to properly design these things, I might not have had the time to code them. By just diving into it, I have lot of working code that does a lot of interesting things. It is messy, messy code that must be cleaned-up, rewritten, and restructured into a well-engineered framework, but at least I have seen the algorithms work for myself; it is not just a theoretical design sitting on paper.
What is Project Z? This is an attempt to take several years worth of writing random graphics or sound related programs I've written, and attempting to extract the useful bits out of them and create a working game development / game engine library.
The project is 'on' github here: http://wiki.github.com/carangil/ProjectZ/ However no code has yet been posted, only a couple of wiki pages.
This project seems huge... Where do you start? Well, many of my projects end up recreating some of the classic structures, such as linked lists, hashtables or vectors. Also, many of them also utilize some kind of thin wrapper on top of malloc, with various stupid names such as xmalloc. These usually end up being a call to malloc, followed by a NULL check, with the program exiting if allocation failed. So, I will begin there. I am currently working on a simple malloc wrapper, which has better options than just 'die on fail.' I am also selecting my 'best linked list', 'best vector', and 'best hashtable' implementations from the code I have, and cleaning them up.
You may be wondering how a professional's personal code base can become so disorganized. Well, the code has been around since before I went 'pro'... I started playing around with OpenGL in high school. In college, a lot of my time was spent on school projects. In both H.S. and college, I didn't want to 'waste' my time with writing design docs and doing actual 'engineering;' I just wanted to jump into some code and see what happens. Now that I have been developing software professionally for a couple of years, I find most of my old designs rather gross. However, I would not go back and change anything; I am very glad that I have recklessly jumped into coding. If I had spent the time to properly design these things, I might not have had the time to code them. By just diving into it, I have lot of working code that does a lot of interesting things. It is messy, messy code that must be cleaned-up, rewritten, and restructured into a well-engineered framework, but at least I have seen the algorithms work for myself; it is not just a theoretical design sitting on paper.
Subscribe to:
Posts (Atom)