refactor: complete OpenGL→Vulkan migration (Phase 7)
Some checks are pending
Build / Build (arm64) (push) Waiting to run
Build / Build (x86-64) (push) Waiting to run
Build / Build (macOS arm64) (push) Waiting to run
Build / Build (windows-arm64) (push) Waiting to run
Build / Build (windows-x86-64) (push) Waiting to run
Security / CodeQL (C/C++) (push) Waiting to run
Security / Semgrep (push) Waiting to run
Security / Sanitizer Build (ASan/UBSan) (push) Waiting to run

Remove all OpenGL/GLEW code and dependencies. The Vulkan renderer has
been the sole active backend for months; these files were dead code.

Deleted (8 files, 641 lines):
- rendering/mesh.cpp+hpp: OpenGL VAO/VBO/EBO wrapper (never instantiated)
- rendering/shader.cpp+hpp: OpenGL GLSL compiler (replaced by VkShaderModule)
- rendering/scene.cpp+hpp: Scene graph holding Mesh objects (created but
  never populated — all rendering uses Vulkan sub-renderers directly)
- rendering/video_player.cpp+hpp: FFmpeg+GL texture uploader (never
  included by any other file — login video feature can be re-implemented
  with VkTexture when needed)

Cleaned up:
- renderer.hpp: remove Scene forward-decl, getScene() accessor, scene member
- renderer.cpp: remove scene.hpp/shader.hpp includes, Scene create/destroy
- application.cpp: remove stale "GL/glew.h removed" comment
- CMakeLists.txt: remove find_package(OpenGL/GLEW), source/header entries,
  and target_link_libraries for OpenGL::GL and GLEW::GLEW
- PKGBUILD: remove glew dependency
- BUILD_INSTRUCTIONS.md: remove glew from all platform install commands
This commit is contained in:
Kelsi 2026-03-30 19:22:36 -07:00
parent 4b379f6fe9
commit 7cfaf2c7e9
14 changed files with 4 additions and 680 deletions

View file

@ -1,56 +0,0 @@
#include "rendering/mesh.hpp"
namespace wowee {
namespace rendering {
Mesh::~Mesh() {
destroy();
}
void Mesh::create(const std::vector<Vertex>& vertices, const std::vector<uint32_t>& indices) {
indexCount = indices.size();
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(uint32_t), indices.data(), GL_STATIC_DRAW);
// Position
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position));
// Normal
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, normal));
// TexCoord
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, texCoord));
glBindVertexArray(0);
}
void Mesh::destroy() {
if (VAO) glDeleteVertexArrays(1, &VAO);
if (VBO) glDeleteBuffers(1, &VBO);
if (EBO) glDeleteBuffers(1, &EBO);
VAO = VBO = EBO = 0;
}
void Mesh::draw() const {
if (VAO && indexCount > 0) {
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
}
} // namespace rendering
} // namespace wowee

View file

@ -1,7 +1,6 @@
#include "rendering/renderer.hpp"
#include "rendering/camera.hpp"
#include "rendering/camera_controller.hpp"
#include "rendering/scene.hpp"
#include "rendering/terrain_renderer.hpp"
#include "rendering/terrain_manager.hpp"
#include "rendering/performance_hud.hpp"
@ -26,7 +25,6 @@
#include "rendering/minimap.hpp"
#include "rendering/world_map.hpp"
#include "rendering/quest_marker_renderer.hpp"
#include "rendering/shader.hpp"
#include "game/game_handler.hpp"
#include "pipeline/m2_loader.hpp"
#include <algorithm>
@ -673,9 +671,6 @@ bool Renderer::initialize(core::Window* win) {
cameraController->setUseWoWSpeed(true); // Use realistic WoW movement speed
cameraController->setMouseSensitivity(0.15f);
// Create scene
scene = std::make_unique<Scene>();
// Create performance HUD
performanceHUD = std::make_unique<PerformanceHUD>();
performanceHUD->setPosition(PerformanceHUD::Position::TOP_LEFT);
@ -877,7 +872,6 @@ void Renderer::shutdown() {
zoneManager.reset();
performanceHUD.reset();
scene.reset();
cameraController.reset();
camera.reset();

View file

@ -1,24 +0,0 @@
#include "rendering/scene.hpp"
#include "rendering/mesh.hpp"
#include <algorithm>
namespace wowee {
namespace rendering {
void Scene::addMesh(std::shared_ptr<Mesh> mesh) {
meshes.push_back(std::move(mesh));
}
void Scene::removeMesh(const std::shared_ptr<Mesh>& mesh) {
auto it = std::find(meshes.begin(), meshes.end(), mesh);
if (it != meshes.end()) {
meshes.erase(it);
}
}
void Scene::clear() {
meshes.clear();
}
} // namespace rendering
} // namespace wowee

View file

@ -1,140 +0,0 @@
#include "rendering/shader.hpp"
#include "core/logger.hpp"
#include <fstream>
#include <sstream>
namespace wowee {
namespace rendering {
Shader::~Shader() {
if (program) glDeleteProgram(program);
if (vertexShader) glDeleteShader(vertexShader);
if (fragmentShader) glDeleteShader(fragmentShader);
}
bool Shader::loadFromFile(const std::string& vertexPath, const std::string& fragmentPath) {
// Load vertex shader
std::ifstream vFile(vertexPath);
if (!vFile.is_open()) {
LOG_ERROR("Failed to open vertex shader: ", vertexPath);
return false;
}
std::stringstream vStream;
vStream << vFile.rdbuf();
std::string vertexSource = vStream.str();
// Load fragment shader
std::ifstream fFile(fragmentPath);
if (!fFile.is_open()) {
LOG_ERROR("Failed to open fragment shader: ", fragmentPath);
return false;
}
std::stringstream fStream;
fStream << fFile.rdbuf();
std::string fragmentSource = fStream.str();
return compile(vertexSource, fragmentSource);
}
bool Shader::loadFromSource(const std::string& vertexSource, const std::string& fragmentSource) {
return compile(vertexSource, fragmentSource);
}
bool Shader::compile(const std::string& vertexSource, const std::string& fragmentSource) {
GLint success;
GLchar infoLog[512];
// Compile vertex shader
const char* vCode = vertexSource.c_str();
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vCode, nullptr);
glCompileShader(vertexShader);
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog);
LOG_ERROR("Vertex shader compilation failed: ", infoLog);
return false;
}
// Compile fragment shader
const char* fCode = fragmentSource.c_str();
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fCode, nullptr);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog);
LOG_ERROR("Fragment shader compilation failed: ", infoLog);
return false;
}
// Link program
program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(program, 512, nullptr, infoLog);
LOG_ERROR("Shader program linking failed: ", infoLog);
return false;
}
return true;
}
void Shader::use() const {
glUseProgram(program);
}
void Shader::unuse() const {
glUseProgram(0);
}
GLint Shader::getUniformLocation(const std::string& name) const {
// Check cache first
auto it = uniformLocationCache.find(name);
if (it != uniformLocationCache.end()) {
return it->second;
}
// Look up and cache
GLint location = glGetUniformLocation(program, name.c_str());
uniformLocationCache[name] = location;
return location;
}
void Shader::setUniform(const std::string& name, int value) {
glUniform1i(getUniformLocation(name), value);
}
void Shader::setUniform(const std::string& name, float value) {
glUniform1f(getUniformLocation(name), value);
}
void Shader::setUniform(const std::string& name, const glm::vec2& value) {
glUniform2fv(getUniformLocation(name), 1, &value[0]);
}
void Shader::setUniform(const std::string& name, const glm::vec3& value) {
glUniform3fv(getUniformLocation(name), 1, &value[0]);
}
void Shader::setUniform(const std::string& name, const glm::vec4& value) {
glUniform4fv(getUniformLocation(name), 1, &value[0]);
}
void Shader::setUniform(const std::string& name, const glm::mat3& value) {
glUniformMatrix3fv(getUniformLocation(name), 1, GL_FALSE, &value[0][0]);
}
void Shader::setUniform(const std::string& name, const glm::mat4& value) {
glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, &value[0][0]);
}
void Shader::setUniformMatrixArray(const std::string& name, const glm::mat4* matrices, int count) {
glUniformMatrix4fv(getUniformLocation(name), count, GL_FALSE, &matrices[0][0][0]);
}
} // namespace rendering
} // namespace wowee

View file

@ -1,259 +0,0 @@
#include "rendering/video_player.hpp"
#include "core/logger.hpp"
#include <GL/glew.h>
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
}
namespace wowee {
namespace rendering {
VideoPlayer::VideoPlayer() = default;
VideoPlayer::~VideoPlayer() {
close();
}
bool VideoPlayer::open(const std::string& path) {
if (!path.empty() && sourcePath == path && formatCtx) return true;
close();
sourcePath = path;
AVFormatContext* fmt = nullptr;
if (avformat_open_input(&fmt, path.c_str(), nullptr, nullptr) != 0) {
LOG_WARNING("VideoPlayer: failed to open ", path);
return false;
}
if (avformat_find_stream_info(fmt, nullptr) < 0) {
LOG_WARNING("VideoPlayer: failed to read stream info for ", path);
avformat_close_input(&fmt);
return false;
}
int streamIndex = -1;
for (unsigned int i = 0; i < fmt->nb_streams; i++) {
if (fmt->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
streamIndex = static_cast<int>(i);
break;
}
}
if (streamIndex < 0) {
LOG_WARNING("VideoPlayer: no video stream in ", path);
avformat_close_input(&fmt);
return false;
}
AVCodecParameters* codecpar = fmt->streams[streamIndex]->codecpar;
const AVCodec* codec = avcodec_find_decoder(codecpar->codec_id);
if (!codec) {
LOG_WARNING("VideoPlayer: unsupported codec for ", path);
avformat_close_input(&fmt);
return false;
}
AVCodecContext* ctx = avcodec_alloc_context3(codec);
if (!ctx) {
avformat_close_input(&fmt);
return false;
}
if (avcodec_parameters_to_context(ctx, codecpar) < 0) {
avcodec_free_context(&ctx);
avformat_close_input(&fmt);
return false;
}
if (avcodec_open2(ctx, codec, nullptr) < 0) {
avcodec_free_context(&ctx);
avformat_close_input(&fmt);
return false;
}
AVFrame* f = av_frame_alloc();
AVFrame* rgb = av_frame_alloc();
AVPacket* pkt = av_packet_alloc();
if (!f || !rgb || !pkt) {
if (pkt) av_packet_free(&pkt);
if (rgb) av_frame_free(&rgb);
if (f) av_frame_free(&f);
avcodec_free_context(&ctx);
avformat_close_input(&fmt);
return false;
}
width = ctx->width;
height = ctx->height;
if (width <= 0 || height <= 0) {
av_packet_free(&pkt);
av_frame_free(&rgb);
av_frame_free(&f);
avcodec_free_context(&ctx);
avformat_close_input(&fmt);
return false;
}
int bufferSize = av_image_get_buffer_size(AV_PIX_FMT_RGB24, width, height, 1);
rgbBuffer.resize(static_cast<size_t>(bufferSize));
av_image_fill_arrays(rgb->data, rgb->linesize,
rgbBuffer.data(), AV_PIX_FMT_RGB24, width, height, 1);
SwsContext* sws = sws_getContext(width, height, ctx->pix_fmt,
width, height, AV_PIX_FMT_RGB24,
SWS_BILINEAR, nullptr, nullptr, nullptr);
if (!sws) {
av_packet_free(&pkt);
av_frame_free(&rgb);
av_frame_free(&f);
avcodec_free_context(&ctx);
avformat_close_input(&fmt);
return false;
}
AVRational fr = fmt->streams[streamIndex]->avg_frame_rate;
if (fr.num <= 0 || fr.den <= 0) {
fr = fmt->streams[streamIndex]->r_frame_rate;
}
double fps = (fr.num > 0 && fr.den > 0) ? static_cast<double>(fr.num) / fr.den : 30.0;
if (fps <= 0.0) fps = 30.0;
frameTime = 1.0 / fps;
accumulator = 0.0;
eof = false;
formatCtx = fmt;
codecCtx = ctx;
frame = f;
rgbFrame = rgb;
packet = pkt;
swsCtx = sws;
videoStreamIndex = streamIndex;
textureReady = false;
return true;
}
void VideoPlayer::close() {
if (textureId) {
glDeleteTextures(1, &textureId);
textureId = 0;
}
textureReady = false;
if (packet) {
av_packet_free(reinterpret_cast<AVPacket**>(&packet));
packet = nullptr;
}
if (rgbFrame) {
av_frame_free(reinterpret_cast<AVFrame**>(&rgbFrame));
rgbFrame = nullptr;
}
if (frame) {
av_frame_free(reinterpret_cast<AVFrame**>(&frame));
frame = nullptr;
}
if (codecCtx) {
avcodec_free_context(reinterpret_cast<AVCodecContext**>(&codecCtx));
codecCtx = nullptr;
}
if (formatCtx) {
avformat_close_input(reinterpret_cast<AVFormatContext**>(&formatCtx));
formatCtx = nullptr;
}
if (swsCtx) {
sws_freeContext(reinterpret_cast<SwsContext*>(swsCtx));
swsCtx = nullptr;
}
videoStreamIndex = -1;
width = 0;
height = 0;
rgbBuffer.clear();
}
void VideoPlayer::update(float deltaTime) {
if (!formatCtx || !codecCtx) return;
accumulator += deltaTime;
while (accumulator >= frameTime) {
if (!decodeNextFrame()) break;
accumulator -= frameTime;
}
}
bool VideoPlayer::decodeNextFrame() {
AVFormatContext* fmt = reinterpret_cast<AVFormatContext*>(formatCtx);
AVCodecContext* ctx = reinterpret_cast<AVCodecContext*>(codecCtx);
AVFrame* f = reinterpret_cast<AVFrame*>(frame);
AVFrame* rgb = reinterpret_cast<AVFrame*>(rgbFrame);
AVPacket* pkt = reinterpret_cast<AVPacket*>(packet);
SwsContext* sws = reinterpret_cast<SwsContext*>(swsCtx);
// Cap iterations to prevent infinite spinning on corrupt/truncated video
// files where av_read_frame fails but av_seek_frame succeeds, looping
// endlessly through the same corrupt region.
constexpr int kMaxDecodeAttempts = 500;
for (int attempt = 0; attempt < kMaxDecodeAttempts; ++attempt) {
int ret = av_read_frame(fmt, pkt);
if (ret < 0) {
if (av_seek_frame(fmt, videoStreamIndex, 0, AVSEEK_FLAG_BACKWARD) >= 0) {
avcodec_flush_buffers(ctx);
continue;
}
return false;
}
if (pkt->stream_index != videoStreamIndex) {
av_packet_unref(pkt);
continue;
}
if (avcodec_send_packet(ctx, pkt) < 0) {
av_packet_unref(pkt);
continue;
}
av_packet_unref(pkt);
ret = avcodec_receive_frame(ctx, f);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
continue;
}
if (ret < 0) {
continue;
}
sws_scale(sws,
f->data, f->linesize,
0, ctx->height,
rgb->data, rgb->linesize);
uploadFrame();
return true;
}
LOG_WARNING("Video decode: exceeded ", kMaxDecodeAttempts, " attempts — possible corrupt file");
return false;
}
void VideoPlayer::uploadFrame() {
if (width <= 0 || height <= 0) return;
if (!textureId) {
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
GL_RGB, GL_UNSIGNED_BYTE, rgbBuffer.data());
glBindTexture(GL_TEXTURE_2D, 0);
textureReady = true;
return;
}
glBindTexture(GL_TEXTURE_2D, textureId);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height,
GL_RGB, GL_UNSIGNED_BYTE, rgbBuffer.data());
glBindTexture(GL_TEXTURE_2D, 0);
textureReady = true;
}
} // namespace rendering
} // namespace wowee