Setting up IXWebSocket with SDL3 and OpenGL (MinGW) Настройка IXWebSocket с SDL3 и OpenGL (MinGW)

Building and running an SDL3 and OpenGL 3.3 desktop application with IXWebSocket networking on Windows using MinGW 13.1 and CMake. Сборка и запуск десктопного приложения SDL3 и OpenGL 3.3 с сетевой частью на IXWebSocket на Windows с помощью MinGW 13.1 и CMake.

3. Project Structure 3. Структура проекта

Create an empty folder named ixwebsocket-opengl-sdl3-cpp and set up the following files:

Создайте пустую папку с именем ixwebsocket-opengl-sdl3-cpp и подготовьте следующие файлы:

ixwebsocket-opengl-sdl3-cpp/
├── CMakeLists.txt
└── src/
    └── main.cpp

4. Project Configuration (CMakeLists.txt) 4. Конфигурация проекта (CMakeLists.txt)

Copy and paste the layout rules below to resolve static headers and add internal Win32 socket subsystems (ws2_32, crypt32, bcrypt):

Скопируйте и вставьте правила конфигурации ниже, чтобы подключить статические заголовки и системные библиотеки сокетов Win32 (ws2_32, crypt32, bcrypt):

set(CMAKE_BUILD_TYPE "Debug")
cmake_minimum_required(VERSION 3.21)
project(ixwebsocket-opengl-sdl3-cpp)

# SDL3 Setup
set(SDL3_DIR "C:/libs/SDL3-devel-3.4.8-mingw/lib/cmake/SDL3")
find_package(SDL3 REQUIRED)

add_executable(app)

# Include Directories
target_include_directories(app PRIVATE 
    "C:/libs/glad-0.1.36/opengl-3.3/include"
    "C:/libs/IXWebSocket-12.0.0-mingw-master/include"
    "C:/libs/mbedtls-4.1.0-mingw/include"
    "C:/libs/zlib-1.3.2-mingw/include"
)

# Source Mapping
target_sources(app PRIVATE
    "C:/libs/glad-0.1.36/opengl-3.3/src/glad.c"
    src/main.cpp
)

# Static Link Targets (Order Matters for MinGW Linker Validation!)
target_link_libraries(app PRIVATE 
    SDL3::SDL3
    "C:/libs/IXWebSocket-12.0.0-mingw-master/lib/libixwebsocket.a"
    "C:/libs/mbedtls-4.1.0-mingw/lib/libmbedx509.a"
    "C:/libs/mbedtls-4.1.0-mingw/lib/libmbedtls.a"
    "C:/libs/mbedtls-4.1.0-mingw/lib/libmbedcrypto.a"
    "C:/libs/zlib-1.3.2-mingw/lib/libzs.a"
    ws2_32
    wsock32
    crypt32
    bcrypt
)

target_link_options(app PRIVATE -mconsole)

5. Source Code 5. Исходный код

This application initializes an OpenGL 3.3 context via the modern SDL3 callback structure while managing a non-blocking WebSocket connection running on a background thread:

Это приложение инициализирует контекст OpenGL 3.3 с помощью современной структуры колбэков SDL3, параллельно управляя неблокирующим WebSocket-подключением, работающим в фоновом потоке:

src/main.cpp
#define SDL_MAIN_USE_CALLBACKS 1

#include <glad/glad.h>
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>

#include <ixwebsocket/IXNetSystem.h> // Required header for Network Init
#include <ixwebsocket/IXWebSocket.h>
#include <iostream>

struct AppContext
{
    SDL_Window *window;
    SDL_GLContext glContext;
    ix::WebSocket webSocket;
};

SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
    // Initialize the network subsystem for Windows (Winsock)
    ix::initNetSystem();

    if (!SDL_Init(SDL_INIT_VIDEO))
    {
        std::cerr << "Failed to init SDL Video" << std::endl;
        ix::uninitNetSystem();
        return SDL_APP_FAILURE;
    }

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);

    SDL_Window *window =SDL_CreateWindow("SDL3 + IXWebSocket", 380, 380, SDL_WINDOW_OPENGL);
    if (!window)
    {
        ix::uninitNetSystem();
        return SDL_APP_FAILURE;
    }

    SDL_GLContext glContext =SDL_GL_CreateContext(window);
    if (!glContext)
    {
        ix::uninitNetSystem();
        return SDL_APP_FAILURE;
    }

    if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress))
    {
        std::cerr << "Failed to init GLAD" << std::endl;
        SDL_GL_DestroyContext(glContext);
        SDL_DestroyWindow(window);
        ix::uninitNetSystem();
        return SDL_APP_FAILURE;
    }

    SDL_GL_SetSwapInterval(1);

    // Allocate the state onto the heap and pass it to SDL
    AppContext *app = new AppContext();
    app->window = window;
    app->glContext = glContext;
    *appstate = app;

    // IXWebSocket Network Initialization
    std::string url("ws://localhost:3000");
    app->webSocket.setUrl(url);

    app->webSocket.setOnMessageCallback([app](const ix::WebSocketMessagePtr &msg) {
        if (msg->type == ix::WebSocketMessageType::Message)
        {
            std::cout << "Received: " << msg->str << std::endl;
        }
        else if (msg->type == ix::WebSocketMessageType::Open)
        {
            std::cout << "Connected to WebSocket Server!" << std::endl;
            app->webSocket.send("Hello from SDL3 Client!");
        }
        else if (msg->type == ix::WebSocketMessageType::Close)
        {
            std::cout << "Disconnected from Server" << std::endl;
        }
        else if (msg->type == ix::WebSocketMessageType::Error)
        {
            std::cerr << "Error: " << msg->errorInfo.reason << std::endl;
        }
    });

    std::cout << "Connecting to " << url << "..." << std::endl;
    app->webSocket.start(); // Non-blocking background worker thread

    return SDL_APP_CONTINUE;
}

SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
    if (event->type == SDL_EVENT_QUIT)
    {
        return SDL_APP_SUCCESS;
    }
    return SDL_APP_CONTINUE;
}

SDL_AppResult SDL_AppIterate(void *appstate)
{
    AppContext *app = (AppContext *)appstate;

    // Render loop backdrop updates
    glClearColor(0.15f, 0.15f, 0.15f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    SDL_GL_SwapWindow(app->window);
    return SDL_APP_CONTINUE;
}

void SDL_AppQuit(void *appstate, SDL_AppResult result)
{
    AppContext *app = (AppContext *)appstate;
    if (app)
    {
        app->webSocket.stop(); // Cleanly stop background socket thread
        SDL_GL_DestroyContext(app->glContext);
        SDL_DestroyWindow(app->window);
        delete app; // Free allocated memory
    }

    // Clean up Windows socket resources on exit
    ix::uninitNetSystem();

    SDL_Quit();
    std::cout << "Application exited cleanly." << std::endl;
}

6. Test Node.js WebSocket Server 6. Тестовый сервер WebSocket на Node.js

To verify your application communication layer locally, follow these steps to set up a small WebSocket server:

Чтобы проверить работоспособность коммуникационного слоя локально, выполните следующие шаги для настройки небольшого WebSocket-сервера:

A. Prerequisites & Installation A. Предварительные требования и установка
  1. Download and install Node.js if you haven't already. Скачайте и установите Node.js, если он еще не установлен.
  2. Open your terminal/command prompt and install nodemon globally for automatic server restarts: Откройте терминал/командную строку и установите nodemon глобально для автоматического перезапуска сервера:
    npm i nodemon -g
B. Create the Server Folder and Script B. Создание папки сервера и скрипта
  1. Create a new folder named server in your project directory. Создайте новую папку с именем server в директории вашего проекта.
  2. Inside the server folder, create a file named server.js and paste the following code: Внутри папки server создайте файл с именем server.js и вставьте следующий код:
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 3000 });

wss.on('connection', (ws) => {
    console.log('Client connected');

    ws.on('message', (message) => {
        console.log('Received message:', message.toString());
    });

    ws.on('close', () => {
        console.log('Client disconnected');
    });
});
console.log('WebSocket server is listening on ws://localhost:3000');
C. Run the Server C. Запуск сервера
  1. Open Command Prompt (CMD) or terminal inside the server folder. Откройте командную строку (CMD) или терминал внутри папки server.
  2. Install the required ws dependency locally: Установите необходимую зависимость ws локально:
    npm install ws
  3. Start the server using nodemon: Запустите сервер с помощью nodemon:
    nodemon server.js

Once the server is running and listening on port 3000, proceed to build and run the client application using the automation scripts below.

Как только сервер запустится и начнет прослушивать порт 3000, переходите к сборке и запуску клиентского приложения с помощью скриптов автоматизации ниже.


7. Automation Scripts (.bat) 7. Скрипты автоматизации (.bat)

Create these three quick launch scripts in the root directory of your project to automate desktop builds:

Создайте три файла автоматизации в корневой папке вашего проекта для быстрой сборки десктопной версии:

1. config-exe.bat
cmake -G "MinGW Makefiles" -S . -B dist/exe
2. build-exe.bat
cd dist\exe
cmake --build .
cd ..\..
3. run-exe.bat
dist\exe\app

6. Source Code & Downloads 6. Исходный код и загрузки

You can download the complete configured project as a ZIP archive or explore the source code directly on GitHub: Вы можете скачать готовую настроенную сборку проекта в виде ZIP-архива или изучить исходный код прямо на GitHub:


Support My Work Поддержать проект

If these tutorials helped you, consider buying me a coffee! Если эти туториалы вам помогли, вы можете поддержать автора.

Sberbank

Sberbank SBP QR Code

Direct transfer via phone number Перевод по номеру телефона

+7 (917) 212-29-59

Bybit (USDT TRC20)

Bybit USDT TRC20 QR Code

Support via Cryptocurrency Поддержка криптовалютой

TMtY1YifNf6FKvgeFmqKGQR4NStKr3csGp