Posts RSS Comments RSS Del.icio.us Digg Technorati Blinklist Furl reddit 65 Posts and Comments till now
This wordpress theme is downloaded from wordpress themes website.

Archive for October, 2015 (2015/10)

Fix minor camera bug (with GLM camera)

My previous post’s Release 001 had a camera bug such that turning right from the initial state was broken.  You can see this if you run the WebGL (Emscripten) previous post’s Release 001 demo – just press “E” to turn right a little.

The bug was related to mixing up degrees and radians.  Basically what happened was that I used a simple camera from this tutorial ( http://bit.ly/1M3FLfL ) (by Tom Dalling) to generate my viewProj matrix.  The tutorial is dated 2013/01/21 and uses GLM ( http://glm.gtruc.net ).  But GLM 0.9.6.0 released 2014/11/30 changed GLM from degrees to radians, which broke the camera.  See GLM release notes “Transition from degrees to radians compatibility break and GLM 0.9.5.4 help” here ( http://glm.g-truc.net/0.9.5/updates.html ).

I fixed this tiny bug (and I started rewriting/refactoring the camera).  I also added keyboard controls “R” to look up and “F” to look down.  Here’s a WebGL (Emscripten) Release 002 with the fix – Release 002

Emscripten build target (JavaScript asm.js WebGL)

I’ve posted a WebGL version of my recent “Tile Map Geometry” post.  It was built using Emscripten, which is just one of the build targets for my (C++, SDL2, GLES2, CMake) project.  For editing the web code (HTML, CSS, JavaScript) not generated by Emscripten, I tried out Brackets (brackts.io).

Rather than embed the JavaScript directly in this WordPress post, I uploaded it to a separate area labeled release “001”.  Click the following screen shot – it’s a link.  For future versions I’ll do the same thing – post a release at “..\pemproj\grfxdemossdl2015\" and link to it from a WordPress post.

Controls: WASD moves, QE turns, ZX flies (up, down).

image

C++ member function pointer, parent class, template, std::function

Today I ran into a C++ scenario where I found std::function to be useful.  I wanted to create a std::queue of member function pointers to functions that are children of the same parent class.  For example:

class Parent
{
public:
    Parent() {};
    virtual ~Parent() {};
};
class ChildA : public Parent
{
public:
    ChildA() : Parent() {};
    ~ChildA() {};
    void Execute01() {printf("A");};
    void Execute02() {printf("B");};
    void Execute03() {printf("C");};
};
class ChildB : public Parent
{
public:
    void Execute01() {printf("D");};
    void Execute02() {printf("E");};
    void Execute03() {printf("F");};
};

To keep it simple, this examples shows two child classes (ChildA, ChildB), but I wanted it to work for lots more child classes.  I wanted to push() member function pointers to ChildA::Execute01() etc into a std::queue…  But I ran into an issue.  The declaration for a member function pointer requires the class to be specified, and the execution requires an instance of the class the be specified.  So the following snippet is valid:

typedef void (ChildA::*funcPtr)(); 
std::queue<funcPtr> theQueue; 
ChildA childA; 
theQueue.push(&ChildA::Execute01); 
funcPtr fn = theQueue.front(); 
(childA.*fn)();

However, I can’t push() a pointer to a ChildB member function into this same std::queue.  If I try referencing the parent class as follows:

typedef void (Parent::*funcPtr)();
std::queue<funcPtr> theQueue;
ChildA childA;
theQueue.push(&ChildA::Execute01);
funcPtr fn = theQueue.front();
(childA.*fn)();

Then Visual Studio 2013 gives me an error:

Error    9    error C2664: ‘void std::queue<funcPtr,std::deque<_Ty,std::allocator<_Ty>>>::push(void (__cdecl Parent::* const &)(void))’ : cannot convert argument 1 from ‘void (__cdecl ChildB::* )(void)’ to ‘void (__cdecl Parent::* &&)(void)’

Ignoring C++14’s variable templates, there are two types of templates – function templates and class templates…  So we can’t just use a template on the function pointer’s typedef.  Instead, my next solution was to make a queue of Delegate’s and use a template to define the delegate class’s children:

class Delegate
{
public:
  Delegate() {};
  virtual ~Delegate() {};
  virtual void ExeFunc() = 0;
};
template<class T>
class DelegateT : public Delegate
{
public:
  DelegateT(T* obj, void (T::*func)()) { m_obj = obj; m_func = func; };
  ~DelegateT() {};
  void ExeFunc() { (m_obj->*m_func)(); }
protected:
  void (T::*m_func)();
  T* m_obj;
};

And here’s an example usage:

std::queue<Delegate *> theQueue;
ChildA childA;
ChildB childB;
theQueue.push(new DelegateT<ChildA>(&childA, &ChildA::Execute01));
theQueue.push(new DelegateT<ChildB>(&childB, &ChildB::Execute01));
while (!theQueue.empty())
{
  Delegate *del = theQueue.front();
  del->ExeFunc();
  theQueue.pop();
  delete del;
}

Finally I ran into a more modern solution (but not that modern seeing as it’s supported by Visual Studio 2010) – use std::function:

ChildA childA;
ChildB childB;
std::queue<std::function<void()>> theQueue;
theQueue.push(std::bind(&ChildA::Execute01, childA));
theQueue.push(std::bind(&ChildB::Execute01, childB));
while (!theQueue.empty())
{
  std::function<void()> func = theQueue.front();
  func();
  theQueue.pop();
}

Tile Map Geometry

Today I implemented tile map geometry.

Basically the way it works is I have a class TileFloorData that stores a 2D array of Tile’s.  For now, each struct Tile contains a height.  In the future, Tile will also have (a) texture ID(s).  For rendering, TiledFloor is an renderable Entity that generates geometry based on its TileFloorData.

To start with, I just did the geometry (no textures yet).  The geometry is designed such that the TileFloorData can be drawn with a single draw call – so it’s a single list of vertex positions, a single list of vertex colors, and a single list of indices.  The geometry is also designed to work with a texture atlas.  So each tile has 5 faces (we ignore the bottom face) and 4 verts per face (so 20 verts per tile).  Vertices are not shared between faces – because we want independent texture coordinates for texture atlas lookup.  Each tile face also has 6 indices per face (so 30 indices per tile).

For GLES2 core profile, glDrawElements() can only use GL_UNSIGNED_BYTE or GL_UNSIGNED_SHORT (ie GL_UNSIGNED_INT is not allowed), so that’s a max of 65536 vertices.  With 20 verts per tile, that’s a max of 3276 tiles, which is only 57×57 tiles.  If we want more tiles than that, then we can break it up into multiple draw calls (such as four draw calls for 114×114 tiles).  Or we could use glDrawArrays() in which case we’d need 30 verts per tile (instead of 20).

Just for fun…  A single vertex has 3 coordinates per position and 3 values (red, green, blue) for color.  Each of these values is a GLfloat.  So a single vertex has (sizeof(GLfloat) is 4 bytes) * (3 + 3 is 6) = 24 bytes.  Each tile has 20 verts, so that’s 480 bytes per tile.  57×57 tiles * 480 bytes per tile would be 1,559,520 bytes or a little under 1.5 MB.  Using GLshort, indices are only 2 bytes each, so 2 bytes * 30 indices per tile = 60 bytes per tile.  57×57 tiles * 60 bytes per tile would be 194,940 bytes.  For both vertices + indices, 57*57*(480+60) = 1,754,460 bytes or a little over 1.67 MB.

Here’s some screen shots – 10×10 stair-step (incrementing) heights, 10×10 random heights, 50×50 random heights.  For the 50×50 example, I had to increase my zFar plane from 100 to 200.  The fourth screen shot shows that with 58×58 we lost some tiles.  This is because on GLushort overflow it wraps around, so any index value of 65536 or greater will wrap-around and cause us to redraw tiles we already drew (ie 65536 becomes 0, 65537 becomes 1, etc).

The final screen shot shows Z-fighting.  This happens because adjacent tiles share bottom verts and their top verts are on the same plane, so we have overlapping triangles (tile faces) on the same plane.  However, we only see this from the bottom side of the tile map.  In the final game, these won’t be visible to the player, so they will all be back face culled.  The top side doesn’t have this problem, because you only see the tallest part of tile sides (everything else gets drawn over).

 image image image image image

C++, SDL2, OpenGL ES 2 (GLES2), CMake, Git

Background, CMake

Two C++ OpenGL side projects I’ve posted about in the last two years are…  One uses (Qt + OpenGL + Qt Creator with qmake .pro build files) for an STL model viewer in Qt Creator for (Windows, Mac OS X, Linux).  The other uses (SDL2 + OpenGL) for cross-platform demos such as a bookshelf style grid view and a shadow mapping demo (using assimp for models).  The build system for this latter project was a bit messy because I started from SDL2 sample projects for (Windows Visual Studio, Linux make files, Android nmake, XCode OSX, XCode iOS).  This made sense at the time (because my real job keeps me busy so I wanted a faster short-term path to see my cross-platform code running).  However, I decided I wanted a cleaner long-term build solution, so I gave this SDL2 project a complete “reboot”.

I started a new (but similar) project from scratch using CMake.  This was a great way to get some experience using CMake.  At my job, we use Visual Studio for Windows and Makefiles for Linux (with GCC).  For this side project there’s a lot more native build systems, so it makes more sense to use a tool like CMake (or SCons etc).

GLES2

To make the cross-platform aspect simpler at this stage, I’m doing all the OpenGL stuff with OpenGL ES 2 core profile (obviously in the long-term I could have multiple rendering paths).  The current list of platforms is – Windows (ANGLE), Linux, OS X, Android, iOS, Emscripten.  I kind of wanted to use GLES3 because of new features like (vertex array objects) and (texture arrays).  However, there is currently better cross-platform support for GLES2.  In particular, for Emscripten GLES3, better WebGL 2 browser support is required.

ANGLE is also currently lacking in GLES3 support.  Wikipedia says OpenGL 4.3 provides full compatibility with OpenGL ES 3.0, but I’m not sure whether it’s 100% true.  Plus I’m eventually planning to use ANGLE for Windows Mobile 10 support (or Universal Windows Platform) too.

OSX is lacking in terms of GLES2 support.  GL_ARB_ES2_compatibility does not provide full compatibility with GLES2.  I found that even simple GLES2 code requires changes to work on OSX – for example, a VAO (vertex array object) must be bound for OSX, while GLES2 core does not support VAOs.  GL_ARB_ES2_compatibility Overview states “will ease the process of porting applications from OpenGL ES 2.0 to OpenGL”, so it’s not full ES2 support.

So for OSX I will need some conditionals (or an alternate rendering path).  Or I could wait for ANGLE to add GLES2 support.  Or I could try MetalGL.  With the release of OSX 10.11 (just a few days ago), OSX now supports Metal, and there is a project MetalGL that can map GLES2 to Metal.  The day OSX 10.11 came out (9/30) I was able to run the demo (DrawLoadDemo) for MetalGL on OSX.  I was able to connect my own project to it (using CMake), but there is some compatibility issue with SDL2.  I’m not yet sure how easy it will be to get MetalGL to work with SDL2 on OSX.  TBD on this.

Qt Creator

I’m using Qt Creator as my primary editor and IDE (when possible).  Qt Creator has support for CMake.

Git

I’m using Git (instead of Subversion).  For basic use, the main difference between Git and Subversion is that Git is not designed around a centralized server.  So when I do a git commit, I also do a git push to push my local commit to the online central server.  Another obvious difference I noticed is that when I check svn log using TortoiseSVN it takes a long time to get the log from the central server (unless you use something to cache it).

Modern C++

An interesting aside is that Linus Torvald (who initially designed and developed git) likes C better than C++.  I actually have some sympathy with that view – C is simpler than C++ (so it’s less likely to result in pointlessly complex code) and it’s lower level (so it’s easier to know what the compiler will do).  Plus my job (GPU modeling) relates to systems software, and systems software programmers (eg computer engineers) tend to like lower layer code (ie closer to the hardware).

For my job we haven’t upgraded our project yet from Visual Studio 2010.

For this side project, I’m making a conscious effort to use more modern C++ features (eg C++11) when useful.

Screen Shots

I’ll figure out later how best to post the Emscripten version (uses JavaScript and WebGL).  For now I’ll just share a screenshot.  I’m also sharing a photo of the same demo running on a Kindle Fire HD 6.  This simple demo also runs on Linux, Windows, iOS, OSX.  A lot of the changes (ie the rewrite) I describe here relate to the cross-platform support (eg CMake usage), so I’m also including a screen shot of CMake in Qt Creator.  I’m also  including a screen shot of SourceTree for Git

image image image  image

Next Steps

I had a great time and learned a lot building this cross-platform infrastructure from the ground up.  I’m tempted to just focus more on that aspect.  I could make it an open source project, focus on making it more robust and better designed as a generic engine base.  Make it simpler and more streamlined for others to use for their projects.  Take feedback and contributions.  Add features and general-use functionality that isn’t specific to a particular application.  Integrate additional libraries (make some parts optional).  It might become more like a game engine or similar to Marmalade ( www.madewithmarmalade.com ).

Another path I’d love to pursue is writing additional graphics demos (eg beyond the basic shadow map demo seen in an earlier post).

However, the path I’ve decided to focus on next is to make a playable game.  I’ve been playing “Clash of Clans”, so I’ve decided to write a cross-platform tower defense game similar to CoC.  Here’s a random screen shot of CoC to give an idea – it’s an isometric tile-based tower defense strategy game.  I’m making it 3D so the rendering may look more like “Galaxy Control”.

image image

To keep things simple, I’m planning to focus on the rendering, basic UI, and a basic single player demo.  This means things like (art, sound, networking, content, game design details) are lower priority (at least initially).  I suspect if my goal was to release a commercial game as a solo developer, then using a pre-existing game engine (like Unity) (or at least Marmalade) would make more sense.  And going all crazy with the ground-up cross-platform support wouldn’t be necessary.  I also have a busy real job (GPU model development) and this project is just for fun and learning…  So we’ll see how far I get :-).  However far I get, I’ll at least expect to get some more great experience and learning 🙂