Add OpenGL test framework with logging and screenshot comparison
- Unified resolution to 1280x720 (same as D3D12) - Added XCEngine Logger integration for debug output - Added screenshot capture at frame 30 (glReadPixels -> PPM) - Added run.bat test script - Added compare_ppm.py for screenshot comparison - Added GT.ppm reference image - Added README.md documentation - Updated CMakeLists.txt to link XCEngine library Test: OpenGL rendering test passed (screenshot comparison 100% match)
This commit is contained in:
@@ -13,9 +13,28 @@
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <windows.h>
|
||||
#include <stdarg.h>
|
||||
#include "XCEngine/Debug/Logger.h"
|
||||
#include "XCEngine/Debug/ConsoleLogSink.h"
|
||||
#include "XCEngine/Debug/FileLogSink.h"
|
||||
|
||||
const unsigned int SCR_WIDTH = 800;
|
||||
const unsigned int SCR_HEIGHT = 600;
|
||||
using namespace XCEngine::Debug;
|
||||
|
||||
#pragma comment(lib, "opengl32.lib")
|
||||
#pragma comment(lib, "gdi32.lib")
|
||||
|
||||
const unsigned int SCR_WIDTH = 1280;
|
||||
const unsigned int SCR_HEIGHT = 720;
|
||||
|
||||
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, buffer);
|
||||
}
|
||||
|
||||
class Shader
|
||||
{
|
||||
@@ -42,7 +61,7 @@ public:
|
||||
}
|
||||
catch (std::ifstream::failure& e)
|
||||
{
|
||||
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
|
||||
Log("ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ: %s", e.what());
|
||||
}
|
||||
|
||||
const char* vShaderCode = vertexCode.c_str();
|
||||
@@ -102,7 +121,7 @@ private:
|
||||
if (!success)
|
||||
{
|
||||
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
|
||||
std::cout << "ERROR::SHADER_COMPILATION_ERROR: " << type << std::endl;
|
||||
Log("ERROR::SHADER_COMPILATION_ERROR: %s - %s", type.c_str(), infoLog);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -111,7 +130,7 @@ private:
|
||||
if (!success)
|
||||
{
|
||||
glGetProgramInfoLog(ID, 1024, NULL, infoLog);
|
||||
std::cout << "ERROR::PROGRAM_LINKING_ERROR" << std::endl;
|
||||
Log("ERROR::PROGRAM_LINKING_ERROR: %s", infoLog);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,10 +236,12 @@ unsigned int TextureFromFile(const char* path, const std::string& directory)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
Log("Texture loaded: %s (%dx%d)", filename.c_str(), width, height);
|
||||
stbi_image_free(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log("Failed to load texture: %s", filename.c_str());
|
||||
stbi_image_free(data);
|
||||
}
|
||||
return textureID;
|
||||
@@ -251,8 +272,10 @@ private:
|
||||
const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FlipUVs);
|
||||
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
|
||||
{
|
||||
Log("Failed to load model: %s", path.c_str());
|
||||
return;
|
||||
}
|
||||
Log("Model loaded: %s", path.c_str());
|
||||
directory = path.substr(0, path.find_last_of('/'));
|
||||
processNode(scene->mRootNode, scene);
|
||||
}
|
||||
@@ -333,8 +356,9 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
Model* model;
|
||||
Shader* shader;
|
||||
Model* model = nullptr;
|
||||
Shader* shader = nullptr;
|
||||
int frameCount = 0;
|
||||
|
||||
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
|
||||
{
|
||||
@@ -349,9 +373,43 @@ void Initialize()
|
||||
exeDir = exeDir.substr(0, exeDir.find_last_of("\\/"));
|
||||
SetCurrentDirectoryA(exeDir.c_str());
|
||||
|
||||
Log("OpenGL Test Application Started");
|
||||
|
||||
model = new Model("res/models/backpack/backpack.obj");
|
||||
shader = new Shader("Shaders/vertexshader.glsl", "Shaders/fragmentshader.glsl");
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
Log("Initialization complete");
|
||||
}
|
||||
|
||||
bool SaveScreenshot(const char* filename)
|
||||
{
|
||||
Log("Saving screenshot: %s", filename);
|
||||
|
||||
int width = SCR_WIDTH;
|
||||
int height = SCR_HEIGHT;
|
||||
|
||||
std::vector<unsigned char> pixels(width * height * 3);
|
||||
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels.data());
|
||||
|
||||
FILE* fp = fopen(filename, "wb");
|
||||
if (!fp) {
|
||||
Log("Failed to open file for screenshot: %s", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
fprintf(fp, "P6\n%d %d\n255\n", width, height);
|
||||
|
||||
std::vector<unsigned char> flippedPixels(width * height * 3);
|
||||
for (int y = 0; y < height; y++) {
|
||||
memcpy(&flippedPixels[y * width * 3], &pixels[(height - 1 - y) * width * 3], width * 3);
|
||||
}
|
||||
|
||||
fwrite(flippedPixels.data(), 1, width * height * 3, fp);
|
||||
fclose(fp);
|
||||
|
||||
Log("Screenshot saved successfully");
|
||||
return true;
|
||||
}
|
||||
|
||||
void Render()
|
||||
@@ -380,6 +438,12 @@ void Render()
|
||||
|
||||
int main()
|
||||
{
|
||||
Logger::Get().AddSink(std::make_unique<FileLogSink>("OpenGL_engine_log.txt"));
|
||||
Logger::Get().SetMinimumLevel(LogLevel::Debug);
|
||||
|
||||
AllocConsole();
|
||||
freopen("CONOUT$", "w", stdout);
|
||||
|
||||
glfwInit();
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
@@ -388,7 +452,7 @@ int main()
|
||||
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "XCRender", NULL, NULL);
|
||||
if (window == NULL)
|
||||
{
|
||||
std::cout << "Failed to create GLFW window" << std::endl;
|
||||
Log("Failed to create GLFW window");
|
||||
glfwTerminate();
|
||||
return -1;
|
||||
}
|
||||
@@ -398,10 +462,13 @@ int main()
|
||||
|
||||
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
|
||||
{
|
||||
std::cout << "Failed to initialize GLAD" << std::endl;
|
||||
Log("Failed to initialize GLAD");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Log("OpenGL Version: %s", glGetString(GL_VERSION));
|
||||
Log("Renderer: %s", glGetString(GL_RENDERER));
|
||||
|
||||
Initialize();
|
||||
|
||||
while (!glfwWindowShouldClose(window))
|
||||
@@ -412,8 +479,19 @@ int main()
|
||||
Render();
|
||||
glfwSwapBuffers(window);
|
||||
glfwPollEvents();
|
||||
|
||||
frameCount++;
|
||||
|
||||
if (frameCount == 30) {
|
||||
Log("Saving screenshot at frame %d", frameCount);
|
||||
SaveScreenshot("screenshot.ppm");
|
||||
glfwSetWindowShouldClose(window, true);
|
||||
}
|
||||
}
|
||||
|
||||
Log("Application closed");
|
||||
|
||||
glfwTerminate();
|
||||
Logger::Get().Shutdown();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user