Since Sunday, I've been working on a custom game engine being written entirely in C++. I've mainly focused on the graphics part which uses OpenGL. I'm much more experienced with DirectX but OpenGL is portable. I'm also using the SOIL library to load image files such as .pngs and .jpgs. Currently the engine should require very little change to port it from Windows to another platform. I plan for the engine to use it's very own scripting language for the game logic which should also work on any platform that has an interpreter for it.
Currently the engine has these things accomplished or almost accomplished:
Initialization Process: This part includes creating the program's window and enabling OpenGL to use it. (DONE)
Rendering Pipeline: This part of code is called every frame to clear the back buffer, render everything on it, then swap the back buffer with the front one so it shows on screen. For any of you who don't know, this is called double buffering, without it you would see everything get drawn on the screen one at a time. With double buffering one buffer gets displayed to the screen while the other gets the next frame drawn onto it. In addition to this, the pipeline also decides in what order to draw certain things, how to draw them, and what GL features should be enabled when drawing them. This part cannot be completed until all the other graphical features have been added. (MOSTLY DONE)
Texture management: The image file is loaded with SOIL and then made into a OpenGL texture. I've created a system to store the ids to these texture so they can properly be deleted at the end of the program or referenced later. First I tried using a linked list. Linked lists are good for storing a list of items with no set amount of them. It can add and delete items at any time with relatively no problem. However, I'm only storing unsigned integers (which are the texture ids) and linked lists are overkill for smaller data types like this. Another problem is that GL's function for deleting textures only takes arrays as a parameter instead of individual texture ids. So instead I ended up using a basic array that is dynamically created at run time and resized to add new textures. This way isn't as good for adding textures on the go, because in order to resize the list to hold the new items, a new bigger array must be created, then have the data from the old array transferred to the new array, and then delete the old array. This must be done every time. While this is could be a problem for adding textures while the game is running, for the most part the game only needs to load new textures during a level switch. I also created a function to resize the array in preparation to add a group of textures instead of one at a time, so it only needs to be resized once. This should optimize the initial loading during a level switch. (DONE)
Text rendering: There's a couple different ways of doing this. All with their advantages and disadvantages. The method I used is to have one big texture with each letter/number/symbol in it. The texture is put on a 3d plane but instead of showing the whole texture, the texture coordinates of the plane is changed to show only the letter/number/symbol needed. This requires only one texture to be loaded and only uses 2 tris for each character drawn. The texture coordinates for each letter are defined by a custom file format I made just for this. Currently these files must be typed by hand and are time consuming to make. However, they allow a lot of flexibility in where the characters can be on the texture and what size they can be. Any letter/number/symbol not defined in the custom file format are ignored by the engine and is simply not drawn. Loading and rendering is all handled by a C++ class I created. Rendered text can be put anywhere in 3d space, at any size, any color, and with a specific character spacing set with a simple function call including the string of text to be drawn and values for these as parameters. Justification to the left, center, or right is planned but not currently working. (MOSTLY DONE)
Particle system: Adding this feature was relatively easy and straightforward than I thought it would be. A single particle system contains several arrays of the same size to represent each particle. It includes particle position, particle velocity, particle lifetime, particle opacity, particle size, and whether the particle is active. The particle system itself also includes variables defining the inital position, random offset, initial velocity, random velocity, initial life time, random life time, initial opacity, random opacity, initial size, random size, max particles, spawn interval, and acceleration. When it's time to creat a new particle, the particle system uses an integer (initially set at 0) to designate which set of array cells are to be initialized for the new particle. The integer is then incremented by one in preparation to set up the next new particle. Once the maximum amount of particles have been created, the integer is reset to the first cell in the arrays to start overriding the oldest particles created. Every frame, a "for" loop is ran to render each active particle as a quad (two tris) with the texture the particle system was loaded with. After being rendered, the particle is then updated which includes adding it's velocity to it's current position and adding the acceleration of the particle system to the current velocity to constantly move the particle. Acceleration is mostly for simulating gravity. The particle system is handled by another C++ class. While the particle system works very well for the most part, I still need to add "one shot" particles which delete when they have created the maximum amount of particles and they have expired. (MOSTLY DONE)
Input: Not much to say about input. Keyboard input is done and optimized to only check for the keys that are actually used by the game and an array of booleans are updated to reflect whether each key is pressed or not. Mouse movement is completed, but not mouse clicks. Mouse movement is accomplished by setting the cursor at the center of the screen, then at every frame checking how much it moved from the center if at all, then setting it back to the center of the screen. (MOSTLY DONE)
These are the major things that are done or close to it. Still a lot more to do and plan.
I was going to use "Instinct" for the engine's name but apparently some fat guy already stole that one.
Currently the engine has these things accomplished or almost accomplished:
Initialization Process: This part includes creating the program's window and enabling OpenGL to use it. (DONE)
Rendering Pipeline: This part of code is called every frame to clear the back buffer, render everything on it, then swap the back buffer with the front one so it shows on screen. For any of you who don't know, this is called double buffering, without it you would see everything get drawn on the screen one at a time. With double buffering one buffer gets displayed to the screen while the other gets the next frame drawn onto it. In addition to this, the pipeline also decides in what order to draw certain things, how to draw them, and what GL features should be enabled when drawing them. This part cannot be completed until all the other graphical features have been added. (MOSTLY DONE)
Texture management: The image file is loaded with SOIL and then made into a OpenGL texture. I've created a system to store the ids to these texture so they can properly be deleted at the end of the program or referenced later. First I tried using a linked list. Linked lists are good for storing a list of items with no set amount of them. It can add and delete items at any time with relatively no problem. However, I'm only storing unsigned integers (which are the texture ids) and linked lists are overkill for smaller data types like this. Another problem is that GL's function for deleting textures only takes arrays as a parameter instead of individual texture ids. So instead I ended up using a basic array that is dynamically created at run time and resized to add new textures. This way isn't as good for adding textures on the go, because in order to resize the list to hold the new items, a new bigger array must be created, then have the data from the old array transferred to the new array, and then delete the old array. This must be done every time. While this is could be a problem for adding textures while the game is running, for the most part the game only needs to load new textures during a level switch. I also created a function to resize the array in preparation to add a group of textures instead of one at a time, so it only needs to be resized once. This should optimize the initial loading during a level switch. (DONE)
Text rendering: There's a couple different ways of doing this. All with their advantages and disadvantages. The method I used is to have one big texture with each letter/number/symbol in it. The texture is put on a 3d plane but instead of showing the whole texture, the texture coordinates of the plane is changed to show only the letter/number/symbol needed. This requires only one texture to be loaded and only uses 2 tris for each character drawn. The texture coordinates for each letter are defined by a custom file format I made just for this. Currently these files must be typed by hand and are time consuming to make. However, they allow a lot of flexibility in where the characters can be on the texture and what size they can be. Any letter/number/symbol not defined in the custom file format are ignored by the engine and is simply not drawn. Loading and rendering is all handled by a C++ class I created. Rendered text can be put anywhere in 3d space, at any size, any color, and with a specific character spacing set with a simple function call including the string of text to be drawn and values for these as parameters. Justification to the left, center, or right is planned but not currently working. (MOSTLY DONE)
Particle system: Adding this feature was relatively easy and straightforward than I thought it would be. A single particle system contains several arrays of the same size to represent each particle. It includes particle position, particle velocity, particle lifetime, particle opacity, particle size, and whether the particle is active. The particle system itself also includes variables defining the inital position, random offset, initial velocity, random velocity, initial life time, random life time, initial opacity, random opacity, initial size, random size, max particles, spawn interval, and acceleration. When it's time to creat a new particle, the particle system uses an integer (initially set at 0) to designate which set of array cells are to be initialized for the new particle. The integer is then incremented by one in preparation to set up the next new particle. Once the maximum amount of particles have been created, the integer is reset to the first cell in the arrays to start overriding the oldest particles created. Every frame, a "for" loop is ran to render each active particle as a quad (two tris) with the texture the particle system was loaded with. After being rendered, the particle is then updated which includes adding it's velocity to it's current position and adding the acceleration of the particle system to the current velocity to constantly move the particle. Acceleration is mostly for simulating gravity. The particle system is handled by another C++ class. While the particle system works very well for the most part, I still need to add "one shot" particles which delete when they have created the maximum amount of particles and they have expired. (MOSTLY DONE)
Input: Not much to say about input. Keyboard input is done and optimized to only check for the keys that are actually used by the game and an array of booleans are updated to reflect whether each key is pressed or not. Mouse movement is completed, but not mouse clicks. Mouse movement is accomplished by setting the cursor at the center of the screen, then at every frame checking how much it moved from the center if at all, then setting it back to the center of the screen. (MOSTLY DONE)
These are the major things that are done or close to it. Still a lot more to do and plan.
I was going to use "Instinct" for the engine's name but apparently some fat guy already stole that one.