domingo, 29 de abril de 2012

Arnow2D: Capturas de pantalla y uso de teclado


Artículo perteneciente a la sección de motores gráficos



Hola a todos...

Este capitulo se basa en explicar como hacer una captura de pantalla desde nuestro motor gráfico , así como usar el teclado con GLFW para activar dicha captura.

La captura de pantalla la realizaremos pidiendole a OpenGL que nos dé el buffer donde se pinta la pantalla y cargandolo mediante corona como si fuera una textura, para despues , mediante esta libreria grabarlo en un fichero.

La lectura de teclado se hace directamente mediante GLFW con la función: glfwGetKey

Así pues, vamos a mirar el código:


char data[1024*1024*4];

void A2D_Capture(char  *file)
{
int i;
corona::Image* imagen=NULL;

glReadPixels(0,0,1024,768, GL_RGBA , GL_BYTE, data);

for(i = 3 ; i<1024*768*4; i+=4)
data[i] = 255;

imagen = corona::CreateImage(1024,768,corona::PF_R8G8B8A8,data);
imagen = corona::FlipImage(imagen,corona::CA_X);
corona::SaveImage(file,corona::FF_AUTODETECT,imagen);
delete(imagen);
}

Como podeis observar: glReadPIxels nos devuelve en el vector data, toda la información correspondiente a la pantalla.

Este código:

for(i = 3 ; i<1024*768*4; i+=4)
data[i] = 255;

Es un apaño para que la imagen resultante me salga más luminosa (es el parametro de alpha).No se por que la imagen me salia todo oscurecida...si alguien tiene propuestas para hacerlo mejor que me lo diga.

Con este código invertimos la imagen en el eje x (el formato de imagen no es el mismo)
imagen = corona::FlipImage(imagen,corona::CA_X);

Y finalmente con este código grabamos el archivo en cuestión:
corona::SaveImage(file,corona::FF_AUTODETECT,imagen);


Finalmente solo nos queda hacer la llamada a esta función cuando el usuario le de a la tecla F12:

void Draw(void)
{
A2D_Draw(0,0,graf[0]);
A2D_Draw(500,0,graf[1]);
A2D_Draw(0,300,graf[2]);
A2D_Draw(500,300,graf[3]);

if ( glfwGetKey(GLFW_KEY_F12) )
{
A2D_Capture("A2DShot.png");
}
}

Y con esto os dejo hasta el siguiente capitulo...

Espero que os haya gustado y hagáis aprendido.

Nos vemos

LordPakusBlog

lunes, 23 de abril de 2012

Arnow2D. Mejorando el pintado

Artículo perteneciente a la sección de motores gráficos

Hola a todos,

En este capitulo nos encargaremos de mejorar el pintado de gráficos 2D por pantalla.

Por un lado, haremos que los gráficos se pinten con el tamaño del gráfico original y no a un valor hardcodeado por código y en segundo lugar permitiremos cargar diferentes tipos de formatos gráficos.

Para pintar gráficos con un tamaño especifico solamente hemos de texturizar en un quad del tamaño que a nosotros nos interese. La información del tamaño del quad la perdemos al eliminar el objeto de gráfico, así que tendremos que guardarlo de alguna forma.....

//Creamos una estructura donde almacenaremos el identificador de textura y sus dimensiones

typedef struct
{
int texture; //Almacenamos el identificador de textura
int w,h; //Ancho y largo de la textura original
}TGraf;

//Modificamos la función de carga...

int A2D_Load(char cad[])
{
GLuint tex;
corona::Image* imagen=NULL;

cout << "Cargamos recurso: " << cad << "\n";

imagen = corona::OpenImage(cad, corona::PF_R8G8B8A8 , corona::FF_AUTODETECT);

if(imagen==NULL)
{
cout << "Recurso no cargado\n";
return -1;
}

printf("Ancho:%d  Alto:%d\n",imagen->getWidth(),imagen->getHeight());
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imagen->getWidth(), imagen->getHeight(),0, GL_RGBA, GL_UNSIGNED_BYTE, imagen->getPixels());
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

GrafList[index_graf].texture = tex;
GrafList[index_graf].h = imagen->getHeight();
GrafList[index_graf].w = imagen->getWidth();

tex = index_graf;
index_graf++;

delete imagen;  

cout << "Recurso cargado\n";

return tex;
}

Y modificamos la función de pintado:

void A2D_Draw(float x, float y, int id)
{
int tex,w,h;

tex = GrafList[id].texture;
w = GrafList[id].w;
h = GrafList[id].h;

glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );

glBegin(GL_QUADS);
glTexCoord2f( 1.0f, 1.0f); glVertex2i( x + w , y + h );
glTexCoord2f( 0.0f, 1.0f); glVertex2i( x     , y + h );
glTexCoord2f( 0.0f, 0.0f); glVertex2i( x     , y  );
glTexCoord2f( 1.0f, 0.0f); glVertex2i( x + w    , y );
glEnd();
}



En cuanto a usar diferentes formatos gráficos corona nos lo deja muy fácil ya que solo nos pide que usemos la siguiente linea:
imagen = corona::OpenImage(cad, corona::PF_R8G8B8A8 , corona::FF_AUTODETECT);

Finalmente, pondremos un código de ejemplo para comprobar como funciona:



#include "Arnow2D.h"

GLuint graf[10];

void Draw(void)
{
int i,j;

A2D_Draw(0,0,graf[0]);
A2D_Draw(500,0,graf[1]);
A2D_Draw(0,300,graf[2]);
A2D_Draw(500,300,graf[3]);

}

void Main_Loop(void)
{
  while(1)
  {
//Limpiamos la pantalla
A2D_Clear();

Draw();

//Renderizamos la escena
A2D_Render();
  }
}

int main(void)
{
  A2D_Init();
  graf[0] = A2D_Load("img_test.png");
  graf[1] = A2D_Load("images.jpg");
  graf[2] = A2D_Load("78bc6b62fEySW.gif");
  graf[3] = A2D_Load("ejemplo.bmp");

  Main_Loop();

  A2D_DeInit();
}

Espero , que aunque sencillo, os haya ayudado, en breve más. Creo que en el próximo capitulo implementaré las z's. Si teneis sugerencias aqui estoy esperandolas

Os dejo el archivo con todo el código y los ejemplos aqui

Nos vemos

LordPakusBlog

lunes, 16 de abril de 2012

Arnow2D. Minimotor 2D funcionando

Hola a todos...

Despues de tanto tiempo ya puedo subir el capitulo 3 del curso de como crear un motor 2D sencillo.

El motor usa opengl, glfw para las ventanas, corona para la carga de gráficos y quicktext para las fuentes.

Recomiendo que le echeis un ojo a :
http://lordpakus.blogspot.com.es/2011/06/gameengine-capitulo-6.html
http://lordpakus.blogspot.com.es/2011/06/gameengine-capitulo-7.html
http://lordpakus.blogspot.com.es/2011/06/gameengine-capitulo-9-graphics2dmanager.html

Le faltan lo sonidos, los tamaños de gráficos están hardcodeados y no tenemos todavía gestión de Z's, peroooo es un inicio de motor sencillo, en un solo cpp y que permite cargar y pintar gráficos.

El código lo podeis ver aqui

En próximos capitulos iremos puliendo recursivamente el código para darle más funcionalidades y que sea más mantenible.

Espero que os guste.

main.cpp


#include "Arnow2D.h"

GLuint graf;

void Draw(void)
{
A2D_Draw(0,0,graf);
}

void Main_Loop(void)
{
  while(1)
  {
//Limpiamos la pantalla
A2D_Clear();

Draw();

//Renderizamos la escena
A2D_Render();
  }
}

int main(void)
{
  A2D_Init();
  graf = A2D_Load("img_test.png");
  Main_Loop();
  glDeleteTextures( 1, &graf );
  A2D_DeInit();
}



Arnow2D.cpp

#include "Arnow2D.h"

//Pasamos a modo 2D
void switchToOrtho(void)
{
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0, 640, 0, 340, -5, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

//Volvemos al modo 3D
void switchBackToFrustum (void)
{
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}

//Función de calculo de FPS
int CalcFPS()
{
static clock_t timer = clock(); //Temporizador para los FPS
static int FPS = 0;
static int LastFPS = 0;
FPS++;

if ( (clock() - timer) > 1000 )
{
LastFPS = FPS;
FPS = 0;
timer = clock();
}

return LastFPS;
}

void A2D_Draw(float x, float y, int id)
{
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, id);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );

glBegin(GL_QUADS);
glTexCoord2f( 1.0f, 1.0f); glVertex2i( x - 128 , y - 128 ); // Top Right Of The Quad (Front)
glTexCoord2f( 0.0f, 1.0f); glVertex2i( x + 128 , y - 128 ); // Top Left Of The Quad (Front)
glTexCoord2f( 0.0f, 0.0f); glVertex2i( x + 128 , y + 128 ); // Bottom Left Of The Quad (Front)
glTexCoord2f( 1.0f, 0.0f); glVertex2i( x - 128 , y + 128 ); // Bottom Right Of The Quad (Front)
glEnd();
}

int A2D_Load(char cad[])
{
GLuint tex;
corona::Image* imagen=NULL;

cout << "Cargamos recurso: " << cad << "\n";

imagen = corona::OpenImage(cad);//corona::PF_R8G8B8A8

if(imagen==NULL)
{
cout << "Recurso no cargado\n";
return -1;
}

printf("Ancho:%d  Alto:%d\n",imagen->getWidth(),imagen->getHeight());
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imagen->getWidth(), imagen->getHeight(),0, GL_RGBA, GL_UNSIGNED_BYTE, imagen->getPixels());
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

delete imagen;  

cout << "Recurso cargado\n";

return tex;
}

void A2D_Init(void)
{
  const int window_width = 1024,
            window_height = 768;

  if (glfwInit() != GL_TRUE)
    Shut_Down(1);

  // 800 x 600, 16 bit color, no depth, alpha or stencil buffers, windowed
  if (glfwOpenWindow(window_width, window_height, 8, 8, 8, 0, 0, 0, GLFW_WINDOW) != GL_TRUE)
    Shut_Down(1);

   glfwSetWindowTitle("Arnow2D Engine");
   glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
   glLoadIdentity(); // Reset The Projection Matrix
   glOrtho(.5*window_width, -.5*window_width, -.5 * window_height, .5 * window_height, 1, 50);

glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
  glEnable(GL_TEXTURE_2D); // Enable Texture Mapping ( NEW )
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
}

void A2D_DeInit(void)
{
Shut_Down(0);
}

void A2D_Clear(void)
{
    // clear the buffer
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0,0, -30);
}

void A2D_Print(int x, int y, char *cad)
{
switchToOrtho();
glQuickText::printfAt(10.0,10.0, 0.0f ,1.0f , cad );
switchBackToFrustum();
}

void A2D_Render(void)
{
    char cadFPS[32];

sprintf(cadFPS,"FPS: %d",CalcFPS());
A2D_Print(10,10,cadFPS);

glfwSwapBuffers();
}

void Shut_Down(int return_code)
{
  glfwTerminate();
  exit(return_code);
}

Nos vemos


Entradas populares