Skip to content

Commit 3f187b4

Browse files
committed
feat(graphics): add real JPEG and transactional texture loading
1 parent 5958d78 commit 3f187b4

40 files changed

Lines changed: 1142 additions & 4035 deletions

.github/workflows/windows-ci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ jobs:
2727
mingw-w64-ucrt-x86_64-toolchain
2828
mingw-w64-ucrt-x86_64-cmake
2929
mingw-w64-ucrt-x86_64-ninja
30+
mingw-w64-ucrt-x86_64-libjpeg-turbo
3031
- name: gcc-release
3132
configuration: Release
3233
configure_preset: gcc-release-tests
@@ -38,6 +39,7 @@ jobs:
3839
mingw-w64-ucrt-x86_64-toolchain
3940
mingw-w64-ucrt-x86_64-cmake
4041
mingw-w64-ucrt-x86_64-ninja
42+
mingw-w64-ucrt-x86_64-libjpeg-turbo
4143
- name: clang-debug
4244
configuration: Debug
4345
configure_preset: clang-debug-tests
@@ -51,6 +53,7 @@ jobs:
5153
mingw-w64-ucrt-x86_64-lld
5254
mingw-w64-ucrt-x86_64-cmake
5355
mingw-w64-ucrt-x86_64-ninja
56+
mingw-w64-ucrt-x86_64-libjpeg-turbo
5457
- name: clang-release
5558
configuration: Release
5659
configure_preset: clang-release-tests
@@ -64,6 +67,7 @@ jobs:
6467
mingw-w64-ucrt-x86_64-lld
6568
mingw-w64-ucrt-x86_64-cmake
6669
mingw-w64-ucrt-x86_64-ninja
70+
mingw-w64-ucrt-x86_64-libjpeg-turbo
6771
6872
steps:
6973
- name: Checkout

AGENTS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
- `Engine/` builds the C++17 `PyramidEngine` library.
66
- Active modules are Core, Graphics, Math, Platform, and Utils.
77
- `Examples/BasicGame` and `Examples/BasicRendering` are the graphical references.
8-
- `Tests/PublicApiLinkage.cpp` protects selected public symbols; `Tests/WindowResizeEventTests.cpp` protects resize callback semantics; `Tests/CameraViewportTests.cpp` protects projection resizing; `Tests/FramebufferResizeTests.cpp` protects framebuffer specification and zero-area resize behavior.
8+
- `Tests/PublicApiLinkage.cpp` protects selected public symbols; `Tests/WindowResizeEventTests.cpp` protects resize callback semantics; `Tests/CameraViewportTests.cpp` protects projection resizing; `Tests/FramebufferResizeTests.cpp` protects framebuffer specification and zero-area resize behavior; `Tests/TextureLoadingTests.cpp` protects transactional file loading and OpenGL upload state.
99
- `Tests/Consumer` validates the installed CMake package.
10-
- `vendor/glad` is a bundled public dependency.
10+
- `vendor/glad` is a bundled public dependency. libjpeg-turbo is an external open-source dependency resolved through CMake `FindJPEG`.
1111
- The supported Windows toolchain is MSYS2 UCRT64 with MinGW-w64 GCC; Clang is also validated. Visual Studio is not required.
1212
- Input, audio, physics, editor, scripting, DirectX, Vulkan, Linux, and macOS are not supported.
1313

CHANGELOG.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@ All notable changes to Pyramid Engine are documented here. The project is pre-al
44

55
## [Unreleased]
66

7+
### Image and texture loading
8+
9+
- Replaced JPEG test-pattern generation with real baseline and progressive JPEG decoding through libjpeg-turbo.
10+
- Normalized JPEG output to tightly packed RGB pixels and added invalid-data, size-overflow, allocation, and scanline failure handling.
11+
- Removed the unused custom JPEG entropy/IDCT/color-conversion pipeline and its misleading public headers/tests.
12+
- Made file-backed OpenGL texture replacement transactional so failed reloads preserve the previous valid GPU object.
13+
- Added explicit texture load state/error reporting, RGB/RGBA format validation, sRGB internal formats, complete mip-filter mapping, border-color parameters, and unpack-alignment restoration.
14+
- Added validated baseline/progressive JPEG fixtures and `Graphics.TextureLoading` coverage for upload state, failed reload preservation, and data-size checks.
15+
- Added libjpeg-turbo to MSYS2 bootstrap, CI, installed package dependencies, and external-consumer resolution.
16+
717
### Framebuffer resize safety
818

919
- Made `OpenGLFramebuffer::Resize()` transactional so failed replacement creation preserves the last valid framebuffer and attachments.
@@ -44,7 +54,6 @@ All notable changes to Pyramid Engine are documented here. The project is pre-al
4454
### Next priorities
4555

4656
- Windows runtime verification for Debug and Release.
47-
- Real JPEG block decoding.
4857
- Texture-format and depth-target completion.
4958
- Scene transform and culling correctness.
5059

CMake/PyramidEngineConfig.cmake.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
include(CMakeFindDependencyMacro)
44
find_dependency(OpenGL)
5+
find_dependency(JPEG)
56

67
include("${CMAKE_CURRENT_LIST_DIR}/PyramidEngineTargets.cmake")
78
check_required_components(PyramidEngine)

Engine/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,12 @@ target_include_directories(PyramidEngine
2626
"${PROJECT_SOURCE_DIR}/vendor"
2727
)
2828

29+
find_package(JPEG REQUIRED)
30+
2931
target_link_libraries(PyramidEngine
3032
PUBLIC
3133
glad
34+
JPEG::JPEG
3235
)
3336

3437
if(WIN32)
Lines changed: 53 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,66 @@
11
#pragma once
22

33
#include "Pyramid/Graphics/Texture.hpp"
4-
#include <glad/glad.h>
54

6-
namespace Pyramid {
5+
#include <glad/glad.h>
76

8-
class OpenGLTexture2D : public ITexture2D
7+
namespace Pyramid
98
{
10-
public:
11-
OpenGLTexture2D(const TextureSpecification& specification, const void* data);
12-
OpenGLTexture2D(const std::string& filepath, bool srgb, bool generateMips);
13-
~OpenGLTexture2D() override;
9+
class OpenGLTexture2D final : public ITexture2D
10+
{
11+
public:
12+
OpenGLTexture2D(const TextureSpecification& specification, const void* data);
13+
OpenGLTexture2D(const std::string& filepath, bool srgb, bool generateMips);
14+
~OpenGLTexture2D() override;
15+
16+
OpenGLTexture2D(const OpenGLTexture2D&) = delete;
17+
OpenGLTexture2D& operator=(const OpenGLTexture2D&) = delete;
1418

15-
void Bind(u32 slot = 0) const override;
16-
void Unbind(u32 slot = 0) const override;
19+
void Bind(u32 slot = 0) const override;
20+
void Unbind(u32 slot = 0) const override;
1721

18-
u32 GetWidth() const override { return m_Specification.Width; }
19-
u32 GetHeight() const override { return m_Specification.Height; }
20-
u32 GetRendererID() const override { return m_RendererID; }
21-
const std::string& GetPath() const override { return m_Filepath; }
22+
u32 GetWidth() const override { return m_Specification.Width; }
23+
u32 GetHeight() const override { return m_Specification.Height; }
24+
u32 GetRendererID() const override { return m_RendererID; }
25+
TextureFormat GetFormat() const override { return m_Specification.Format; }
26+
const std::string& GetPath() const override { return m_Filepath; }
27+
bool IsLoaded() const override { return m_IsLoaded; }
28+
std::string GetLastError() const override { return m_LastError; }
2229

23-
// virtual void SetData(void* data, u32 size) override; // Implement if needed
30+
void SetData(const void* data, u32 size) override;
31+
void GenerateMipmaps() override;
32+
u32 GetMipLevels() const override;
33+
bool LoadFromFile(const std::string& filepath, bool srgb = false, bool generateMips = true) override;
2434

25-
private:
26-
void Invalidate(const void* data); // Helper to create/recreate texture
27-
void SetParameters();
35+
private:
36+
static bool ResolveFormats(
37+
TextureFormat format,
38+
bool srgb,
39+
GLenum& internalFormat,
40+
GLenum& dataFormat,
41+
u32& bytesPerPixel);
42+
static GLenum ToGLMinFilter(TextureFilter filter, bool hasMipmaps);
43+
static GLenum ToGLMagFilter(TextureFilter filter);
44+
static GLenum ToGLWrap(TextureWrap wrap);
45+
static bool HasMipmapFilter(TextureFilter filter);
2846

29-
TextureSpecification m_Specification;
30-
std::string m_Filepath; // Empty if not loaded from file
31-
GLuint m_RendererID = 0;
32-
GLenum m_InternalFormat = GL_RGBA8; // Determined from TextureSpecification::Format
33-
GLenum m_DataFormat = GL_RGBA; // Determined from TextureSpecification::Format
34-
};
47+
bool CreateTextureObject(
48+
const TextureSpecification& specification,
49+
GLenum internalFormat,
50+
GLenum dataFormat,
51+
const void* data,
52+
GLuint& texture,
53+
std::string& error) const;
54+
void ApplyParameters(const TextureSpecification& specification) const;
55+
void SetError(const std::string& error);
3556

57+
TextureSpecification m_Specification;
58+
std::string m_Filepath;
59+
std::string m_LastError;
60+
GLuint m_RendererID = 0;
61+
GLenum m_InternalFormat = GL_RGBA8;
62+
GLenum m_DataFormat = GL_RGBA;
63+
u32 m_BytesPerPixel = 4;
64+
bool m_IsLoaded = false;
65+
};
3666
} // namespace Pyramid

Engine/Graphics/include/Pyramid/Graphics/Texture.hpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,14 @@ class ITexture
9090
virtual std::string GetLastError() const { return ""; }
9191

9292
// Dynamic texture updates (optional - can have default implementations)
93-
virtual void SetData(const void* data, u32 size) {}
94-
virtual void SetSubData(const void* data, u32 x, u32 y, u32 width, u32 height) {}
93+
virtual void SetData(const void*, u32) {}
94+
virtual void SetSubData(const void*, u32, u32, u32, u32) {}
9595

9696
// Texture parameters (optional - can have default implementations)
97-
virtual void SetFilter(TextureFilter minFilter, TextureFilter magFilter) {}
98-
virtual void SetWrap(TextureWrap wrapS, TextureWrap wrapT) {}
99-
virtual void SetBorderColor(f32 r, f32 g, f32 b, f32 a) {}
100-
virtual void SetMaxAnisotropy(f32 anisotropy) {}
97+
virtual void SetFilter(TextureFilter, TextureFilter) {}
98+
virtual void SetWrap(TextureWrap, TextureWrap) {}
99+
virtual void SetBorderColor(f32, f32, f32, f32) {}
100+
virtual void SetMaxAnisotropy(f32) {}
101101
};
102102

103103
class ITexture2D : public ITexture
@@ -118,8 +118,8 @@ class ITexture2D : public ITexture
118118
virtual u32 GetMipLevels() const { return 1; }
119119

120120
// Texture streaming and loading (optional implementations)
121-
virtual bool LoadFromFile(const std::string& filepath, bool srgb = false, bool generateMips = true) { return false; }
122-
virtual bool SaveToFile(const std::string& filepath) const { return false; }
121+
virtual bool LoadFromFile(const std::string&, bool = false, bool = true) { return false; }
122+
virtual bool SaveToFile(const std::string&) const { return false; }
123123
};
124124

125125
} // namespace Pyramid

0 commit comments

Comments
 (0)