在精灵表(OpenGL、C++)上的纹理之间切换

Swapping between textures on a sprite sheet (OpenGL, C++)

本文关键字:纹理 之间 C++ 精灵 OpenGL      更新时间:2023-10-16

我正在进行一个项目,希望使用OpenGL在精灵表上的两个纹理之间进行切换。我在窗口中分别渲染了两个纹理,没有任何问题,但我无法用我设置的按键切换它们。有人能告诉我我做错了什么/错过了什么吗?

#include "LUtil.h"
#include <IL/il.h>
#include <IL/ilu.h>
#include "LTexture.h"
int gViewportMode = VIEWPORT_MODE_C;
//Sprite texture
LTexture gArrowTexture;
//Sprite area
LFRect gArrowClips[ 4 ];
bool initGL()
{
//Set the viewport
glViewport( 0.f, 0.f, SCREEN_WIDTH, SCREEN_HEIGHT );
//Initialize Projection Matrix
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho( 0.0, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0, 1.0, -1.0 );
//Initialize Modelview Matrix
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
//Initialize clear color
glClearColor( 0.f, 0.f, 0.f, 1.f );
//Enable texturing
glEnable( GL_TEXTURE_2D );
//Check for error
GLenum error = glGetError();
if( error != GL_NO_ERROR )
{
    printf( "Error initializing OpenGL! %sn", gluErrorString(error);
    return false;
}
//Initialize DevIL
ilInit();
ilClearColour( 255, 255, 255, 000 );
//Check for error
ILenum ilError = ilGetError();
if( ilError != IL_NO_ERROR )
{
 printf( "Error initializing DevIL! %sn", iluErrorString(ilError) );
    return false;
}
return true;
}
bool loadMedia()
{
//Set clip rectangles
if ( gViewportMode == VIEWPORT_MODE_C) {
gArrowClips[ 0 ].x = 0.f;
gArrowClips[ 0 ].y = 0.f;
gArrowClips[ 0 ].w = 330.f;
gArrowClips[ 0 ].h = 355.f;
gArrowClips[ 1 ].x = 330.f;
gArrowClips[ 1 ].y = 0.f;
gArrowClips[ 1 ].w = 310.f;
gArrowClips[ 1 ].h = 480.f;
gArrowClips[ 2 ].x = 0.f;
gArrowClips[ 2 ].y = 355.f;
gArrowClips[ 2 ].w = 330.f;
gArrowClips[ 2 ].h = 125.f;
}
else if ( gViewportMode == VIEWPORT_MODE_N) {
gArrowClips[ 0 ].x = 0.f;
gArrowClips[ 0 ].y = 480.f;
gArrowClips[ 0 ].w = 330.f;
gArrowClips[ 0 ].h = 355.f;
gArrowClips[ 1 ].x = 330.f;
gArrowClips[ 1 ].y = 480.f;
gArrowClips[ 1 ].w = 310.f;
gArrowClips[ 1 ].h = 480.f;
gArrowClips[ 2 ].x = 0.f;
gArrowClips[ 2 ].y = 835.f;
gArrowClips[ 2 ].w = 330.f;
gArrowClips[ 2 ].h = 125.f;
}
//Load texture
if( !gArrowTexture.loadTextureFromFile( "SpriteSheet.png" ) )
{
    printf( "Unable to load texture!n" );
    return false;
}
return true;
}
void update()
{
}
void render()
{
//Clear color buffer
glClear( GL_COLOR_BUFFER_BIT );
//Render arrows
gArrowTexture.render( 0.f, 0.f, &gArrowClips[ 0 ] );
gArrowTexture.render( SCREEN_WIDTH - gArrowClips[ 1 ].w, 0.f, &gArrowClips[ 1 ] );
gArrowTexture.render( 0.f, SCREEN_HEIGHT - gArrowClips[ 2 ].h, &gArrowClips[ 2 ] );


//Update screen
glutSwapBuffers();
}
void handleKeys( unsigned char key, int x, int y )
{
//If the user presses q
if( key == 'q' )
{
gViewportMode++;
if ( gViewportMode > VIEWPORT_MODE_N ) 
{
gViewportMode == VIEWPORT_MODE_C;
}
}
}

正如我之前所说的,通过在includes下的int gViewPortMode中交换VIEWPORT_MODE_C和VIEWPPORT_MODE_N,我可以获得不同的纹理来渲染。

我的问题是,我无法使用切换视口的键命令来交换它们,所以我必须停止程序,更改代码,然后再次启动它来更改纹理。

切换视口不起作用吗?如果是,有其他选择吗?如果没有,我需要修复/更改什么?

OpenGL代码看起来不错,只需要每次按下q键时更新gArrowClips即可。从您提供的代码示例来看,在调用loadMedia()时,您似乎只设置了gArrowClips。由于在按下q键后永远不会调用loadMedia(),这意味着gArrowClips永远不会更新,因此对纹理的更改不会生效。我假设loadMedia()在程序启动时只调用过一次,因为它处理从文件加载纹理,而在代码的其他任何地方都不会调用它。

我还没有测试下面的代码,但它应该符合您的要求。实际上,我将您在loadMedia()中的代码移到了它自己的函数updateSpriteAreas()中,该代码处理gArrowClips的设置。然后,当调用loadMedia()以初始化gArrowClips时,我调用该函数一次,当在handleKeys()中按下q键以更改精灵纹理时,我再次调用该函数。

#include "LUtil.h"
#include <IL/il.h>
#include <IL/ilu.h>
#include "LTexture.h"
int gViewportMode = VIEWPORT_MODE_C;
//Sprite texture
LTexture gArrowTexture;
//Sprite area
LFRect gArrowClips[ 4 ];
bool initGL()
{
    //Set the viewport
    glViewport( 0.f, 0.f, SCREEN_WIDTH, SCREEN_HEIGHT );
    //Initialize Projection Matrix
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    glOrtho( 0.0, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0, 1.0, -1.0 );
    //Initialize Modelview Matrix
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
    //Initialize clear color
    glClearColor( 0.f, 0.f, 0.f, 1.f );
    //Enable texturing
    glEnable( GL_TEXTURE_2D );
    //Check for error
    GLenum error = glGetError();
    if( error != GL_NO_ERROR )
    {
        printf( "Error initializing OpenGL! %sn", gluErrorString(error);
        return false;
    }
    //Initialize DevIL
    ilInit();
    ilClearColour( 255, 255, 255, 000 );
    //Check for error
    ILenum ilError = ilGetError();
    if( ilError != IL_NO_ERROR )
    {
        printf( "Error initializing DevIL! %sn", iluErrorString(ilError) );
        return false;
    }
    return true;
}
//Move the sprite changes to a new function that gets called every time you make changes
void updateSpriteAreas()
{
    //Set clip rectangles
    if ( gViewportMode == VIEWPORT_MODE_C) {
        gArrowClips[ 0 ].x = 0.f;
        gArrowClips[ 0 ].y = 0.f;
        gArrowClips[ 0 ].w = 330.f;
        gArrowClips[ 0 ].h = 355.f;
        gArrowClips[ 1 ].x = 330.f;
        gArrowClips[ 1 ].y = 0.f;
        gArrowClips[ 1 ].w = 310.f;
        gArrowClips[ 1 ].h = 480.f;
        gArrowClips[ 2 ].x = 0.f;
        gArrowClips[ 2 ].y = 355.f;
        gArrowClips[ 2 ].w = 330.f;
        gArrowClips[ 2 ].h = 125.f;
    }
    else if ( gViewportMode == VIEWPORT_MODE_N) {
        gArrowClips[ 0 ].x = 0.f;
        gArrowClips[ 0 ].y = 480.f;
        gArrowClips[ 0 ].w = 330.f;
        gArrowClips[ 0 ].h = 355.f;
        gArrowClips[ 1 ].x = 330.f;
        gArrowClips[ 1 ].y = 480.f;
        gArrowClips[ 1 ].w = 310.f;
        gArrowClips[ 1 ].h = 480.f;
        gArrowClips[ 2 ].x = 0.f;
        gArrowClips[ 2 ].y = 835.f;
        gArrowClips[ 2 ].w = 330.f;
        gArrowClips[ 2 ].h = 125.f;
    }
}
bool loadMedia()
{
    //Initialize the sprite rectangles
    updateSpriteAreas()
    //Load texture
    if( !gArrowTexture.loadTextureFromFile( "SpriteSheet.png" ) )
    {
        printf( "Unable to load texture!n" );
        return false;
    }
    return true;
}
void update()
{
}
void render()
{
    //Clear color buffer
    glClear( GL_COLOR_BUFFER_BIT );
    //Render arrows
    gArrowTexture.render( 0.f, 0.f, &gArrowClips[ 0 ] );
    gArrowTexture.render( SCREEN_WIDTH - gArrowClips[ 1 ].w, 0.f, &gArrowClips[ 1 ] );
    gArrowTexture.render( 0.f, SCREEN_HEIGHT - gArrowClips[ 2 ].h, &gArrowClips[ 2 ] );
    //Update screen
    glutSwapBuffers();
}
void handleKeys( unsigned char key, int x, int y )
{
    //If the user presses q
    if( key == 'q' )
    {
        gViewportMode++;
        if ( gViewportMode > VIEWPORT_MODE_N ) 
        {
            gViewportMode == VIEWPORT_MODE_C;
        }
        //Update the sprite rectangles so the texture change takes effect
        updateSpriteAreas();
    }
}

我简单地解决了我的问题,只需将一个精灵表变成2(每组图像有1个精灵表),并添加一个值为0的int,然后在我的handle-keys函数中放入一个if和else-if语句,这两个语句都检查是否按下了q,然后检查int的值。在if语句中,如果按下q时int的值为0,它将更改图像并在int中加1。在else-if语句中,它检查按下q时int的值是否为1,更改图像,然后从int中减去1。