Загрузка данных


Да, лучше сделать **две отдельные программы**: одну для ЛР №4, вторую для ЛР №5.

---

# Лабораторная №4

4 куба без вращения:

* слева сверху — ортографическая
* слева снизу — диметрическая, `fz = 5/8`
* справа сверху — изометрическая
* справа снизу — перспективная
* каждый куб одного сплошного цвета
* цвета у кубов разные

```cpp
#include <GL/glut.h>
#pragma comment(lib, "freeglut.lib")
#include <stdlib.h>

GLfloat vertices[8][3] = {
    {-1.0f, -1.0f, -1.0f},
    { 1.0f, -1.0f, -1.0f},
    { 1.0f,  1.0f, -1.0f},
    {-1.0f,  1.0f, -1.0f},
    {-1.0f, -1.0f,  1.0f},
    { 1.0f, -1.0f,  1.0f},
    { 1.0f,  1.0f,  1.0f},
    {-1.0f,  1.0f,  1.0f}
};

GLfloat cubeColors[4][3] = {
    {1.0f, 0.2f, 0.2f},
    {0.2f, 1.0f, 0.2f},
    {0.2f, 0.4f, 1.0f},
    {1.0f, 0.8f, 0.2f}
};

int windowWidth = 800;
int windowHeight = 800;

const float ISO_THETA = 35.264f;
const float ISO_PHI = 45.0f;

const float DIM_THETA = 20.7f;
const float DIM_PHI = 32.0f;

float eyeX = 5.0f;
float eyeY = 5.0f;
float eyeZ = 5.0f;

void drawFace(int a, int b, int c, int d) {
    glBegin(GL_POLYGON);
    glVertex3fv(vertices[a]);
    glVertex3fv(vertices[b]);
    glVertex3fv(vertices[c]);
    glVertex3fv(vertices[d]);
    glEnd();
}

void drawCube(int colorIndex) {
    glColor3fv(cubeColors[colorIndex]);

    drawFace(0, 3, 2, 1);
    drawFace(2, 3, 7, 6);
    drawFace(0, 4, 7, 3);
    drawFace(1, 2, 6, 5);
    drawFace(4, 5, 6, 7);
    drawFace(0, 1, 5, 4);
}

void renderCubeInViewport(int x, int y, int w, int h, int projectionType, int colorIndex) {
    glViewport(x, y, w, h);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    if (projectionType == 3) {
        double aspect = (double)w / (double)h;
        gluPerspective(45.0, aspect, 1.0, 20.0);
    } else {
        glOrtho(-2.5, 2.5, -2.5, 2.5, -10.0, 10.0);
    }

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    if (projectionType == 3) {
        gluLookAt(
            eyeX, eyeY, eyeZ,
            0.0, 0.0, 0.0,
            0.0, 1.0, 0.0
        );
    }

    switch (projectionType) {
    case 1:
        glRotatef(ISO_PHI, 0.0f, 1.0f, 0.0f);
        glRotatef(ISO_THETA, 1.0f, 0.0f, 0.0f);
        break;

    case 2:
        glRotatef(DIM_PHI, 0.0f, 1.0f, 0.0f);
        glRotatef(DIM_THETA, 1.0f, 0.0f, 0.0f);
        break;
    }

    drawCube(colorIndex);
}

void display() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_FLAT);

    int halfW = windowWidth / 2;
    int halfH = windowHeight / 2;

    renderCubeInViewport(0, halfH, halfW, halfH, 0, 0);
    renderCubeInViewport(0, 0, halfW, halfH, 2, 1);
    renderCubeInViewport(halfW, halfH, halfW, halfH, 1, 2);
    renderCubeInViewport(halfW, 0, halfW, halfH, 3, 3);

    glutSwapBuffers();
}

void reshape(int w, int h) {
    if (h == 0) h = 1;

    windowWidth = w;
    windowHeight = h;

    glViewport(0, 0, w, h);
}

void keyboard(unsigned char key, int x, int y) {
    switch (key) {
    case 27:
        exit(0);
        break;
    }
}

void init() {
    glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
    glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_FLAT);
}

int main(int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(windowWidth, windowHeight);
    glutCreateWindow("Laboratory Work 4");

    init();

    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutKeyboardFunc(keyboard);

    glutMainLoop();

    return 0;
}
```

---

# Лабораторная №5

Нужно:

* загрузить изображение через `stb_image.h`
* вывести изображение через `glDrawPixels`
* наложить это изображение как текстуру на все грани куба
* куб вращается

Файл картинки положи рядом с `.cpp`, например:

```cpp
"texture.bmp"
```

Также добавь в проект файл `stb_image.h`.

```cpp
#include <GL/glut.h>
#pragma comment(lib, "freeglut.lib")
#include <stdlib.h>
#include <stdio.h>

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

GLfloat vertices[8][3] = {
    {-1.0f, -1.0f, -1.0f},
    { 1.0f, -1.0f, -1.0f},
    { 1.0f,  1.0f, -1.0f},
    {-1.0f,  1.0f, -1.0f},
    {-1.0f, -1.0f,  1.0f},
    { 1.0f, -1.0f,  1.0f},
    { 1.0f,  1.0f,  1.0f},
    {-1.0f,  1.0f,  1.0f}
};

GLuint textureID;

unsigned char* imageData = NULL;
int imageWidth = 0;
int imageHeight = 0;
int imageChannels = 0;

int windowWidth = 1000;
int windowHeight = 600;

float angleX = 25.0f;
float angleY = 30.0f;

void drawTexturedFace(int a, int b, int c, int d) {
    glBegin(GL_QUADS);

    glTexCoord2f(0.0f, 0.0f);
    glVertex3fv(vertices[a]);

    glTexCoord2f(1.0f, 0.0f);
    glVertex3fv(vertices[b]);

    glTexCoord2f(1.0f, 1.0f);
    glVertex3fv(vertices[c]);

    glTexCoord2f(0.0f, 1.0f);
    glVertex3fv(vertices[d]);

    glEnd();
}

void drawTexturedCube() {
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, textureID);
    glColor3f(1.0f, 1.0f, 1.0f);

    drawTexturedFace(0, 3, 2, 1);
    drawTexturedFace(2, 3, 7, 6);
    drawTexturedFace(0, 4, 7, 3);
    drawTexturedFace(1, 2, 6, 5);
    drawTexturedFace(4, 5, 6, 7);
    drawTexturedFace(0, 1, 5, 4);

    glDisable(GL_TEXTURE_2D);
}

void loadTexture(const char* filename) {
    imageData = stbi_load(filename, &imageWidth, &imageHeight, &imageChannels, 3);

    if (!imageData) {
        printf("Image loading error: %s\n", filename);
        exit(1);
    }

    glGenTextures(1, &textureID);
    glBindTexture(GL_TEXTURE_2D, textureID);

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    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_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

    glTexImage2D(
        GL_TEXTURE_2D,
        0,
        GL_RGB,
        imageWidth,
        imageHeight,
        0,
        GL_RGB,
        GL_UNSIGNED_BYTE,
        imageData
    );
}

void drawImageLeftSide() {
    glViewport(0, 0, windowWidth / 2, windowHeight);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0, windowWidth / 2, 0, windowHeight);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glDisable(GL_DEPTH_TEST);
    glDisable(GL_TEXTURE_2D);

    float scaleX = (float)(windowWidth / 2) / imageWidth;
    float scaleY = (float)windowHeight / imageHeight;
    float scale = scaleX < scaleY ? scaleX : scaleY;

    float drawW = imageWidth * scale;
    float drawH = imageHeight * scale;

    float posX = ((windowWidth / 2) - drawW) / 2.0f;
    float posY = (windowHeight - drawH) / 2.0f;

    glRasterPos2f(posX, posY);
    glPixelZoom(scale, scale);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    glDrawPixels(
        imageWidth,
        imageHeight,
        GL_RGB,
        GL_UNSIGNED_BYTE,
        imageData
    );

    glPixelZoom(1.0f, 1.0f);
    glEnable(GL_DEPTH_TEST);
}

void drawCubeRightSide() {
    glViewport(windowWidth / 2, 0, windowWidth / 2, windowHeight);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    double aspect = (double)(windowWidth / 2) / (double)windowHeight;
    gluPerspective(45.0, aspect, 1.0, 20.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    gluLookAt(
        4.0, 4.0, 6.0,
        0.0, 0.0, 0.0,
        0.0, 1.0, 0.0
    );

    glRotatef(angleX, 1.0f, 0.0f, 0.0f);
    glRotatef(angleY, 0.0f, 1.0f, 0.0f);

    drawTexturedCube();
}

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

    drawImageLeftSide();
    drawCubeRightSide();

    glutSwapBuffers();
}

void reshape(int w, int h) {
    if (h == 0) h = 1;

    windowWidth = w;
    windowHeight = h;

    glViewport(0, 0, w, h);
}

void idle() {
    angleY += 0.3f;

    if (angleY >= 360.0f) {
        angleY -= 360.0f;
    }

    glutPostRedisplay();
}

void keyboard(unsigned char key, int x, int y) {
    switch (key) {
    case 'a':
        angleY -= 5.0f;
        break;
    case 'd':
        angleY += 5.0f;
        break;
    case 'w':
        angleX -= 5.0f;
        break;
    case 's':
        angleX += 5.0f;
        break;
    case 27:
        if (imageData) {
            stbi_image_free(imageData);
        }
        exit(0);
        break;
    }

    glutPostRedisplay();
}

void init() {
    glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
    glEnable(GL_DEPTH_TEST);

    loadTexture("texture.bmp");
}

int main(int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(windowWidth, windowHeight);
    glutCreateWindow("Laboratory Work 5");

    init();

    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutKeyboardFunc(keyboard);
    glutIdleFunc(idle);

    glutMainLoop();

    return 0;
}
```

Для ЛР №5 в папке проекта должны быть:

```text
main.cpp
stb_image.h
texture.bmp
```

В ЛР №4 кубы **не вращаются**.
В ЛР №5 куб **вращается**, и текстура наложена на все его грани.