From eaee6b426ba7aa70e85a66d22226d00136c1aa0c Mon Sep 17 00:00:00 2001 From: Jean Philippe Date: Wed, 2 Sep 2026 08:26:01 +0900 Subject: [PATCH 1/2] =?UTF-8?q?refactor(bitmap):=20reshape=20API=20?= =?UTF-8?q?=E2=80=94=20enum=20class,=20factory=20functions,=20BitmapConver?= =?UTF-8?q?t=20namespace,=20Bitmap.cpp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ZEngine/ZEngine/Importers/AssetCodec.cpp | 5 +- .../Importers/EnvironmentMapImporter.cpp | 8 +- ZEngine/ZEngine/Rendering/Buffers/Bitmap.cpp | 285 ++++++++++++++ ZEngine/ZEngine/Rendering/Buffers/Bitmap.h | 354 ++---------------- .../Rendering/RenderResourceManager.cpp | 6 +- ZEngine/tests/Memory/bitmap_test.cpp | 45 ++- 6 files changed, 349 insertions(+), 354 deletions(-) create mode 100644 ZEngine/ZEngine/Rendering/Buffers/Bitmap.cpp diff --git a/ZEngine/ZEngine/Importers/AssetCodec.cpp b/ZEngine/ZEngine/Importers/AssetCodec.cpp index 7f186a49..1bf77de6 100644 --- a/ZEngine/ZEngine/Importers/AssetCodec.cpp +++ b/ZEngine/ZEngine/Importers/AssetCodec.cpp @@ -335,8 +335,7 @@ namespace ZEngine::Importers::AssetCodec if (!in.good() || header.MagicNumber != ZENVMAP_MAGIC) return false; - out_cubemap = Rendering::Buffers::Bitmap(header.FaceWidth, header.FaceHeight, header.LayerCount, header.Channel, Rendering::Buffers::BitmapFormat::FLOAT); - out_cubemap.Type = Rendering::Buffers::BitmapType::CUBE; + out_cubemap = Rendering::Buffers::Bitmap::Create(header.FaceWidth, header.FaceHeight, header.LayerCount, header.Channel, Rendering::Buffers::BitmapFormat::Float, Rendering::Buffers::BitmapType::CubeMap); in.read(reinterpret_cast(out_cubemap.Buffer), static_cast(header.BufferByteSize)); return in.good(); } @@ -374,7 +373,7 @@ namespace ZEngine::Importers::AssetCodec .FaceWidth = cubemap.Width, .FaceHeight = cubemap.Height, .Channel = cubemap.Channel, - .LayerCount = cubemap.Depth, + .LayerCount = cubemap.Layers, .BufferByteSize = static_cast(cubemap.BufferSize), }; diff --git a/ZEngine/ZEngine/Importers/EnvironmentMapImporter.cpp b/ZEngine/ZEngine/Importers/EnvironmentMapImporter.cpp index ad0d7715..f71a7c11 100644 --- a/ZEngine/ZEngine/Importers/EnvironmentMapImporter.cpp +++ b/ZEngine/ZEngine/Importers/EnvironmentMapImporter.cpp @@ -41,12 +41,12 @@ namespace ZEngine::Importers return Core::VFS::VFSResult::Fail(Core::VFS::VFSError::IOError); } - Core::Memory::TLSFSlab* slab = Helpers::GetWorkerSlab(); - Bitmap equirect(width, height, 4, BitmapFormat::FLOAT, image_data, slab); + Core::Memory::TLSFSlab* slab = Helpers::GetWorkerSlab(); + Bitmap equirect = Bitmap::FromData(width, height, 1, 4, BitmapFormat::Float, BitmapType::Texture2D, image_data, slab); stbi_image_free(const_cast(image_data)); - Bitmap vertical_cross = Bitmap::EquirectangularMapToVerticalCross(equirect, slab); - Bitmap cubemap = Bitmap::VerticalCrossToCubemap(vertical_cross, slab); + Bitmap vertical_cross = BitmapConvert::EquirectToCross(equirect, slab); + Bitmap cubemap = BitmapConvert::CrossToCubemap(vertical_cross, slab); // Write to project://_cache/envmaps/.zenvmap via VFS. // Keyed by UUID — regenerable, gitignored, transparent to game code. diff --git a/ZEngine/ZEngine/Rendering/Buffers/Bitmap.cpp b/ZEngine/ZEngine/Rendering/Buffers/Bitmap.cpp new file mode 100644 index 00000000..690a2af1 --- /dev/null +++ b/ZEngine/ZEngine/Rendering/Buffers/Bitmap.cpp @@ -0,0 +1,285 @@ +#include +#include +#include +#include +#include + +namespace ZEngine::Rendering::Buffers +{ + Bitmap::~Bitmap() + { + FreeBuffer(); + } + + Bitmap::Bitmap(Bitmap&& o) noexcept + : Width(o.Width), Height(o.Height), Layers(o.Layers), Channel(o.Channel), Type(o.Type), Format(o.Format), Buffer(o.Buffer), BufferSize(o.BufferSize), Slab(o.Slab) + { + o.Buffer = nullptr; + o.BufferSize = 0; + o.Slab = nullptr; + } + + Bitmap& Bitmap::operator=(Bitmap&& o) noexcept + { + if (this != &o) + { + FreeBuffer(); + Width = o.Width; + Height = o.Height; + Layers = o.Layers; + Channel = o.Channel; + Type = o.Type; + Format = o.Format; + Buffer = o.Buffer; + BufferSize = o.BufferSize; + Slab = o.Slab; + + o.Buffer = nullptr; + o.BufferSize = 0; + o.Slab = nullptr; + } + return *this; + } + + Bitmap Bitmap::Create(int w, int h, int layers, int ch, BitmapFormat fmt, BitmapType type, Core::Memory::TLSFSlab* slab) + { + Bitmap b; + b.Width = w; + b.Height = h; + b.Layers = layers; + b.Channel = ch; + b.Format = fmt; + b.Type = type; + b.Slab = slab; + b.Alloc(static_cast(w) * h * layers * ch * BytePerChannel(fmt)); + return b; + } + + Bitmap Bitmap::FromData(int w, int h, int layers, int ch, BitmapFormat fmt, BitmapType type, const void* data, Core::Memory::TLSFSlab* slab) + { + Bitmap b; + b.Width = w; + b.Height = h; + b.Layers = layers; + b.Channel = ch; + b.Format = fmt; + b.Type = type; + b.Slab = slab; + + size_t sz = static_cast(w) * h * layers * ch * BytePerChannel(fmt); + if (data) + { + b.AllocNoZero(sz); + if (b.Buffer) + ZENGINE_VALIDATE_ASSERT(Helpers::secure_memcpy(b.Buffer, b.BufferSize, data, b.BufferSize) == Helpers::MEMORY_OP_SUCCESS, "Bitmap::FromData: memcpy failed") + } + else + { + b.Alloc(sz); + } + return b; + } + + int Bitmap::BytePerChannel(BitmapFormat fmt) + { + switch (fmt) + { + case BitmapFormat::UnsignedByte: return 1; + case BitmapFormat::Float: return 4; + } + return 0; + } + + void Bitmap::SetPixel(int x, int y, const Core::Maths::Vec4f& pixel) + { + if (Format == BitmapFormat::UnsignedByte) + { + const int ofs = Channel * (y * Width + x); + if (Channel > 0) Buffer[ofs + 0] = uint8_t(pixel.x * 255.0f); + if (Channel > 1) Buffer[ofs + 1] = uint8_t(pixel.y * 255.0f); + if (Channel > 2) Buffer[ofs + 2] = uint8_t(pixel.z * 255.0f); + if (Channel > 3) Buffer[ofs + 3] = uint8_t(pixel.w * 255.0f); + } + else if (Format == BitmapFormat::Float) + { + const int ofs = Channel * (y * Width + x); + float* data = reinterpret_cast(Buffer); + if (Channel > 0) data[ofs + 0] = pixel.x; + if (Channel > 1) data[ofs + 1] = pixel.y; + if (Channel > 2) data[ofs + 2] = pixel.z; + if (Channel > 3) data[ofs + 3] = pixel.w; + } + } + + Core::Maths::Vec4f Bitmap::GetPixel(int x, int y) const + { + if (Format == BitmapFormat::UnsignedByte) + { + const int ofs = Channel * (y * Width + x); + return Core::Maths::Vec4f( + Channel > 0 ? float(Buffer[ofs + 0]) / 255.0f : 0.0f, + Channel > 1 ? float(Buffer[ofs + 1]) / 255.0f : 0.0f, + Channel > 2 ? float(Buffer[ofs + 2]) / 255.0f : 0.0f, + Channel > 3 ? float(Buffer[ofs + 3]) / 255.0f : 0.0f); + } + else if (Format == BitmapFormat::Float) + { + const int ofs = Channel * (y * Width + x); + const float* data = reinterpret_cast(Buffer); + return Core::Maths::Vec4f( + Channel > 0 ? data[ofs + 0] : 0.0f, + Channel > 1 ? data[ofs + 1] : 0.0f, + Channel > 2 ? data[ofs + 2] : 0.0f, + Channel > 3 ? data[ofs + 3] : 0.0f); + } + return Core::Maths::Vec4f(); + } + + void Bitmap::Alloc(size_t n) + { + if (n == 0) + return; + BufferSize = n; + if (Slab) + { + Buffer = static_cast(Slab->Alloc(n)); + Helpers::secure_memset(Buffer, 0, n, n); + } + else + { + Buffer = new uint8_t[n](); + } + } + + void Bitmap::AllocNoZero(size_t n) + { + if (n == 0) + return; + BufferSize = n; + Buffer = Slab ? static_cast(Slab->Alloc(n)) : new uint8_t[n]; + } + + void Bitmap::FreeBuffer() + { + if (Buffer) + { + if (Slab) + Slab->Free(Buffer); + else + delete[] Buffer; + Buffer = nullptr; + BufferSize = 0; + Slab = nullptr; + } + } + + namespace BitmapConvert + { + static Core::Maths::Vec3f FaceCoordToXYZ(int i, int j, int face_id, int face_size) + { + const float A = 2.0f * float(i) / face_size; + const float B = 2.0f * float(j) / face_size; + + switch (face_id) + { + case 0: return Core::Maths::Vec3f(-1.0f, A - 1.0f, B - 1.0f); + case 1: return Core::Maths::Vec3f(A - 1.0f, -1.0f, 1.0f - B); + case 2: return Core::Maths::Vec3f(1.0f, A - 1.0f, 1.0f - B); + case 3: return Core::Maths::Vec3f(1.0f - A, 1.0f, 1.0f - B); + case 4: return Core::Maths::Vec3f(B - 1.0f, A - 1.0f, 1.0f); + case 5: return Core::Maths::Vec3f(1.0f - B, A - 1.0f, -1.0f); + default: return Core::Maths::Vec3f{}; + } + } + + Bitmap EquirectToCross(const Bitmap& input, Core::Memory::TLSFSlab* slab) + { + if (input.Type != BitmapType::Texture2D) + return Bitmap(); + + const int face_size = input.Width / 4; + Bitmap out = Bitmap::Create(face_size * 3, face_size * 4, 1, input.Channel, input.Format, BitmapType::Texture2D, slab); + + const Core::Maths::IVec2 face_offsets[] = { + Core::Maths::IVec2{ face_size, face_size * 3}, + Core::Maths::IVec2{ 0, face_size}, + Core::Maths::IVec2{ face_size, face_size}, + Core::Maths::IVec2{face_size * 2, face_size}, + Core::Maths::IVec2{ face_size, 0}, + Core::Maths::IVec2{ face_size, face_size * 2} + }; + + const int cw = input.Width - 1; + const int ch = input.Height - 1; + + for (int face = 0; face < 6; ++face) + { + for (int i = 0; i < face_size; ++i) + { + for (int j = 0; j < face_size; ++j) + { + const Core::Maths::Vec3f P = FaceCoordToXYZ(i, j, face, face_size); + const float R = hypot(P.x, P.y); + const float theta = atan2(P.y, P.x); + const float phi = atan2(P.z, R); + const float Uf = float(2.0f * face_size * (theta + Core::Maths::PI) / Core::Maths::PI); + const float Vf = float(2.0f * face_size * (Core::Maths::PI / 2.0f - phi) / Core::Maths::PI); + + const int U1 = Core::Maths::clamp(int(floor(Uf)), 0, cw); + const int V1 = Core::Maths::clamp(int(floor(Vf)), 0, ch); + const int U2 = Core::Maths::clamp(U1 + 1, 0, cw); + const int V2 = Core::Maths::clamp(V1 + 1, 0, ch); + + const float s = Uf - U1; + const float t = Vf - V1; + + const Core::Maths::Vec4f A = input.GetPixel(U1, V1); + const Core::Maths::Vec4f B = input.GetPixel(U2, V1); + const Core::Maths::Vec4f C = input.GetPixel(U1, V2); + const Core::Maths::Vec4f D = input.GetPixel(U2, V2); + + out.SetPixel(i + face_offsets[face].x, j + face_offsets[face].y, A * (1 - s) * (1 - t) + B * s * (1 - t) + C * (1 - s) * t + D * s * t); + } + } + } + return out; + } + + Bitmap CrossToCubemap(const Bitmap& input, Core::Memory::TLSFSlab* slab) + { + const int face_w = input.Width / 3; + const int face_h = input.Height / 4; + const int px_size = input.Channel * Bitmap::BytePerChannel(input.Format); + + Bitmap out = Bitmap::Create(face_w, face_h, 6, input.Channel, input.Format, BitmapType::CubeMap, slab); + const uint8_t* src = input.Buffer; + uint8_t* dst = out.Buffer; + + for (int face = 0; face < 6; ++face) + { + for (int j = 0; j < face_h; ++j) + { + for (int i = 0; i < face_w; ++i) + { + int px = 0, py = 0; + switch (face) + { + case 0: px = i; py = face_h + j; break; // right + case 1: px = 2 * face_w + i; py = face_h + j; break; // left + case 2: px = 2 * face_w - (i + 1); py = face_h - (j + 1); break; // up + case 3: px = 2 * face_w - (i + 1); py = 3 * face_h - (j + 1); break; // down + case 4: px = 2 * face_w - (i + 1); py = input.Height - (j + 1); break; // front + case 5: px = face_w + i; py = face_h + j; break; // back + } + ZENGINE_VALIDATE_ASSERT( + Helpers::secure_memcpy(dst, px_size, src + (py * input.Width + px) * px_size, px_size) == Helpers::MEMORY_OP_SUCCESS, + "BitmapConvert::CrossToCubemap: pixel copy failed") + dst += px_size; + } + } + } + return out; + } + } // namespace BitmapConvert + +} // namespace ZEngine::Rendering::Buffers diff --git a/ZEngine/ZEngine/Rendering/Buffers/Bitmap.h b/ZEngine/ZEngine/Rendering/Buffers/Bitmap.h index 9b75310d..9c8b9a2b 100644 --- a/ZEngine/ZEngine/Rendering/Buffers/Bitmap.h +++ b/ZEngine/ZEngine/Rendering/Buffers/Bitmap.h @@ -1,351 +1,65 @@ #pragma once -#include -#include #include -#include -#include -#include +#include +#include +#include namespace ZEngine::Rendering::Buffers { - - enum BitmapType - { - TEXTURE_2D, - CUBE - }; - - enum BitmapFormat + enum class BitmapType : uint8_t { - UNSIGNED_BYTE, - FLOAT + Texture2D = 0, + CubeMap = 1, }; - struct BitmapPixel + enum class BitmapFormat : uint8_t { - /* - * Mapping pixel coordinates on a specific face of a cubemap to 3D Cartesian coordinates - * - * The A and B values are normalized coordinates in the range [-1, 1], calculated from pixel coordinates (i, j) - * and the face size. - * - * Reference: "Real-Time Rendering, Fourth Edition" by Tomas Akenine-M?ller, Eric Haines, Naty Hoffman - */ - static ZEngine::Core::Maths::Vec3f FaceCoordToXYZ(int i, int j, int face_id, int face_size) - { - const float A = 2.0f * float(i) / face_size; - const float B = 2.0f * float(j) / face_size; - - if (face_id == 0) - return ZEngine::Core::Maths::Vec3f(-1.0f, A - 1.0f, B - 1.0f); - if (face_id == 1) - return ZEngine::Core::Maths::Vec3f(A - 1.0f, -1.0f, 1.0f - B); - if (face_id == 2) - return ZEngine::Core::Maths::Vec3f(1.0f, A - 1.0f, 1.0f - B); - if (face_id == 3) - return ZEngine::Core::Maths::Vec3f(1.0f - A, 1.0f, 1.0f - B); - if (face_id == 4) - return ZEngine::Core::Maths::Vec3f(B - 1.0f, A - 1.0f, 1.0f); - if (face_id == 5) - return ZEngine::Core::Maths::Vec3f(1.0f - B, A - 1.0f, -1.0f); - return ZEngine::Core::Maths::Vec3f{}; - } + UnsignedByte = 0, + Float = 1, }; struct Bitmap { Bitmap() = default; - - /// @brief Allocate a zeroed buffer. When slab is non-null the buffer is slab-backed - /// and freed via slab on destruction; otherwise heap-allocated (new[]). - Bitmap(int width, int height, int channel, BitmapFormat format, Core::Memory::TLSFSlab* slab = nullptr) : Width(width), Height(height), Channel(channel), Format(format), Slab(slab) - { - Alloc(static_cast(width) * height * channel * BytePerChannel(format)); - } - - /// @brief Cubemap / depth variant. - Bitmap(int width, int height, int depth, int channel, BitmapFormat format, Core::Memory::TLSFSlab* slab = nullptr) : Width(width), Height(height), Depth(depth), Channel(channel), Format(format), Slab(slab) - { - Alloc(static_cast(width) * height * depth * channel * BytePerChannel(format)); - } - - /// @brief Allocate and copy from data. slab parameter routes the buffer allocation. - Bitmap(int width, int height, int channel, BitmapFormat format, const void* data, Core::Memory::TLSFSlab* slab = nullptr) : Width(width), Height(height), Channel(channel), Format(format), Slab(slab) - { - size_t sz = static_cast(width) * height * channel * BytePerChannel(format); - if (data) - { - AllocNoZero(sz); - if (Buffer) - ZENGINE_VALIDATE_ASSERT(Helpers::secure_memcpy(Buffer, BufferSize, data, BufferSize) == Helpers::MEMORY_OP_SUCCESS, "Bitmap: memcpy from source data failed") - } - else - { - Alloc(sz); - } - } - - ~Bitmap() - { - Free(); - } + ~Bitmap(); Bitmap(const Bitmap&) = delete; Bitmap& operator=(const Bitmap&) = delete; - Bitmap(Bitmap&& o) noexcept : Width(o.Width), Height(o.Height), Depth(o.Depth), Channel(o.Channel), Type(o.Type), Format(o.Format), Buffer(o.Buffer), BufferSize(o.BufferSize), Slab(o.Slab) - { - o.Buffer = nullptr; - o.BufferSize = 0; - o.Slab = nullptr; - } - - Bitmap& operator=(Bitmap&& o) noexcept - { - if (this != &o) - { - Free(); - Width = o.Width; - Height = o.Height; - Depth = o.Depth; - Channel = o.Channel; - Type = o.Type; - Format = o.Format; - Buffer = o.Buffer; - BufferSize = o.BufferSize; - Slab = o.Slab; - - o.Buffer = nullptr; - o.BufferSize = 0; - o.Slab = nullptr; - } - return *this; - } - - void SetPixel(int x, int y, const ZEngine::Core::Maths::Vec4f& pixel) - { - if (Format == BitmapFormat::UNSIGNED_BYTE) - { - const int ofs = Channel * (y * Width + x); - if (Channel > 0) - Buffer[ofs + 0] = uint8_t(pixel.x * 255.0f); - if (Channel > 1) - Buffer[ofs + 1] = uint8_t(pixel.y * 255.0f); - if (Channel > 2) - Buffer[ofs + 2] = uint8_t(pixel.z * 255.0f); - if (Channel > 3) - Buffer[ofs + 3] = uint8_t(pixel.w * 255.0f); - } - else if (Format == BitmapFormat::FLOAT) - { - const int ofs = Channel * (y * Width + x); - float* data = reinterpret_cast(Buffer); - if (Channel > 0) - data[ofs + 0] = pixel.x; - if (Channel > 1) - data[ofs + 1] = pixel.y; - if (Channel > 2) - data[ofs + 2] = pixel.z; - if (Channel > 3) - data[ofs + 3] = pixel.w; - } - } - - ZEngine::Core::Maths::Vec4f GetPixel(int x, int y) const - { - if (Format == BitmapFormat::UNSIGNED_BYTE) - { - const int ofs = Channel * (y * Width + x); - return ZEngine::Core::Maths::Vec4f(Channel > 0 ? float(Buffer[ofs + 0]) / 255.0f : 0.0f, Channel > 1 ? float(Buffer[ofs + 1]) / 255.0f : 0.0f, Channel > 2 ? float(Buffer[ofs + 2]) / 255.0f : 0.0f, Channel > 3 ? float(Buffer[ofs + 3]) / 255.0f : 0.0f); - } - else if (Format == BitmapFormat::FLOAT) - { - const int ofs = Channel * (y * Width + x); - const float* data = reinterpret_cast(Buffer); - return ZEngine::Core::Maths::Vec4f(Channel > 0 ? data[ofs + 0] : 0.0f, Channel > 1 ? data[ofs + 1] : 0.0f, Channel > 2 ? data[ofs + 2] : 0.0f, Channel > 3 ? data[ofs + 3] : 0.0f); - } - return ZEngine::Core::Maths::Vec4f(); - } - - inline static int BytePerChannel(BitmapFormat format) - { - if (format == BitmapFormat::UNSIGNED_BYTE) - return 1; - if (format == BitmapFormat::FLOAT) - return 4; - return 0; - } - - /// @brief slab is forwarded to all internal Bitmap allocations within this call. - inline static Bitmap EquirectangularMapToVerticalCross(const Bitmap& input_map, Core::Memory::TLSFSlab* slab = nullptr) - { - if (input_map.Type != BitmapType::TEXTURE_2D) - return Bitmap(); + Bitmap(Bitmap&& o) noexcept; + Bitmap& operator=(Bitmap&& o) noexcept; - const int face_size = input_map.Width / 4; - const int width = face_size * 3; - const int height = face_size * 4; + /// @brief Allocate a zeroed buffer. layers=1 for Texture2D, layers=6 for CubeMap. + static Bitmap Create(int w, int h, int layers, int ch, BitmapFormat fmt, BitmapType type, Core::Memory::TLSFSlab* slab = nullptr); - Bitmap vertical_cross(width, height, input_map.Channel, input_map.Format, slab); + /// @brief Allocate and copy from data. + static Bitmap FromData(int w, int h, int layers, int ch, BitmapFormat fmt, BitmapType type, const void* data, Core::Memory::TLSFSlab* slab = nullptr); - const ZEngine::Core::Maths::IVec2 face_offsets[] = { - ZEngine::Core::Maths::IVec2{ face_size, face_size * 3}, - ZEngine::Core::Maths::IVec2{ 0, face_size}, - ZEngine::Core::Maths::IVec2{ face_size, face_size}, - ZEngine::Core::Maths::IVec2{face_size * 2, face_size}, - ZEngine::Core::Maths::IVec2{ face_size, 0}, - ZEngine::Core::Maths::IVec2{ face_size, face_size * 2} - }; + void SetPixel(int x, int y, const Core::Maths::Vec4f& pixel); + Core::Maths::Vec4f GetPixel(int x, int y) const; - const int clamped_width = input_map.Width - 1; - const int clamped_height = input_map.Height - 1; - - for (int face = 0; face < 6; ++face) - { - for (int i = 0; i < face_size; ++i) - { - for (int j = 0; j < face_size; ++j) - { - const ZEngine::Core::Maths::Vec3f P = BitmapPixel::FaceCoordToXYZ(i, j, face, face_size); - const float R = hypot(P.x, P.y); - const float theta = atan2(P.y, P.x); - const float phi = atan2(P.z, R); - - const float Uf = float(2.0f * face_size * (theta + ZEngine::Core::Maths::PI) / ZEngine::Core::Maths::PI); - const float Vf = float(2.0f * face_size * (ZEngine::Core::Maths::PI / 2.0f - phi) / ZEngine::Core::Maths::PI); - - const int U1 = ZEngine::Core::Maths::clamp(int(floor(Uf)), 0, clamped_width); - const int V1 = ZEngine::Core::Maths::clamp(int(floor(Vf)), 0, clamped_height); - const int U2 = ZEngine::Core::Maths::clamp(U1 + 1, 0, clamped_width); - const int V2 = ZEngine::Core::Maths::clamp(V1 + 1, 0, clamped_height); - - const float s = Uf - U1; - const float t = Vf - V1; - - const ZEngine::Core::Maths::Vec4f A = input_map.GetPixel(U1, V1); - const ZEngine::Core::Maths::Vec4f B = input_map.GetPixel(U2, V1); - const ZEngine::Core::Maths::Vec4f C = input_map.GetPixel(U1, V2); - const ZEngine::Core::Maths::Vec4f D = input_map.GetPixel(U2, V2); - - const ZEngine::Core::Maths::Vec4f color = A * (1 - s) * (1 - t) + B * (s) * (1 - t) + C * (1 - s) * t + D * (s) * (t); - vertical_cross.SetPixel(i + face_offsets[face].x, j + face_offsets[face].y, color); - } - } - } - return vertical_cross; - } - - /// @brief slab is forwarded to the cubemap buffer allocation. - inline static Bitmap VerticalCrossToCubemap(const Bitmap& input_map, Core::Memory::TLSFSlab* slab = nullptr) - { - const int face_width = input_map.Width / 3; - const int face_height = input_map.Height / 4; - - Bitmap cubemap(face_width, face_height, 6, input_map.Channel, input_map.Format, slab); - cubemap.Type = CUBE; - - const uint8_t* source = input_map.Buffer; - uint8_t* destination = cubemap.Buffer; - int pixel_size = cubemap.Channel * BytePerChannel(cubemap.Format); - - const int RIGHT_FACE = 0; - const int LEFT_FACE = 1; - const int UP_FACE = 2; - const int DOWN_FACE = 3; - const int FRONT_FACE = 4; - const int BACK_FACE = 5; - - for (int face = 0; face < 6; ++face) - { - for (int j = 0; j < face_height; ++j) - { - for (int i = 0; i < face_width; ++i) - { - int pixel_pos_x = 0; - int pixel_pos_y = 0; - - switch (face) - { - case RIGHT_FACE: - pixel_pos_x = i; - pixel_pos_y = face_height + j; - break; - case LEFT_FACE: - pixel_pos_x = 2 * face_width + i; - pixel_pos_y = 1 * face_height + j; - break; - case UP_FACE: - pixel_pos_x = 2 * face_width - (i + 1); - pixel_pos_y = 1 * face_height - (j + 1); - break; - case DOWN_FACE: - pixel_pos_x = 2 * face_width - (i + 1); - pixel_pos_y = 3 * face_height - (j + 1); - break; - case FRONT_FACE: - pixel_pos_x = 2 * face_width - (i + 1); - pixel_pos_y = input_map.Height - (j + 1); - break; - case BACK_FACE: - pixel_pos_x = face_width + i; - pixel_pos_y = face_height + j; - break; - } - ZENGINE_VALIDATE_ASSERT(Helpers::secure_memcpy(destination, pixel_size, source + (pixel_pos_y * input_map.Width + pixel_pos_x) * pixel_size, pixel_size) == Helpers::MEMORY_OP_SUCCESS, "Bitmap: pixel copy failed in VerticalCrossToCubemap") - destination += pixel_size; - } - } - } - return cubemap; - } + static int BytePerChannel(BitmapFormat fmt); int Width = 0; int Height = 0; - int Depth = 1; + int Layers = 1; ///< 1 for Texture2D; 6 for CubeMap. int Channel = 3; - BitmapType Type = BitmapType::TEXTURE_2D; - BitmapFormat Format = BitmapFormat::UNSIGNED_BYTE; - uint8_t* Buffer = nullptr; ///< Pixel data. Owned by this Bitmap. - size_t BufferSize = 0; ///< Size of Buffer in bytes. - Core::Memory::TLSFSlab* Slab = nullptr; ///< Non-null when Buffer is slab-backed. + BitmapType Type = BitmapType::Texture2D; + BitmapFormat Format = BitmapFormat::UnsignedByte; + uint8_t* Buffer = nullptr; + size_t BufferSize = 0; + Core::Memory::TLSFSlab* Slab = nullptr; private: - void Alloc(size_t n) - { - if (n == 0) - return; - BufferSize = n; - if (Slab) - { - Buffer = static_cast(Slab->Alloc(n)); - Helpers::secure_memset(Buffer, 0, n, n); - } - else - { - Buffer = new uint8_t[n](); - } - } + void Alloc(size_t n); + void AllocNoZero(size_t n); + void FreeBuffer(); + }; - void AllocNoZero(size_t n) - { - if (n == 0) - return; - BufferSize = n; - Buffer = Slab ? static_cast(Slab->Alloc(n)) : new uint8_t[n]; - } + namespace BitmapConvert + { + Bitmap EquirectToCross(const Bitmap& equirect, Core::Memory::TLSFSlab* slab = nullptr); + Bitmap CrossToCubemap (const Bitmap& cross, Core::Memory::TLSFSlab* slab = nullptr); + } - void Free() - { - if (Buffer) - { - if (Slab) - Slab->Free(Buffer); - else - delete[] Buffer; - Buffer = nullptr; - BufferSize = 0; - Slab = nullptr; - } - } - }; } // namespace ZEngine::Rendering::Buffers diff --git a/ZEngine/ZEngine/Rendering/RenderResourceManager.cpp b/ZEngine/ZEngine/Rendering/RenderResourceManager.cpp index bc93ec12..7a479ac5 100644 --- a/ZEngine/ZEngine/Rendering/RenderResourceManager.cpp +++ b/ZEngine/ZEngine/Rendering/RenderResourceManager.cpp @@ -1382,14 +1382,14 @@ namespace ZEngine::Rendering } stbi_image_free((void*) image_data); - Rendering::Buffers::Bitmap in(w, h, 4, Rendering::Buffers::BitmapFormat::FLOAT, output_buf, slab); + Rendering::Buffers::Bitmap in = Rendering::Buffers::Bitmap::FromData(w, h, 1, 4, Rendering::Buffers::BitmapFormat::Float, Rendering::Buffers::BitmapType::Texture2D, output_buf, slab); if (slab) slab->Free(output_buf); else delete[] output_buf; - Rendering::Buffers::Bitmap vertical_cross = Rendering::Buffers::Bitmap::EquirectangularMapToVerticalCross(in, slab); - Rendering::Buffers::Bitmap cubemap = Rendering::Buffers::Bitmap::VerticalCrossToCubemap(vertical_cross, slab); + Rendering::Buffers::Bitmap vertical_cross = Rendering::Buffers::BitmapConvert::EquirectToCross(in, slab); + Rendering::Buffers::Bitmap cubemap = Rendering::Buffers::BitmapConvert::CrossToCubemap(vertical_cross, slab); size_t bytes = cubemap.BufferSize; buffer.resize(bytes); diff --git a/ZEngine/tests/Memory/bitmap_test.cpp b/ZEngine/tests/Memory/bitmap_test.cpp index 4d6ef12b..1e641178 100644 --- a/ZEngine/tests/Memory/bitmap_test.cpp +++ b/ZEngine/tests/Memory/bitmap_test.cpp @@ -5,22 +5,22 @@ #include #include #include +#include using namespace ZEngine::Rendering::Buffers; constexpr float epsilon = 1e-2; -static bool approximatelyEqual(float a, float b, float epsilon) +static bool approximatelyEqual(float a, float b, float eps) { - return fabs(a - b) <= epsilon * fmax(1.0f, fmax(fabs(a), fabs(b))); + return fabs(a - b) <= eps * fmax(1.0f, fmax(fabs(a), fabs(b))); } TEST(BitmapTest, GetOrSetPixel) { - ZEngine::Core::Maths::Vec4f p(0.5, 0.5, 0.8, 0.0); - Bitmap bitmap(100, 100, 3, BitmapFormat::UNSIGNED_BYTE); + Bitmap bitmap = Bitmap::Create(100, 100, 1, 3, BitmapFormat::UnsignedByte, BitmapType::Texture2D); bitmap.SetPixel(0, 0, p); auto pp = bitmap.GetPixel(0, 0); @@ -33,11 +33,11 @@ TEST(BitmapTest, GetOrSetPixel) TEST(BitmapTest, TestVerticalCross) { int width = 0, height = 0, channel = 0; - const float* image_data = stbi_loadf("piazza_bologni_1k.hdr", &width, &height, &channel, 3); + const float* image_data = stbi_loadf("piazza_bologni_1k.hdr", &width, &height, &channel, 3); - Bitmap in = {width, height, channel, BitmapFormat::FLOAT, image_data}; - Bitmap vertical_cross = Bitmap::EquirectangularMapToVerticalCross(in); - Bitmap cubemap = Bitmap::VerticalCrossToCubemap(vertical_cross); + Bitmap in = Bitmap::FromData(width, height, 1, channel, BitmapFormat::Float, BitmapType::Texture2D, image_data); + Bitmap vertical_cross = BitmapConvert::EquirectToCross(in); + Bitmap cubemap = BitmapConvert::CrossToCubemap(vertical_cross); stbi_image_free((void*) image_data); stbi_write_hdr("screenshot.hdr", vertical_cross.Width, vertical_cross.Height, vertical_cross.Channel, (const float*) vertical_cross.Buffer); @@ -51,34 +51,31 @@ TEST(BitmapTest, TestVerticalCross) TEST(BitmapTest, TestVerticalCross2) { - int width = 0, height = 0, channel = 0; - const float* image_data = stbi_loadf("piazza_bologni_1k.hdr", &width, &height, &channel, 3); + int width = 0, height = 0, channel = 0; + const float* image_data = stbi_loadf("piazza_bologni_1k.hdr", &width, &height, &channel, 3); - std::vector image_buffer_32bit = {}; + std::vector image_buffer_32bit; if (image_data) { const int total_pixel = width * height; image_buffer_32bit.resize(total_pixel * 4); - auto source_buffer_24 = image_data; - auto destination_buffer_32 = image_buffer_32bit.data(); + auto source = image_data; + auto destination = image_buffer_32bit.data(); for (int i = 0; i != total_pixel; i++) { - // Copy RGB channels from source to destination - *destination_buffer_32++ = *source_buffer_24++; - *destination_buffer_32++ = *source_buffer_24++; - *destination_buffer_32++ = *source_buffer_24++; - - // Set alpha channel to 1.0f - *destination_buffer_32++ = 1.0f; + *destination++ = *source++; + *destination++ = *source++; + *destination++ = *source++; + *destination++ = 1.0f; } } stbi_image_free((void*) image_data); - Bitmap in = {width, height, 4, BitmapFormat::FLOAT, image_buffer_32bit.data()}; - Bitmap vertical_cross = Bitmap::EquirectangularMapToVerticalCross(in); - Bitmap cubemap = Bitmap::VerticalCrossToCubemap(vertical_cross); + Bitmap in = Bitmap::FromData(width, height, 1, 4, BitmapFormat::Float, BitmapType::Texture2D, image_buffer_32bit.data()); + Bitmap vertical_cross = BitmapConvert::EquirectToCross(in); + Bitmap cubemap = BitmapConvert::CrossToCubemap(vertical_cross); stbi_write_hdr("screenshot3.hdr", vertical_cross.Width, vertical_cross.Height, vertical_cross.Channel, (const float*) vertical_cross.Buffer); stbi_write_hdr("screenshot4.hdr", cubemap.Width, cubemap.Height, cubemap.Channel, (const float*) cubemap.Buffer); @@ -88,4 +85,4 @@ TEST(BitmapTest, TestVerticalCross2) EXPECT_TRUE(std::filesystem::exists(current_path + "/screenshot3.hdr")); EXPECT_TRUE(std::filesystem::exists(current_path + "/screenshot4.hdr")); -} \ No newline at end of file +} From faa11588d9830b909cdd6556f6a208763bcb8d11 Mon Sep 17 00:00:00 2001 From: Jean Philippe Date: Wed, 2 Sep 2026 08:26:17 +0900 Subject: [PATCH 2/2] style: clang-format bitmap reshape --- .../Importers/EnvironmentMapImporter.cpp | 4 +- ZEngine/ZEngine/Rendering/Buffers/Bitmap.cpp | 142 ++++++++++-------- ZEngine/ZEngine/Rendering/Buffers/Bitmap.h | 18 +-- ZEngine/tests/Memory/bitmap_test.cpp | 16 +- 4 files changed, 102 insertions(+), 78 deletions(-) diff --git a/ZEngine/ZEngine/Importers/EnvironmentMapImporter.cpp b/ZEngine/ZEngine/Importers/EnvironmentMapImporter.cpp index f71a7c11..fa2486ab 100644 --- a/ZEngine/ZEngine/Importers/EnvironmentMapImporter.cpp +++ b/ZEngine/ZEngine/Importers/EnvironmentMapImporter.cpp @@ -45,8 +45,8 @@ namespace ZEngine::Importers Bitmap equirect = Bitmap::FromData(width, height, 1, 4, BitmapFormat::Float, BitmapType::Texture2D, image_data, slab); stbi_image_free(const_cast(image_data)); - Bitmap vertical_cross = BitmapConvert::EquirectToCross(equirect, slab); - Bitmap cubemap = BitmapConvert::CrossToCubemap(vertical_cross, slab); + Bitmap vertical_cross = BitmapConvert::EquirectToCross(equirect, slab); + Bitmap cubemap = BitmapConvert::CrossToCubemap(vertical_cross, slab); // Write to project://_cache/envmaps/.zenvmap via VFS. // Keyed by UUID — regenerable, gitignored, transparent to game code. diff --git a/ZEngine/ZEngine/Rendering/Buffers/Bitmap.cpp b/ZEngine/ZEngine/Rendering/Buffers/Bitmap.cpp index 690a2af1..b012e7c4 100644 --- a/ZEngine/ZEngine/Rendering/Buffers/Bitmap.cpp +++ b/ZEngine/ZEngine/Rendering/Buffers/Bitmap.cpp @@ -11,8 +11,7 @@ namespace ZEngine::Rendering::Buffers FreeBuffer(); } - Bitmap::Bitmap(Bitmap&& o) noexcept - : Width(o.Width), Height(o.Height), Layers(o.Layers), Channel(o.Channel), Type(o.Type), Format(o.Format), Buffer(o.Buffer), BufferSize(o.BufferSize), Slab(o.Slab) + Bitmap::Bitmap(Bitmap&& o) noexcept : Width(o.Width), Height(o.Height), Layers(o.Layers), Channel(o.Channel), Type(o.Type), Format(o.Format), Buffer(o.Buffer), BufferSize(o.BufferSize), Slab(o.Slab) { o.Buffer = nullptr; o.BufferSize = 0; @@ -24,15 +23,15 @@ namespace ZEngine::Rendering::Buffers if (this != &o) { FreeBuffer(); - Width = o.Width; - Height = o.Height; - Layers = o.Layers; - Channel = o.Channel; - Type = o.Type; - Format = o.Format; - Buffer = o.Buffer; - BufferSize = o.BufferSize; - Slab = o.Slab; + Width = o.Width; + Height = o.Height; + Layers = o.Layers; + Channel = o.Channel; + Type = o.Type; + Format = o.Format; + Buffer = o.Buffer; + BufferSize = o.BufferSize; + Slab = o.Slab; o.Buffer = nullptr; o.BufferSize = 0; @@ -84,8 +83,10 @@ namespace ZEngine::Rendering::Buffers { switch (fmt) { - case BitmapFormat::UnsignedByte: return 1; - case BitmapFormat::Float: return 4; + case BitmapFormat::UnsignedByte: + return 1; + case BitmapFormat::Float: + return 4; } return 0; } @@ -95,19 +96,27 @@ namespace ZEngine::Rendering::Buffers if (Format == BitmapFormat::UnsignedByte) { const int ofs = Channel * (y * Width + x); - if (Channel > 0) Buffer[ofs + 0] = uint8_t(pixel.x * 255.0f); - if (Channel > 1) Buffer[ofs + 1] = uint8_t(pixel.y * 255.0f); - if (Channel > 2) Buffer[ofs + 2] = uint8_t(pixel.z * 255.0f); - if (Channel > 3) Buffer[ofs + 3] = uint8_t(pixel.w * 255.0f); + if (Channel > 0) + Buffer[ofs + 0] = uint8_t(pixel.x * 255.0f); + if (Channel > 1) + Buffer[ofs + 1] = uint8_t(pixel.y * 255.0f); + if (Channel > 2) + Buffer[ofs + 2] = uint8_t(pixel.z * 255.0f); + if (Channel > 3) + Buffer[ofs + 3] = uint8_t(pixel.w * 255.0f); } else if (Format == BitmapFormat::Float) { const int ofs = Channel * (y * Width + x); float* data = reinterpret_cast(Buffer); - if (Channel > 0) data[ofs + 0] = pixel.x; - if (Channel > 1) data[ofs + 1] = pixel.y; - if (Channel > 2) data[ofs + 2] = pixel.z; - if (Channel > 3) data[ofs + 3] = pixel.w; + if (Channel > 0) + data[ofs + 0] = pixel.x; + if (Channel > 1) + data[ofs + 1] = pixel.y; + if (Channel > 2) + data[ofs + 2] = pixel.z; + if (Channel > 3) + data[ofs + 3] = pixel.w; } } @@ -116,21 +125,13 @@ namespace ZEngine::Rendering::Buffers if (Format == BitmapFormat::UnsignedByte) { const int ofs = Channel * (y * Width + x); - return Core::Maths::Vec4f( - Channel > 0 ? float(Buffer[ofs + 0]) / 255.0f : 0.0f, - Channel > 1 ? float(Buffer[ofs + 1]) / 255.0f : 0.0f, - Channel > 2 ? float(Buffer[ofs + 2]) / 255.0f : 0.0f, - Channel > 3 ? float(Buffer[ofs + 3]) / 255.0f : 0.0f); + return Core::Maths::Vec4f(Channel > 0 ? float(Buffer[ofs + 0]) / 255.0f : 0.0f, Channel > 1 ? float(Buffer[ofs + 1]) / 255.0f : 0.0f, Channel > 2 ? float(Buffer[ofs + 2]) / 255.0f : 0.0f, Channel > 3 ? float(Buffer[ofs + 3]) / 255.0f : 0.0f); } else if (Format == BitmapFormat::Float) { const int ofs = Channel * (y * Width + x); const float* data = reinterpret_cast(Buffer); - return Core::Maths::Vec4f( - Channel > 0 ? data[ofs + 0] : 0.0f, - Channel > 1 ? data[ofs + 1] : 0.0f, - Channel > 2 ? data[ofs + 2] : 0.0f, - Channel > 3 ? data[ofs + 3] : 0.0f); + return Core::Maths::Vec4f(Channel > 0 ? data[ofs + 0] : 0.0f, Channel > 1 ? data[ofs + 1] : 0.0f, Channel > 2 ? data[ofs + 2] : 0.0f, Channel > 3 ? data[ofs + 3] : 0.0f); } return Core::Maths::Vec4f(); } @@ -182,13 +183,20 @@ namespace ZEngine::Rendering::Buffers switch (face_id) { - case 0: return Core::Maths::Vec3f(-1.0f, A - 1.0f, B - 1.0f); - case 1: return Core::Maths::Vec3f(A - 1.0f, -1.0f, 1.0f - B); - case 2: return Core::Maths::Vec3f(1.0f, A - 1.0f, 1.0f - B); - case 3: return Core::Maths::Vec3f(1.0f - A, 1.0f, 1.0f - B); - case 4: return Core::Maths::Vec3f(B - 1.0f, A - 1.0f, 1.0f); - case 5: return Core::Maths::Vec3f(1.0f - B, A - 1.0f, -1.0f); - default: return Core::Maths::Vec3f{}; + case 0: + return Core::Maths::Vec3f(-1.0f, A - 1.0f, B - 1.0f); + case 1: + return Core::Maths::Vec3f(A - 1.0f, -1.0f, 1.0f - B); + case 2: + return Core::Maths::Vec3f(1.0f, A - 1.0f, 1.0f - B); + case 3: + return Core::Maths::Vec3f(1.0f - A, 1.0f, 1.0f - B); + case 4: + return Core::Maths::Vec3f(B - 1.0f, A - 1.0f, 1.0f); + case 5: + return Core::Maths::Vec3f(1.0f - B, A - 1.0f, -1.0f); + default: + return Core::Maths::Vec3f{}; } } @@ -197,8 +205,8 @@ namespace ZEngine::Rendering::Buffers if (input.Type != BitmapType::Texture2D) return Bitmap(); - const int face_size = input.Width / 4; - Bitmap out = Bitmap::Create(face_size * 3, face_size * 4, 1, input.Channel, input.Format, BitmapType::Texture2D, slab); + const int face_size = input.Width / 4; + Bitmap out = Bitmap::Create(face_size * 3, face_size * 4, 1, input.Channel, input.Format, BitmapType::Texture2D, slab); const Core::Maths::IVec2 face_offsets[] = { Core::Maths::IVec2{ face_size, face_size * 3}, @@ -225,10 +233,10 @@ namespace ZEngine::Rendering::Buffers const float Uf = float(2.0f * face_size * (theta + Core::Maths::PI) / Core::Maths::PI); const float Vf = float(2.0f * face_size * (Core::Maths::PI / 2.0f - phi) / Core::Maths::PI); - const int U1 = Core::Maths::clamp(int(floor(Uf)), 0, cw); - const int V1 = Core::Maths::clamp(int(floor(Vf)), 0, ch); - const int U2 = Core::Maths::clamp(U1 + 1, 0, cw); - const int V2 = Core::Maths::clamp(V1 + 1, 0, ch); + const int U1 = Core::Maths::clamp(int(floor(Uf)), 0, cw); + const int V1 = Core::Maths::clamp(int(floor(Vf)), 0, ch); + const int U2 = Core::Maths::clamp(U1 + 1, 0, cw); + const int V2 = Core::Maths::clamp(V1 + 1, 0, ch); const float s = Uf - U1; const float t = Vf - V1; @@ -247,13 +255,13 @@ namespace ZEngine::Rendering::Buffers Bitmap CrossToCubemap(const Bitmap& input, Core::Memory::TLSFSlab* slab) { - const int face_w = input.Width / 3; - const int face_h = input.Height / 4; - const int px_size = input.Channel * Bitmap::BytePerChannel(input.Format); + const int face_w = input.Width / 3; + const int face_h = input.Height / 4; + const int px_size = input.Channel * Bitmap::BytePerChannel(input.Format); - Bitmap out = Bitmap::Create(face_w, face_h, 6, input.Channel, input.Format, BitmapType::CubeMap, slab); - const uint8_t* src = input.Buffer; - uint8_t* dst = out.Buffer; + Bitmap out = Bitmap::Create(face_w, face_h, 6, input.Channel, input.Format, BitmapType::CubeMap, slab); + const uint8_t* src = input.Buffer; + uint8_t* dst = out.Buffer; for (int face = 0; face < 6; ++face) { @@ -264,16 +272,32 @@ namespace ZEngine::Rendering::Buffers int px = 0, py = 0; switch (face) { - case 0: px = i; py = face_h + j; break; // right - case 1: px = 2 * face_w + i; py = face_h + j; break; // left - case 2: px = 2 * face_w - (i + 1); py = face_h - (j + 1); break; // up - case 3: px = 2 * face_w - (i + 1); py = 3 * face_h - (j + 1); break; // down - case 4: px = 2 * face_w - (i + 1); py = input.Height - (j + 1); break; // front - case 5: px = face_w + i; py = face_h + j; break; // back + case 0: + px = i; + py = face_h + j; + break; // right + case 1: + px = 2 * face_w + i; + py = face_h + j; + break; // left + case 2: + px = 2 * face_w - (i + 1); + py = face_h - (j + 1); + break; // up + case 3: + px = 2 * face_w - (i + 1); + py = 3 * face_h - (j + 1); + break; // down + case 4: + px = 2 * face_w - (i + 1); + py = input.Height - (j + 1); + break; // front + case 5: + px = face_w + i; + py = face_h + j; + break; // back } - ZENGINE_VALIDATE_ASSERT( - Helpers::secure_memcpy(dst, px_size, src + (py * input.Width + px) * px_size, px_size) == Helpers::MEMORY_OP_SUCCESS, - "BitmapConvert::CrossToCubemap: pixel copy failed") + ZENGINE_VALIDATE_ASSERT(Helpers::secure_memcpy(dst, px_size, src + (py * input.Width + px) * px_size, px_size) == Helpers::MEMORY_OP_SUCCESS, "BitmapConvert::CrossToCubemap: pixel copy failed") dst += px_size; } } diff --git a/ZEngine/ZEngine/Rendering/Buffers/Bitmap.h b/ZEngine/ZEngine/Rendering/Buffers/Bitmap.h index 9c8b9a2b..bef74305 100644 --- a/ZEngine/ZEngine/Rendering/Buffers/Bitmap.h +++ b/ZEngine/ZEngine/Rendering/Buffers/Bitmap.h @@ -1,6 +1,6 @@ #pragma once -#include #include +#include #include #include @@ -27,18 +27,18 @@ namespace ZEngine::Rendering::Buffers Bitmap& operator=(const Bitmap&) = delete; Bitmap(Bitmap&& o) noexcept; - Bitmap& operator=(Bitmap&& o) noexcept; + Bitmap& operator=(Bitmap&& o) noexcept; /// @brief Allocate a zeroed buffer. layers=1 for Texture2D, layers=6 for CubeMap. - static Bitmap Create(int w, int h, int layers, int ch, BitmapFormat fmt, BitmapType type, Core::Memory::TLSFSlab* slab = nullptr); + static Bitmap Create(int w, int h, int layers, int ch, BitmapFormat fmt, BitmapType type, Core::Memory::TLSFSlab* slab = nullptr); /// @brief Allocate and copy from data. - static Bitmap FromData(int w, int h, int layers, int ch, BitmapFormat fmt, BitmapType type, const void* data, Core::Memory::TLSFSlab* slab = nullptr); + static Bitmap FromData(int w, int h, int layers, int ch, BitmapFormat fmt, BitmapType type, const void* data, Core::Memory::TLSFSlab* slab = nullptr); - void SetPixel(int x, int y, const Core::Maths::Vec4f& pixel); - Core::Maths::Vec4f GetPixel(int x, int y) const; + void SetPixel(int x, int y, const Core::Maths::Vec4f& pixel); + Core::Maths::Vec4f GetPixel(int x, int y) const; - static int BytePerChannel(BitmapFormat fmt); + static int BytePerChannel(BitmapFormat fmt); int Width = 0; int Height = 0; @@ -59,7 +59,7 @@ namespace ZEngine::Rendering::Buffers namespace BitmapConvert { Bitmap EquirectToCross(const Bitmap& equirect, Core::Memory::TLSFSlab* slab = nullptr); - Bitmap CrossToCubemap (const Bitmap& cross, Core::Memory::TLSFSlab* slab = nullptr); - } + Bitmap CrossToCubemap(const Bitmap& cross, Core::Memory::TLSFSlab* slab = nullptr); + } // namespace BitmapConvert } // namespace ZEngine::Rendering::Buffers diff --git a/ZEngine/tests/Memory/bitmap_test.cpp b/ZEngine/tests/Memory/bitmap_test.cpp index 1e641178..c6c2fa55 100644 --- a/ZEngine/tests/Memory/bitmap_test.cpp +++ b/ZEngine/tests/Memory/bitmap_test.cpp @@ -11,7 +11,7 @@ using namespace ZEngine::Rendering::Buffers; constexpr float epsilon = 1e-2; -static bool approximatelyEqual(float a, float b, float eps) +static bool approximatelyEqual(float a, float b, float eps) { return fabs(a - b) <= eps * fmax(1.0f, fmax(fabs(a), fabs(b))); } @@ -20,7 +20,7 @@ TEST(BitmapTest, GetOrSetPixel) { ZEngine::Core::Maths::Vec4f p(0.5, 0.5, 0.8, 0.0); - Bitmap bitmap = Bitmap::Create(100, 100, 1, 3, BitmapFormat::UnsignedByte, BitmapType::Texture2D); + Bitmap bitmap = Bitmap::Create(100, 100, 1, 3, BitmapFormat::UnsignedByte, BitmapType::Texture2D); bitmap.SetPixel(0, 0, p); auto pp = bitmap.GetPixel(0, 0); @@ -33,11 +33,11 @@ TEST(BitmapTest, GetOrSetPixel) TEST(BitmapTest, TestVerticalCross) { int width = 0, height = 0, channel = 0; - const float* image_data = stbi_loadf("piazza_bologni_1k.hdr", &width, &height, &channel, 3); + const float* image_data = stbi_loadf("piazza_bologni_1k.hdr", &width, &height, &channel, 3); - Bitmap in = Bitmap::FromData(width, height, 1, channel, BitmapFormat::Float, BitmapType::Texture2D, image_data); - Bitmap vertical_cross = BitmapConvert::EquirectToCross(in); - Bitmap cubemap = BitmapConvert::CrossToCubemap(vertical_cross); + Bitmap in = Bitmap::FromData(width, height, 1, channel, BitmapFormat::Float, BitmapType::Texture2D, image_data); + Bitmap vertical_cross = BitmapConvert::EquirectToCross(in); + Bitmap cubemap = BitmapConvert::CrossToCubemap(vertical_cross); stbi_image_free((void*) image_data); stbi_write_hdr("screenshot.hdr", vertical_cross.Width, vertical_cross.Height, vertical_cross.Channel, (const float*) vertical_cross.Buffer); @@ -51,8 +51,8 @@ TEST(BitmapTest, TestVerticalCross) TEST(BitmapTest, TestVerticalCross2) { - int width = 0, height = 0, channel = 0; - const float* image_data = stbi_loadf("piazza_bologni_1k.hdr", &width, &height, &channel, 3); + int width = 0, height = 0, channel = 0; + const float* image_data = stbi_loadf("piazza_bologni_1k.hdr", &width, &height, &channel, 3); std::vector image_buffer_32bit;