§ Основной файл main.cpp

Необходимо, чтобы был установлен DevC++
#include <windows.h>
#include <gl/gl.h>
#include "window.cpp"

// Главное окно
AppWindow* app;

// Стартовое окно
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow) {

    app = new AppWindow();
    return app->start(hInstance, "Example Window", 640, 640);
}

// Обработчик
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    app->EventProc(hWnd, message, wParam, lParam);
}

§ Файл для сборки (makefile.bat)

@echo off
echo Build...

REM Пути к файлам
set MINGW=C:/Program Files/Dev-Cpp/MinGW64
set PLATFORM=x86_64-w64-mingw32
set VERSION=4.9.2

REM Пути к библиотекам
set INC1=%MINGW%/include
set INC2=%MINGW%/%PLATFORM%/include
set INC3=%MINGW%/lib/gcc/%PLATFORM%/%VERSION%/include
set INC4=%MINGW%/lib/gcc/%PLATFORM%/%VERSION%/include/c++
set INCLIB=-I"%INC1%" -I"%INC2%" -I"%INC3%" -I"%INC4%" -std=gnu++11 -m32

REM Компиляция файлов
rm -f main.exe
g++ -c main.cpp -o main.o %INCLIB%
g++ -c app.cpp -o app.o %INCLIB%
g++ -c window.cpp -o window.o %INCLIB%

REM Сборка и очистка
g++ main.o app.o window.o -o main.exe -L"%MINGW%/%PLATFORM%/lib32" -static-libgcc -mwindows -lopengl32 -lglu32 -lm -m32
rm -f *.o

REM Запуск
main.exe
pause

§ Основной класс (app.cpp)

#include <windows.h>

// Индентификатор таймера
#define IDT_TIMER1 1001

// Объявление процедур для окна
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM);

// Основные функции для работы
class Application {

protected:

    WNDCLASS wc;
    HWND     hWnd;
    HDC      hDC;
    HGLRC    hRC;
    MSG      msg;
    BOOL     bQuit = FALSE;
    int      width, height;

public:

    virtual void InitHook() { }

    // Запуск кода
    int start(HINSTANCE hInstance, LPCSTR title, int _width, int _height) {

        // Регистрация класса
        wc.style           = CS_OWNDC;
        wc.lpfnWndProc     = WndProc;
        wc.cbClsExtra      = 0;
        wc.cbWndExtra      = 0;
        wc.hInstance       = hInstance;
        wc.hIcon           = LoadIcon (NULL, IDI_APPLICATION);
        wc.hCursor         = LoadCursor (NULL, IDC_ARROW);
        wc.hbrBackground   = (HBRUSH) GetStockObject (BLACK_BRUSH);
        wc.lpszMenuName    = NULL;
        wc.lpszClassName   = "APPClass";
        RegisterClass (&wc);

        // Установка размера
        width  = _width;
        height = _height;

        // Создать основное окно
        hWnd = CreateWindow (
            "APPClass",
            title, WS_CAPTION | WS_POPUPWINDOW | WS_VISIBLE,
            0, 0, width, height, NULL, NULL, hInstance, NULL);

        // Подрубка OpenGL
        EnableOpenGL (hWnd, &hDC, &hRC);

        // Вызвать функцию потомка
        InitHook();

        // Создать таймер
        SetTimer(hWnd, IDT_TIMER1, 20, NULL);

        // Основной программный цикл
        while (!bQuit)
        {
            // Проверить новые сообщения
            if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) {

                // Выход
                if (msg.message == WM_QUIT) {
                    bQuit = TRUE;
                } else {
                    TranslateMessage (&msg);
                    DispatchMessage (&msg);
                }
            }
        }

        // Удалить таймер
        KillTimer(hWnd, IDT_TIMER1);

        // Остановка OpenGL
        DisableOpenGL (hWnd, hDC, hRC);

        // Выключить окно
        DestroyWindow (hWnd);

        return msg.wParam;
    }

    // Обработчик события окна
    LRESULT CALLBACK EventWnd(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {

        switch (message)
        {
            // Создание окна
            case WM_CREATE:
                return 0;

            // Закрытие окна
            case WM_CLOSE:

                PostQuitMessage (0);
                return 0;

            // Удаление окна из памяти
            case WM_DESTROY:
                return 0;

            // Нажатие на клавишу
            case WM_KEYDOWN:

                switch (wParam)
                {
                    case VK_ESCAPE:

                        PostQuitMessage(0);
                        return 0;
                }
                return 0;

            // Таймер
            case WM_TIMER:
                return 0;

            default:
                return DefWindowProc (hWnd, message, wParam, lParam);
        }
    }

    // Включение OpenGL
    void EnableOpenGL (HWND hWnd, HDC *hDC, HGLRC *hRC) {

        PIXELFORMATDESCRIPTOR pfd;
        int iFormat;

        /* get the device context (DC) */
        *hDC = GetDC (hWnd);

        /* set the pixel format for the DC */
        ZeroMemory (&pfd, sizeof (pfd));
        pfd.nSize = sizeof (pfd);
        pfd.nVersion = 1;
        pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
        pfd.iPixelType = PFD_TYPE_RGBA;
        pfd.cColorBits = 24;
        pfd.cDepthBits = 16;
        pfd.iLayerType = PFD_MAIN_PLANE;
        iFormat = ChoosePixelFormat (*hDC, &pfd);
        SetPixelFormat (*hDC, iFormat, &pfd);

        /* create and enable the render context (RC) */
        *hRC = wglCreateContext( *hDC );
        wglMakeCurrent( *hDC, *hRC );
    }

    // Отключение OpenGL
    void DisableOpenGL (HWND hWnd, HDC hDC, HGLRC hRC) {

        wglMakeCurrent (NULL, NULL);
        wglDeleteContext (hRC);
        ReleaseDC (hWnd, hDC);
    }
};

§ Класс с реализацией OpenGL (window.cpp)

#include <math.h>
#include <gl/gl.h>
#include <gl/GLU.h>

#include "app.cpp"

// Главное окно-обработчик
class AppWindow : public Application {
protected:

    float   theta;
    GLuint  texture_id;

public:

    // Наследованная виртуальная функция
    void InitHook() {

        // Включение возможностей
        glEnable(GL_DEPTH_TEST);                // Включить Z-буфер
        glEnable(GL_TEXTURE_2D);                // Включить текстурирование

        int w = 512, h = 512;
        GLuint bgra[w*h];

        // Создать тестовую текстуру
        for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            bgra[i*h + j] = i ^ j;
        } }

        // Текстура создается в памяти, назначается GLuint
        glGenTextures(1, (GLuint *) & texture_id);

        // Выбираем эту текстуру, работаем с 2D: x, y.
        glBindTexture(GL_TEXTURE_2D, texture_id);

        // Интерполяция для приближенных и удаленных объектов
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

        // Повторять текстуры
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

        // https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glTexImage2D.xhtml
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, bgra);
    }

    // Отслеживаемое событие
    LRESULT CALLBACK EventProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {

        // Обработка таймера
        switch (message) {

            case WM_TIMER:

                switch (wParam)
                {
                    case IDT_TIMER1:

                        // Построение перспективной проекции
                        glMatrixMode(GL_PROJECTION);
                        glLoadIdentity();
                        gluPerspective(50, 1, 1, 1000);

                        // Сформировать угол обзора
                        glMatrixMode(GL_MODELVIEW);
                        glLoadIdentity();
                        gluLookAt(0.0, 0.0, 2.0, // Глаз
                                  0.0, 0.0, 0.0, // Куда смотрим
                                  0.0, 1.0, 0.0); // Направление верха

                        // Анимация начинается тут
                        glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
                        glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

                        // Нарисовать треугольник
                        glRotatef (theta, 0.0f, 0.0f, 1.0f);
                        glBegin (GL_TRIANGLES);
                        glBindTexture(GL_TEXTURE_2D, texture_id);
                        glTexCoord2f(0.0f, 0.0f); glVertex3f (-1.0f,  1.0f, -1.0f);
                        glTexCoord2f(1.0f, 0.0f); glVertex3f ( 1.0f,  1.0f, -1.0f);
                        glTexCoord2f(1.0f, 1.0f); glVertex3f ( 1.0f, -1.0f, -1.0f);
                        glEnd ();

                        // Обмен буферами
                        SwapBuffers (hDC);

                        theta += 1.0f;
                        return 0;
                }
        }

        return EventWnd(hWnd, message, wParam, lParam);
    }
};
Загрузка шаблона template_gl.zip