2009-10-26 3 views
0

MISE À JOUR:

J'ai posté le code Renderer ci-dessous, puisque ce code ne semble pas être le problème ici.OpenGL - Textures chargement incorrectement

Je rencontre un problème avec un de mes codes où lorsque j'essaie de télécharger plusieurs textures vers openGL, une à la fois, cela échoue quelque peu de manière spectaculaire, le rendu ne finissant qu'avec une seule texture. J'ai fait un peu de débogage pour tracer l'erreur de cette fonction, mais j'ai des problèmes pour déterminer quelle partie de la fonction est en cause. Y a-t-il des clichés particulièrement évidents que je fais que je ne vois tout simplement pas, ou y a-t-il une faille plus subtile dans mon code?

Here're les struct-je utiliser pour stocker des informations de texture et généralement juste garder la trace de tous mes pointeurs

typedef struct { 
    float Width; 
    float Height; 
} texInfo; 

typedef struct { 
    dshlib::utfstr ResourceName; 
    texInfo * TextureInfo; 
    GLuint TextureNum; 
    SDL_Surface * Image; 
} texCacheItem; 

Et voici le graphique en cours de chargement WIP. Fondamentalement, il charge un fichier .png nommé à partir d'une archive .zip en utilisant une bibliothèque pré-écrite (d'ailleurs, il est testé avec ce programme). Ensuite, il est chargé avec libpng et ensuite chargé comme une texture, avec la mise en cache pour accélérer le chargement et éviter de charger une seule texture plus d'une fois. J'ai omis les instructions #include car elles étaient juste cruelles.

texCacheItem * loadGraphics(dshlib::utfstr FileName) { 

    for(int i = 0; i < NumTexCached; i++) { //First see if this texture has already been loaded 
    if(TextureCache[i]->ResourceName == FileName) 
     return TextureCache[i]; 
    } 

    dshlib::utfstr FullFileName = "Data/Graphics/"; //If not, create the full file path in the archive 
    FullFileName += FileName; 
    dshlib::FilePtr file = resourceCtr.OpenFile(FullFileName); //And open the file 

    if (!file->IsOk()) { //If the file failed to load... 
    EngineState = ENGINESTATE_ERR; 
    return NULL; 
    } 

    SDL_Surface * T = loadPNG(file); 
    texCacheItem * Texture = new texCacheItem; 
    Texture->TextureInfo = new texInfo; 

    glGenTextures(1, &Texture->TextureNum); //Allocate one more texture and save the name to the texCacheItem 
    glBindTexture(GL_TEXTURE_2D, Texture->TextureNum); //Then create it 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, T->w, T->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, T->pixels); 

    Texture->TextureInfo->Width = (float)T->w; //Write the useful data 
    Texture->TextureInfo->Height = (float)T->h; 
    Texture->ResourceName = FileName; //And the caching info needed 
    Texture->Image = T; //And save the image for if it's needed later and for deleting 

    if (!TexCacheSize) { //If this is the first load this is 0, so allocate the first 8 Cache slots. 
    TexCacheSize = 8; 
    TextureCache = new texCacheItem*[8]; 
    } 

    if(NumTexCached == TexCacheSize) { //If we're out of cache space 
    if (TexCacheSize == 32768) { //If too many cache items, error out 
     EngineState = ENGINESTATE_ERR; 
     return NULL; 
    } 
    TexCacheSize <<= 1; //Double cache size 
    texCacheItem ** NewSet = new texCacheItem*[TexCacheSize]; 
    memcpy(NewSet, TextureCache, NumTexCached * sizeof(texCacheItem*)); //And copy over the old cache 
    delete TextureCache; //Delete the old cache 
    TextureCache = NewSet; //And assign the pointer to the new one 
    } 
    TextureCache[NumTexCached++] = Texture; //Store the texCacheItem to the Cache 

    file->Close(); //Close the file 
    file = NULL; //And NULL the smart pointer. [NTS: Confirm with Disch this is what won't cause a memory leak] 

    return Texture; //And return the loaded texture in texCacheItem form. 
} 

SDL_Surface *loadPNG(dshlib::FilePtr File) 
{ 
    Uint8 *PNGFile = new Uint8[(long)File->GetSize()]; 
    File->GetAr<Uint8>(PNGFile, (long)File->GetSize()); 
    return IMG_LoadPNG_RW(SDL_RWFromMem(PNGFile, (long)File->GetSize())); 
} 

Voici le fichier de code du moteur de rendu. C'est assez désordonné en ce moment, excuses pour ça. level-> activeMap indique au renderer quel "layer" du tilemap (0 étant le front, 3 le back) pour dessiner les sprites ci-dessus.

#include "../MegaJul.h" 
void render(void) { 

    //Render the current tilemap to the screen 

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); 
glLoadIdentity(); 
glTranslatef(0.0f, 0.0f, -4.0f); 

if (level) { 

glBegin(GL_QUADS); 
float dT = 32.0f/level->dTex; 
float sX, fX, fXa, sY, tX, tY, sYa, sYb, sXa, tXa, tYa; 
unsigned long m = level->mapDimensions[0] * level->mapDimensions[1]; 
float ai; long long t; Sint16 * p; 
glBindTexture(GL_TEXTURE_2D, level->tilemap->TextureNum); 

for (int i = 3; i >= 0; i--) { 

    if (level->layers[i]->mapPosition[0] > 0) 
    level->layers[i]->mapPosition[0] = 0; 
    if (level->layers[i]->mapPosition[0] < 0 - (signed long)((level->mapDimensions[0] - 21) * 32)) 
    level->layers[i]->mapPosition[0] = 0 - (signed long)((level->mapDimensions[0] - 21) * 32); 

    if (level->layers[i]->mapPosition[1] < 0) 
    level->layers[i]->mapPosition[1] = 0; 
    if (level->layers[i]->mapPosition[1] > (signed long)((level->mapDimensions[1] - 16) * 32)) 
    level->layers[i]->mapPosition[1] = (signed long)((level->mapDimensions[1] - 16) * 32); 

    if (i == level->activeMap) { 
    for (int j = 0; j < NumSprites; j++) { 
     glBindTexture(GL_TEXTURE_2D, Sprites[j]->Graphics->TextureNum); 
     Sprites[j]->render(level->layers[i]->mapPosition[0], level->layers[i]->mapPosition[1]); 
    } 
    for (int j = 0; j < NumBullets; j++) { 
     glBindTexture(GL_TEXTURE_2D, Bullets[j]->Texture->TextureNum); 
     Bullets[j]->render(level->layers[i]->mapPosition[0], level->layers[i]->mapPosition[1]); 
    } 
    } 

    glBindTexture(GL_TEXTURE_2D, level->tilemap->TextureNum); 

    t = 0 - ((level->layers[i]->mapPosition[0] - (level->layers[i]->mapPosition[0] % 32)) /32) + (((level->layers[i]->mapPosition[1] - (level->layers[i]->mapPosition[1] % 32)) /32) * level->mapDimensions[0]); 
    ai = (float)(3 - i); //Invert Z-Index 
    sX = (float)((level->layers[i]->mapPosition[0] % 32)); 
    sY = (float)((level->layers[i]->mapPosition[1] % 32)); 
    if (sX > 0) 
     sX -= 32; 
    if (sY < 0) 
     sY += 32; 
    fX = sX /= 32.0f; 
    sY /= 32.0f; 
    fXa = sXa = sX + 1.0f; 
    sYa = sY + 14.0f; 
    sYb = sY + 15.0f; 

    for (int y = 0; y < 16; y++) { 
    for (int x = 0; x < 21; x++) { 
     p = level->tiles[level->layers[i]->map[t]]->position; 
     tX = p[0]/level->dTex; 
     tY = p[1]/level->dTex; 
     tXa = tX + dT; 
     tYa = tY + dT; 
     glTexCoord2f(tX, tYa);  glVertex3f(fX, sYa, ai); // Bottom Left Of The Texture and Quad 
     glTexCoord2f(tXa,tYa);  glVertex3f(fXa, sYa, ai); // Bottom Right Of The Texture and Quad 
     glTexCoord2f(tXa,tY);  glVertex3f(fXa, sYb, ai); // Top Right Of The Texture and Quad 
      glTexCoord2f(tX, tY);  glVertex3f(fX, sYb, ai);  // Top Left Of The Texture and Quad 
      fX += 1.0f; 
      fXa += 1.0f; 
      t++; 
      if (t >= m) break; 
     } 
     sYb -= 1.0f; sYa -= 1.0f; 
     fXa = sXa; fX = sX; 
     t += level->mapDimensions[0] - 21; //21 is the number of tiles drawn on a line (20 visible + 1 extra for scrolling) 
     } 

    } 
    glEnd(); 
    } 

SDL_GL_SwapBuffers(); 
} 

est ici les segments de code qui définissent les données tilemap pour les sprites et le niveau:

Niveau:

void loadLevel(dshlib::utfstr FileName) { 
-snip- 
    texCacheItem * Tex = loadGraphics(FileName); 

    if (!Tex) { //Load the tile graphics for the level 
    unloadLevel(); 
    EngineState = ENGINESTATE_ERR; 
    return; 
    } else { 
    level->dTex = Tex->TextureInfo->Width; 
    level->tilemap = Tex; 
    } 
-snip- 
} 

Sprite:

void SpriteBase::created() { 
    this->Graphics = loadGraphics(DefaultGFX()); 
-snip- 
} 

MISE À JOUR 2:

Sid Farkus n OTED une grosse erreur que je fait avec le moteur de rendu, voici donc une renderer.cpp mise à jour:

#include "../MegaJul.h" 
void render(void) { 

    //Render the current tilemap to the screen 

    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); 
    glLoadIdentity(); 
    glTranslatef(0.0f, 0.0f, -4.0f); 

    if (level) { 

    float dT = 32.0f/level->dTex; 
    float sX, fX, fXa, sY, tX, tY, sYa, sYb, sXa, tXa, tYa; 
    unsigned long m = level->mapDimensions[0] * level->mapDimensions[1]; 
    float ai; long long t; Sint16 * p; 

    for (int i = 3; i >= 0; i--) { 

     if (level->layers[i]->mapPosition[0] > 0) 
     level->layers[i]->mapPosition[0] = 0; 
     if (level->layers[i]->mapPosition[0] < 0 - (signed long)((level->mapDimensions[0] - 21) * 32)) 
     level->layers[i]->mapPosition[0] = 0 - (signed long)((level->mapDimensions[0] - 21) * 32); 

     if (level->layers[i]->mapPosition[1] < 0)  
     level->layers[i]->mapPosition[1] = 0; 
     if (level->layers[i]->mapPosition[1] > (signed long)((level->mapDimensions[1] - 16) * 32)) 
     level->layers[i]->mapPosition[1] = (signed long)((level->mapDimensions[1] - 16) * 32); 

     if (i == level->activeMap) { 
     for (int j = 0; j < NumSprites; j++) { 
      glBindTexture(GL_TEXTURE_2D, Sprites[j]->Graphics->TextureNum); 
      glBegin(GL_QUADS); 
      Sprites[j]->render(level->layers[i]->mapPosition[0], level->layers[i]->mapPosition[1]); 
      glEnd(); 
     } 
     for (int j = 0; j < NumBullets; j++) { 
      glBindTexture(GL_TEXTURE_2D, Bullets[j]->Texture->TextureNum); 
      glBegin(GL_QUADS); 
      Bullets[j]->render(level->layers[i]->mapPosition[0], level->layers[i]->mapPosition[1]); 
      glEnd(); 
     } 
     } 

     glBindTexture(GL_TEXTURE_2D, level->tilemap->TextureNum); 
     glBegin(GL_QUADS); 

    -snipped out renderer since it was bloat 

    glEnd(); 
    } 

    SDL_GL_SwapBuffers(); 
} 
+1

Votre code semble très bien, avez-vous vérifié que votre chargeur PNG fonctionne correctement? Créez une texture 4x4 et vérifiez les valeurs pour vous assurer que vous avez les bonnes choses du chargeur et que l'ordre des octets correspond à ce que vous passez à glTexImage2D. Sauf que je me concentrerais sur votre code de rendu. –

+0

Btw, convention de nommage bizarre pour démarrer les noms de variables avec majuscule. J'ai été confus pendant 10 bonnes secondes quand j'ai regardé votre code. (pour ne pas dire que c'est faux, juste bizarre) – sbk

Répondre

2

Dans votre renderer, appelez-vous glBindTexture de façon appropriée? Il semble que votre moteur de rendu n'utilise que la dernière texture que vous avez téléchargée depuis que vous avez appelé glBindTexture pour la dernière fois. glBindTexture est ce que dit la texture OpenGL à utiliser pour vos polygones.

+0

Non, je m'assure que j'appelle toujours glBindTexture() dans le moteur de rendu. Serait-il utile que j'envoie les parties pertinentes pour référence? – Sukasa

+0

Oui, certainement, car il n'y a rien d'évident dans le code de chargement. (Ceci suppose que vous chargez des textures différentes, bien sûr.) –

+0

Imprimez le TextureNum avant d'appeler bind pour être sûr que vous êtes au moins en train de définir une texture opengl différente. Aussi, essayez d'utiliser GLintercept pour voir si vous pouvez repérer quelque chose en utilisant cela. (Je l'utilise tout le temps pour localiser mes problèmes opengl.) –

0

Je suppose que vous ne pouvez pas faire de débogage ou de journalisation pour cela? Si vous le pouviez, je m'attendrais à ce que ce soit trivial à diagnostiquer.

La principale chose qui me semble dangereuse est que vous ne vérifiez pas la valeur de retour de loadPNG. Je mettrais quelque chose là comme la première chose que j'ai faite.

Je considérerais aussi de commenter la vérification initiale d'une texture déjà mise en cache. Si les choses commencent à fonctionner à ce moment-là, vous savez que c'est un problème avec les noms de ressources ou les noms de fichiers (ou la comparaison de ceux-ci). En aparté, je suis surpris que vous utilisiez des classes et des pointeurs intelligents, mais en roulant votre propre vecteur std :: avec des pointeurs et des tableaux nus.;)

+0

J'ai fait du débogage - et je n'ai pas eu de chance, c'est pourquoi je demande ici. En ce qui concerne l'entremettage, eh bien, je suis sûr que je vais me débrouiller pour le rendre sensé assez tôt. – Sukasa

3

Avec votre code de rendu, je vois que vous appelez BindTexture dans un bloc glBegin/End. A partir des documents OpenGL:

GL_INVALID_OPERATION est généré si glBindTexture est exécuté entre l'exécution de glBegin et l'exécution correspondante de glEnd.

Déplacez vos appels BindTexture en dehors du bloc glBegin()/glEnd() et vous devriez être en or. Vous devrez probablement avoir plusieurs blocs pour adapter votre style de rendu.

modifier:

Avec le code mis à jour, assurez-vous d'un couple de choses; vos positions d'image-objet sont visibles à l'écran avec la matrice de projection/modèle actuelle et vos identifiants de texture d'image-objet sont des textures valides. Il n'y a rien de techniquement faux qui me saute aux yeux maintenant mais vos valeurs peuvent être éteintes.

+0

Hm, maintenant je reçois le même problème, mais à la place la texture * other * est utilisée ... Copie dans la version plus récente, sachant que je l'ai complètement gaffée ... – Sukasa

+0

Assurez-vous que l'intérieur de votre render() vous appelle Ne faites rien non plus. Rappelez-vous qu'il existe un sous-ensemble limité de fonctions que vous êtes autorisé à appeler entre glBegin et glEnd. –

+0

La seule chose que fait le rendu de l'image-objet est de calculer quelques décalages, puis d'appeler glTexCoord2f et glVertex3f. – Sukasa

Questions connexes