2011-06-07 52 views
0

我想開發一個遊戲,但我有一個問題。 使用I'm PNG圖像和創建我自己的精靈類PNG圖像問題與OpenGL和C++

這是我如何加載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

我不明白爲什麼會這樣。我想用我的精靈類的第二種形式

+0

只是一個小細節:glTexImage的第三個參數被標記爲* internal_format *,而不是* components * - 組件數量的工作原因是由於OpenGL-1.1的一些兼容機制,但OpenGL-ES不支持它。內部格式爲GL_RGBA,GL_ALPHA或類似格式。所以,實際上你現在稱之爲* glcolors *的是什麼。 * format *參數(現在是glcolors)指定您傳遞的數據的格式。因爲它代表和使用PNG圖像文件,您的代碼很好,但您應該將* glcolors *作爲格式參數傳遞。 – datenwolf 2011-06-07 07:05:34

+0

@Daniel Vera:這個好運氣嗎?你成功解決了這個問題嗎? – 2011-08-30 01:45:38

回答

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 = 0,然後this->sprite = NULL,直到一個幀被添加到精靈。當然,在使用任何地方之前,您需要檢查sprite是否爲空。

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

我認爲應該工作。