Skip to content

Instantly share code, notes, and snippets.

@Shaptic
Last active December 12, 2015 09:28
Show Gist options
  • Save Shaptic/4751252 to your computer and use it in GitHub Desktop.
Save Shaptic/4751252 to your computer and use it in GitHub Desktop.
Animation loading implementation
#include "Entity/Animation.hpp"
bool CAnimation::LoadFromFile(const std::string& filename,
gfx::CVertexBuffer& VBO)
{
// Open the .icanim file.
std::ifstream anim(filename, std::ios::binary);
CAnimation::AnimationHeader& header = m_SheetDetails;
memset(&header, NULL, sizeof header);
if(!anim.is_open()) return false;
// Parse the header data.
anim >> header.width;
anim >> header.height;
anim >> header.columns;
anim >> header.rows;
// Bad header if it has any zeroes.
if(!(header.width && header.height && header.columns && header.rows))
return false;
// Get file size.
const std::streampos begin = anim.tellg();
anim.seekg(0, std::ios::end);
const std::streampos end = anim.tellg();
anim.seekg(begin);
// Load raw texture data into a local buffer.
unsigned char* data = new unsigned char[end - begin];
anim.read((char*)data, end - begin);
// Use GLFW to load a .tga file from raw pixel data.
// GLFW_NO_RESCALE_BIT is specified because modern OpenGL
// can deal with non-power-of-two textures.
GLFWimage img;
glfwReadMemoryImage(data, end - begin, &img, GLFW_NO_RESCALE_BIT);
// Small shortcut.
uint16_t w = img.Width; // or header.width
uint16_t h = img.Height; // or header.height
// Individual sprite width.
uint16_t sprite_w = w / header.columns;
uint16_t sprite_h = h / header.rows;
vertex2_t quad_v[4];
uint16_t quad_i[6] = {0, 1, 3, 3, 2, 1};
// This gives the texture coordinates necessary to render a
// single sprite in the sheet. For example, in a 2x2 sheet of
// 32x32 sprites, this would give the vector <0.5, 0.5>, meaning
// that each sprite is half the width and half the height of the
// entire sprite sheet, which is true.
m_TexcDim = math::vector2_t(1.f / header.columns, 1.f / header.rows);
// Mesh coordinates for the quad.
quad_v[0].Position = math::vector2_t(0, 0);
quad_v[1].Position = math::vector2_t(sprite_w, 0);
quad_v[2].Position = math::vector2_t(sprite_w, sprite_h);
quad_v[3].Position = math::vector2_t(0, sprite_h);
// Texture coordinates are for the entire sprite sheet.
// Later, these are used to calculate the offset within
// the shader. See Animate.fs for more detail.
quad_v[0].TexCoord = math::vector2_t(0.f, 1.f);
quad_v[1].TexCoord = math::vector2_t(1.f, 1.f);
quad_v[2].TexCoord = math::vector2_t(1.f, 0.f);
quad_v[3].TexCoord = math::vector2_t(0.f, 0.f);
asset::CTexture* pTexture = asset::CAssetManager::Create<asset::CTexture>();
pTexture->SetFilename(filename);
pTexture->LoadFromRaw(img.Format, img.Format, w, h, img.Data);
header.pTexture = pTexture;
glfwFreeImage(&img);
// Load quad mesh
m_Mesh.LoadMesh(quad_v, 4, quad_i, 6);
// Load whole sprite sheet into surface.
m_Mesh.GetSurfaces()[0]->pMaterial->pTexture = pTexture;
// Load the rendering shader.
gfx::CShaderPair* pShader = m_Mesh.GetSurfaces()[0]->pMaterial->pShader;
if(pShader == NULL)
{
pShader = new gfx::CShaderPair;
if(!pShader->LoadFromFile("Shaders/Default.vs", "Shaders/Animate.fs"))
return false;
}
// The shader contains an offset so that the texture coordinates
// can be shifted to reflect the current sprite.
pShader->Bind();
m_tc_loc = pShader->GetUniformLocation("tc_offset");
m_tc_str = pShader->GetUniformLocation("tc_start");
glUniform2f(m_tc_loc, m_TexcDim.x, m_TexcDim.y);
glUniform2f(m_tc_str, 0.f, 0.f); // We want the top-left sprite
pShader->Unbind();
// Assign the shader to the mesh
m_Mesh.GetSurfaces()[0]->pMaterial->pShader = pShader;
// Rigid body collision should be to a single sprite.
m_CollisionBox.w = m_SheetDetails.width / m_SheetDetails.columns;
m_CollisionBox.h = m_SheetDetails.height / m_SheetDetails.rows;
// Load the quad into the VBO and return the result.
return m_Mesh.LoadIntoVBO(VBO);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment