PNG图像问题与OpenGL和C ++

时间:2011-06-07 00:44:43

标签: c++ opengl

我正在尝试开发游戏,但我遇到了问题。 我正在使用png图像,我创建了自己的精灵类

这就是我加载png的方式:

loadImage.cpp

#include "loadImage.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;
};

这是我的精灵课程:

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();
}

这是我的主要课程:

的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;
}

结果如下:

https://i1094.photobucket.com/albums/i450/Daniel_Vera/bien.jpg

但如果我更改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(); 

    //****** 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;
}

结果如下:

https://i1094.photobucket.com/albums/i450/Daniel_Vera/mal.jpg

我不明白为什么会这样。我想以第二种形式使用我的精灵类

2 个答案:

答案 0 :(得分:3)

我想它在这里:

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 );

在绘制之前,你正在覆盖this->sprite[estado].texture

取出

glGenTextures(1, &this->sprite[estado].texture);

    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 );

我认为这应该有用。

答案 1 :(得分:1)

如果我理解正确,我认为问题在于:

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;
}

您已将'帧数'(nf)设置为1,并创建了一个包含一个条目的CFrame指针数组,但您永远不会初始化该帧。

我最初会设置nf = this->nframes = 0this->sprite = NULL,直到将一个帧添加到精灵中。当然,在任何地方使用它之前,您需要检查sprite是否为空。