我想開發一個遊戲,但我有一個問題。 使用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;
}
的結果是這樣的:
,但如果我改變了顯示功能和主要功能在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;
}
的結果是這樣的:
我不明白爲什麼會這樣。我想用我的精靈類的第二種形式
只是一個小細節: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
@Daniel Vera:這個好運氣嗎?你成功解決了這個問題嗎? – 2011-08-30 01:45:38