PNG Images issue with OpenGL and C++
I'm trying to develop a game, but I have a problem. I´m using png images and I create my own sprite class
This is how I load the png's:
loadImage.cpp:
#include "load开发者_如何学运维Image.h"
#include <cstdio>
#include <cstdlib>
struct Texture2D
{
unsigned int Texture;
unsigned char *Pixels;
int Width;
int Height;
};
int GetTextureInfo(int ColourType)
{
int ret;
switch(ColourType)
{
case PNG_COLOR_TYPE_GRAY:
ret = 1;
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
ret = 2;
break;
case PNG_COLOR_TYPE_RGB:
ret = 3;
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
ret = 4;
break;
default:
ret = -1;
};
return ret;
};
GLuint loadImage(const char *filename,struct Texture2D *image)
{
GLuint texture;
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
png_bytep *row_pointers = NULL;
int bitDepth, colourType;
FILE *pngFile = fopen(filename, "rb");
if(!pngFile)
return 0;
png_byte sig[8];
fread(&sig, 8, sizeof(png_byte), pngFile);
rewind(pngFile);//so when we init io it won't bitch
if(!png_check_sig(sig, 8))
return 0;
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,NULL,NULL);
if(!png_ptr)
return 0;
if(setjmp(png_jmpbuf(png_ptr)))
return 0;
info_ptr = png_create_info_struct(png_ptr);
if(!info_ptr)
return 0;
png_init_io(png_ptr, pngFile);
png_read_info(png_ptr, info_ptr);
bitDepth = png_get_bit_depth(png_ptr, info_ptr);
colourType = png_get_color_type(png_ptr, info_ptr);
if(colourType == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png_ptr);
if(colourType == PNG_COLOR_TYPE_GRAY && bitDepth < 8)
png_set_expand_gray_1_2_4_to_8(png_ptr);
if(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(png_ptr);
if(bitDepth == 16)
png_set_strip_16(png_ptr);
else if(bitDepth < 8)
png_set_packing(png_ptr);
png_read_update_info(png_ptr, info_ptr);
png_uint_32 width, height;
png_get_IHDR(png_ptr, info_ptr, &width, &height,
&bitDepth, &colourType, NULL, NULL, NULL);
int components = GetTextureInfo(colourType);
if(components == -1)
{
if(png_ptr)
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return 0;
}
GLubyte *pixels = (GLubyte *)malloc(sizeof(GLubyte) * (width * height * components));
row_pointers = (png_bytep *)malloc(sizeof(png_bytep) * height);
for(int i = 0; i < height; ++i)
row_pointers[i] = (png_bytep)(pixels + (i * width * components));
png_read_image(png_ptr, row_pointers);
png_read_end(png_ptr, NULL);
// make it
glGenTextures(1, &texture);
// bind it
glBindTexture(GL_TEXTURE_2D, texture);
// stretch it
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
// technologic - I MEAN
// here we has the problems
GLuint glcolours;
(components==4) ? (glcolours = GL_RGBA): (0);
(components==3) ? (glcolours = GL_RGB): (0);
(components==2) ? (glcolours = GL_LUMINANCE_ALPHA): (0);
(components==1) ? (glcolours = GL_LUMINANCE): (0);
glTexImage2D(GL_TEXTURE_2D, 0, components, width, height, 0, glcolours, GL_UNSIGNED_BYTE, pixels);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(pngFile);
free(row_pointers);
free(pixels);
//Texture2D image;
image->Texture = texture;
image->Pixels = pixels;
image->Width = width;
image->Height = height;
//return image;
return texture;
};
This is my sprite class:
csprite.cpp:
#include "csprite.h"
#include "loadImage.h"
void CFrame::load(const char *path) {
this->texture=loadImage(path,&img);
}
void CFrame::unload(){
this->texture=NULL;
}
CSprite::CSprite(int nf) {
this->estado=0;
this->posx=0;
this->posy=0;
this->sprite=new CFrame[nf];
this->nframes=nf;
this->cont=0;
}
CSprite::CSprite() {
int nf=1;
this->estado=0;
this->posx=0;
this->posy=0;
this->sprite=new CFrame[nf];
this->nframes=nf;
this->cont=0;
}
CSprite::~CSprite(){
this->finalize();
}
void CSprite::glEnable2D( void )
{
GLint iViewport[4];
// Get a copy of the viewport
glGetIntegerv( GL_VIEWPORT, iViewport );
// Save a copy of the projection matrix so that we can restore it
// when it's time to do 3D rendering again.
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glLoadIdentity();
// Set up the orthographic projection
glOrtho( iViewport[0], iViewport[0]+iViewport[2],iViewport[1]+iViewport[3], iViewport[1], -1, 1 );
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadIdentity();
// Make sure depth testing and lighting are disabled for 2D rendering until
// we are finished rendering in 2D
glPushAttrib( GL_DEPTH_BUFFER_BIT | GL_LIGHTING_BIT );
glDisable( GL_DEPTH_TEST );
glDisable( GL_LIGHTING );
}
void CSprite::glDisable2D( void )
{
glPopAttrib();
glMatrixMode( GL_PROJECTION );
glPopMatrix();
glMatrixMode( GL_MODELVIEW );
glPopMatrix();
}
void CSprite::finalize() {
int i;
for (i=0 ; i<=this->nframes-1 ; i++)
this->sprite[i].unload();
}
void CSprite::addframe(CFrame frame) {
if (this->cont<this->nframes) {
this->sprite[this->cont]=frame;
this->cont++;
}
}
int CSprite::selframe(int nf) {
if (nf<this->nframes) {
this->estado=nf;
return 1;
}
else {
return 0;
}
}
void CSprite::animate(){
if (this->estado<this->nframes) {
this->estado++;
}
else{
this->estado=0;
}
}
void CSprite::draw() {
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glGenTextures(1, &this->sprite[estado].texture);
//printf("++++ %d",sprite[estado].texture);
glBindTexture( GL_TEXTURE_RECTANGLE_ARB, this->sprite[estado].texture );
//glTexParameteri( sprite[estado].texture, GL_TEXTURE_PRIORITY, 1);
/*
GLclampf priorities;
priorities=1;
GLfloat p=1;
glPrioritizeTextures(1,&sprite[estado].texture, &p);*/
// Write the 32-bit RGBA texture buffer to video memory
glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, this->sprite[estado].img.Width, this->sprite[estado].img.Height,
0, GL_RGBA, GL_UNSIGNED_BYTE, this->sprite[estado].img.Pixels );
glEnable2D();
// Make the sprite 2 times bigger (optional)
//glScalef( 2.0f, 2.0f, 0.0f );
// Blend the color key into oblivion! (optional)
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
// Set the primitive color to white
glColor3f( 1.0f, 1.0f, 1.0f );
// Bind the texture to the polygons
glBindTexture( GL_TEXTURE_RECTANGLE_ARB, this->sprite[estado].texture );
}
void CSprite::drawNormal(){
draw();
// Save a copy of the texture's dimensions for later use
int TextureWidth = this->sprite[estado].img.Width;
int TextureHeight = this->sprite[estado].img.Height;
//para cargar texturas normal se cargar el punto: cuadrado(0,0)con textura(0,0)
//normal
glBegin( GL_QUADS );
glTexCoord2i(0,0);
glVertex2f(this->posx,this->posy);
glTexCoord2i( 0,TextureHeight);
glVertex2f( this->posx, this->posy+TextureHeight );
glTexCoord2i( TextureWidth, TextureHeight );
glVertex2f( this->posx+TextureWidth, this->posy+TextureHeight );
glTexCoord2i( TextureWidth,0 );
glVertex2f( this->posx+TextureWidth, this->posy );
glEnd();
// Disable 2D rendering
glDisable2D();
}
void CSprite::drawTurned(){
draw();
// Save a copy of the texture's dimensions for later use
int TextureWidth = this->sprite[estado].img.Width;
int TextureHeight = this->sprite[estado].img.Height;
//para cargar texturas al revez se cargar el punto: cuadrado(0,0)con textura(1,0)
//volteado
glBegin( GL_QUADS );
glTexCoord2i(0,0);
glVertex2f( this->posx+TextureWidth, this->posy );
glTexCoord2i( TextureWidth,0 );
glVertex2f(this->posx,this->posy);
glTexCoord2i( TextureWidth, TextureHeight );
glVertex2f( this->posx, this->posy+TextureHeight );
glTexCoord2i( 0,TextureHeight);
glVertex2f( this->posx+TextureWidth, this->posy+TextureHeight );
glEnd();
// Disable 2D rendering
glDisable2D();
}
and this my main class:
main.cpp:
#include <iostream>
#include <OpenGL/gl.h>
#include "GLUT/glut.h"
#include "loadImage.h"
#include "csprite.h"
CFrame fplay1;
CSprite splay1;
void reshape(int width, int height) {
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-1, 1, -1, 1);
glMatrixMode(GL_MODELVIEW);
}
void display() {
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
fplay1.load("Sasuke_run002.png");
splay1.addframe(fplay1);
splay1.setPosition(100,100);
splay1.drawNormal();
glFlush();
glutSwapBuffers();
}
void init() {
glClearColor(0,0,0,0);
}
int main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition(50, 50);
glutInitWindowSize(500, 500);
glutCreateWindow("Hello OpenGL");
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
the result is this:
but if I change the display function and the main function in main.cpp, like this:
#include <iostream>
#include <OpenGL/gl.h>
#include "GLUT/glut.h"
#include "loadImage.h"
#include "csprite.h"
CFrame fplay1;
CSprite splay1;
void reshape(int width, int height) {
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-1, 1, -1, 1);
glMatrixMode(GL_MODELVIEW);
}
void display() {
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
//****** CHANGE ******//
splay1.drawNormal();
glFlush();
glutSwapBuffers();
}
void init() {
glClearColor(0,0,0,0);
}
int main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition(50, 50);
glutInitWindowSize(500, 500);
glutCreateWindow("Hello OpenGL");
init();
//****** CHANGE ******//
fplay1.load("Sasuke_run002.png");
splay1.addframe(fplay1);
splay1.setPosition(100,100);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
the result is this:
I don´t understand why this happened. I want to use my sprite class in the second form
I think its here:
void CSprite::draw() {
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glGenTextures(1, &this->sprite[estado].texture);
//printf("++++ %d",sprite[estado].texture);
glBindTexture( GL_TEXTURE_RECTANGLE_ARB, this->sprite[estado].texture );
//glTexParameteri( sprite[estado].texture, GL_TEXTURE_PRIORITY, 1);
/*
GLclampf priorities;
priorities=1;
GLfloat p=1;
glPrioritizeTextures(1,&sprite[estado].texture, &p);*/
// Write the 32-bit RGBA texture buffer to video memory
glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, this->sprite[estado].img.Width, this->sprite[estado].img.Height,
0, GL_RGBA, GL_UNSIGNED_BYTE, this->sprite[estado].img.Pixels );
You're overwriting this->sprite[estado].texture
just before drawing it.
Take out
glGenTextures(1, &this->sprite[estado].texture);
and
glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, this->sprite[estado].img.Width, this->sprite[estado].img.Height,
0, GL_RGBA, GL_UNSIGNED_BYTE, this->sprite[estado].img.Pixels );
I think that should work.
If I understand correctly, I think the problem is here:
CSprite::CSprite() {
int nf=1;
this->estado=0;
this->posx=0;
this->posy=0;
this->sprite=new CFrame[nf];
this->nframes=nf;
this->cont=0;
}
You've set the 'number of frames' (nf
) to 1 and created an array of CFrame
pointers with one entry, but you never initialize that frame.
I would set nf = this->nframes = 0
initially, and this->sprite = NULL
, until a frame is added to the sprite. Of course, you'll then need to check if sprite
is null before using it anywhere.
精彩评论