From 9ce32da1195aabbbf57f82341e5bc83592ecfa1f Mon Sep 17 00:00:00 2001
From: Tamir Atias <engine.games@gmail.com>
Date: Sun, 8 Apr 2012 02:34:33 +0300
Subject: [PATCH] [Add] Texture class. [Fix] Texture loading. [Add] Sprites.

---
 Bin/VC10/VC10.vcxproj         |  9 ++++
 Bin/VC10/VC10.vcxproj.filters | 33 ++++++++++++++
 src/Main/Game.cpp             | 28 +++++++-----
 src/Main/Game.h               |  5 ++-
 src/Sprite/Sprite.cpp         | 62 +++++++++++++++++++++++++
 src/Sprite/Sprite.h           | 34 ++++++++++++++
 src/Texture/Texture.cpp       | 85 ++++++++++++++++++++++++++++++++---
 src/Texture/Texture.h         | 18 ++++++++
 8 files changed, 256 insertions(+), 18 deletions(-)
 create mode 100644 src/Sprite/Sprite.cpp
 create mode 100644 src/Sprite/Sprite.h

diff --git a/Bin/VC10/VC10.vcxproj b/Bin/VC10/VC10.vcxproj
index 7c7cc52..d080f01 100644
--- a/Bin/VC10/VC10.vcxproj
+++ b/Bin/VC10/VC10.vcxproj
@@ -88,6 +88,11 @@
     <ClInclude Include="..\..\src\glx\wglext.h" />
     <ClInclude Include="..\..\src\Main\Game.h" />
     <ClInclude Include="..\..\src\Main\GLWindow.h" />
+    <ClInclude Include="..\..\src\Math\FPS.h" />
+    <ClInclude Include="..\..\src\Math\MathBox.h" />
+    <ClInclude Include="..\..\src\Math\Timer.h" />
+    <ClInclude Include="..\..\src\Math\Vec2.h" />
+    <ClInclude Include="..\..\src\Sprite\Sprite.h" />
     <ClInclude Include="..\..\src\Texture\Texture.h" />
   </ItemGroup>
   <ItemGroup>
@@ -95,6 +100,10 @@
     <ClCompile Include="..\..\src\Main\Game.cpp" />
     <ClCompile Include="..\..\src\Main\GLWindow.cpp" />
     <ClCompile Include="..\..\src\Main\main.cpp" />
+    <ClCompile Include="..\..\src\Math\FPS.cpp" />
+    <ClCompile Include="..\..\src\Math\Timer.cpp" />
+    <ClCompile Include="..\..\src\Math\Vec2.cpp" />
+    <ClCompile Include="..\..\src\Sprite\Sprite.cpp" />
     <ClCompile Include="..\..\src\Texture\Texture.cpp" />
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
diff --git a/Bin/VC10/VC10.vcxproj.filters b/Bin/VC10/VC10.vcxproj.filters
index 156e57d..83fbefc 100644
--- a/Bin/VC10/VC10.vcxproj.filters
+++ b/Bin/VC10/VC10.vcxproj.filters
@@ -13,6 +13,12 @@
     <Filter Include="Texture">
       <UniqueIdentifier>{93e01b38-0451-468e-9283-d8533feac24f}</UniqueIdentifier>
     </Filter>
+    <Filter Include="Sprite">
+      <UniqueIdentifier>{97b8d845-3714-4ef7-94b4-8ac3033675a3}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Math">
+      <UniqueIdentifier>{cea04fae-e026-4f1f-b2be-1accb582d0a4}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\src\Main\GLWindow.h">
@@ -33,6 +39,21 @@
     <ClInclude Include="..\..\src\Actor\Player.h">
       <Filter>Actor</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\Sprite\Sprite.h">
+      <Filter>Sprite</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\Math\Timer.h">
+      <Filter>Math</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\Math\Vec2.h">
+      <Filter>Math</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\Math\FPS.h">
+      <Filter>Math</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\Math\MathBox.h">
+      <Filter>Math</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\src\Main\main.cpp">
@@ -50,5 +71,17 @@
     <ClCompile Include="..\..\src\Actor\Player.cpp">
       <Filter>Actor</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\Math\Timer.cpp">
+      <Filter>Math</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\Math\Vec2.cpp">
+      <Filter>Math</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\Math\FPS.cpp">
+      <Filter>Math</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\Sprite\Sprite.cpp">
+      <Filter>Sprite</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/src/Main/Game.cpp b/src/Main/Game.cpp
index 2a82cd7..f637b37 100644
--- a/src/Main/Game.cpp
+++ b/src/Main/Game.cpp
@@ -6,6 +6,8 @@
 #include <GL/glu.h>
 
 #include "Game.h"
+#include "../Sprite/Sprite.h"
+#include "../Texture/Texture.h"
 
 Game::Game(void) {
 	_rotationAngle = 0.0f;
@@ -19,6 +21,12 @@ bool Game::Init(void) {
 	glEnable(GL_DEPTH_TEST);
 	glDepthFunc(GL_LEQUAL);
 	
+  Texture* testTexture = new Texture();
+  testTexture->Load("../../Data/Img/test.png");
+  
+  _testSprite = new Sprite();
+  _testSprite->SetTexture(testTexture);
+
 	// Return success.
 	return true;
 }
@@ -33,22 +41,20 @@ void Game::Prepare(float dt) {
 
 void Game::Render(void) {
 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-	glLoadIdentity();
 	
-	glRotatef(_rotationAngle, 0, 0, 1);
+  glMatrixMode(GL_PROJECTION);
+  glLoadIdentity();
+  glOrtho(0.0, 800.0, 600.0, 0.0, 0.0, 1.0);
+
+  glMatrixMode(GL_MODELVIEW);
+  glLoadIdentity();
 	
-	glBegin(GL_TRIANGLES);
-	  glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
-		glVertex3f(-1.0f, -0.5f, -4.0f);
-		glColor4f(1.0f, 1.0f, 0.0f, 1.0f);
-		glVertex3f(1.0f, -0.5f, -4.0f);
-		glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
-		glVertex3f(0.0f, 0.5f, -4.0f);
-	glEnd();
+	_testSprite->Draw();
 }
 
 void Game::Shutdown(void) {
-	
+	delete _testSprite->GetTexture();
+  delete _testSprite;
 }
 
 void Game::OnResize(int width, int height) {
diff --git a/src/Main/Game.h b/src/Main/Game.h
index 074e516..8ab2c71 100644
--- a/src/Main/Game.h
+++ b/src/Main/Game.h
@@ -1,5 +1,7 @@
 #pragma once
 
+class Sprite;
+
 class Game {
 public:
 	Game(void);
@@ -11,7 +13,8 @@ public:
 	void Shutdown(void);
 	
 	void OnResize(int width, int height);
-	
+
 private:
 	float _rotationAngle;
+  Sprite* _testSprite;
 };
diff --git a/src/Sprite/Sprite.cpp b/src/Sprite/Sprite.cpp
new file mode 100644
index 0000000..24378c4
--- /dev/null
+++ b/src/Sprite/Sprite.cpp
@@ -0,0 +1,62 @@
+#include "Sprite.h"
+#include "../Texture/Texture.h"
+
+Sprite::Sprite() {
+  texture = NULL;
+  size = Vec2(0.0f, 0.0f);
+  scale = Vec2(1.0f, 1.0f);
+  handle = Vec2(0.0f, 0.0f);
+}
+
+Sprite::~Sprite() {
+}
+
+void Sprite::Update(float dt) {
+}
+
+void Sprite::Draw() const {
+  // Awesome artwork to describe this:
+  // 0---------1
+  // .         .
+  // .         .
+  // .         .
+  // 3---------2
+
+  Vec2 vertices[4] = {
+    Vec2(handle.x, handle.y),
+    Vec2(handle.x + size.x, handle.y),
+    Vec2(handle.x + size.x, handle.y + size.y),
+    Vec2(handle.x, handle.y + size.y),
+  };
+
+  Vec2 texCoords[4] = {
+    Vec2(0.0f, 0.0f),
+    Vec2(1.0f, 0.0f),
+    Vec2(1.0f, 1.0f),
+    Vec2(0.0f, 1.0f),
+  };
+
+  for(int i = 0; i < 4; i++){
+    vertices[i].x *= scale.x;
+    vertices[i].y *= scale.y;
+  }
+
+  glEnable(GL_TEXTURE_2D);
+  BindTexture(texture->GetTexID());
+
+  glBegin(GL_QUADS);
+  glTexCoord2fv((const GLfloat*)&texCoords[0]);
+  glVertex2fv((const GLfloat*)&vertices[0]);
+  glTexCoord2fv((const GLfloat*)&texCoords[1]);
+  glVertex2fv((const GLfloat*)&vertices[1]);
+  glTexCoord2fv((const GLfloat*)&texCoords[2]);
+  glVertex2fv((const GLfloat*)&vertices[2]);
+  glTexCoord2fv((const GLfloat*)&texCoords[3]);
+  glVertex2fv((const GLfloat*)&vertices[3]);
+  glEnd();
+}
+
+void Sprite::SetTexture(Texture* texture) {
+  this->texture = texture;
+  this->size = Vec2(texture->GetWidth(), texture->GetHeight());
+}
diff --git a/src/Sprite/Sprite.h b/src/Sprite/Sprite.h
new file mode 100644
index 0000000..67dff99
--- /dev/null
+++ b/src/Sprite/Sprite.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "../Math/Vec2.h"
+
+class Texture;
+
+class Sprite {
+public:
+  Sprite();
+  virtual ~Sprite();
+
+  virtual void Update(float dt);
+  virtual void Draw() const;
+
+  const Vec2&     GetHandle() const { return handle; }
+  const Vec2&     GetSize() const { return size; }
+  const Vec2&     GetScale() const { return scale; }
+  float           GetRotation() const { return rotation; }
+  Texture*        GetTexture() { return texture; }
+  const Texture*  GetTexture() const { return texture; }
+
+  void SetHandle(const Vec2& handle) { this->handle = handle; }
+  void SetScale(const Vec2& scale) { this->scale = scale; }
+  void SetRotation(float rotation) { this->rotation = rotation; }
+  void SetTexture(Texture* texture);
+
+private:
+  Vec2 handle;
+  Vec2 size;
+  Vec2 scale;
+  float rotation;
+  Texture* texture;
+};
+
diff --git a/src/Texture/Texture.cpp b/src/Texture/Texture.cpp
index 00694a5..e4617e5 100644
--- a/src/Texture/Texture.cpp
+++ b/src/Texture/Texture.cpp
@@ -2,11 +2,24 @@
 #include <iostream>
 using namespace std;
 
+static GLuint boundTexture = 0;
+
+static bool IsBGR(SDL_Surface* surf) {
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+  return (surf->format->Rmask & 0x00FF0000) &&
+         (surf->format->Bmask & 0x000000FF);
+#else
+  return (surf->format->Bmask & 0xFF000000) &&
+         (surf->format->Rmask & 0x0000FF00);
+#endif
+}
+
 int BuildTexture(const char* filename, GLuint* texID, GLint param, bool genMips) {
   // Create a storage space for the texture.
   SDL_Surface* textureImage;
   // Format to pass to texture generation method.
-  GLint textureFormat;
+  GLint format;
+  GLint internalFormat;
 
   // Load the image, check for errors, if it isn't found, quit.
   textureImage = IMG_Load(filename);
@@ -15,12 +28,43 @@ int BuildTexture(const char* filename, GLuint* texID, GLint param, bool genMips)
     std::cerr << "Warning: could not load " << filename << std::endl;
     return false;
   }
+
+  switch(textureImage->format->BitsPerPixel) {
+  case 8:
+    internalFormat = format = GL_ALPHA;
+    break;
+  case 16:
+    internalFormat = format = GL_LUMINANCE_ALPHA;
+    break;
+  case 24:
+    internalFormat = GL_RGB;
+    if (IsBGR(textureImage))
+      format = GL_BGR_EXT;
+    else
+      format = GL_RGB;
+    break;
+  case 32:
+    internalFormat = GL_RGBA;
+    if (IsBGR(textureImage))
+      format = GL_BGR_EXT;
+    else
+      format = GL_RGBA;
+    break;
+  default:
+    format = internalFormat = GL_NONE;
+  }
+
+  if(internalFormat == GL_NONE || format == GL_NONE) {
+    std::cerr << "Warning: invalid texture format for " << filename << std::endl;
+    SDL_FreeSurface(textureImage);
+    return false;
+  }
   
   // Create the texture.
   glGenTextures(1, texID);
   
   // Typical texture generation using data from the bitmap.
-  glBindTexture(GL_TEXTURE_2D, *texID);
+  BindTexture(*texID);
   
   // Setup filtering.
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, param);
@@ -30,13 +74,13 @@ int BuildTexture(const char* filename, GLuint* texID, GLint param, bool genMips)
   if(genMips) {
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
     // Generate the textures and mipmaps.
-    gluBuild2DMipmaps(GL_TEXTURE_2D, textureFormat, textureImage->w,
-                      textureImage->h, GL_RGB, GL_UNSIGNED_BYTE,
+    gluBuild2DMipmaps(GL_TEXTURE_2D, internalFormat, textureImage->w,
+                      textureImage->h, format, GL_UNSIGNED_BYTE,
                       textureImage->pixels);
   } else {
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    glTexImage2D(GL_TEXTURE_2D, 0, textureFormat, textureImage->w,
-                      textureImage->h, 0, GL_RGB, GL_UNSIGNED_BYTE,
+    glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, textureImage->w,
+                      textureImage->h, 0, format, GL_UNSIGNED_BYTE,
                       textureImage->pixels);
   }
   // Free up the memory we used.
@@ -173,3 +217,32 @@ int WriteTGAFile(const char* filename, short int width, short int height, unsign
   
   return 1;
 }
+
+void BindTexture(GLuint texID) {
+  if(boundTexture != texID){
+    glBindTexture(GL_TEXTURE_2D, texID);
+    boundTexture = texID;
+  }
+}
+
+Texture::Texture() {
+  texID = 0;
+  width = 0;
+  height = 0;
+}
+
+Texture::~Texture() {
+  if(texID != 0) {
+    glDeleteTextures(1, &texID);
+    texID = 0;
+  }
+}
+
+bool Texture::Load(const char* filename) {
+  if(BuildTexture(filename, &texID, GL_CLAMP, false)) {
+    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
+    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
+    return true;
+  }
+  return false;
+}
diff --git a/src/Texture/Texture.h b/src/Texture/Texture.h
index 194a6cd..0d33df4 100644
--- a/src/Texture/Texture.h
+++ b/src/Texture/Texture.h
@@ -23,3 +23,21 @@ typedef struct {
 int BuildTexture(const char* filename, GLuint* texID, GLint param, bool genMips);
 int LoadTGAFile(const char* filename, TGAFILE* tgaFile);
 int WriteTGAFile(const char* filename, short int width, short int height, unsigned char* textureData);
+void BindTexture(GLuint texID);
+
+class Texture {
+public:
+  Texture();
+  ~Texture();
+
+  bool Load(const char* filename);
+
+  GLuint  GetTexID() const { return texID; }
+  int     GetWidth() const { return width; }
+  int     GetHeight() const { return height; }
+
+private:
+  GLuint texID;
+  int width;
+  int height;
+};