Jump to content

  • Log In with Google      Sign In   
  • Create Account


Member Since 16 Jan 2007
Offline Last Active Mar 03 2016 09:41 PM

#5247304 Different Resolutions

Posted by on 17 August 2015 - 10:06 PM

As mentioned above, there are many ways to handle this. One way we dealt with this at a video game company I worked at was work in a fixed-height coordinate space. Instead of having all of your coordinates match up to pixels, come up with some arbitrary fixed height value (test it out though). The fixed height will be the domain of your screen's coordinate space. The width would vary between screen sizes, and you could find it by multiplying your fixed height value by the aspect ratio. That said, make sure all of your fullscreen background artwork produced with the height of your fixed-height value, and its width being whatever it is multiplied by your most extreme aspect ratio (most-likely 16:9, if working in landscape). Then, the sides would just be clipped on screens with fuller aspect ratios, most-notably the 4:3 aspect ratio. You'd design most of your UI in the middle of the screen, making sure it fits nicely in 4:3. You could attach certain UI elements to the edges of the screen so that they hug the sides regardless of fullscreen or widescreen aspect ratios. 9-slicing will be a huge part of this as well. A good deal of your panels and other large UI elements would most-likely be percentage-based if you want them to scale with the screen. The beauty here is that your UI is no longer resolution-dependent, and mostly not aspect-ratio dependent. You could get more creative, and have different resolution images for different resolution devices. For example, high-res iamges for Quad HD and 4K displays (many mobile devices are going Quad HD today). You could use lower-resolution versions of your images for lower-resolution devices --something I highly recommend. Lower-resolution devices are generally older devices as resolutions have been increasing almost every year. These older devices won't have the memory, or the GPU bandwidth to support these higher-resolution textures, so I'd suggest having some sort of content pipeline in place that automatically cooks up low-end builds with lower-resolution images.


Regarding having multiple resolutions of your game's assets, I'd use PC games as an example. With varying hardware and screen resolutions, gamers can usually lower graphical settings, such as texture resolutions, if there isn't enough resources to go around.


You can also use techniques mentioned above alongside this process.

#5247298 Code Review

Posted by on 17 August 2015 - 09:34 PM

Sorry if this is tl;dr. It took me 3 hours to write up a response. Took it to heart though.


I'd venture to guess that your lack of experience (two years) contributed fairly significantly to your being considered "too junior," but the demo you submitted probably didn't help.


This is what I thought too. The sprite packer and signed-distance font generator were the only two presentable projects I really had. All of my ambitious projects break over time due to underlying code changes from a shared code base. I'm fixing that by providing version control --something I never really used until 2 years ago.




Quick glance at the code, you pass parameters by value specially std::string, you do not use const anywhere including marking methods which do not change state of an object. Those two things would be give me the impression that you are a junior.







std::string are objects (class) and can be expensive, specialy if it needs to copy data, so I "always" pass by const ref.


Another big concern of mine. I know that passing things by value's kills performance, but I haven't wrapped my head around how to use references, const references, and const getters effectively. I was going to make this a future priority, but since that half the replies are about how to properly pass data into functions, it sounds like it's a fundamental I need to work on right now.


I can see how passing by const reference acts as a security concern, but does it also increase performance as well making it read-only? The same goes for plain references: security in the sense that they're restricted pointer. They can't be re-assigned after assignment, no direct pointer arithmetic, can't ever be NULL, and can't take the address of references. These points were brought up in this Stack Overflow thread, but I'm not sure what the 3rd point means. Also, is it proper to return const references/pointers from methods? I've tried wrapping my head around this as well.


There are a lot of things I'll write, but I'll write them in weird ways because I'm unsure of the proper way for it to be written in certain situations. Josh brings up some of them.


@Josh Petrie: Thank you for taking the time during your lunch break to go over this. There are plenty of gems here for a junior like myself, and I did find your comments very informative. Here are my responses:



  • I wrote my header guards like this since that's how I saw them early-on in C++ tutorials. As time went on, I adopted this convention. Then again, I've seen plenty of examples online that don't use underscores like this. It sounds like a potential issue for some compilers, so I'll remove both the preceeding and trailing underscores.

  • Regarding BinRect and inheritance abuse: I agree with you. I thought about using composition here as I think simple types like VectorX, MatrixX, ColorX, Rect, etc should all be final classes. I should be implementing that as well. When I wrote this code back in November, 2014, I was just getting exposed to the idea that inheritance isn't the end-all solution in C++. I tried staying away from it, which is why BinPacker is generic, but again, inheritance prevailed as a design choice in every class contained in the BinPacker module. Providing a HAS A Rect relationship with BinRect and BinNode should help fix some points that you bring up later.

  • 'rotated' is supposed to be treated as a bool value. I use uint8_t because I wanted it strictly typed for POD purposes so it's more portable when exporting to a file. I try to stay away from bool when working with POD due varying to compiler implementation. bool can vary between platforms/implementations, so I wanted to strictly type something to an unsigned 8-bit value. Also, it doesn't seem like I can XOR bools on some compiler. I use XOR to toggle rotation state of my BinRects. If using a bool, I could toggle simply by myBoolVar = !myBoolVar. Checking > 0 is true, but again, I should just check if(rotated == true) { }. Would a bool still be a better way to go? It'd certainly make it more readable.

  • I always thought I had to check if my pointer was NULL before deleting it. Since this isn't the case, I'll remove the checks.

  • You bring up a good point about CompareBinRects() as a template is unnecessary. I can't remember why I even did that, but again, making it a template function doesn't make sense. I moved it into BinPacker as a private method.

  • BinPacker is a template because it's meant to take a subclass BinRect. BinRect::CanPack() was a hasty addition to the original design because I realized that some rects included in the rects vector shouldn't be packed due to some sort of invalidation in some implementations of this class. This is obviously poor design. Rect validation should be done before adding them to the packer.

  • I agree with ForceSquare(): it sounds like an action. I was uneasy when I wrote it. It does set a state that'll be applied when Commit() gets called, but again, doesn't perform any action. This should be renamed something better, such as ForceSquareFlag() maybe?

  • I agree with using "unsigned" when negative values should never be used. I only kept it signed as I thought this was a common convention, and also performed better. I remember reading about signed vs unsigned ints, and performance impact a while ago when I did PSP development. I'm probably wrong. I'll use "unsigned" in places where values should be unsigned, such as looking up an array item by index. Everything should be [0, max value), but don't some compilers yield a warning if I use an unsigned datatype instead of a signed int?

  • I've gone back in forth between throwing an error, and bounding indices that are out-of-bounds. I'll throw an error instead. I'm starting to use assert() for rare situations like this. I stay away from exception handling in commonly-used code as it can be slow. Does this sound practical?

  • I agree with logging in utility code: it shouldn't be used, but still should be reported. I'm a fan of error codes, but there are caveats to that such as providing a bunch of different defines. I'd like to use C++11 enum classes as error codes here, but I'm not sure if that's good design simply because I haven't seen that yet. I'm sure exceptions have their purpose (I use them in C# in cases where I'd typically use assert() in C++). What is your take on exception handling?

  • I agree, NULL rects shouldn't be allows, and it'd be a much better practice to use a vector of objects instead a vector of pointers in this case. The only reason I'm doing this is because BinRect was originally intended to be subclassed. In reading your feedback, inheritance doesn't sound like a solid design. If I were to store objects instead of pointers in my vector, how should I match up those rects with my images or glyphs? The rects are re-ordered by size to make the packer work. I thought of providing a separate class to store my sprite info that gets "packed" by storing a pointer to the corresponding BinRect that actually gets packed, but if I'm pushing objects into a vector that could potentially resize. This could move my objects around in memory; invalidating my sprite info objects' pointers. Should an STL list of objects be a better solution? I try to stick with vectors as much as possible for cache reasons.

  • I moved that function into BinPacker as a method since it's only practical purpose is specific to that class.
  • Good call with the BinNode root. It'll become part of the stack.
  • Again, right about GetNumPackedRects(): it literally does nothing but return zero. I forget what that was even supposed to do. It's not even used in the entire applications. It's deleted.



  • Should have seen that one coming. I'll go with error codes for BinPacker::Divide(). It currently only returns a bool value, but I could convert that into error codes to get more specific on what went wrong.


  • I've recently started to get away from being too vague about naming conventions, specifically functions/methods. I'd try to overload methods as much as possible, but I've seen cases where I've gone overboard in other projects. By naming these methods.
  • I see your point, and I could provide documentation on this. This class uses its data in a column-major format as every graphics API I've seen uses the column-major interpretation (DirectX, OpenGL, the PSP's GU). I've considered this a given, but you're right: it wouldn't hurt to specify somewhere.
  • NOTE: Just like all other complex math types I have in classes, they all have operator overloads. There are many opportunities for const reference parameters.


  • I was wondering if SpritePacker would violate SRP. In fact, I'm not very confident in my philosophy of the single responsibility pattern to derived classes without violating SRP. The CanPack() virtual method will be removed, as stated above. I initially thought the same thing: the packer should only pack rects, not sprites. I abandoned that philosophy because I wasn't sure how to associate sprites with packed rects if my BinRects are moved around in memory as a vector (might have to go with a list on this one, unfortunately). The idea was that SpriteBinRects could be pushed into the SpritePacker even when a texture wasn't working. Of course, if a texture were to fail, the SpriteBinRect shouldn't be instantiated in the first place.
  • I thought the same thing about the ternary state: it returns a boolean value. The only reason I explicitly specify true : false is because I think I ran into a compiler error when assigning a bool to an expression evaluation.
  • Again, you're right, passing by value is largely unneeded. I'm cleaning this up as I get the time to do so. Hopefully I'll have an amended version of this code completed by the end of the week.
  • Yeah, SpritePacker will suffer the same issues from BinPacker.


  • INPLACESWAP and SwapRedBlue32 aren't my own code. I took it from FreeImage, and put it in my code-base since these functions aren't always available in every version of FreeImage's source code. I need it to swap Blue/Red components since FreeImage has the nerve to store those components in a BGR format. Some people... lol jk, FreeImage has been VERY useful. biggrin.png
  • I've wondered about where to put the vertex/shader source code. I put it in InitCommon() because it doesn't need to exist past setting up a few stock shaders. After that, the data isn't needed anymore. I let it release from the stack after InitCommon() reaches the end of its scope. Do I still need to move it somewhere as static common data? It'd only eat up a few KB of memory if I did that.


  • I setup the assignment operator overloads properly where the parameter takes a const reference, and returns a reference. I've seen this in others' code (tinyxml, FreeImage, STL, Box2D, etc). Again, I've stayed away from references and const references out of lack of understanding. As stated above, it sounds like this should be a top priority.




Most of the above is not too bad, the biggest problems I would say are the way you use run- and compile-time polymorphism, the way you deal with ownership, and the apparent consideration you put in to the shape and surface area of your APIs

I still struggle with all of these. I can nail a lot of the simple stuff, but I don't most of the time. I've been programming in C++ as an obsessive hobby since I was in middle school, about 11 years ago. That said, I still do consider myself novice. I've started to notice that I need to get feedback from other programmers to grow, otherwise I'll just be stuck in my old ways. I just gotta face that I'm not John Carmack --I'm just a regular guy lol. I'll to ask more questions, and apply the advice in smaller test cases to reinforce what I'm being taught.


I can't thank you all enough for the feedback.

#5244311 Constructor Initializer List and Heap Allocation

Posted by on 03 August 2015 - 10:24 AM

Whenever I have a field that should be initialized onto the heap upon initialization in a class, I usually initialize it to nullptr in the initializer list, and then allocate it in the constructor's body. For example:

class Test
Model *model;


Test() : model(nullptr)
model = new Model();

if(model) delete model;


I notice in Qt, that my designer-derived class will allocate its UI pointer onto the heap in the constructor's initializer list. Is this a good practice? If my heap-allocated objects' constructors are lean, would this make better sense?

#5243902 [Qt 5] Moving Rows For Scene Tree (QAbstractItemModel)

Posted by on 31 July 2015 - 03:48 PM

I'm having some problems trying to read the post. What are you trying to ask exactly?

I'm having issues with dropMimeData() in my code whenever have it return true on a successful drop. Nodes seem to disappear a frame later. I found out why, and I'll elaborate below.




I don't have much experience in the area, when I have to deal with QAbstractItemModel it's usually for QML and everything I do there works (which is not much and less than you want there). Have you tried doing something that absolutely forces the QTreeView to reevaluate the model? Like setting an empty model and then setting the real model back? That's not a solution but it would be nice to know for sure if the model is basically sound.

I wanted to do this myself, but I'm unable to. The reason being because I need to reset my model once SceneModel's dropMimeData() method is called. I would emit a signal to a slot in my MainWindow class where I could reset my model. The problem is, it seems like the only way one could reset a model in Qt5 is by unsetting the model from the QTreeView, releasing the model from memory, reallocating it, and re-setting the newly allocated model to the QTreeView. This will cause a crash because this is happening from emitting a signal within the scope of a method from an object that's going to be destroyed during the emitting call because the method hasn't returned yet.



Solution Found!

I found that when SceneModel::dropMimeData() returns true, SceneModel's base class, QAbstractItemModel, would internally call removeRows() on the node I just moved. My reimplementation of removeRows(), which is required, tells the parent node to delete the new child node I just moved under it. This would make sense why my pointers to nodes became dangling pointers. I looked into why this was, and it was due to my dropAction being set to InternalMove for my QTreeView. I thought InternalMove was what I needed, but it looks like DragDrop, does the job. The dangling pointer issue is resolved since my SceneModel no-longer removes nodes unexpectedly. My QTreeView's drag and drop performance also seems to work more fluidly. I used to have to select my node in a sweet spot to get it to work. I can also drag nodes into my the top-level hierarchy.


My hierarchy system is usable, but still kind of clunky. Here is a list of outstanding issues:

  1. My QTreeView only has single selection enabled, but when I child two nodes under another node, the second node under the new parent is always selected until I select it.
  2. Whenever I child a node, selection defaults to the second child to the parent node instead of what was selected
  3. Whenever moving a node to another node, it always gets added to the bottom of the list when I place it between two nodes. I have to set its parent, then I can reorder the siblings. I think this is due to my Node class' functionality.
  4. Whenever dragging Nodes to the top-level view, I'll get a warning in the console saying that there's an invalid index, although I still get the desired results.


I've found some answers to these issues:

  1. It appears that whatever sourceRow is highlights that row indefinitely for some reason. It happened to be the second row under the new parent because I've been dragging the second child to the scene's root (index of 1) to the new parent. Then, I provide sourceRow to beginMoveRows(). I think this is to preserve selection after a move occurs, but it should be based on the destination child's index. After some Googling, I found that another person was having an issue with how their QTreeView would visually display his model's selection. It was due to how he overrode QAbstractItemModel::parent(). My thought was if modifying parent() fixed his selection behavior, then that's probably where my issue lies. In my parent() implementation, I wasn't allowing parent() to create a valid QModelIndex if the Node's parent was the scene's root. This is advice I got from a previous tutorial, but I'm not sure why that logic's there. I'm not sure what parent() even does. I removed the extra check against my scene's root, and this issue seems to be resolved.
  2. See the previous point. This is fixed.
  3. This was my SetParent() logic, as mentioned previously. I've added additional logic to my SetParent() method that resolves this issue.
  4. Still working on this, but I think it has to do with how I'm passing parameters to beginMoveRows().

#5243661 2D Platformer Camera

Posted by on 30 July 2015 - 03:55 PM

Does your 2D camera or any of the tiles rotate? If not, your camera and all tiles are axis-aligned bounding boxes (AABBs). For a simple culling test, you could just loop through every tile in your level, and do a simple AABB intersection test. Looping through each tile in your scene can also be a bottleneck if you have a lot of tiles. A better solution would be to use a scene graph at that point. You'd pre-calculate them into a quadtree, or whatever scene graph you'd like. Then, loop through the scene graph's nodes recursively, and add all bottom-level nodes' tiles to the batch buffer for that frame.

#5243654 Safety vs Efficiency

Posted by on 30 July 2015 - 03:33 PM

Using asserts for code that shouldn't go wrong. For example: pointers that can't ever be NULL/invalid because they're allocated in the constructor. Code changes, and guarantees that exist today probably won't tomorrow. It's common that you'll have enough on your plate that you'll occasionally overlook some piece of code that relies on conditions no longer guarantee this code. Assert's good for these cases.

#5238832 Anyone here a self-taught graphics programmer?

Posted by on 07 July 2015 - 12:52 PM

I coded some text based games and then tried a basic 3D renderer using high school maths.

I'm born and raised in the US. Say what you want about our "low test scores" (I'm a believer), but I can't stress this enough: much of the math skills you need are covered in the high school. I also went to public school, so I got the standard curriculum. We did all kinds of vector and matrix operations. We even covered basic concepts such as how to tell if vectors were orthogonal to each other. This brought me to the conclusion that much of the basics of 3D linear algebra is covered in high school. We didn't cover matrix transforms, or how to get the angle between vectors, but we knew how to multiply matrices, find their determinants, do vector addition, subtract, dot/cross vectors.


The big problem is that we didn't cover much of the concept, let alone the application, of these operations. So, we know how to calculate the dot product, yes, but did you know that value is the product of the magnitude of both vectors and cos of the angle between them?




We also learned very basic boolean algebra. You wouldn't know it from just school though, because George Boole, nor the term "boolean" was ever mentioned. We learned all of these seemingly useless skills. It's not like this stuff was relevant in anyone else's lives outside of my own, who already knew this stuff... Regardless of how well kids did on the test (many did quite well, IIRC), they'll forget about it later. Even I forget how quaternions work if I haven't needed to know the math behind them in months. All I need to do is get a refresher from Wolfram, and I'm all set. It's really not that difficult.


All of my friends who aren't programmers say that it's interesting, but the math turns them off. The thing is, they're just talking about programming in general. Just the act of "programming" itself is mathematically elementary. It's really what you want to do that determines the math complexity of your project. On top of that, they think 3D graphics are difficult to wrap their heads around. Ironically, just about all they need to know to get a jump on the math-side of graphics was already taught to them way back in high school.


I'd also like to point out that we also covered Bezier curves. This became relevant for me the year before I "learned" them.

#5238636 Animated Model Format for ASSIMP

Posted by on 06 July 2015 - 10:59 AM

I'm currently using ASSIMP as a decent model importer just to get something up and running. Upon deployment, any model data I'll use will get serialized into an engine-ready format to be actually used in a production environment. It supports a variety formats that are decent for static meshes, such as .3ds, .ase, .lwo and .obj. The problem is, I'm not sure about which format to export skinned, animated models to. MD5 might work, but I've yet to find a decent exporter that'll work in Max, Maya and Blender. I've never written an importer and renderer for MD5 in the past. They have COLLADA support, but that format's MASSIVE in both spec and file size as it's in XML rather than JSON for a text-based schema. I've never seen a decent exporter for COLLADA either. ASSIMP doesn't list FBX as a supported model format, but I've seen that it has limited support for that in the past as you have to export with an old-enough version of the FBX spec. It's also a massively-complex 3D model format (like COLLADA) that's designed to cover anything from architectural data for CAD to real-time game models. Autodesk also appears to update its format every 6 months, the libraries are way more complex than needed for me, the licensing is restrictive (I think, anyway), and new ones are released every 6 months by Autodesk. There's support for .blend files, but those are binary scene dumps created by Blender, and not really meant to be used as an intermediate model format. That said, the format's like FBX: overly-complex for a game's needs, and the data format may change from version to version of Blender, which gets updated every 6 months. Any suggestions here?


Then, there's OpenGEX for my intermediate, animated model solution:

The OpenGEX format was developed, along with the markup language it's built on top of, OpenDDL (data description language/layer). It was developed by Eric Lengyel, author of the C4 Engine (he's pretty frequent on GameDev.Net), as the result of a successful crowd funding campaign back in 2013. The format seems pretty solid for a jack-of-all-trades format. It's another attempt at what COLLADA and FBX have tried to do in the past as being a generic 3D model standard. It's an open, well-documented format, unlike FBX, and has a MUCH simpler spec than both FBX and COLLADA. The text overhead due to metadata is also kept at a minimum. He's also released exporters for all 3 major 3D modeling packages, and provides some good boilerplate code to get started in writing an importer as well. I have nothing to say, but good things about this format's structure.


That said, there are some drawbacks:

1) Although really nice and generic to the point where it's simple, it's still pretty complex for my needs for what I need to do right now. I went through the importer template back in November, and I did come to the conclusion that I could write an implementation for a basic model importer. I'm not sure how well I'd do to support animations just yet, but the main problem is me. There's SO much potential here, and I'm like a kid in a candy shop: I want it all. I want to support everything, and I can't seem to keep to just the current project requirements. I'm also concerned that the format will undergo change over time that could break previous functionality. Not sure how valid that concern it though.

2) The exporters seem pretty solid, and maintained by Eric, but if I recall, there are some slight differences in support for the exporters between 3D modeling packages. I remember the Blender version not supporting LODs for meshes, which is probably more of a Blender thing than an OpenGEX thing. Not really necessary for me, but there might be other support Blender lacks as that's probably what we'll use.

3) Not a huge adoption yet. Although it's pretty solid, and of course, part of Eric's own C4 Engine, I haven't seen others use it much. There's a lot of official documentation on it, but it'd be nice to talk to others about their experience implementing it. I personally hope it takes off.


The more I talk about OpenGEX, the more I want to pick up where I left off with it. I already have a pretty solid OBJ loader for static models. It seems to load any OBJ I've found online or made in Blender so far. It's also been able to optimize it well enough as well. The OBJ importer also dumps its data into a generic Model class where attributes, and surface descriptions are held. It's a simple-enough mesh storage class that'd act as a nice in-memory application of OpenGEX's format nicely.


It's just that ASSIMP has all of these nice import options, such as normal generation, optimizing, etc. Then again, I have those features implemented...

#5230140 Signed-Distance Field Font

Posted by on 20 May 2015 - 05:14 PM

Can you post a picture of the signed distance field for the image?  That' might help.  Also, how big is the source image and how small is the scaled SDF alpha channel?

So this is where I think I'm doing it all wrong. I'm using Freetype2 to generate my glyph's source image. For the letter 'A', Freetype2 gives me a 18x18 pixel image. Then, I run through that image with the code above that'll add padding for the spread, then pad that image to a power of 2 size. I just save it out as an 8-bit buffer to a file, so it might be more convenient to provide you the ASCII version:

   0    0    0    0    0    0    0    0   25   25   25   25   25   25   25   25   25    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0 
   0    0    0    0    0    0    0   25   50   50   50   50   50   50   50   50   50   25    0    0    0    0    0    0    0    0    0    0    0    0    0    0 
   0    0    0    0    0    0   25   50   76   76   76   76   76   76   76   76   76   50   25    0    0    0    0    0    0    0    0    0    0    0    0    0 
   0    0    0    0    0    0   25   50   76  101  101  101  101  101  101  101   76   50   25    0    0    0    0    0    0    0    0    0    0    0    0    0 
   0    0    0    0    0    0   25   50   76  101  128  128  128  128  128  101   76   50   25    0    0    0    0    0    0    0    0    0    0    0    0    0 
   0    0    0    0    0   25   50   76   76  101  128  255  255  255  128  101   76   76   50   25    0    0    0    0    0    0    0    0    0    0    0    0 
   0    0    0    0    0   25   50   76  101  101  128  255  255  255  128  101  101   76   50   25    0    0    0    0    0    0    0    0    0    0    0    0 
   0    0    0    0   25   50   76   76  101  128  255  255  128  255  255  128  101   76   76   50   25    0    0    0    0    0    0    0    0    0    0    0 
   0    0    0    0   25   50   76  101  101  128  255  128  101  128  255  128  101  101   76   50   25    0    0    0    0    0    0    0    0    0    0    0 
   0    0    0    0   25   50   76  101  128  255  255  128  101  128  255  255  128  101   76   50   25    0    0    0    0    0    0    0    0    0    0    0 
   0    0    0   25   50   76   76  101  128  255  128  101  101  101  128  255  128  101   76   76   50   25    0    0    0    0    0    0    0    0    0    0 
   0    0    0   25   50   76  101  101  128  255  128  101   76  101  128  255  128  101  101   76   50   25    0    0    0    0    0    0    0    0    0    0 
   0    0    0   25   50   76  101  128  255  255  128  101   76  101  128  255  255  128  101   76   50   25    0    0    0    0    0    0    0    0    0    0 
   0    0   25   50   76   76  101  128  255  128  101  101  101  101  101  128  255  128  101   76   76   50   25    0    0    0    0    0    0    0    0    0 
   0    0   25   50   76  101  101  128  255  255  128  128  128  128  128  255  255  128  101  101   76   50   25    0    0    0    0    0    0    0    0    0 
   0   25   50   76   76  101  128  255  255  128  128  128  128  128  128  128  255  255  128  101   76   76   50   25    0    0    0    0    0    0    0    0 
   0   25   50   76  101  101  128  255  128  101  101  101  101  101  101  101  128  255  128  101  101   76   50   25    0    0    0    0    0    0    0    0 
   0   25   50   76  101  128  255  255  128  101   76   76   76   76   76  101  128  255  255  128  101   76   50   25    0    0    0    0    0    0    0    0 
  25   50   76   76  101  128  255  128  101  101   76   50   50   50   76  101  101  128  255  128  101   76   76   50   25    0    0    0    0    0    0    0 
  25   50   76  101  101  128  255  128  101   76   76   50   25   50   76   76  101  128  255  128  101  101   76   50   25    0    0    0    0    0    0    0 
  25   50   76  101  128  128  128  128  101   76   50   25    0   25   50   76  101  128  128  128  128  101   76   50   25    0    0    0    0    0    0    0 
  25   50   76  101  101  101  101  101  101   76   50   25    0   25   50   76  101  101  101  101  101  101   76   50   25    0    0    0    0    0    0    0 
  25   50   76   76   76   76   76   76   76   76   50   25    0   25   50   76   76   76   76   76   76   76   76   50   25    0    0    0    0    0    0    0 
   0   25   50   50   50   50   50   50   50   50   25    0    0    0   25   50   50   50   50   50   50   50   50   25    0    0    0    0    0    0    0    0 
   0    0   25   25   25   25   25   25   25   25    0    0    0    0    0   25   25   25   25   25   25   25   25    0    0    0    0    0    0    0    0    0 

#5194213 Textured Quads Appear White

Posted by on 22 November 2014 - 08:33 PM

I solved it. Turns out, the code above was fine, and the issue was within my vertex buffer:

glGenBuffers(2, vbo);
	glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[1]);
	glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices, GL_STATIC_DRAW);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint16_t) * numIndices, indices, GL_STATIC_DRAW);
	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)sizeof(Vector2));
	delete vertices;
	delete indices;

My second vertex attribute was set to 4 for the size, GL_UNSIGNED_BYTE for the type and GL_TRUE for the normalized arguments. This was a simple copy and paste mistake as the vertex format from another test state uses position and color. This one uses position and texture coordinates. False alarm!

#5191550 Resource management

Posted by on 06 November 2014 - 12:22 PM

I've thought against having a resource manager due to problems that could occur myself, but then my controller class ends up having a bunch of pointers to allocated resources for things like textures, models, scenes, etc. Then, having to explicitly release all of that data in my State's LoadContent() and UnloadContent() override methods gets kind of large for switching states and scenes. Then, I found myself writing the same resource loading code for most things, and that a subclass could handle a lot of the base functionality.


Since I'm using C++, I thought that OOP principles could help cut down on the redundant code. I think maybe my AssetManager system is taking on too much, honestly. I plan on having a File I/O namespace that'll include I/O classes for reading and writing data in binary blobs with speed and integrity checks as well as handling text/schema-based syntax formats such as XML and JSON for intermediate file data.


I really would like to learn more about software engineering, and systems development. I have quite a bit of experience doing things on my own. When it comes to developing a software system, such as an engine, or even a complete game, everything I'm currently capable of is a result of almost purely figuring things out on my own and experimentation. Are there any good software design books that cover OOP or important software engineering concepts in general, such as SRP? I've been reading papers online, but I'd like to find a course book that walks me through design patterns.

#5191384 Resource management

Posted by on 05 November 2014 - 01:12 PM

I've seen many arguments against a resource manager on these forums in the past in favor for writing a separate factory system per type of asset, but I think have a unified foundation with a factory system built on top for the specific needs of the asset is a better way to work on it. Here's the source to the beginning of my asset system:

#include <iostream>
#include <vector>
#include <map>

using namespace std;

class Asset
	template<class T> friend class AssetRef;
	bool persistent;
	vector<void**> references;
	virtual void Load() {}
		persistent = false;
		for(int i=0;i<(int)references.size();++i)
			*references[i] = NULL;
	void MakePersistent(bool persistent) { this->persistent = persistent; }
	bool IsPersistent() { return persistent; }
	int GetReferenceCount() { return (int)references.size(); }

enum class AssetError

template<class T>
class AssetRef
	T *ref;
	void RemoveRef()
			for(vector<void**>::iterator iter = ref->references.begin();iter != ref->references.end();++iter)
				if(**iter == ref)
					Asset *ptr = ref;
			ref = NULL;
		ref = NULL;
	void operator=(T *opt2)
		// reduce old reference's count, and set the new one if not NULL
			ref = opt2;
	T *Get() { return ref; }

class AssetManager
	static map<string, Asset*> assets;
	static bool Add(string name, Asset *asset)
		// make sure the asset isn't NULL and the name is unique
		if(!asset || assets.find(name) != assets.end())
			return false;
		// make sure asset doesn't already exist
		map<string, Asset*>::iterator iter = assets.begin();
		while(iter != assets.end())
			if(iter->second == asset)
				cout << "asset already exists" << endl;
				return false;
		assets[name] = asset;
		return true;
	static bool Remove(string name)
		if(assets.find(name) == assets.end())
			cout << "could not find asset: " << name << endl;
			return false;
		//Base::Release(&assets[name]); // TODO: implement this
		return true;
	template<class T>
	static void Purge()
		map<string, Asset*> *purgeAssets = GetAssets<T*>();
			map<string, Asset*>::iterator iter = purgeAssets->begin();
			while(iter != purgeAssets->end())
			delete purgeAssets;
	static void Flush()
		// only flushes assets deemed non-persistent
	static void Clear()
		map<string, Asset*>::iterator iter = assets.begin();
		while(iter != assets.begin())
			//Base::Release(&iter->second); // TODO: implement this
			iter->second = NULL;
	template<class T>
	static T *Get(string name)
		// make sure an asset with that name exists
		if(assets.find(name) == assets.end())
			cout << "could not find asset: " << name << endl;
			return NULL;
		return dynamic_cast<T*>(assets[name]);
	template<class T>
	static map<string, T*> GetAssets()
		// allocate a new map and setup an iterator
		map<string, T*> *set = new map<string, T*>;
		map<string, Asset*>::iterator iter = assets.begin();
		// populate with the correct type of assets
		while(iter != assets.end())
			T *ptr = dynamic_cast<T*>(iter->second);
				*set[iter->first] = iter->second;
		// delete the allocate map if there are no assets of that type
			delete set;
			set = NULL;
		return set;
	template<class T>
	static int GetNumAssets()
		int count = 0;
		map<string, Asset*>::iterator iter = assets.begin();
		while(iter != assets.end())
		return count;
	static int GetNumAssets() { return (int)assets.size(); }

map<string, Asset*> AssetManager::assets;

class Texture2D : public Asset

class Font : public Asset

typedef AssetRef<Texture2D> Texture2DRef;
typedef AssetRef<Font> FontRef;

int main(int argc, const char **argv)
	bool result = false;
	Texture2D *texture1 = new Texture2D();
	Texture2D *texture2 = new Texture2D();
	result = AssetManager::Add("test_asset1", texture1);
	cout << "add result: " << (int)result << "  num assets: " << AssetManager::GetNumAssets() << endl;
	result = AssetManager::Add("test_asset2", texture2);
	cout << "add result: " << (int)result << "  num assets: " << AssetManager::GetNumAssets() << endl;
	result = AssetManager::Remove("test_asset1");
	cout << "remove result: " << (int)result << "  num assets: " << AssetManager::GetNumAssets() << endl;
	Font *ptr = AssetManager::Get<Font>("test_asset2");
		cout << "ptr is VALID" << endl;
		cout << "ptr is NULL" << endl;
	Texture2DRef texRef;
	texRef = AssetManager::Get<Texture2D>("test_asset2");
	Texture2D *tex = AssetManager::Get<Texture2D>("test_asset2");
		cout << "test_asset2 count: " << tex->GetReferenceCount() << endl;
	cout << "finished..." << "  num assets: " << AssetManager::GetNumAssets() << endl;
    return 0;

Using C++-11's new smart pointer system probably would have been a better way to go instead of supporting my own reference counting system, but I haven't figured them out yet. The ideas is that every different type of asset you'd have in your game (textures, models, definition files, etc.) would derive from Asset. Then, you'd create an AssetRef typedef variant for shorthand. An AssetRef is simply a pointer to the asset that's (hopefully) already loaded into the AssetManager.


Even though I don't assume all assets are loaded from files (for example, textures generated from rendering to a texture), I may add a filename field to Asset. I'm also thinking about adding an MD5 hash generated from the data stored in the asset, which the subclass is responsible for providing the data to hash. This is so if I wanted to create a visual editor like UE4 and Unity have, I can create an asset database that acts like a database in the sense that it keeps track of where everything is, or when files are moved in and out of the file project's root folder. Anyway, there's some funky scope to the editor side of things, and I haven't drawn up that namespace yet...


EDIT: The main() function at the bottom demonstrates how this currently works. I don't want any assets to be created without the AssetManager owning them though, but I also want it to be transparent to the end-programmer. I'm thinking about replacing AssetManager::Add() with a method like AssetManager::Load<T>(const char *filename, const char *filename) which can be specialized with its own loader code for every new Asset subclass that's created. I want AssetManager to own all assets allocated into memory, and do it transparently so its reference counting system works correctly. For generated assets, I'd like to override the new operator that'll allocate the asset, but automatically add the asset to the AssetManager like AssetManager::Add() does right now.


This is how I'd handle my game-ready content pipeline. AssetManager is intended to use models, textures, config files, etc that are serialized into some engine-ready binary blob setup, possibly combined into a file atlas (similar to how texture atlases), zip archive, or both. My engine will handle common image formats for things like textures and icons as well as a text-based, intermediate file format for models, but those are handled through the ContentProcessor pipeline, which is a separate namespace.

#5191259 Current state of custom and commercial game engines as of 2014

Posted by on 04 November 2014 - 09:45 PM

I've been wondering this myself. I work for a small studio developing freemium games for children using Unity, and it's a love-hate sort of thing. I'm really, really analytically when it comes to performance, and the fact that I can't see how things are being handled on the back-end drives me insane sometimes. The good part is though: I get to actually build games, and get paid for it. I was neither building games, or getting paid for that over a year ago... I was building an engine for fun fantasizing about making a game when I had the proper art team as a hobby.


That said, I think there are still benefits in at least attempting to build your engine, or using UE4 outside of using Unity exclusively. When you write your own engine or work with UE4, you're forced to work closer to the hardware than you'd normally would in Unity. I mean, there's plenty of utilization for 3D math, and the need to develop gameplay systems, but Unity hides a bunch of stuff pretty nicely. Sometimes, it's nice to understand how vertices are working under the hood, what a draw call really is, etc. Using Unity is certain a huge game-changer, but I think that it's also good to get back to the lower-level APIs Unity is build on top of (DirectX, OpenGL), and write your own math libraries. That's what'll get you really good, really fast. Then, you can take your new-found savvy-ness with you to Unity or UE4, and extend it to meet your specific needs much easier than before.


I still toil away at lower-level C++-based hobbyist engine stuff on my free time, though. I think it's good to learn this stuff from the ground up, and learn from first-hand experience. It makes me a better C++ programmer, and maybe I can make an engine that could compete with Unity that's also blazing fast itself. In the end, I'll understand what engine's doing under the hood because I've been under the hood. I believe that's what will help me get higher-paying programmer jobs as a senior-programmer in the long-run.


EDIT: Further more, I think we're entering an exciting time for graphics programming. AMD's Mantle is a more efficient API that DirectX 12 is getting close to. We have Apple's Metal, which is the Mantle of the mobile GPU world, but those are all proprietary technologies. Not that Microsoft or Apple don't have huge market-shares that investing in their APIs aren't worthwhile, but OpenGL's next-gen effort may provide a much more efficient API for accessing our GPUs. More-so, General-Purpose GPU programming, known as GPGPU is relatively new. OpenCL allows for parallel programming directly on GPUs, and NVIDIA's CUDA allows us to do the same. With this much freedom over the GPU, we finally have the leverage to start considering things like physics-based lighting techniques such as raytracing and Global Illumination with interactive frame rates. Unity 5 is already moving towards this by partnering up with a company in Texas I think called Geomerics who will provide their GI plugin, Enlighten, to Unity 5.


Not only is software hopefully getting a lot more efficient in using the provided hardware, but hardware's made huge leaps. NVIDIA just launched their new GTX 970 and 980 (non-titan right now), which is not only $200 cheaper than last year's Titans, but even faster. Earlier this year, they had some sort of demo where they had 19 of their network renderers (rumored to be $50,000 with > 32,000 CUDA cores a piece, so $950,000 USD of hardware, MSRP) was able to reproduce the collective processing power of the most powerful supercomputer documented in 2008 that originally cost $500,000,000 --in only 6 years.


That said, fast hardware is getting cheaper, and it's only going to get more exciting. Along with these new development, new innovations in game design and graphics processing will be possible. The algorithms will also get more complex, and in a few years, I think concepts that a lead engineer at Pixar had to know working on RenderMan 10 years ago will become commonly relevant in the real-time game development world.


I remember 10 years ago when I first started to learn C++ and DirectX. Things were simple. These "shader" things existed in DirectX 9c back in September, 2004, but they weren't required. In fact, my computer's GPU didn't support shaders at that time until I upgraded to an ATI Radeon that had 64MB of VRAM lol... If you wanted lighting, you just had to make some API calls, and the fixed-function magic made vertex lighting happened. It took me days to figure out why my large, lowpoly models weren't getting lit properly until I heard about per-pixel lighting.


That said, I would absolutely support others' efforts in developing their own engines. They'll either strike it rich like Unity did, make an admirable open source contribution to the the programming world like Blender, or at least acquire some serious graphics and software engineering skills that'll make that so much more effective at using commercial tools of any caliber.

#5191060 Datatype Size and Struct Compiler Padding

Posted by on 03 November 2014 - 11:40 PM

When it comes to storing my data in a game-ready format that's quick to load, I like to store my data using C's stdio library, so fread() and fwrite().There are a few problems with that, however:

-Changing the data structure will inevitably cause a crash when loading an older version of the file. Versioning can help here, or serializing the data in XML/JSON could help if it still wasn't so slow for large volumes of data on embedded devices.

-Compiler padding


I've noticed that some of my data types are odd numbers of bytes might pad the structure at different points in the struct's data. I think I've ran into issues where having a bool stored in a struct could cause issues too, but I usually store those in bit-fields if I have a group of them anyway. Are there any good guidelines I should follow when storing my data as binary blob files? I tend to write binary blob files for certain resources I serialize on my desktop computer in Visual Studio (Windows), or from Xcode (Mac), then load those files on any desktop OS or even mobile OS's like iOS and Android.


Also, is int the only datatype that changes its size based on processor? For example, int is usually 32-bit on 32-bit machines, and 64-bit on 64-bit machines. I tend to stay away from storing my integers as ints for this reason, and store my data as a long datatype as I'm pretty sure that it's always 32-bit whereas int is hardware-dependent. Is this correct so far?


If so, do any of C++'s other basic datatypes change their size? Also, is it wise to keep track of whether the CPU is little-endian or big-endian when writing files? I never really wrapped my head around that...

#5189557 General Programmer Salary

Posted by on 27 October 2014 - 06:43 PM

What's the average video game programmer's salary in the USA? Wikipedia (reliable source, right?!) says that some 2010 survey make anywhere between $72,000 (< 3 years experience) - $124,000 (6+ experience) at an average of $93,500. These numbers sound extremely high for me.