From 7cfaf2c7e9a3d50eed4fcd89b9111cfb349ec597 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Mon, 30 Mar 2026 19:22:36 -0700 Subject: [PATCH] =?UTF-8?q?refactor:=20complete=20OpenGL=E2=86=92Vulkan=20?= =?UTF-8?q?migration=20(Phase=207)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- BUILD_INSTRUCTIONS.md | 9 +- CMakeLists.txt | 22 --- PKGBUILD | 1 - include/rendering/mesh.hpp | 33 ---- include/rendering/renderer.hpp | 4 - include/rendering/scene.hpp | 27 --- include/rendering/shader.hpp | 51 ------ include/rendering/video_player.hpp | 51 ------ src/core/application.cpp | 1 - src/rendering/mesh.cpp | 56 ------- src/rendering/renderer.cpp | 6 - src/rendering/scene.cpp | 24 --- src/rendering/shader.cpp | 140 ---------------- src/rendering/video_player.cpp | 259 ----------------------------- 14 files changed, 4 insertions(+), 680 deletions(-) delete mode 100644 include/rendering/mesh.hpp delete mode 100644 include/rendering/scene.hpp delete mode 100644 include/rendering/shader.hpp delete mode 100644 include/rendering/video_player.hpp delete mode 100644 src/rendering/mesh.cpp delete mode 100644 src/rendering/scene.cpp delete mode 100644 src/rendering/shader.cpp delete mode 100644 src/rendering/video_player.cpp diff --git a/BUILD_INSTRUCTIONS.md b/BUILD_INSTRUCTIONS.md index 207fbbcd..c06296d8 100644 --- a/BUILD_INSTRUCTIONS.md +++ b/BUILD_INSTRUCTIONS.md @@ -12,7 +12,7 @@ This document provides platform-specific build instructions for WoWee. sudo apt update sudo apt install -y \ build-essential cmake pkg-config git \ - libsdl2-dev libglew-dev libglm-dev \ + libsdl2-dev libglm-dev \ libssl-dev zlib1g-dev \ libvulkan-dev vulkan-tools glslc \ libavcodec-dev libavformat-dev libavutil-dev libswscale-dev \ @@ -28,7 +28,7 @@ sudo apt install -y \ ```bash sudo pacman -S --needed \ base-devel cmake pkgconf git \ - sdl2 glew glm openssl zlib \ + sdl2 glm openssl zlib \ vulkan-headers vulkan-icd-loader vulkan-tools shaderc \ ffmpeg unicorn stormlib ``` @@ -83,7 +83,7 @@ Vulkan on macOS is provided via MoltenVK (a Vulkan-to-Metal translation layer), which is included in the `vulkan-loader` Homebrew package. ```bash -brew install cmake pkg-config sdl2 glew glm openssl@3 zlib ffmpeg unicorn \ +brew install cmake pkg-config sdl2 glm openssl@3 zlib ffmpeg unicorn \ stormlib vulkan-loader vulkan-headers shaderc ``` @@ -137,7 +137,6 @@ pacman -S --needed \ mingw-w64-x86_64-ninja \ mingw-w64-x86_64-pkgconf \ mingw-w64-x86_64-SDL2 \ - mingw-w64-x86_64-glew \ mingw-w64-x86_64-glm \ mingw-w64-x86_64-openssl \ mingw-w64-x86_64-zlib \ @@ -174,7 +173,7 @@ For users who prefer Visual Studio over MSYS2. ### vcpkg Dependencies ```powershell -vcpkg install sdl2 glew glm openssl zlib ffmpeg stormlib --triplet x64-windows +vcpkg install sdl2 glm openssl zlib ffmpeg stormlib --triplet x64-windows ``` ### Clone diff --git a/CMakeLists.txt b/CMakeLists.txt index af8a30fe..3b06a7fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -340,12 +340,6 @@ endif() if(CMAKE_CROSSCOMPILING AND CMAKE_SYSTEM_NAME STREQUAL "Darwin") set(WOWEE_MACOS_CROSS_COMPILE TRUE) endif() -# GL/GLEW kept temporarily for unconverted sub-renderers during Vulkan migration. -# These files compile against GL types but their code is never called — the Vulkan -# path is the only active rendering backend. Remove in Phase 7 when all renderers -# are converted and grep confirms zero GL references. -find_package(OpenGL QUIET) -find_package(GLEW QUIET) find_package(OpenSSL REQUIRED) find_package(Threads REQUIRED) find_package(ZLIB REQUIRED) @@ -584,12 +578,9 @@ set(WOWEE_SOURCES # Rendering src/rendering/renderer.cpp src/rendering/amd_fsr3_runtime.cpp - src/rendering/shader.cpp - src/rendering/mesh.cpp src/rendering/camera.cpp src/rendering/camera_controller.cpp src/rendering/material.cpp - src/rendering/scene.cpp src/rendering/terrain_renderer.cpp src/rendering/terrain_manager.cpp src/rendering/frustum.cpp @@ -617,7 +608,6 @@ set(WOWEE_SOURCES src/rendering/levelup_effect.cpp src/rendering/charge_effect.cpp src/rendering/loading_screen.cpp - $<$:${CMAKE_CURRENT_SOURCE_DIR}/src/rendering/video_player.cpp> # UI src/ui/ui_manager.cpp @@ -704,12 +694,9 @@ set(WOWEE_HEADERS include/rendering/vk_pipeline.hpp include/rendering/vk_render_target.hpp include/rendering/renderer.hpp - include/rendering/shader.hpp - include/rendering/mesh.hpp include/rendering/camera.hpp include/rendering/camera_controller.hpp include/rendering/material.hpp - include/rendering/scene.hpp include/rendering/terrain_renderer.hpp include/rendering/terrain_manager.hpp include/rendering/frustum.hpp @@ -728,7 +715,6 @@ set(WOWEE_HEADERS include/rendering/character_preview.hpp include/rendering/wmo_renderer.hpp include/rendering/loading_screen.hpp - include/rendering/video_player.hpp include/ui/ui_manager.hpp include/ui/auth_screen.hpp @@ -828,14 +814,6 @@ target_link_libraries(wowee PRIVATE ${CMAKE_DL_LIBS} ) -# GL/GLEW linked temporarily for unconverted sub-renderers (removed in Phase 7) -if(TARGET OpenGL::GL) - target_link_libraries(wowee PRIVATE OpenGL::GL) -endif() -if(TARGET GLEW::GLEW) - target_link_libraries(wowee PRIVATE GLEW::GLEW) -endif() - if(HAVE_FFMPEG) target_compile_definitions(wowee PRIVATE HAVE_FFMPEG) target_link_libraries(wowee PRIVATE ${FFMPEG_LIBRARIES}) diff --git a/PKGBUILD b/PKGBUILD index ca419ffe..15091216 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -15,7 +15,6 @@ depends=( 'zlib' # Network packet decompression and Warden module inflate 'ffmpeg' # Video playback (login cinematics) 'unicorn' # Warden anti-cheat x86 emulation (cross-platform, no Wine) - 'glew' # OpenGL extensions (legacy fallback, linked but unused at runtime) 'libx11' # X11 windowing support 'stormlib' # AUR — MPQ extraction (wowee-extract-assets uses libstorm.so) ) diff --git a/include/rendering/mesh.hpp b/include/rendering/mesh.hpp deleted file mode 100644 index 670b5397..00000000 --- a/include/rendering/mesh.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace wowee { -namespace rendering { - -struct Vertex { - glm::vec3 position; - glm::vec3 normal; - glm::vec2 texCoord; -}; - -class Mesh { -public: - Mesh() = default; - ~Mesh(); - - void create(const std::vector& vertices, const std::vector& indices); - void destroy(); - void draw() const; - -private: - GLuint VAO = 0; - GLuint VBO = 0; - GLuint EBO = 0; - size_t indexCount = 0; -}; - -} // namespace rendering -} // namespace wowee diff --git a/include/rendering/renderer.hpp b/include/rendering/renderer.hpp index 80b33fe6..35943572 100644 --- a/include/rendering/renderer.hpp +++ b/include/rendering/renderer.hpp @@ -30,7 +30,6 @@ namespace rendering { class Camera; class CameraController; -class Scene; class TerrainRenderer; class TerrainManager; class PerformanceHUD; @@ -54,7 +53,6 @@ class Minimap; class WorldMap; class QuestMarkerRenderer; class CharacterPreview; -class Shader; class AmdFsr3Runtime; class Renderer { @@ -119,7 +117,6 @@ public: Camera* getCamera() { return camera.get(); } CameraController* getCameraController() { return cameraController.get(); } - Scene* getScene() { return scene.get(); } TerrainRenderer* getTerrainRenderer() const { return terrainRenderer.get(); } TerrainManager* getTerrainManager() const { return terrainManager.get(); } PerformanceHUD* getPerformanceHUD() { return performanceHUD.get(); } @@ -219,7 +216,6 @@ private: core::Window* window = nullptr; std::unique_ptr camera; std::unique_ptr cameraController; - std::unique_ptr scene; std::unique_ptr terrainRenderer; std::unique_ptr terrainManager; std::unique_ptr performanceHUD; diff --git a/include/rendering/scene.hpp b/include/rendering/scene.hpp deleted file mode 100644 index 9f640b06..00000000 --- a/include/rendering/scene.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include -#include - -namespace wowee { -namespace rendering { - -class Mesh; - -class Scene { -public: - Scene() = default; - ~Scene() = default; - - void addMesh(std::shared_ptr mesh); - void removeMesh(const std::shared_ptr& mesh); - void clear(); - - const std::vector>& getMeshes() const { return meshes; } - -private: - std::vector> meshes; -}; - -} // namespace rendering -} // namespace wowee diff --git a/include/rendering/shader.hpp b/include/rendering/shader.hpp deleted file mode 100644 index 27b79729..00000000 --- a/include/rendering/shader.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace wowee { -namespace rendering { - -class Shader { -public: - Shader() = default; - ~Shader(); - - [[nodiscard]] bool loadFromFile(const std::string& vertexPath, const std::string& fragmentPath); - [[nodiscard]] bool loadFromSource(const std::string& vertexSource, const std::string& fragmentSource); - - void use() const; - void unuse() const; - - void setUniform(const std::string& name, int value); - void setUniform(const std::string& name, float value); - void setUniform(const std::string& name, const glm::vec2& value); - void setUniform(const std::string& name, const glm::vec3& value); - void setUniform(const std::string& name, const glm::vec4& value); - void setUniform(const std::string& name, const glm::mat3& value); - void setUniform(const std::string& name, const glm::mat4& value); - void setUniformMatrixArray(const std::string& name, const glm::mat4* matrices, int count); - - GLuint getProgram() const { return program; } - - // Adopt an externally-created program (no ownership of individual shaders) - void setProgram(GLuint prog) { program = prog; } - // Release ownership without deleting (caller retains the GL program) - void releaseProgram() { program = 0; vertexShader = 0; fragmentShader = 0; } - -private: - bool compile(const std::string& vertexSource, const std::string& fragmentSource); - GLint getUniformLocation(const std::string& name) const; - - GLuint program = 0; - GLuint vertexShader = 0; - GLuint fragmentShader = 0; - - // Cache uniform locations to avoid expensive glGetUniformLocation calls - mutable std::unordered_map uniformLocationCache; -}; - -} // namespace rendering -} // namespace wowee diff --git a/include/rendering/video_player.hpp b/include/rendering/video_player.hpp deleted file mode 100644 index 3d093715..00000000 --- a/include/rendering/video_player.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include -#include -#include - -typedef unsigned int GLuint; - -namespace wowee { -namespace rendering { - -class VideoPlayer { -public: - VideoPlayer(); - ~VideoPlayer(); - - bool open(const std::string& path); - void update(float deltaTime); - void close(); - - bool isReady() const { return textureReady; } - GLuint getTextureId() const { return textureId; } - int getWidth() const { return width; } - int getHeight() const { return height; } - -private: - bool decodeNextFrame(); - void uploadFrame(); - - void* formatCtx = nullptr; - void* codecCtx = nullptr; - void* frame = nullptr; - void* rgbFrame = nullptr; - void* packet = nullptr; - void* swsCtx = nullptr; - - int videoStreamIndex = -1; - int width = 0; - int height = 0; - double frameTime = 1.0 / 30.0; - double accumulator = 0.0; - bool eof = false; - - GLuint textureId = 0; - bool textureReady = false; - std::string sourcePath; - std::vector rgbBuffer; -}; - -} // namespace rendering -} // namespace wowee diff --git a/src/core/application.cpp b/src/core/application.cpp index 4bf1a4c2..4da62a1c 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -48,7 +48,6 @@ #include "pipeline/dbc_layout.hpp" #include -// GL/glew.h removed — Vulkan migration Phase 1 #include #include #include diff --git a/src/rendering/mesh.cpp b/src/rendering/mesh.cpp deleted file mode 100644 index 59d40893..00000000 --- a/src/rendering/mesh.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "rendering/mesh.hpp" - -namespace wowee { -namespace rendering { - -Mesh::~Mesh() { - destroy(); -} - -void Mesh::create(const std::vector& vertices, const std::vector& 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 diff --git a/src/rendering/renderer.cpp b/src/rendering/renderer.cpp index 17b7e996..e4735b0b 100644 --- a/src/rendering/renderer.cpp +++ b/src/rendering/renderer.cpp @@ -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 @@ -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(); - // Create performance HUD performanceHUD = std::make_unique(); performanceHUD->setPosition(PerformanceHUD::Position::TOP_LEFT); @@ -877,7 +872,6 @@ void Renderer::shutdown() { zoneManager.reset(); performanceHUD.reset(); - scene.reset(); cameraController.reset(); camera.reset(); diff --git a/src/rendering/scene.cpp b/src/rendering/scene.cpp deleted file mode 100644 index c10ad56d..00000000 --- a/src/rendering/scene.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "rendering/scene.hpp" -#include "rendering/mesh.hpp" -#include - -namespace wowee { -namespace rendering { - -void Scene::addMesh(std::shared_ptr mesh) { - meshes.push_back(std::move(mesh)); -} - -void Scene::removeMesh(const std::shared_ptr& 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 diff --git a/src/rendering/shader.cpp b/src/rendering/shader.cpp deleted file mode 100644 index 2a748539..00000000 --- a/src/rendering/shader.cpp +++ /dev/null @@ -1,140 +0,0 @@ -#include "rendering/shader.hpp" -#include "core/logger.hpp" -#include -#include - -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 diff --git a/src/rendering/video_player.cpp b/src/rendering/video_player.cpp deleted file mode 100644 index dc9d94fd..00000000 --- a/src/rendering/video_player.cpp +++ /dev/null @@ -1,259 +0,0 @@ -#include "rendering/video_player.hpp" -#include "core/logger.hpp" -#include - -extern "C" { -#include -#include -#include -#include -} - -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(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(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(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(&packet)); - packet = nullptr; - } - if (rgbFrame) { - av_frame_free(reinterpret_cast(&rgbFrame)); - rgbFrame = nullptr; - } - if (frame) { - av_frame_free(reinterpret_cast(&frame)); - frame = nullptr; - } - if (codecCtx) { - avcodec_free_context(reinterpret_cast(&codecCtx)); - codecCtx = nullptr; - } - if (formatCtx) { - avformat_close_input(reinterpret_cast(&formatCtx)); - formatCtx = nullptr; - } - if (swsCtx) { - sws_freeContext(reinterpret_cast(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(formatCtx); - AVCodecContext* ctx = reinterpret_cast(codecCtx); - AVFrame* f = reinterpret_cast(frame); - AVFrame* rgb = reinterpret_cast(rgbFrame); - AVPacket* pkt = reinterpret_cast(packet); - SwsContext* sws = reinterpret_cast(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