gui is annoying.
This commit is contained in:
@@ -9,7 +9,12 @@
|
||||
#include "../util/output/aviwriter.hpp"
|
||||
#include "../util/output/bmpwriter.hpp"
|
||||
#include "../util/timing_decorator.cpp"
|
||||
|
||||
#include "../imgui/imgui.h"
|
||||
#include "../imgui/backends/imgui_impl_glfw.h"
|
||||
#include "../imgui/backends/imgui_impl_opengl3.h"
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
|
||||
struct AnimationConfig {
|
||||
int width = 1024;
|
||||
@@ -206,37 +211,62 @@ void mainLogic(){
|
||||
}
|
||||
|
||||
int main() {
|
||||
static bool window = true;
|
||||
ImGui::SetNextWindowSize(ImVec2(1110,667));
|
||||
auto beg = ImGui::Begin("Gradient thing", &window);
|
||||
if (beg) {
|
||||
//static bool window = true;
|
||||
if (!glfwInit()) {
|
||||
std::cerr << "gui stuff is dumb in c++." << std::endl;
|
||||
glfwTerminate();
|
||||
return 1;
|
||||
}
|
||||
//ImGui::SetNextWindowSize(ImVec2(1110,667));
|
||||
//auto beg = ImGui::Begin("Gradient thing", &window);
|
||||
//if (beg) {
|
||||
std::cout << "stuff breaks at 220" << std::endl;
|
||||
bool application_not_closed = true;
|
||||
//IMGUI_CHECKVERSION(); //this was listed in imgui docs to add. dont know version strings to put here yet.
|
||||
ImGui::CreateContext();
|
||||
std::cout << "context created" << std::endl;
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
std::cout << "io init?" << std::endl;
|
||||
//float main_scale = ImGui_ImplGlfw_GetContentScaleForMonitor(glfwGetPrimaryMonitor());
|
||||
GLFWwindow* window = glfwCreateWindow((int)(1280), (int)(800), "Dear ImGui GLFW+OpenGL3 example", nullptr, nullptr);
|
||||
std::cout << "created glfw window" << std::endl;
|
||||
|
||||
ImGui_ImplGlfw_InitForOpenGL(window, true); // Second param install_callback=true will install GLFW callbacks and chain to existing ones.
|
||||
ImGui_ImplOpenGL3_Init();
|
||||
|
||||
while (true) {
|
||||
std::cout << "stuff breaks at 220" << std::endl;
|
||||
|
||||
ImGui::SetCursorPos(ImVec2(435.5,200));
|
||||
ImGui::PushItemWidth(200);
|
||||
static int i1 = 123;
|
||||
ImGui::InputInt("Width", &i1);
|
||||
ImGui::PopItemWidth();
|
||||
std::cout << "stuff breaks at 227" << std::endl;
|
||||
|
||||
ImGui::SetCursorPos(ImVec2(432,166));
|
||||
ImGui::PushItemWidth(200);
|
||||
static int i2 = 123;
|
||||
ImGui::InputInt("Height", &i2);
|
||||
ImGui::PopItemWidth();
|
||||
std::cout << "stuff breaks at 234" << std::endl;
|
||||
|
||||
ImGui::SetCursorPos(ImVec2(533.5,271));
|
||||
ImGui::Button("Start", ImVec2(43,19)); //remove size argument (ImVec2) to auto-resize
|
||||
std::cout << "stuff breaks at 238" << std::endl;
|
||||
|
||||
ImGui::SetCursorPos(ImVec2(400.5,366));
|
||||
ImGui::PushItemWidth(200);
|
||||
static int i6 = 123;
|
||||
ImGui::InputInt("number of Seeds", &i6);
|
||||
ImGui::PopItemWidth();
|
||||
std::cout << "stuff breaks at 245" << std::endl;
|
||||
|
||||
}
|
||||
ImGui::End();
|
||||
//ImGui::End();
|
||||
FunctionTimer::printStats(FunctionTimer::Mode::ENHANCED);
|
||||
return 0;
|
||||
}
|
||||
//I need this: https://raais.github.io/ImStudio/
|
||||
// or this: https://github.com/tpecholt/imrad/
|
||||
// g++ -std=c++23 -O3 -march=native -o ./bin/g2gradc ./tests/g2chromatic2.cpp -I./imgui -L./imgui -limgui `pkg-config --cflags --libs glfw3` && ./bin/g2gradc
|
||||
// g++ -std=c++23 -O3 -march=native -o ./bin/g2gradc ./tests/g2chromatic2.cpp -I./imgui -L./imgui -limgui -lstb `pkg-config --cflags --libs glfw3` && ./bin/g2gradc
|
||||
239
tests/spritegen.cpp
Normal file
239
tests/spritegen.cpp
Normal file
@@ -0,0 +1,239 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <tuple>
|
||||
#include <unordered_set>
|
||||
#include "../util/grid/grid2.hpp"
|
||||
#include "../util/output/aviwriter.hpp"
|
||||
#include "../util/output/bmpwriter.hpp"
|
||||
#include "../util/timing_decorator.cpp"
|
||||
#include "../imgui/imgui.h"
|
||||
|
||||
struct AnimationConfig {
|
||||
int width = 1024;
|
||||
int height = 1024;
|
||||
int totalFrames = 480;
|
||||
float fps = 30.0f;
|
||||
int numSeeds = 8;
|
||||
};
|
||||
|
||||
Grid2 setup(AnimationConfig config) {
|
||||
TIME_FUNCTION;
|
||||
Grid2 grid;
|
||||
std::vector<Vec2> pos;
|
||||
std::vector<Vec4> colors;
|
||||
std::vector<float> sizes;
|
||||
for (int y = 0; y < config.height; ++y) {
|
||||
for (int x = 0; x < config.width; ++x) {
|
||||
float gradient = (x + y) / float(config.width + config.height - 2);
|
||||
pos.push_back(Vec2(x,y));
|
||||
colors.push_back(Vec4(gradient, gradient, gradient, 1.0f));
|
||||
sizes.push_back(1.0f);
|
||||
}
|
||||
}
|
||||
grid.bulkAddObjects(pos,colors,sizes);
|
||||
return grid;
|
||||
}
|
||||
|
||||
void Preview(Grid2 grid) {
|
||||
TIME_FUNCTION;
|
||||
int width;
|
||||
int height;
|
||||
//std::vector<uint8_t> rgbData;
|
||||
|
||||
frame rgbData = grid.getGridAsFrame(frame::colormap::RGB);
|
||||
bool success = BMPWriter::saveBMP("output/grayscalesource.bmp", rgbData);
|
||||
if (!success) {
|
||||
std::cout << "yo! this failed in Preview" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::tuple<size_t, Vec2, Vec4>> pickSeeds(Grid2 grid, AnimationConfig config) {
|
||||
TIME_FUNCTION;
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_int_distribution<> xDist(0, config.width - 1);
|
||||
std::uniform_int_distribution<> yDist(0, config.height - 1);
|
||||
std::uniform_real_distribution<> colorDist(0.2f, 0.8f);
|
||||
|
||||
std::vector<std::tuple<size_t, Vec2, Vec4>> seeds;
|
||||
|
||||
for (int i = 0; i < config.numSeeds; ++i) {
|
||||
Vec2 point(xDist(gen), yDist(gen));
|
||||
Vec4 color(colorDist(gen), colorDist(gen), colorDist(gen), 255);
|
||||
size_t id = grid.getPositionVec(point);
|
||||
grid.setColor(id, color);
|
||||
seeds.push_back(std::make_tuple(id,point, color));
|
||||
}
|
||||
return seeds;
|
||||
}
|
||||
|
||||
void expandPixel(Grid2& grid, AnimationConfig config, std::vector<std::tuple<size_t, Vec2, Vec4>>& seeds) {
|
||||
TIME_FUNCTION;
|
||||
std::vector<std::tuple<size_t, Vec2, Vec4>> newseeds;
|
||||
|
||||
std::unordered_set<size_t> visitedThisFrame;
|
||||
for (const auto& seed : seeds) {
|
||||
visitedThisFrame.insert(std::get<0>(seed));
|
||||
}
|
||||
|
||||
//#pragma omp parallel for
|
||||
for (const std::tuple<size_t, Vec2, Vec4>& seed : seeds) {
|
||||
size_t id = std::get<0>(seed);
|
||||
Vec2 seedPOS = std::get<1>(seed);
|
||||
Vec4 seedColor = std::get<2>(seed);
|
||||
std::vector<size_t> neighbors = grid.getNeighbors(id);
|
||||
//grid.setSize(id, grid.getSize(id)+4);
|
||||
for (size_t neighbor : neighbors) {
|
||||
if (visitedThisFrame.count(neighbor)) {
|
||||
continue;
|
||||
}
|
||||
visitedThisFrame.insert(neighbor);
|
||||
|
||||
Vec2 neipos = grid.getPositionID(neighbor);
|
||||
Vec4 neighborColor = grid.getColor(neighbor);
|
||||
float distance = seedPOS.distance(neipos);
|
||||
float angle = seedPOS.directionTo(neipos);
|
||||
|
||||
float normalizedAngle = (angle + M_PI) / (2.0f * M_PI);
|
||||
float blendFactor = 0.3f + 0.4f * std::sin(normalizedAngle * 2.0f * M_PI);
|
||||
blendFactor = std::clamp(blendFactor, 0.1f, 0.9f);
|
||||
|
||||
Vec4 newcolor = Vec4(
|
||||
seedColor.r * blendFactor + neighborColor.r * (1.0f - blendFactor),
|
||||
seedColor.g * (1.0f - blendFactor) + neighborColor.g * blendFactor,
|
||||
seedColor.b * (0.5f + 0.5f * std::sin(normalizedAngle * 4.0f * M_PI)),
|
||||
1.0f
|
||||
);
|
||||
|
||||
newcolor = newcolor.clamp(0.0f, 1.0f);
|
||||
|
||||
grid.setColor(neighbor, newcolor);
|
||||
newseeds.emplace_back(neighbor, neipos, newcolor);
|
||||
}
|
||||
}
|
||||
seeds.clear();
|
||||
seeds.shrink_to_fit();
|
||||
seeds = std::move(newseeds);
|
||||
}
|
||||
|
||||
//bool exportavi(std::vector<std::vector<uint8_t>> frames, AnimationConfig config) {
|
||||
bool exportavi(std::vector<frame> frames, AnimationConfig config) {
|
||||
TIME_FUNCTION;
|
||||
std::string filename = "output/chromatic_transformation.avi";
|
||||
|
||||
std::cout << "Frame count: " << frames.size() << std::endl;
|
||||
|
||||
// Log compression statistics for all frames
|
||||
std::cout << "\n=== Frame Compression Statistics ===" << std::endl;
|
||||
size_t totalOriginalSize = 0;
|
||||
size_t totalCompressedSize = 0;
|
||||
|
||||
for (int i = 0; i < frames.size(); ++i) {
|
||||
totalOriginalSize += frames[i].getSourceSize();
|
||||
totalCompressedSize += frames[i].getTotalCompressedSize();
|
||||
}
|
||||
|
||||
double overallRatio = static_cast<double>(totalOriginalSize) / totalCompressedSize;
|
||||
double overallSavings = (1.0 - 1.0/overallRatio) * 100.0;
|
||||
|
||||
std::cout << "\n=== Overall Compression Summary ===" << std::endl;
|
||||
std::cout << "Total frames: " << frames.size() << std::endl;
|
||||
std::cout << "Compressed frames: " << frames.size() << std::endl;
|
||||
std::cout << "Total original size: " << totalOriginalSize << " bytes ("
|
||||
<< std::fixed << std::setprecision(2) << (totalOriginalSize / (1024.0 * 1024.0)) << " MB)" << std::endl;
|
||||
std::cout << "Total compressed size: " << totalCompressedSize << " bytes ("
|
||||
<< std::fixed << std::setprecision(2) << (totalCompressedSize / (1024.0 * 1024.0)) << " MB)" << std::endl;
|
||||
std::cout << "Overall compression ratio: " << std::fixed << std::setprecision(2) << overallRatio << ":1" << std::endl;
|
||||
std::cout << "Overall space savings: " << std::fixed << std::setprecision(1) << overallSavings << "%" << std::endl;
|
||||
|
||||
std::filesystem::path dir = "output";
|
||||
if (!std::filesystem::exists(dir)) {
|
||||
if (!std::filesystem::create_directories(dir)) {
|
||||
std::cout << "Failed to create output directory!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool success = AVIWriter::saveAVIFromCompressedFrames(filename, frames, frames[0].getWidth(), frames[0].getHeight(), config.fps);
|
||||
|
||||
if (success) {
|
||||
// Check if file actually exists
|
||||
if (std::filesystem::exists(filename)) {
|
||||
auto file_size = std::filesystem::file_size(filename);
|
||||
std::cout << "\nAVI file created successfully: " << filename
|
||||
<< " (" << file_size << " bytes, "
|
||||
<< std::fixed << std::setprecision(2) << (file_size / (1024.0 * 1024.0)) << " MB)" << std::endl;
|
||||
}
|
||||
} else {
|
||||
std::cout << "Failed to save AVI file!" << std::endl;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void mainLogic(){
|
||||
AnimationConfig config;
|
||||
// std::cout << "g2c2175" << std::endl;
|
||||
|
||||
Grid2 grid = setup(config);
|
||||
// std::cout << "g2c2178" << std::endl;
|
||||
Preview(grid);
|
||||
std::vector<std::tuple<size_t, Vec2, Vec4>> seeds = pickSeeds(grid,config);
|
||||
std::vector<frame> frames;
|
||||
|
||||
for (int i = 0; i < config.totalFrames; ++i){
|
||||
expandPixel(grid,config,seeds);
|
||||
|
||||
// Print compression info for this frame
|
||||
if (i % 10 == 0 ) {
|
||||
frame bgrframe;
|
||||
std::cout << "Processing frame " << i + 1 << "/" << config.totalFrames << std::endl;
|
||||
bgrframe = grid.getGridAsFrame(frame::colormap::BGR);
|
||||
bgrframe.printCompressionStats();
|
||||
//(bgrframe, i + 1);
|
||||
frames.push_back(bgrframe);
|
||||
//bgrframe.decompress();
|
||||
//BMPWriter::saveBMP(std::format("output/grayscalesource.{}.bmp", i), bgrframe);
|
||||
bgrframe.compressFrameLZ78();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
exportavi(frames,config);
|
||||
}
|
||||
|
||||
int main() {
|
||||
static bool window = true;
|
||||
ImGui::SetNextWindowSize(ImVec2(1110,667));
|
||||
auto beg = ImGui::Begin("Gradient thing", &window);
|
||||
if (beg) {
|
||||
|
||||
ImGui::SetCursorPos(ImVec2(435.5,200));
|
||||
ImGui::PushItemWidth(200);
|
||||
static int i1 = 123;
|
||||
ImGui::InputInt("Width", &i1);
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
ImGui::SetCursorPos(ImVec2(432,166));
|
||||
ImGui::PushItemWidth(200);
|
||||
static int i2 = 123;
|
||||
ImGui::InputInt("Height", &i2);
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
ImGui::SetCursorPos(ImVec2(533.5,271));
|
||||
ImGui::Button("Start", ImVec2(43,19)); //remove size argument (ImVec2) to auto-resize
|
||||
|
||||
ImGui::SetCursorPos(ImVec2(400.5,366));
|
||||
ImGui::PushItemWidth(200);
|
||||
static int i6 = 123;
|
||||
ImGui::InputInt("number of Seeds", &i6);
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
}
|
||||
ImGui::End();
|
||||
FunctionTimer::printStats(FunctionTimer::Mode::ENHANCED);
|
||||
return 0;
|
||||
}
|
||||
@@ -6,20 +6,20 @@
|
||||
|
||||
class SpriteMap2 : public Grid2 {
|
||||
private:
|
||||
|
||||
// id, sprite
|
||||
std::unordered_map<size_t, frame> spritesComped;
|
||||
std::unordered_map<size_t, int> Layers;
|
||||
std::unordered_map<size_t, float> Orientations;
|
||||
|
||||
public:
|
||||
|
||||
using Grid2::Grid2;
|
||||
|
||||
size_t addSprite(const Vec2& pos, frame sprite, int layer = 0, float orientation = 0.0f) {
|
||||
size_t id = addObject(pos, Vec4(0,0,0,0));
|
||||
spritesComped[id] = sprite;
|
||||
Layers[id] = layer;
|
||||
Orientations[id] = orientation;
|
||||
return id;
|
||||
}
|
||||
|
||||
frame getSprite(size_t id) {
|
||||
@@ -42,13 +42,15 @@ public:
|
||||
float getOrientation(size_t id) {
|
||||
return Orientations.at(id);
|
||||
}
|
||||
|
||||
size_t setOrientation(size_t id, float orientation) {
|
||||
Orientations[id] = orientation;
|
||||
return id;
|
||||
}
|
||||
|
||||
void getGridRegionAsBGR(const Vec2& minCorner, const Vec2& maxCorner, int& width, int& height, std::vector<uint8_t>& rgbData) const {
|
||||
TIME_FUNCTION;
|
||||
// std::cout << "excessdebug g2.483" << std::endl;
|
||||
|
||||
// Calculate dimensions
|
||||
width = static_cast<int>(maxCorner.x - minCorner.x);
|
||||
height = static_cast<int>(maxCorner.y - minCorner.y);
|
||||
@@ -59,17 +61,105 @@ public:
|
||||
rgbData.shrink_to_fit();
|
||||
return;
|
||||
}
|
||||
// std::cout << "excessdebug g2.494" << std::endl;
|
||||
|
||||
// Initialize RGB data (3 bytes per pixel: R, G, B)
|
||||
// Initialize RGBA buffer for compositing
|
||||
std::vector<Vec4> rgbaBuffer(width * height, Vec4(0.0f, 0.0f, 0.0f, 0.0f));
|
||||
|
||||
// For each position in the grid, find the corresponding pixel
|
||||
// Group sprites by layer for proper rendering order
|
||||
std::vector<std::pair<int, size_t>> layeredSprites;
|
||||
for (const auto& [id, pos] : Positions) {
|
||||
// std::cout << "excessdebug g2.501." << id << std::endl;
|
||||
if (spritesComped.find(id) != spritesComped.end()) {
|
||||
layeredSprites.emplace_back(Layers.at(id), id);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by layer (lower layers first)
|
||||
std::sort(layeredSprites.begin(), layeredSprites.end(),
|
||||
[](const auto& a, const auto& b) { return a.first < b.first; });
|
||||
|
||||
// Render each sprite in layer order
|
||||
for (const auto& [layer, id] : layeredSprites) {
|
||||
const Vec2& pos = Positions.at(id);
|
||||
const frame& sprite = spritesComped.at(id);
|
||||
float orientation = Orientations.at(id);
|
||||
|
||||
// Decompress sprite if needed
|
||||
frame decompressedSprite = sprite;
|
||||
if (sprite.isCompressed()) {
|
||||
decompressedSprite.decompress();
|
||||
}
|
||||
|
||||
const std::vector<uint8_t>& spriteData = decompressedSprite.getData();
|
||||
size_t spriteWidth = decompressedSprite.getWidth();
|
||||
size_t spriteHeight = decompressedSprite.getHeight();
|
||||
|
||||
if (spriteData.empty() || spriteWidth == 0 || spriteHeight == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Calculate sprite bounds in world coordinates
|
||||
float halfWidth = spriteWidth / 2.0f;
|
||||
float halfHeight = spriteHeight / 2.0f;
|
||||
|
||||
// Apply rotation if needed
|
||||
// TODO: Implement proper rotation transformation
|
||||
int pixelXm = static_cast<int>(pos.x - halfWidth - minCorner.x);
|
||||
int pixelXM = static_cast<int>(pos.x + halfWidth - minCorner.x);
|
||||
int pixelYm = static_cast<int>(pos.y - halfHeight - minCorner.y);
|
||||
int pixelYM = static_cast<int>(pos.y + halfHeight - minCorner.y);
|
||||
|
||||
// Clamp to output bounds
|
||||
pixelXm = std::max(0, pixelXm);
|
||||
pixelXM = std::min(width - 1, pixelXM);
|
||||
pixelYm = std::max(0, pixelYm);
|
||||
pixelYM = std::min(height - 1, pixelYM);
|
||||
|
||||
// Skip if completely outside bounds
|
||||
if (pixelXm >= width || pixelXM < 0 || pixelYm >= height || pixelYM < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Render sprite pixels
|
||||
for (int py = pixelYm; py <= pixelYM; ++py) {
|
||||
for (int px = pixelXm; px <= pixelXM; ++px) {
|
||||
// Calculate sprite-relative coordinates
|
||||
int spriteX = px - pixelXm;
|
||||
int spriteY = py - pixelYm;
|
||||
|
||||
// Skip if outside sprite bounds
|
||||
if (spriteX < 0 || spriteX >= spriteWidth || spriteY < 0 || spriteY >= spriteHeight) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get sprite pixel color based on color format
|
||||
Vec4 spriteColor = getSpritePixelColor(spriteData, spriteX, spriteY, spriteWidth, spriteHeight, decompressedSprite.colorFormat);
|
||||
|
||||
// Alpha blending
|
||||
int bufferIndex = py * width + px;
|
||||
Vec4& dest = rgbaBuffer[bufferIndex];
|
||||
|
||||
float srcAlpha = spriteColor.a;
|
||||
if (srcAlpha > 0.0f) {
|
||||
float invSrcAlpha = 1.0f - srcAlpha;
|
||||
dest.r = spriteColor.r * srcAlpha + dest.r * invSrcAlpha;
|
||||
dest.g = spriteColor.g * srcAlpha + dest.g * invSrcAlpha;
|
||||
dest.b = spriteColor.b * srcAlpha + dest.b * invSrcAlpha;
|
||||
dest.a = srcAlpha + dest.a * invSrcAlpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Also render regular colored objects (from base class)
|
||||
for (const auto& [id, pos] : Positions) {
|
||||
// Skip if this is a sprite (already rendered above)
|
||||
if (spritesComped.find(id) != spritesComped.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t size = Sizes.at(id);
|
||||
|
||||
// Calculate pixel coordinates
|
||||
// Calculate pixel coordinates for colored objects
|
||||
int pixelXm = static_cast<int>(pos.x - size/2 - minCorner.x);
|
||||
int pixelXM = static_cast<int>(pos.x + size/2 - minCorner.x);
|
||||
int pixelYm = static_cast<int>(pos.y - size/2 - minCorner.y);
|
||||
@@ -79,42 +169,36 @@ public:
|
||||
pixelXM = std::min(width - 1, pixelXM);
|
||||
pixelYm = std::max(0, pixelYm);
|
||||
pixelYM = std::min(height - 1, pixelYM);
|
||||
// std::cout << "excessdebug g2.514." << id << std::endl;
|
||||
|
||||
// Ensure within bounds
|
||||
if (pixelXM >= minCorner.x && pixelXm < width && pixelYM >= minCorner.y && pixelYm < height) {
|
||||
// std::cout << "excessdebug g2.518." << id << " - (" << pixelXm << "," << pixelYM << ")" << std::endl;
|
||||
const Vec4& color = Colors.at(id);
|
||||
float srcAlpha = color.a;
|
||||
float invSrcAlpha = 1.0f - srcAlpha;
|
||||
for (int py = pixelYm; py <= pixelYM; ++py){
|
||||
for (int px = pixelXm; px <= pixelXM; ++px){
|
||||
// std::cout << "excessdebug g2.524." << id << " - (" << py << "," << px << ")" << std::endl;
|
||||
int index = (py * width + px);
|
||||
Vec4 dest = rgbaBuffer[index];
|
||||
for (int py = pixelYm; py <= pixelYM; ++py) {
|
||||
for (int px = pixelXm; px <= pixelXM; ++px) {
|
||||
int index = py * width + px;
|
||||
Vec4& dest = rgbaBuffer[index];
|
||||
|
||||
dest.r = color.r * srcAlpha + dest.r; // * invSrcAlpha;
|
||||
dest.g = color.g * srcAlpha + dest.g; // * invSrcAlpha;
|
||||
dest.b = color.b * srcAlpha + dest.b; // * invSrcAlpha;
|
||||
dest.a = srcAlpha + dest.a; // * invSrcAlpha;
|
||||
rgbaBuffer[index] = dest;
|
||||
float invSrcAlpha = 1.0f - srcAlpha;
|
||||
dest.r = color.r * srcAlpha + dest.r * invSrcAlpha;
|
||||
dest.g = color.g * srcAlpha + dest.g * invSrcAlpha;
|
||||
dest.b = color.b * srcAlpha + dest.b * invSrcAlpha;
|
||||
dest.a = srcAlpha + dest.a * invSrcAlpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert RGBA buffer to BGR output
|
||||
rgbData.resize(rgbaBuffer.size() * 3);
|
||||
for (int i = 0; i < rgbaBuffer.size(); ++i) {
|
||||
for (size_t i = 0; i < rgbaBuffer.size(); ++i) {
|
||||
const Vec4& color = rgbaBuffer[i];
|
||||
int bgrIndex = i * 3;
|
||||
|
||||
// Convert from [0,1] to [0,255] and store as RGB
|
||||
// rgbData.push_back(color.r);
|
||||
// rgbData.push_back(color.g);
|
||||
// rgbData.push_back(color.b);
|
||||
rgbData[bgrIndex + 2] = static_cast<unsigned char>(color.r * 255);
|
||||
rgbData[bgrIndex + 1] = static_cast<unsigned char>(color.g * 255);
|
||||
rgbData[bgrIndex + 0] = static_cast<unsigned char>(color.b * 255);
|
||||
size_t bgrIndex = i * 3;
|
||||
|
||||
// Convert from [0,1] to [0,255] and store as BGR
|
||||
rgbData[bgrIndex + 2] = static_cast<uint8_t>(color.r * 255); // R -> third position
|
||||
rgbData[bgrIndex + 1] = static_cast<uint8_t>(color.g * 255); // G -> second position
|
||||
rgbData[bgrIndex + 0] = static_cast<uint8_t>(color.b * 255); // B -> first position
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,6 +240,68 @@ public:
|
||||
return spritesComped.size();
|
||||
}
|
||||
|
||||
private:
|
||||
// Helper function to extract pixel color from sprite data based on color format
|
||||
Vec4 getSpritePixelColor(const std::vector<uint8_t>& spriteData,
|
||||
int x, int y,
|
||||
size_t spriteWidth, size_t spriteHeight,
|
||||
frame::colormap format) const {
|
||||
size_t pixelIndex = y * spriteWidth + x;
|
||||
size_t channels = 3; // Default to RGB
|
||||
|
||||
switch (format) {
|
||||
case frame::colormap::RGB:
|
||||
channels = 3;
|
||||
if (pixelIndex * channels + 2 < spriteData.size()) {
|
||||
return Vec4(spriteData[pixelIndex * channels] / 255.0f,
|
||||
spriteData[pixelIndex * channels + 1] / 255.0f,
|
||||
spriteData[pixelIndex * channels + 2] / 255.0f,
|
||||
1.0f);
|
||||
}
|
||||
break;
|
||||
|
||||
case frame::colormap::RGBA:
|
||||
channels = 4;
|
||||
if (pixelIndex * channels + 3 < spriteData.size()) {
|
||||
return Vec4(spriteData[pixelIndex * channels] / 255.0f,
|
||||
spriteData[pixelIndex * channels + 1] / 255.0f,
|
||||
spriteData[pixelIndex * channels + 2] / 255.0f,
|
||||
spriteData[pixelIndex * channels + 3] / 255.0f);
|
||||
}
|
||||
break;
|
||||
|
||||
case frame::colormap::BGR:
|
||||
channels = 3;
|
||||
if (pixelIndex * channels + 2 < spriteData.size()) {
|
||||
return Vec4(spriteData[pixelIndex * channels + 2] / 255.0f, // BGR -> RGB
|
||||
spriteData[pixelIndex * channels + 1] / 255.0f,
|
||||
spriteData[pixelIndex * channels] / 255.0f,
|
||||
1.0f);
|
||||
}
|
||||
break;
|
||||
|
||||
case frame::colormap::BGRA:
|
||||
channels = 4;
|
||||
if (pixelIndex * channels + 3 < spriteData.size()) {
|
||||
return Vec4(spriteData[pixelIndex * channels + 2] / 255.0f, // BGRA -> RGBA
|
||||
spriteData[pixelIndex * channels + 1] / 255.0f,
|
||||
spriteData[pixelIndex * channels] / 255.0f,
|
||||
spriteData[pixelIndex * channels + 3] / 255.0f);
|
||||
}
|
||||
break;
|
||||
|
||||
case frame::colormap::B:
|
||||
channels = 1;
|
||||
if (pixelIndex < spriteData.size()) {
|
||||
float value = spriteData[pixelIndex] / 255.0f;
|
||||
return Vec4(value, value, value, 1.0f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Return transparent black if out of bounds
|
||||
return Vec4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user