Hola a todos,
Bienvenidos a una nueva entrega sobre como hacer tu propio game engine desde 0.
En este capítulo explicaremos la implementación del texture manager. A grandes rasgos es lo mismo que el soundmanager pero para texturas. Es decir, cargaremos las texturas mediante un archivo de loading y accederemos a ellas mediante tags.
La carga de texturas (por ahora) la implementaremos con SOIL (quien quiera hacerlo con otra libreria y pasarmelo , yo se lo publico). La libreria SOIL es una manera muy potente de cargar texturas para su uso en 2D/3D . Os la podeis bajar de
aquí
Como unir SOIL al proyecto.
Una vez tengáis instalada la librería (mirad por Internet, no os lo voy ha hacer yo todo :D ) tendremos que linkarla al proyecto. Como ya hicimos en algún capítulo anterior:
1.propiedades de proyecto > C/C++ > Directorios de inclusión adicionales > “la ruta donde tengais instalados los .h de SOIL”
2. propiedades de proyecto > Vinculador>.Entrada > Dependencias adicionales : SOIL.lib
Con esto os deberia de funcionar todo. Si teneis problemas poned un comentario en este post y lo miraremos.
Como implementar el TextureManager
El texture manager se compone de un .h y un .cpp c on una estructura interna muy parecida al Sound Manager , así como de cambios en el GraphicsManager (inicialización , carga, descarga ,etc..) y en el Graphics3DManager (texturizaremos el cubo que teniamos hasta ahora con un gráfico de madera)
El código es el siguiente:
TextureManager.h:
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un game engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
/**************************************************************************************************/
// TextureManager.h : Código del gestor de texturas del game engine
// El código del cargador de texturas se obtiene de http://www.lonesock.net/soil.html
/**************************************************************************************************/
#ifndef __TextureManager__
#define __TextureManager__
#include "MyGL.h"
#include "FileManager.h" //Sirve para cargar el archivo de loading de texturas
#define MAX_ELEMENTS_LOADED 256 //por ahora hardcodeado, lo arreglaremos en algún momento.
class TextureManager
{
private:
// Constructor y destructor de la clase
static TextureManager instance;
TextureManager();
~TextureManager();
public:
static TextureManager& singleton();
public:
//Funcion para inicializar el motor de sonido
void Init(int* argc, char* argv[]);
//Funcion para desinicializar el motor de sonido
void DeInit();
public:
int LoadTexture( char cad[] );
void Texture(char id[]);
private:
FileManager filemanager;
char loaded[MAX_ELEMENTS_LOADED][256]; //Matriz donde guardamos los identificadores de textura y sus indices.
};
#endif // __FileManager__
TextureManager.cpp:
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un game engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
/**************************************************************************************************/
// TextureManager.cpp : Código del gestor de texturas del game engine
// El código del cargador de texturas se obtiene de http://www.lonesock.net/soil.html
/**************************************************************************************************/
#include "TextureManager.h"
#include "MyGL.h"
#include <SOIL/SOIL.h> //Libreria usada para cargar texturas
#include <iostream> //Usada para imprimir por consola
using namespace std;
//Instancia única del sound manager
TextureManager TextureManager::instance;
TextureManager::TextureManager()
{
}
TextureManager::~TextureManager()
{
}
//Devolvemos el puntero al singleton
TextureManager& TextureManager::singleton()
{
return instance;
}
//Sounds functions
void TextureManager::Init(int* argc, char* argv[])
{
char cad[256]; //Cadena donde guardaremos cada linea que leamos
char id[256]; //Cadena donde guardaremos el identificador de cada recurso
char ruta[256]; //Cadena donde guardaremos la ruta de cada recurso
int num_id; //número que nos asigna la función de carga del recurso.... un -1 significa que no lo ha podido cargar
cout << "Inicializamos el texture manager\n";
//alutInit(argc, argv) ;
filemanager.Init("Data\\LoadTexture.txt");
//Todo este código tendrá que ir al filemanager, pero por el momento lo dejamos aquí
//Leemos cada linea del archivo
while( filemanager.GetLine(cad) )
{
for( int i = 0 ; i < strlen(cad); ++i)
{
if ( cad[i] == '=' )
{
cad[i]='\0';
sprintf(id,"%s",cad);
sprintf(ruta,"%s",&cad[i+1]);
i = 257;
}
}
num_id = LoadTexture(ruta); //Cargamos el recurso
cout << "Intentamos cargar textura con ruta:" << ruta << "\n";
if (num_id == -1) //Si el recurso no se ha podido cargar, vamos a cargar el siguiente recurso
continue;
cout << "textura cargada con identificadores:" << id << " " << num_id << "\n";
sprintf( loaded[ num_id ] ,"%s" , id ); //Nos guardamos la referencia al recurso
}
}
void TextureManager::DeInit()
{
cout << "Desinicializamos el texture manager\n";
filemanager.DeInit();
}
//Carga el sonido cad y devuelve su posición en la que se ha guardado
int TextureManager::LoadTexture( char cad[] )
{
//TODO : Evaluar los casos en los que el archivo no se puede cargar y devolver un -1 en consecuencia
return ( SOIL_load_OGL_texture(
cad,
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID,
SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT)
);
}
//Función usada para seleccionar una textura en especial
void TextureManager::Texture(char id[])
{
int i; //Iterador
for ( i = 0 ; i < MAX_ELEMENTS_LOADED ; ++i ) //Para cada elemento cargado
{
if( !strcmp(loaded[i],id) ) //Hemos encontrado la cadena que nos interesa
{
continue;
}
}
if ( i == MAX_ELEMENTS_LOADED)
return;
//Texturizamos
glBindTexture(GL_TEXTURE_2D, i);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
}
GraphicsManager.cpp:
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un game engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
/**************************************************************************************************/
// GraphicsManager.cpp : Código del motor gráfico.
/**************************************************************************************************/
#include "GraphicsManager.h"
#include "MyGL.h"
#include "Graphics3DManager.h" //Parte de 3D del motor gráfico
#include "TextureManager.h" //Inclusión del motor de texturas
#include <iostream> //Usada para imprimir por consola
using namespace std;
//Instancia única del graphics manager
GraphicsManager GraphicsManager::instance;
//Constructor
GraphicsManager::GraphicsManager()
{
}
//Destructor
GraphicsManager::~GraphicsManager()
{
}
//Devolvemos el puntero al singleton
GraphicsManager& GraphicsManager::singleton()
{
return instance;
}
//Funcion para inicializar el motor gráfico
void GraphicsManager::Init(int* argc, char* argv[])
{
cout << "Inicializamos el Graphics Manager\n";
//Creamos la ventana principal del programa utilizando la libreria GLUT
glutInit(argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowPosition(0, 0);
glutInitWindowSize(640, 480);
int mainWindow = glutCreateWindow("Lord Pakus Engine!!!"); //Viva la originalidad!!! :)
glutSetWindow(mainWindow);
//Asignamos todas las funciones gráficas de callback del glut
//a las funciones que definiremos posteriormente
glutDisplayFunc(Render);
// glutReshapeFunc(Reshape); //Por ahora la dejamos comentada por que no nos hace falta
TextureManager::singleton().Init(argc,argv); //Inicializamos las texturas
Graphics3DManager::singleton().Init(argc,argv); //Inicializamos la parte de 3D
}
//Funcion para desinicializar el bucle principal
void GraphicsManager::DeInit()
{
TextureManager::singleton().DeInit(); //Desinicializamos la parte de texturas
Graphics3DManager::singleton().DeInit(); //Desinicializamos la parte de 3D
cout << "Desinicializamos el Graphics Manager\n";
}
//CALLBACKS DE GLUT, por ahora
//Funcion que se ejecuta automaticamente desde glut (por ahora)
void GraphicsManager::Render()
{
//Pintado de la parte de 3D
Graphics3DManager::singleton().Render();
//IMPORTANTE: Función encargada de realizar el double-buffering
glutSwapBuffers();
}
//Funcion que se ejecuta automaticamente desde glut (por ahora). Por el momento la dejamos comentada por que no nos hace falta
//void GraphicsManager::Reshape()
//{
// //AQUI IRÁ NUESTRA FUNCIÓN DE REESCALADO. Por ahora vacia
//}
Graphics3DManager: Se aplica solo este cambio dentro de la función de pintado.
glEnable(GL_TEXTURE_2D);
glColor3f(1.0f,1.0f,1.0f); //Limpiamos el buffer de color
TextureManager::singleton().Texture("wood"); //Usamos la textura
glBegin(GL_QUADS); // Start Drawing The Cube
//glColor3f(0.0f,1.0f,0.0f); // Set The Color To Green
glTexCoord2f( 0.0f, 0.0f); glVertex3f( 1.0f, 1.0f,-1.0f); // Top Right Of The Quad (Top)
glTexCoord2f( 0.0f, 1.0f); glVertex3f(-1.0f, 1.0f,-1.0f); // Top Left Of The Quad (Top)
glTexCoord2f( 1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Bottom Left Of The Quad (Top)
glTexCoord2f( 1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // Bottom Right Of The Quad (Top)
//glColor3f(1.0f,0.5f,0.0f); // Set The Color To Orange
glTexCoord2f( 0.0f, 0.0f); glVertex3f( 1.0f,-1.0f, 1.0f); // Top Right Of The Quad (Bottom)
glTexCoord2f( 0.0f, 1.0f); glVertex3f(-1.0f,-1.0f, 1.0f); // Top Left Of The Quad (Bottom)
glTexCoord2f( 1.0f, 1.0f); glVertex3f(-1.0f,-1.0f,-1.0f); // Bottom Left Of The Quad (Bottom)
glTexCoord2f( 1.0f, 0.0f); glVertex3f( 1.0f,-1.0f,-1.0f); // Bottom Right Of The Quad (Bottom)
//glColor3f(1.0f,0.0f,0.0f); // Set The Color To Red
glTexCoord2f( 0.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // Top Right Of The Quad (Front)
glTexCoord2f( 0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Top Left Of The Quad (Front)
glTexCoord2f( 1.0f, 1.0f); glVertex3f(-1.0f,-1.0f, 1.0f); // Bottom Left Of The Quad (Front)
glTexCoord2f( 1.0f, 0.0f); glVertex3f( 1.0f,-1.0f, 1.0f); // Bottom Right Of The Quad (Front)
//glColor3f(1.0f,1.0f,0.0f); // Set The Color To Yellow
glTexCoord2f( 0.0f, 0.0f); glVertex3f( 1.0f,-1.0f,-1.0f); // Bottom Left Of The Quad (Back)
glTexCoord2f( 0.0f, 1.0f); glVertex3f(-1.0f,-1.0f,-1.0f); // Bottom Right Of The Quad (Back)
glTexCoord2f( 1.0f, 1.0f); glVertex3f(-1.0f, 1.0f,-1.0f); // Top Right Of The Quad (Back)
glTexCoord2f( 1.0f, 0.0f); glVertex3f( 1.0f, 1.0f,-1.0f); // Top Left Of The Quad (Back)
//glColor3f(0.0f,0.0f,1.0f); // Set The Color To Blue
glTexCoord2f( 0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Top Right Of The Quad (Left)
glTexCoord2f( 0.0f, 1.0f); glVertex3f(-1.0f, 1.0f,-1.0f); // Top Left Of The Quad (Left)
glTexCoord2f( 1.0f, 1.0f); glVertex3f(-1.0f,-1.0f,-1.0f); // Bottom Left Of The Quad (Left)
glTexCoord2f( 1.0f, 0.0f); glVertex3f(-1.0f,-1.0f, 1.0f); // Bottom Right Of The Quad (Left)
//glColor3f(1.0f,0.0f,1.0f); // Set The Color To Violet
glTexCoord2f( 0.0f, 0.0f); glVertex3f( 1.0f, 1.0f,-1.0f); // Top Right Of The Quad (Right)
glTexCoord2f( 0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // Top Left Of The Quad (Right)
glTexCoord2f( 1.0f, 1.0f); glVertex3f( 1.0f,-1.0f, 1.0f); // Bottom Left Of The Quad (Right)
glTexCoord2f( 1.0f, 0.0f); glVertex3f( 1.0f,-1.0f,-1.0f); // Bottom Right Of The Quad (Right)
glEnd(); // Done Drawing The Quad
glDisable(GL_TEXTURE_2D);
Espero que os haya gustado. Aunque este capitulo os parezca una tonteria es el que nos servirá de base para absolutamente todo el módulo de Graphics2DManager y lo usaremos con cierta recurrencia para múltiples utilidades (graficos 2D, fuentes bitmapeadas , HUD , texturización de modelos 3D ,etc...)
Probad que os funcione y si veis que os falla, lo miramo.
Nos vemosss