非専門的シンギュラリティー研究所

無限に動き続けるシステムを表す方法を AI なども使って考えていきます。

X68000(16)

「IOCSコール」のグラフィックス機能を調べるために

  • Windows ではウィンドウに描画する
  • X68000 ではグラフィックス機能で描画する

プログラムを作ろうと考えています。そのため、まず Windows のコンソールからウィンドウに描画するプログラムを ChatGPT で作ってもらいました。

  • Windows でコンソールアプリからウィンドウを作成して、コンソールからのコマンドでウィンドウに描画を行う C++ のサンプルを作ってください
  • 以下のコマンドが使えるようにしてください(color は色番号またはRGBで指定するとします):
    • clear color (全体を塗りつぶす)
    • drawline x1 y1 x2 y2 color (線を描画する)
    • drawstring s x y (文字列 s を描画する)
    • drawrectangle x y width height color (四角形を描画する)
    • drawellipse x y width height color (楕円を描画する)
    • drawroundedrectangle x y width height radiusx radiusy color (角が丸い四角形を描画する)
    • fillrectangle x y width height color (四角形を塗りつぶす)
    • fillellipse x y width height color (楕円を塗りつぶす)
    • fillroundedrectangle x y width height radiusx radiusy color (角が丸い四角形を塗りつぶす)

と入力すると、以下のようなサンプルを作ってくれました。

#include <windows.h>
#include <thread>
#include <iostream>
#include <string>
#include <queue>
#include <sstream>
#include <vector>
#include <mutex>

#define WM_USER_DRAW (WM_USER + 1)

enum class DrawType {
    Clear, Line, String, Rect, Ellipse, RoundRect, FillRect, FillEllipse, FillRoundRect
};

struct DrawCommand {
    DrawType type;
    COLORREF color;
    int x1, y1, x2, y2, w, h, rx, ry;
    std::wstring text;
};

std::queue<DrawCommand> g_drawQueue;
std::mutex g_queueMutex;
HWND g_hWnd = nullptr;

// 文字列を分割
std::vector<std::string> split(const std::string& str) {
    std::istringstream iss(str);
    std::vector<std::string> result;
    std::string s;
    while (iss >> s) result.push_back(s);
    return result;
}

// 色を解釈(整数 or R,G,B)
COLORREF parseColor(const std::string& s) {
    if (s.find(',') != std::string::npos) {
        int r, g, b;
        sscanf_s(s.c_str(), "%d,%d,%d", &r, &g, &b);
        return RGB(r, g, b);
    }
    else {
        int c = std::stoi(s);
        return PALETTEINDEX(c);
    }
}

void enqueue(const DrawCommand& cmd) {
    std::lock_guard<std::mutex> lock(g_queueMutex);
    g_drawQueue.push(cmd);
    InvalidateRect(g_hWnd, nullptr, FALSE);
}

// ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
    case WM_PAINT: {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        std::lock_guard<std::mutex> lock(g_queueMutex);
        while (!g_drawQueue.empty()) {
            const DrawCommand& cmd = g_drawQueue.front();
            HPEN hPen = CreatePen(PS_SOLID, 1, cmd.color);
            HBRUSH hBrush = CreateSolidBrush(cmd.color);
            SelectObject(hdc, hPen);
            SelectObject(hdc, hBrush);

            switch (cmd.type) {
            case DrawType::Clear:
                FillRect(hdc, &ps.rcPaint, hBrush);
                break;
            case DrawType::Line:
                MoveToEx(hdc, cmd.x1, cmd.y1, nullptr);
                LineTo(hdc, cmd.x2, cmd.y2);
                break;
            case DrawType::String:
                TextOutW(hdc, cmd.x1, cmd.y1, cmd.text.c_str(), (int)cmd.text.length());
                break;
            case DrawType::Rect:
                Rectangle(hdc, cmd.x1, cmd.y1, cmd.x1 + cmd.w, cmd.y1 + cmd.h);
                break;
            case DrawType::Ellipse:
                Ellipse(hdc, cmd.x1, cmd.y1, cmd.x1 + cmd.w, cmd.y1 + cmd.h);
                break;
            case DrawType::RoundRect:
                RoundRect(hdc, cmd.x1, cmd.y1, cmd.x1 + cmd.w, cmd.y1 + cmd.h, cmd.rx, cmd.ry);
                break;
            case DrawType::FillRect:
                Rectangle(hdc, cmd.x1, cmd.y1, cmd.x1 + cmd.w, cmd.y1 + cmd.h);
                break;
            case DrawType::FillEllipse:
                Ellipse(hdc, cmd.x1, cmd.y1, cmd.x1 + cmd.w, cmd.y1 + cmd.h);
                break;
            case DrawType::FillRoundRect:
                RoundRect(hdc, cmd.x1, cmd.y1, cmd.x1 + cmd.w, cmd.y1 + cmd.h, cmd.rx, cmd.ry);
                break;
            }

            DeleteObject(hPen);
            DeleteObject(hBrush);
            g_drawQueue.pop();
        }
        EndPaint(hwnd, &ps);
        return 0;
    }
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

// ウィンドウスレッド
void WindowThread() {
    const wchar_t CLASS_NAME[] = L"MyDrawWindowClass";
    WNDCLASS wc = {};
    wc.lpfnWndProc = WndProc;
    wc.hInstance = GetModuleHandle(nullptr);
    wc.lpszClassName = CLASS_NAME;
    RegisterClass(&wc);

    g_hWnd = CreateWindowEx(0, CLASS_NAME, L"Drawing Window",
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
        800, 600, nullptr, nullptr, wc.hInstance, nullptr);

    ShowWindow(g_hWnd, SW_SHOW);

    MSG msg;
    while (GetMessage(&msg, nullptr, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

// メイン関数
int main() {
    std::thread winThread(WindowThread);
    std::string line;
    std::cout << "Enter draw commands (type 'exit' to quit):\n";

    while (std::getline(std::cin, line)) {
        if (line == "exit") {
            PostMessage(g_hWnd, WM_CLOSE, 0, 0);
            break;
        }
        auto tokens = split(line);
        if (tokens.empty()) continue;

        DrawCommand cmd = {};
        try {
            if (tokens[0] == "clear" && tokens.size() == 2) {
                cmd.type = DrawType::Clear;
                cmd.color = parseColor(tokens[1]);
            }
            else if (tokens[0] == "drawline" && tokens.size() == 6) {
                cmd.type = DrawType::Line;
                cmd.x1 = std::stoi(tokens[1]);
                cmd.y1 = std::stoi(tokens[2]);
                cmd.x2 = std::stoi(tokens[3]);
                cmd.y2 = std::stoi(tokens[4]);
                cmd.color = parseColor(tokens[5]);
            }
            else if (tokens[0] == "drawstring" && tokens.size() >= 4) {
                cmd.type = DrawType::String;
                cmd.text = std::wstring(tokens[1].begin(), tokens[1].end());
                cmd.x1 = std::stoi(tokens[2]);
                cmd.y1 = std::stoi(tokens[3]);
                cmd.color = RGB(0, 0, 0); // 固定色(必要に応じて拡張)
            }
            else if (tokens[0] == "drawrectangle" && tokens.size() == 6) {
                cmd.type = DrawType::Rect;
                cmd.x1 = std::stoi(tokens[1]);
                cmd.y1 = std::stoi(tokens[2]);
                cmd.w = std::stoi(tokens[3]);
                cmd.h = std::stoi(tokens[4]);
                cmd.color = parseColor(tokens[5]);
            }
            else if (tokens[0] == "drawellipse" && tokens.size() == 6) {
                cmd.type = DrawType::Ellipse;
                cmd.x1 = std::stoi(tokens[1]);
                cmd.y1 = std::stoi(tokens[2]);
                cmd.w = std::stoi(tokens[3]);
                cmd.h = std::stoi(tokens[4]);
                cmd.color = parseColor(tokens[5]);
            }
            else if (tokens[0] == "drawroundedrectangle" && tokens.size() == 8) {
                cmd.type = DrawType::RoundRect;
                cmd.x1 = std::stoi(tokens[1]);
                cmd.y1 = std::stoi(tokens[2]);
                cmd.w = std::stoi(tokens[3]);
                cmd.h = std::stoi(tokens[4]);
                cmd.rx = std::stoi(tokens[5]);
                cmd.ry = std::stoi(tokens[6]);
                cmd.color = parseColor(tokens[7]);
            }
            else if (tokens[0] == "fillrectangle" && tokens.size() == 6) {
                cmd.type = DrawType::FillRect;
                cmd.x1 = std::stoi(tokens[1]);
                cmd.y1 = std::stoi(tokens[2]);
                cmd.w = std::stoi(tokens[3]);
                cmd.h = std::stoi(tokens[4]);
                cmd.color = parseColor(tokens[5]);
            }
            else if (tokens[0] == "fillellipse" && tokens.size() == 6) {
                cmd.type = DrawType::FillEllipse;
                cmd.x1 = std::stoi(tokens[1]);
                cmd.y1 = std::stoi(tokens[2]);
                cmd.w = std::stoi(tokens[3]);
                cmd.h = std::stoi(tokens[4]);
                cmd.color = parseColor(tokens[5]);
            }
            else if (tokens[0] == "fillroundedrectangle" && tokens.size() == 8) {
                cmd.type = DrawType::FillRoundRect;
                cmd.x1 = std::stoi(tokens[1]);
                cmd.y1 = std::stoi(tokens[2]);
                cmd.w = std::stoi(tokens[3]);
                cmd.h = std::stoi(tokens[4]);
                cmd.rx = std::stoi(tokens[5]);
                cmd.ry = std::stoi(tokens[6]);
                cmd.color = parseColor(tokens[7]);
            }
            else {
                std::cout << "Unknown or malformed command.\n";
                continue;
            }
            enqueue(cmd);
        }
        catch (...) {
            std::cout << "Error parsing command.\n";
        }
    }

    winThread.join();
    return 0;
}