Files
XCEngine/tests/RHI/OpenGL/integration/minimal/main.cpp
ssdfasd 460a2477c3 OpenGL: Add minimal integration test and enable integration test framework
- Add OpenGL_Minimal integration test using Win32 native API + glad
- Copy run_integration_test.py and compare_ppm.py from D3D12
- Create minimal/main.cpp with red clear color (matching D3D12)
- Generate GT.ppm golden template for 1280x720 red window
- Add VertexArray_Bind_MultipleAttributes unit test
- Update integration/CMakeLists.txt to build OpenGL_Minimal target
2026-03-20 18:30:38 +08:00

211 lines
5.4 KiB
C++

#include <windows.h>
#include <glad/glad.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "XCEngine/Debug/Logger.h"
#include "XCEngine/Debug/ConsoleLogSink.h"
#include "XCEngine/Containers/String.h"
#pragma comment(lib, "opengl32.lib")
using namespace XCEngine::Debug;
using namespace XCEngine::Containers;
static const int gWidth = 1280;
static const int gHeight = 720;
static HWND gHWND = nullptr;
static HDC gHDC = nullptr;
static HGLRC gHGLRC = nullptr;
void Log(const char* format, ...) {
char buffer[1024];
va_list args;
va_start(args, format);
vsnprintf(buffer, sizeof(buffer), format, args);
va_end(args);
Logger::Get().Debug(LogCategory::Rendering, String(buffer));
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CLOSE:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
bool InitOpenGL() {
gHDC = GetDC(gHWND);
if (!gHDC) {
Log("[ERROR] Failed to get DC");
return false;
}
PIXELFORMATDESCRIPTOR pfd = {};
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 24;
pfd.cStencilBits = 8;
pfd.iLayerType = PFD_MAIN_PLANE;
int pixelFormat = ChoosePixelFormat(gHDC, &pfd);
if (!pixelFormat) {
Log("[ERROR] Failed to choose pixel format");
return false;
}
if (!SetPixelFormat(gHDC, pixelFormat, &pfd)) {
Log("[ERROR] Failed to set pixel format");
return false;
}
gHGLRC = wglCreateContext(gHDC);
if (!gHGLRC) {
Log("[ERROR] Failed to create GL context");
return false;
}
if (!wglMakeCurrent(gHDC, gHGLRC)) {
Log("[ERROR] Failed to make GL context current");
return false;
}
if (!gladLoadGL()) {
Log("[ERROR] Failed to load OpenGL functions");
return false;
}
Log("[INFO] OpenGL initialized: %s", glGetString(GL_RENDERER));
Log("[INFO] OpenGL Version: %s", glGetString(GL_VERSION));
glViewport(0, 0, gWidth, gHeight);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
return true;
}
void ShutdownOpenGL() {
if (gHGLRC) {
wglDeleteContext(gHGLRC);
gHGLRC = nullptr;
}
if (gHDC) {
ReleaseDC(gHWND, gHDC);
gHDC = nullptr;
}
}
void SaveScreenshotPPM(const char* filename) {
unsigned char* pixels = (unsigned char*)malloc(gWidth * gHeight * 3);
if (!pixels) {
Log("[ERROR] Failed to allocate pixel buffer");
return;
}
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0, 0, gWidth, gHeight, GL_RGB, GL_UNSIGNED_BYTE, pixels);
FILE* f = fopen(filename, "wb");
if (!f) {
Log("[ERROR] Failed to open file for screenshot: %s", filename);
free(pixels);
return;
}
fprintf(f, "P6\n%d %d\n255\n", gWidth, gHeight);
unsigned char* row = (unsigned char*)malloc(gWidth * 3);
for (int y = gHeight - 1; y >= 0; y--) {
memcpy(row, pixels + y * gWidth * 3, gWidth * 3);
fwrite(row, 1, gWidth * 3, f);
}
free(row);
free(pixels);
fclose(f);
Log("[INFO] Screenshot saved to %s", filename);
}
void RenderFrame() {
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
SwapBuffers(gHDC);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
Logger::Get().Initialize();
Logger::Get().AddSink(std::make_unique<ConsoleLogSink>());
Logger::Get().SetMinimumLevel(LogLevel::Debug);
Log("[INFO] OpenGL Integration Test Starting");
WNDCLASSEX wc = {};
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = L"OpenGLTest";
if (!RegisterClassEx(&wc)) {
MessageBox(NULL, L"Failed to register window class", L"Error", MB_OK);
return -1;
}
RECT rect = { 0, 0, gWidth, gHeight };
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
gHWND = CreateWindowEx(0, L"OpenGLTest", L"OpenGL Integration Test",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
rect.right - rect.left, rect.bottom - rect.top,
NULL, NULL, hInstance, NULL);
if (!gHWND) {
MessageBox(NULL, L"Failed to create window", L"Error", MB_OK);
return -1;
}
if (!InitOpenGL()) {
MessageBox(NULL, L"Failed to initialize OpenGL", L"Error", MB_OK);
return -1;
}
ShowWindow(gHWND, nShowCmd);
UpdateWindow(gHWND);
MSG msg = {};
int frameCount = 0;
const int targetFrameCount = 30;
while (true) {
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
} else {
RenderFrame();
frameCount++;
if (frameCount >= targetFrameCount) {
Log("[INFO] Reached target frame count %d - taking screenshot!", targetFrameCount);
SaveScreenshotPPM("minimal.ppm");
break;
}
}
}
ShutdownOpenGL();
Logger::Get().Shutdown();
Log("[INFO] OpenGL Integration Test Finished");
return 0;
}