Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Cargar Textura En Png Con Opengl-sdl

Iniciado por javiel, 21 de Diciembre de 2005, 06:20:28 PM

« anterior - próximo »

javiel

 Bueno, estoy intentando cargar una textura PNG que tiene alpha. La cosa es que me salen cosas muy muy raras. Esto de las texturas de opengl me está matando, hay que acostumbrarse. Lo que haga es cargar un sdl_surface con IMG_Load de SDL_Image y luego ponerlo en la textura. Con los BMP van de escándalo pero el png salen un monton de puntos desordenados. Pongo el código:


SDL_Surface *LoadTex(char *filename)
{
   Uint8 *rowhi, *rowlo;
   Uint8 *tmpbuf, tmpch;
   SDL_Surface *image;
   int i, j;

   image = IMG_Load(filename);
   if ( image == NULL ) {
       fprintf(stderr, "Unable to load %s: %s\n", filename, SDL_GetError());
       return(NULL);
   }
   
   w = image->w;
   h = image->h;

   /* GL surfaces are upsidedown and RGB, not BGR :-) */
   tmpbuf = (Uint8 *)malloc(image->pitch);
   if ( tmpbuf == NULL ) {
       fprintf(stderr, "Out of memory\n");
       return(NULL);
   }
   
   rowhi = (Uint8 *)image->pixels;
   rowlo = rowhi + (image->h * image->pitch) - image->pitch;
   for ( i=0; i<image->h/2; ++i ) {
       for ( j=0; j<image->w; ++j ) {
           tmpch = rowhi[j*3];
           rowhi[j*3] = rowhi[j*3+2];
           rowhi[j*3+2] = tmpch;
           tmpch = rowlo[j*3];
           rowlo[j*3] = rowlo[j*3+2];
           rowlo[j*3+2] = tmpch;
       }
       memcpy(tmpbuf, rowhi, image->pitch);
       memcpy(rowhi, rowlo, image->pitch);
       memcpy(rowlo, tmpbuf, image->pitch);
       rowhi += image->pitch;
       rowlo -= image->pitch;
   }
   //free(tmpbuf);
   return(image);
}


Supongo que uno de los errores es que necesito RGBA, pero no se como usarlo. La verdad que estoy un poco muy liado.

¿alguien me puede ayudar?

muchas gracias a todos por vuestra paciencia
uper-Tirititran: el superhéroe gaditano (http://www.super-tirititran.com)

Zaelsius

 Así a ojo, por la pinta del bucle, parece que ese código está pensado para trabajar únicamente con imágenes en formato BGR(3 canales, como los BMP). Supongo que el problema es que los ficheros PNG suelen usar 4 canales (RGBA), por lo que el código no hace lo esperado.

No sabria aconsejarte una solución concreta, porque no sé qué es lo que pretendes exáctamente, y tampoco tengo experiencia en SDL.

javiel

 La cuestion es que estoy haciendo pruebas. De principio estoy interesado en la programación en OpenGL para crear videojuegos en 2D, para mejorar el rendimiento. En el futuro ya veremos

La cosa es que estoy haciendo un juego y si veo que pasarlo a OpenGL no es demasiado complicado, pues lo pasaré. Ahora mismo estoy haciendo pruebas. El juego que estoy haciendo todos los tiles son PNG, por lo que me gustaría cargar imágenes en PNG con los 4 canales RGBA y que los alpha salgan bien. Mi primera prueba fue cargar un BMP usando Proyeccción Ortográfica y todo ha ido bien. Ahora que quiero empezar a acostumbrar a los moviemintos y rotaciones y eso, lo que quiero primero es cargar un PNG como textura de un GL_QUADS

Esos son los problemas que tengo. Ahora simplemente lo que quiero y poner en medio de la pantalla un PNG y que se vea.

¿alguien que me pueda ayudar?

gracias a todos y perdón por no explicarme antes
uper-Tirititran: el superhéroe gaditano (http://www.super-tirititran.com)

marcode

 Haz una prueba ignorando (con los /*    */)  la parte de intercambiar los colores, si te sale bien los pixels pero mal los colores, tendrás que hacer una rutina para intercambiar los componentes de color, igual que la que ya hay pero sobre 4 bytes, actualmente el intercambio es sobre grupos de 3.
size=9]afortunadamente siempre ha habido alguien dispuesto a reinventar la rueda, de lo contrario seguiríamos usando un disco de piedra con un agujero.[/size]

javiel

 Es un poco rollo esto. Os cuento

He cambiado un archivo jpg a bmp, y luego un png a bmp. Pues los dos se ven mal. Ahora, cambiar el BMP que se veía bien a PNG y se ve perfecto, pero si le pongo algo de alpha al archivos con un programa de retoque se ve mal (evidentemente).

He estado mirando los parámetros del BMP q se ve bien, 24 bit de profundidas y 96x96 dpi. He puesto los bmps que no salían a esa resolución y siguen sin salir.

La verdad que no se que puede estar pasando, no todos los bmps sales, los pngs y jpgs transoformados desde un archivos BMP que sale, sale si no tienes canal alpha. Un lío vamos

He decidido usar glPng, que parece que está muy bien, he compilado la librería para Dev-C++ que es el compilador que uso. He metido las cabeceras y las .lib y me da un error en el linker. ¿Alguien ha podido usar glPng con Dev-c++?

gracias a todos
uper-Tirititran: el superhéroe gaditano (http://www.super-tirititran.com)

marcode

 Creo que no me he explicado bien.

El bmp que te funciona tiene formato BGR, 3 componentes de 8 bits cada uno.

Creo que en el código que has puesto lo que hace es intercambiar el azul por el rojo para obtener RGB, de manera que la memoria que está así.

B.G.R-B.G.R-B.G.R

quedaría así despues de hacer el intercambio:

R.G.B-R.G.B-R.G.B

el png con canal alpha tiene 32 bits RGBA. 4 componentes de color.

R.G.B.A-R.G.B.A-R.G.B.A

si haces la misma operación de intercambio (el primero por el tercero) va a salir un desastre. Tienes que intercambiar los componentes adecuadamente hasta obtener el formato deseado.

si tienes RGBA de jpg, pero necesitas que esté en formato ARGB tienes que usar una rutina que lo modifique, o crearla tu mismo.

size=9]afortunadamente siempre ha habido alguien dispuesto a reinventar la rueda, de lo contrario seguiríamos usando un disco de piedra con un agujero.[/size]

javiel

 la verdad que no lo entiendo. He quitado todo lo del cambio de colores para ver si salían las cosas. Tambien he cambiado esto:

glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->w, image1->h, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->pixels);

por

glTexImage2D(GL_TEXTURE_2D, 0, 4, image1->w, image1->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image1->pixels);


ahora meto un png que tenía por ahí de un icono y se ve perfecto (sin colores raros, lo unico que el transparente es negro, pero bueno), pero creo yo un PNG con el Gimp o cualquier imagen en jpg, etc que tenga la paso a png y no se ve.

la verdad que me estoy volviendo loco.

El glPng tampoco me funciona con el Dev-c++ por mas vueltas que le estoy dando

¿alguien tiene alguna forma de poder cargar texturas sin problemas? Png, jpg o lo que sea, una forma sencilla supongo que tendrá OpenGl para eso, me da igual que sea mediante un SDL_Surface o lo que sea, pero que funcione

gracias a todos por vuestra ayuda y comprensión
uper-Tirititran: el superhéroe gaditano (http://www.super-tirititran.com)

marcode

 Lo único que tienes que hacer es comprobar el formato de pixel de la surface y crear la textura con el mismo formato.

El formato de pixel lo puedes obtener de la propia surface, alguien que sepa del SDL podrá decirte como hacerlo, y con un switch asignar a una variable el formato del OpenGL, y posteriormente usarlo al crear la textura.

El problema del bmp creo que usa el formato BGR, que creo que no usa el OpenGL, entonces tienes que usar el codigo que has puesto al principio para intercambiar el Red por el Blue y que quede como RGB, pero solo en ese caso tendrás que hacerlo.

Seguramente el png del icono tiene canal alpha (RGBA), y el que has guardado con el gimp no (RGB), por eso te vuelves loco.
size=9]afortunadamente siempre ha habido alguien dispuesto a reinventar la rueda, de lo contrario seguiríamos usando un disco de piedra con un agujero.[/size]

javiel

 po killo, yo me harto de mirar por todos lados, los archivos he probado con todos los tipos de formato uno a uno posibles a pasar a glTexImage2D y nada de nada. He mirado en libsdl.org a ver que puede sacar del sdl_surface, y no se que pasa. No se que tiene el icono que no tenga mi png para que uno aparezca y el otro aparezca en blanco. Es de locos

Pongo el código y un enlace a los dos archivos que estoy probando a ver si algún alma caritativa podría verlo y sacarme de dudas pq creo que tiene que ser de algo que esta fuera de lo que estoy mirando y a lo mejor alguno de ustedes puede verlo

Aqui dejo los dos archivos





Aqui va el código


//
// This code was created by Jeff Molofee '99
// (ported to SDL by Sam Lantinga '2000)
//
// If you've found this code useful, please let me know.
//
// Visit me at www.demonews.com/hosted/nehe
//
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#if defined(__APPLE__) && defined(__MACH__)
#include <OpenGL/gl.h> // Header File For The OpenGL32 Library
#include <OpenGL/glu.h> // Header File For The GLu32 Library
#else
#include <GL/gl.h> // Header File For The OpenGL32 Library
#include <GL/glu.h> // Header File For The GLu32 Library
#endif
#include "SDL.h"
#include <SDL_image.h>
#include <stdlib.h>


/* floats for x rotation, y rotation, z rotation */
float xrot, yrot, zrot;
int posx, posy;
float escala;
float fescala = 0.01f;

/* storage for one texture  */
GLuint texture[1];
int w, h;

SDL_Surface *LoadTex(char *filename)
{
   Uint8 *rowhi, *rowlo;
   Uint8 *tmpbuf, tmpch;
   SDL_Surface *image, *temp;
   int i, j;

   //image = SDL_LoadBMP(filename);
   temp = IMG_Load(filename);
   if ( temp == NULL ) {
       fprintf(stderr, "Unable to load %s: %s\n", filename, SDL_GetError());
       return(NULL);
   }
   
   image = SDL_DisplayFormatAlpha(temp);
   
   w = image->w;
   h = image->h;

   SDL_FreeSurface(temp);
   return(image);
}

// Load Bitmaps And Convert To Textures
void LoadGLTextures(void)
{
   // Load Texture

   SDL_Surface *surf;
   
   surf = LoadTex("alien.png");//prueba.png
   if (!surf) {
       SDL_Quit();
       //exit(1);
   }

   // Create Texture
   glGenTextures(1, &texture[0]);
   glBindTexture(GL_TEXTURE_2D, texture[0]);   // 2d texture (x and y size)

   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // scale linearly when image bigger than texture
   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // scale linearly when image smalled than texture

   // 2d texture, level of detail 0 (normal), 3 components (red, green, blue), x size from image, y size from image,
   // border 0 (normal), rgb color data, unsigned byte data, and finally the data itself.
   //glPixelStorei(GL_UNPACK_ROW_LENGTH, surf->pitch / surf->format->BytesPerPixel);
   glTexImage2D(GL_TEXTURE_2D, 0, 4, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels);
   glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);

};

/* A general OpenGL initialization function.  Sets all of the initial parameters. */
void InitGL(int Width, int Height)         // We call this right after our OpenGL window is created.
{
   glViewport(0, 0, Width, Height);
   LoadGLTextures();    // Load The Texture(s)
   glEnable(GL_TEXTURE_2D);   // Enable Texture Mapping
   glClearColor(0.0f, 0.0f, 1.0f, 0.0f); // Clear The Background Color To Blue
   glClearDepth(1.0);    // Enables Clearing Of The Depth Buffer
   glDepthFunc(GL_LESS);   // The Type Of Depth Test To Do
   glEnable(GL_DEPTH_TEST);   // Enables Depth Testing
   glShadeModel(GL_SMOOTH);   // Enables Smooth Color Shading
   
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   glOrtho(0, Width, Height, 0, 0, 1);    
   
   glMatrixMode(GL_MODELVIEW);
   
   posx = Width/2;
   posy = Height/2;
}

/* The main drawing function. */
void DrawGLScene()
{
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  // Clear The Screen And The Depth Buffer
   glLoadIdentity();    // Reset The View

   glEnable(GL_TEXTURE_2D);
   glEnable(GL_BLEND);
   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

   glTranslatef(posx,posy,0);  
   glRotatef(zrot,0.0f,0.0f,1.0f);
   glScalef(escala, escala, escala);

   glBindTexture(GL_TEXTURE_2D, texture[0]);   // choose the texture to use.
   

 
   glBegin(GL_QUADS);
     glTexCoord2f(0.0f, 1.0f);
     glVertex2f(-w/2, h/2);      
     glTexCoord2f(1.0f, 1.0f);
     glVertex2f(w/2, h/2);
     glTexCoord2f(1.0f, 0.0f);
     glVertex2f(w/2, -h/2);
     glTexCoord2f(0.0f, 0.0f);
     glVertex2f(-w/2,-h/2);
   glEnd();

   xrot+=1.0f;                  // X Axis Rotation
   yrot+=1.0f;                  // Y Axis Rotation
   zrot+=1.0f;                  // Y Axis Rotation
   if ( (escala > 2) || (escala < 0)) {
       fescala = -fescala;
   }
   escala += fescala;
   
   glDisable(GL_TEXTURE_2D);
   glDisable(GL_BLEND);

   SDL_GL_SwapBuffers();
}

int main(int argc, char **argv)
{  
 int done;
 Uint8 *keys;

 /* Initialize SDL for video output */
 if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
   fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError());
   //exit(1);
 }

 /* Create a 640x480 OpenGL screen */
 if ( SDL_SetVideoMode(640, 480, 0, SDL_OPENGL) == NULL ) {
   fprintf(stderr, "Unable to create OpenGL screen: %s\n", SDL_GetError());
   SDL_Quit();
   //exit(2);
 }

 /* Set the title bar in environments that support it */
 SDL_WM_SetCaption("Jeff Molofee's GL Code Tutorial ... NeHe '99", NULL);

 /* Loop, drawing and checking events */
 InitGL(640, 480);
 done = 0;
 int speed = 1;
 while ( ! done ) {
   DrawGLScene();

   /* This could go in a separate function */
   { SDL_Event event;
     while ( SDL_PollEvent(&event) ) {
       if ( event.type == SDL_QUIT ) {
         done = 1;
       }

       if ( event.type == SDL_KEYDOWN ) {
         if ( event.key.keysym.sym == SDLK_ESCAPE ) {
           done = 1;
         }
       }
     }
     keys = SDL_GetKeyState(NULL);
     if ( keys[SDLK_UP] == SDL_PRESSED ) {
         posy -= speed;
     }
     if ( keys[SDLK_DOWN] == SDL_PRESSED ) {
         posy += speed;
     }
     if ( keys[SDLK_LEFT] == SDL_PRESSED ) {
         posx -= speed;
     }
     if ( keys[SDLK_RIGHT] == SDL_PRESSED ) {
         posx += speed;
     }
       
   }
 }
 SDL_Quit();
 return 1;
}


gracias
uper-Tirititran: el superhéroe gaditano (http://www.super-tirititran.com)

marcode

 Las texturas en OpenGL tienen que ser potencia de dos.

Solución:

Ampliar la textura a 512x512 y luego darle otras coordenadas de textura.

Puedes usar la siguiente fórmula para obtener las coordenadas a partir de la posición en la imagen (si no me equivoco):

MinTexturaX = PosSpriteX / TamTextura;
MinTexturaY = PosSpriteY / TamTextura;
MaxTexturaX = (PosSpriteX + TaxSpriteX) / TamTextura;
MaxTexturaY = (PosSpriteY + TaxSpriteY)  / TamTextura);

También puedes meter varias texturas en una única imagen de 1024x1024 y calcular las coordenadas a partir de su posición y su tamaño dentro de la imagen, con esa fórmula.

Yo te recomendaría que creases una clase una clase "Sprite" que contenga la información de textura, el ID (bind) de la imagen, su tamaño, características, etc, y funciones para crear, situar, dibujar, etc. También vendría bien hacer una clase "Imagen". En realidad como no hagas clases vas a tener un follón de narices cuando haya muchos sprites diferentes y te va a ser dificilísimo mantenerlo y actualizarlo.

Quizás te parezca un coñazo hacerlo, pero cuando lo termines bastará con hacer esto:



MiImagen.Cargar("imagen1.png");

MiSprite.Crear( &MiImagen, 0,0, 400, 300 );

MiSprite.Situar( 100, 20 );

MiSprite.Dibujar();



Despues crea otra clase llamada "Entidad" , que entre sus propiedades tenga un puntero a un Sprite, o varios punteros a Sprites para hacer animaciones, su posición, rotación, velocidad, etc. y métodos para comprobar colisiones, animar, etc, etc, etc..............

Empiezas respondiendo a una cuestión rapida y al final acabas haciendo un tutorial  :lol:
size=9]afortunadamente siempre ha habido alguien dispuesto a reinventar la rueda, de lo contrario seguiríamos usando un disco de piedra con un agujero.[/size]






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.