§ Основной код

* hInstance        Переданная текущая программа
* hPrevInstance    Программа, которая передала управление
* lpCmdLine        Строка запроса (нулевой символ в конце)
* nShowCmd         Показывает состояние окна
Подробное описание в этой статье.
@echo off
g++ -m32 -g3 -static-libgcc -mwindows -lgdi32 main.cpp -o main.exe
strip main.exe
main.exe
#include "demoapp.cpp"

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    DemoApp app;
    app.init(hInstance, 1280, 800, "Windows", 50, 4);

    int test = 0;
    while (app.wait()) {

        // Срабатывает на таймере
        if (app.is_timer()) {

            test++;
            for (int y = 0; y < 200; y++)
            for (int x = 0; x < 320; x++)
                app.pset(x, y, x*y + test);
        }

        app.repaint();
    }

    return 0;
}

§ Класс-обработчик demoapp.cpp

// Опции компилятора -static-libgcc -mwindows -lgdi32

// Убрать лишнее из генерируемого файла
#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

#include "demoapp.h"

// ---------------------------------------------------------------------------------------

class DemoApp {
protected:

    HWND            hWnd;
    INT64           frameMillisecond;
    int             last_events;

public:

    // Инициализация окна, создание и назначение обработчиков
    // fps количество кадров в секунду
    // scale: 0=1x1, 1=2x2, 2=4x4, ...
    void init(HINSTANCE hInstance, int width, int height, const char* name, int fps, int scale) {

        DWORD dwExStyle = WS_EX_APPWINDOW;
        DWORD dwStyle   = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU;

        int x, y, w, h;

        WNDCLASS wc;
        RECT     rc;

        wc.style            = CS_OWNDC;
        wc.lpfnWndProc      = MainWndProc;
        wc.cbClsExtra       = 0;
        wc.cbWndExtra       = 0;
        wc.hInstance        = hInstance;
        wc.hIcon            = LoadIcon(NULL, IDI_APPLICATION);
        wc.hCursor          = LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground    = NULL;
        wc.lpszMenuName     = NULL;
        wc.lpszClassName    = TEXT("MainWndEx");

        if (!RegisterClass(&wc)) {

            MessageBox(NULL, TEXT("RegisterClass failed!"), TEXT("Error"), MB_ICONERROR | MB_OK | MB_SETFOREGROUND);
            return;
        }

        rc.left   = 0;
        rc.top    = 0;
        rc.right  = width;
        rc.bottom = height;

        window_width  = width;
        window_height = height;

        win_ws = window_width  / scale;
        win_hs = window_height / scale;

        if (!AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle)) {

            MessageBox(NULL, TEXT("AdjustWindowRectEx failed!"), TEXT("Error"), MB_ICONERROR | MB_OK | MB_SETFOREGROUND);
            return;
        }

        w = width;
        h = height;
        x = (GetSystemMetrics(SM_CXSCREEN) - w) / 2;
        y = (GetSystemMetrics(SM_CYSCREEN) - h) / 2;

        EventAccept      = 0;
        last_events      = 0;
        frameMillisecond = 1000 / fps;

        // Выделить память для пиксельного буфера
        pixels = (COLORREF*) malloc (width * height * sizeof(COLORREF));

        hWnd = CreateWindowEx(dwExStyle, wc.lpszClassName, name, dwStyle, x, y, w, h, NULL, NULL, hInstance, NULL);
        if (!hWnd) {
            MessageBox(NULL, TEXT("CreateWindowEx failed."), TEXT("Error"), MB_ICONERROR | MB_OK | MB_SETFOREGROUND);
            return;
        }

        bitmapInfo.bmiHeader.biSize     = sizeof(bitmapInfo);
        bitmapInfo.bmiHeader.biWidth    = width / scale;
        bitmapInfo.bmiHeader.biHeight   = -height / scale;
        bitmapInfo.bmiHeader.biPlanes   = 1;
        bitmapInfo.bmiHeader.biBitCount = 32;
        bitmapInfo.bmiHeader.biCompression = BI_RGB;

        SetTimer(hWnd, 0, frameMillisecond, NULL);
        ShowWindow(hWnd, SW_SHOWNORMAL);
        UpdateWindow(hWnd);
    }

    // Перерисовка окна
    void repaint() {

        if (is_timer()) {
            InvalidateRect(hWnd, NULL, FALSE);
        }
    }

    // Сработал таймер
    int is_timer() {
        return last_events & MYEVENT_WM_TIMER ? 1 : 0;
    }

    // Сработала клавиатура
    int is_keydown() { return last_events & MYEVENT_WM_KEYDOWN ? 1 : 0; }
    int is_keyup()   { return last_events & MYEVENT_WM_KEYUP   ? 1 : 0; }
    int kb_key()     { return DataKeyboard; }

    // Обработка сообщений от windows
    int peek_messages() {

        MSG msg;

        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {

            // Выход из процедуры ожидания
            if (msg.message == WM_QUIT)
                return 0;

            TranslateMessage (&msg);
            DispatchMessage  (&msg);
        }

        Sleep(1);
        return 1;
    }

    // Процедура ожидания
    int wait() {

        EventAccept = 0;
        do {

            if (peek_messages() == 0)
                return 0;

        } while (!EventAccept);

        last_events = EventAccept;
        return EventAccept;
    }

    // ==== Графические процедуры ====

    // Поставить точку в буфере
    void pset(int x, int y, int color) {

        if (x >= 0 && y >= 0 && x < win_ws && y < win_hs) {
            pixels[win_ws*y + x] = color;
        }
    }

     // Нарисовать линию
    void line(int x1, int y1, int x2, int y2, int color) {

        int deltax = abs(x2 - x1);
        int deltay = abs(y2 - y1);
        int signx  = x1 < x2 ? 1 : -1;
        int signy  = y1 < y2 ? 1 : -1;

        int error = deltax - deltay;
        int error2;

        pset(x2, y2, color);
        while (x1 != x2 || y1 != y2)
        {
            pset(x1, y1, color);
            error2 = error * 2;

            if (error2 > -deltay) {
                error -= deltay;
                x1 += signx;
            }

            if (error2 < deltax) {
                error += deltax;
                y1 += signy;
            }
        }
    }

    // Очистить весь экран
    void cls(int color) {

        for (int i = 0; i < win_ws * win_hs; i++)
            pixels[i] = color;
    }
};

// Обработчик событий от Windows
LRESULT CALLBACK MainWndProc(HWND MyWnd, UINT msg, WPARAM wParam, LPARAM lParam) {

    switch (msg) {

        case WM_CLOSE:
        case WM_DESTROY:

            PostQuitMessage(0);
            return 0;

        case WM_ERASEBKGND:
            return TRUE;

        case WM_KEYDOWN:

            EventAccept |= MYEVENT_WM_KEYDOWN;
            DataKeyboard = wParam;
            return 0;

        case WM_KEYUP:

            EventAccept |= MYEVENT_WM_KEYUP;
            DataKeyboard = wParam;
            return 0;

        case WM_TIMER:

            EventAccept |= MYEVENT_WM_TIMER;
            return 0;

        case WM_PAINT:

            PAINTSTRUCT ps;
            RECT r;
            HDC  hDC;

            hDC = BeginPaint(MyWnd, &ps);
            GetClientRect(MyWnd, &r);

            // dstx, dsty, dstw, dsth, srcx, srcy, scrw, scrh
            StretchDIBits(
                hDC,
                0, 0, window_width, window_height,
                0, 0, win_ws, win_hs,
                pixels, &bitmapInfo, DIB_RGB_COLORS, SRCCOPY);

            EndPaint(MyWnd, &ps);
            return 0;
    }

    return DefWindowProc(MyWnd, msg, wParam, lParam);
}

§ Заголовочный файл demoapp.h

// Объявление процедуры обработки данных
LRESULT CALLBACK  MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
int     WINAPI    WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow);

// Глобальные данные
int         window_width, window_height;
int         win_ws, win_hs;
int         EventAccept;
WPARAM      DataKeyboard;

// Хранение пиксельных данных
static COLORREF*   pixels;
static BITMAPINFO  bitmapInfo;

enum Events {

    MYEVENT_WM_TIMER    = 1,
    MYEVENT_WM_KEYDOWN  = 2,
    MYEVENT_WM_KEYUP    = 4,
};
25 июн, 2021
© 2007-2022 Жесть в том, что Нифёдов кусает над землей