Sunday, February 10, 2013

Animating 2D Sprites in OpenGL

In working on my latest game, Praecursor, it came time to develop a system for easily animating sprites on the screen. I found a very nice sprite for a hero on OpenGameArt, and wanted to integrate his various animations into player actions. In the process, I created a CAnimation class that would extend the CRigidBody class, making it eligible to act just like a physical entity and be rendered on the screen with relative ease. The entire process was fairly challenging, requiring a custom file format parser and a new fragment shader. The following is a tutorial-like thought process that went into the development of animate-able sprites.

Layout

The CAnimation class is supposed to act exactly like a regular physical entity, but should support loading of custom .icanim files and have various functions related to animation. These include toggling animation, setting an automatic animation rate, quick-swapping sprite sheets, and manually switching sprites.

Quick-swapping seems like a pointless functionality of an animation class; after all, why not just create a separate instance and load it with the new sprite sheet? Well, I didn't think about this until I started trying to swap-out animations for running, jumping, and standing with the main player instance. When I would just have a list of animations and do m_Player = m_allAnimations[JUMP], the player would lose his physics properties, such as gravity or jump force. I tried a few workarounds, but none of them turned out like expected, so I decided to add a SwapSpriteSheet() method to the CAnimation class. This will attach a new texture to the material and give the shader new parameters based on width and heights.

In the future, I think I will change the class to incorporate animation boundaries, so I don't need to load a separate image for each animate-able action. I would be able to do something like SetAnimationIndex(0, JUMP), and the animation would only loop through sprites [0:JUMP], then if I wanted to just play the standing animation, I could do SetAnimationIndex(JUMP + 1, STAND), assuming the standing animation comes after the jumping one in the sprite sheet. This would likely all but eliminate the need for the swapping method.

Sunday, February 3, 2013

Rendering Text in OpenGL Using FreeType Fonts

EDIT (04.14.2013): Tutorial updated to handle new-lines (\n character)

I finally decided to tackle the rendering of TrueType fonts in my engine. It proved to be a much bigger challenge than I had originally anticipated; I perused over dozens of outdated guides, tutorials, code snippets, and documentation files to finally achieve something legible on screen. I decided to provide a complete guide to this process so that if anyone should decide to follow in my footsteps, they will know where to go.

Tuesday, January 22, 2013

First Praecursor Screenshots

I'm trying so hard to stay motivated on this project, it has a lot of potential in my mind. With the spring semester just starting, I hope I'll be able to keep time available to work on Praecursor. Feel free to follow my progress on the game's GitHub page.

I've made some progress on the game. I found an excellent free texture pack with lots of textures perfect for an urban, impoverished setting. They are incredibly realistic, so the main hero stands out like a sore thumb. Here are a few screenshots:

Player is way too small!

Tuesday, January 15, 2013

A New Beginning

For the past several weeks, I've been working on implementing a 2D OpenGL rendering engine dubbed IronClad. A lot of progress has been made, and I have decided to start working on a new project that will fully utilize the features of my engine. You can find the source code on my GitHub page here.

Implemented Features

  • Full use of modern OpenGL features such as vertex array objects
  • Instanced geometry which allows for high-speed, batched rendering of many vertices
  • Per-pixel shader-based lighting (currently only point lights)
  • Optimized mesh loading
  • Entity wrapper for easily controllable mesh instances
  • Minimalistic physics system
  • Loading of a custom level format for easy scene creation



Latest Project: Praecursor


Precursor - n. 
  1. A person or thing that comes before another of the same kind; a forerunner
  2. A substance from which another is formed, esp. by metabolic reaction. 

Story


Tuesday, November 13, 2012

A Guide to Instanced Geometry

As stated in the title, this is more of a guide than a tutorial. It isn't for the complete beginner, some experience is necessary. Throughout this I assume you have a general knowledge of what a mesh is, basic understanding of how matrices work, basic knowledge of GLSL, and experience with C++ or another object-oriented language. I am just writing about my own personal implementation of instanced geometry, which is definitely open for comments and suggestions. The code snippets are stripped down versions directly from my basic 2D OpenGL rendering engine I have dubbed IronClad.

What Is Instanced Geometry?

Primitive rendering techniques have many copies of a single object's data. Say you wanted to draw a tiled map, with 2 unique tiles. Say, for instance (no pun intended), a floor tile and a wall tile. Now, each of these objects contains, at the very least, 8 floats for vertex positions, and 8 floats for texture coordinates. That's 8 * 4 + 8 * 4 = 64 bytes. If each instance of a tile contains this information for rendering, and you have 1000 wall tiles, that's 64 kilobytes of memory! And that's not even considering the other tile types. Obviously, this is an example of a very simple mesh with only 4 vertices. Most games have models with hundreds if not thousands of vertices, so you can see why it'd be a serious problem to have multiple copies of that data.

Of course, there's a simple solution to this problem; you keep around one copy of the data in the first object you create, and the other objects simply refer to the original, just in their own position. Well, that's exactly where instancing comes in!

Friday, October 19, 2012

Development On Hold

Throughout the course of development for Collapse, I had been relying on OpenGL's age-old immediate mode for rendering. This proved to be a serious hindrance as I kept adding more advanced features such as lighting and shadows. My previous post about shadows works extremely well when shadows are limited to a single light. Clearly this is unacceptable, and the various techniques I tried to get it functioning with many lights either proved to be much too slow in immediate mode, or would require a serious amount of restructuring of the rendering system.

So, I put everything on hold temporarily and decided to learn modern OpenGL. I found a superb series of tutorials through StumbleUpon, and have been following them to gain a good base in the modern features of OpenGL, such as vertex array objects, matrices, and indexed geometry.

This task has sparked the development of a 2D engine, which I have dubbed IronClad. I've made a lot of progress in the past few weeks, implementing a VAO wrapper, support for a custom mesh file format, indexed geometry, shaders, and other nice features. I have also made a switch from SDL to GLFW for window management, and abandoned SDL_ttf in favor of FTGL. The reason for this is that the latest stable version of SDL only supports OpenGL contexts using versions <= 2.1, and I need more than that. The latest development build, SDL 2.0, supports the versions I need, but I'd most likely need a serious refactoring of my SDL code base to support it, so I decided to just make the switch to something OpenGL-specific.

Saturday, September 29, 2012

Working With Shadows

The logical course of action after finishing lighting is to move on to shadows. I opted for a relatively simple, software-based approach. It involves casting rays from the light source to individual edges of the tiles in the collision map, and drawing black quads based on the rays.


In my current implementation, the shadows are independent of the other lights. Thus, shadows cast by one light will be left untouched if there is another light in the way. This obviously causes problems, and a better method that will calculate cumulative shadows is currently in progress. But for a single light, the following algorithm suffices. Hopefully some OpenGL beginners trying to create shadows can gain some knowledge from my own trial-and-error!