Текстура не накладывается на сферу

Пытаюсь налижить текстуру на сферу в OpenGL c помощью UV-параметризации.

Написал следующий код, но текстура не накладывается:

#define _USE_MATH_DEFINES
#define _CRT_SECURE_NO_WARNINGS
#include "glew.h"
#include "glut.h"
#include <cmath>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <windows.h>

static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;

typedef struct
{
    GLbyte identsize; // Size of ID field that follows header(0)
    GLbyte colorMapType; // 0 = None, 1 = paletted
    GLbyte imageType; // 0 = none, 1 = indexed, 2 = rgb, 3 = grey, +8 = rle
    unsigned short colorMapStart; // First colour map entry
    unsigned short colorMapLength; // Number of colors
    unsigned char colorMapBits; // bits per palette entry
    unsigned short xstart; // image x origin
    unsigned short ystart; // image y origin
    unsigned short width; // width in pixels
    unsigned short height; // height in pixels
    GLbyte bits; // bits per pixel (8 16, 24, 32)
    GLbyte descriptor; // image descriptor
} TGAHEADER;

GLbyte* gltLoadTGA(const char* szFileName, GLint* iWidth, GLint* iHeight,
    GLint* iComponents, GLenum* eFormat)
{
    FILE* pFile; // File pointer
    TGAHEADER tgaHeader; // TGA file header
    unsigned long lImageSize; // Size in bytes of image
    short sDepth; // Pixel depth;
    GLbyte* pBits = NULL; // Pointer to bits
    // Default/Failed values
    *iWidth = 0;
    *iHeight = 0;
    *eFormat = GL_BGR_EXT;
    *iComponents = GL_RGB8;
    // Attempt to open the file
    pFile = fopen(szFileName, "rb");
    if (pFile == NULL) return NULL;
    // Read in header (binary)
    fread(&tgaHeader, 18, 1, pFile);
    // Do byte swap for big vs little endian
#ifdef __APPLE__
    BYTE_SWAP(tgaHeader.colorMapStart);
    BYTE_SWAP(tgaHeader.colorMapLength);
    BYTE_SWAP(tgaHeader.xstart);
    BYTE_SWAP(tgaHeader.ystart);
    BYTE_SWAP(tgaHeader.width);
    BYTE_SWAP(tgaHeader.height);
#endif
    // Get width, height, and depth of texture
    * iWidth = tgaHeader.width;
    *iHeight = tgaHeader.height;
    sDepth = tgaHeader.bits / 8;
    // Put some validity checks here. Very simply, I only understand
    // or care about 8, 24, or 32 bit targa's.
    if (tgaHeader.bits != 8 && tgaHeader.bits != 24 && tgaHeader.bits != 32)
        return NULL;
    // Calculate size of image buffer
    lImageSize = tgaHeader.width * tgaHeader.height * sDepth;
    // Allocate memory and check for success
    pBits = (GLbyte*)malloc(lImageSize * sizeof(GLbyte));
    if (pBits == NULL) return NULL;
    // Read in the bits
    // Check for read error. This should catch RLE or other
    // weird formats that I don't want to recognize
    if (fread(pBits, lImageSize, 1, pFile) != 1)
    {
        free(pBits);
        return NULL;
    }
    // Set OpenGL format expected
    switch (sDepth)
    {
    case 3: // Most likely case
        *eFormat = GL_BGR_EXT;
        *iComponents = GL_RGB8;
        break;
    case 4:
        *eFormat = GL_BGRA_EXT;
        *iComponents = GL_RGBA8;
        break;
    case 1:
        *eFormat = GL_LUMINANCE;
        *iComponents = GL_LUMINANCE8;
        break;
    };
    // Done with File
    fclose(pFile);
    // Return pointer to image data
    return pBits;
}

void uvSphere(float radius, int slices, int stacks) {
    for (int i = 0; i <= stacks; ++i) {
        float v = i / (float)stacks;
        float phi = v * M_PI;

        for (int j = 0; j <= slices; ++j) {
            float u = j / (float)slices;
            float theta = u * 2 * M_PI;

            float x = cos(theta) * sin(phi);
            float y = cos(phi);
            float z = sin(theta) * sin(phi);

            glTexCoord2f(u, v);
            glNormal3f(x, y, z);
            glVertex3f(x * radius, y * radius, z * radius);
        }
    }
}

GLuint textureID;

void display() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Установка матрицы проекции
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0f, (float)glutGet(GLUT_WINDOW_WIDTH) / (float)glutGet(GLUT_WINDOW_HEIGHT), 0.1f, 100.0f);

    // Установка матрицы модели
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    // Поворот сферы
    glRotatef(xRot, 1.0f, 0.0f, 0.0f);
    glRotatef(yRot, 0.0f, 1.0f, 0.0f);

    // Перемещение камеры вглубь сцены
    glTranslatef(0.0f, 0.0f, -5.0f);

    // Установка цвета
    glColor3f(1.0f, 1.0f, 1.0f);

    // Включение текстурирования
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, textureID);

    // Рисование сферы
    glBegin(GL_QUADS);
    uvSphere(1.0f, 20, 20);
    glEnd();

    // Отключение текстурирования
    glDisable(GL_TEXTURE_2D);

    glutSwapBuffers();
}

void SpecialKeys(int key, int x, int y)
{
    if (key == GLUT_KEY_UP) xRot -= 5.0f;
    if (key == GLUT_KEY_DOWN) xRot += 5.0f;
    if (key == GLUT_KEY_LEFT) yRot -= 5.0f;
    if (key == GLUT_KEY_RIGHT) yRot += 5.0f;
    xRot = (GLfloat)((const int)xRot % 360);
    yRot = (GLfloat)((const int)yRot % 360);
    // Refresh the Window
    glutPostRedisplay();
}

void reshape(int width, int height) {
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0f, (float)width / (float)height, 0.1f, 100.0f);
}

void SetupRC() {
    // Включение тестирования глубины
    glEnable(GL_DEPTH_TEST);

    GLubyte* pBytes;
    GLint iWidth, iHeight, iComponents;
    GLenum eFormat;

    pBytes = (GLubyte*)gltLoadTGA("planet 1024.tga", &iWidth, &iHeight, &iComponents,
        &eFormat);
    glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat,
        GL_UNSIGNED_BYTE, pBytes);
    free(pBytes);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    glEnable(GL_TEXTURE_2D);
}

int main(int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutCreateWindow("Sphere UV Parametrization with Texture");
    glutInitWindowSize(800, 800);
    // Настройка контекста рендеринга
    SetupRC();

    // Регистрация функций обратного вызова
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutSpecialFunc(SpecialKeys);

    // Запуск главного цикла GLUT
    glutMainLoop();

    return 0;
}

Ответы (0 шт):