lots of improvements and changes. trying to fix grid being bad.
This commit is contained in:
@@ -22,6 +22,10 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
|
#ifndef M_PI
|
||||||
|
#define M_PI = 3.1415
|
||||||
|
#endif
|
||||||
|
|
||||||
std::mutex m;
|
std::mutex m;
|
||||||
std::atomic<bool> isGenerating{false};
|
std::atomic<bool> isGenerating{false};
|
||||||
std::future<void> generationFuture;
|
std::future<void> generationFuture;
|
||||||
@@ -109,7 +113,7 @@ std::vector<std::tuple<size_t, Vec2, Vec4>> pickSeeds(Grid2 grid, AnimationConfi
|
|||||||
for (int i = 0; i < config.numSeeds; ++i) {
|
for (int i = 0; i < config.numSeeds; ++i) {
|
||||||
Vec2 point(xDist(gen), yDist(gen));
|
Vec2 point(xDist(gen), yDist(gen));
|
||||||
Vec4 color(colorDist(gen), colorDist(gen), colorDist(gen), 255);
|
Vec4 color(colorDist(gen), colorDist(gen), colorDist(gen), 255);
|
||||||
size_t id = grid.getPositionVec(point);
|
size_t id = grid.getOrCreatePositionVec(point, 0.0, true);
|
||||||
grid.setColor(id, color);
|
grid.setColor(id, color);
|
||||||
seeds.push_back(std::make_tuple(id,point, color));
|
seeds.push_back(std::make_tuple(id,point, color));
|
||||||
}
|
}
|
||||||
@@ -220,10 +224,16 @@ bool exportavi(std::vector<frame> frames, AnimationConfig config) {
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mainLogic(const AnimationConfig& config, Shared& state) {
|
void mainLogic(const AnimationConfig& config, Shared& state, int gradnoise) {
|
||||||
isGenerating = true;
|
isGenerating = true;
|
||||||
try {
|
try {
|
||||||
Grid2 grid = setup(config);
|
Grid2 grid;
|
||||||
|
if (gradnoise == 0) {
|
||||||
|
grid = setup(config);
|
||||||
|
} else if (gradnoise == 1) {
|
||||||
|
grid = grid.noiseGenGrid(0,0,config.height, config.width);
|
||||||
|
}
|
||||||
|
grid.setDefault(Vec4(0,0,0,0));
|
||||||
{
|
{
|
||||||
std:: lock_guard<std::mutex> lock(state.mutex);
|
std:: lock_guard<std::mutex> lock(state.mutex);
|
||||||
state.grid = grid;
|
state.grid = grid;
|
||||||
@@ -364,12 +374,14 @@ int main() {
|
|||||||
static int i2 = 1024;
|
static int i2 = 1024;
|
||||||
static int i3 = 480;
|
static int i3 = 480;
|
||||||
static int i4 = 8;
|
static int i4 = 8;
|
||||||
|
static float fs = 1.0;
|
||||||
|
|
||||||
std::future<void> mainlogicthread;
|
std::future<void> mainlogicthread;
|
||||||
Shared state;
|
Shared state;
|
||||||
Grid2 grid;
|
Grid2 grid;
|
||||||
AnimationConfig config;
|
AnimationConfig config;
|
||||||
previewText = "Please generate";
|
previewText = "Please generate";
|
||||||
|
int gradnoise = true;
|
||||||
while (!glfwWindowShouldClose(window)) {
|
while (!glfwWindowShouldClose(window)) {
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
|
|
||||||
@@ -379,13 +391,16 @@ int main() {
|
|||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
{
|
{
|
||||||
|
|
||||||
ImGui::Begin("Gradient settings");
|
ImGui::Begin("settings");
|
||||||
|
|
||||||
ImGui::SliderFloat("fps", &f, 20.0f, 60.0f);
|
ImGui::SliderFloat("fps", &f, 20.0f, 60.0f);
|
||||||
ImGui::SliderInt("width", &i1, 256, 4096);
|
ImGui::SliderInt("width", &i1, 256, 4096);
|
||||||
ImGui::SliderInt("height", &i2, 256, 4096);
|
ImGui::SliderInt("height", &i2, 256, 4096);
|
||||||
ImGui::SliderInt("framecount", &i3, 10, 5000);
|
ImGui::SliderInt("framecount", &i3, 10, 5000);
|
||||||
ImGui::SliderInt("numSeeds", &i4, 0, 10);
|
ImGui::SliderInt("numSeeds", &i4, 0, 10);
|
||||||
|
ImGui::SliderFloat("ScalePreview", &fs, 0.0, 2.0);
|
||||||
|
ImGui::RadioButton("Gradient", &gradnoise, 0);
|
||||||
|
ImGui::RadioButton("Perlin Noise", &gradnoise, 1);
|
||||||
|
|
||||||
if (isGenerating) {
|
if (isGenerating) {
|
||||||
ImGui::BeginDisabled();
|
ImGui::BeginDisabled();
|
||||||
@@ -393,17 +408,16 @@ int main() {
|
|||||||
|
|
||||||
if (ImGui::Button("Generate Animation")) {
|
if (ImGui::Button("Generate Animation")) {
|
||||||
config = AnimationConfig(i1, i2, i3, f, i4);
|
config = AnimationConfig(i1, i2, i3, f, i4);
|
||||||
mainlogicthread = std::async(std::launch::async, mainLogic, config, std::ref(state));
|
mainlogicthread = std::async(std::launch::async, mainLogic, config, std::ref(state), gradnoise);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isGenerating) {
|
if (isGenerating && textu != 0) {
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Button("Cancel")) {
|
if (ImGui::Button("Cancel")) {
|
||||||
cancelGeneration();
|
cancelGeneration();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for new frames from the generation thread
|
// Check for new frames from the generation thread
|
||||||
bool hasNewFrame = false;
|
bool hasNewFrame = false;
|
||||||
{
|
{
|
||||||
@@ -418,7 +432,41 @@ int main() {
|
|||||||
ImGui::Text(previewText.c_str());
|
ImGui::Text(previewText.c_str());
|
||||||
|
|
||||||
if (textu != 0) {
|
if (textu != 0) {
|
||||||
ImVec2 imageSize = ImVec2(config.width * 0.3f, config.height * 0.3f); // Scale down for preview
|
ImVec2 imageSize = ImVec2(config.width * fs, config.height * fs);
|
||||||
|
ImVec2 uv_min = ImVec2(0.0f, 0.0f);
|
||||||
|
ImVec2 uv_max = ImVec2(1.0f, 1.0f);
|
||||||
|
ImGui::Image((void*)(intptr_t)textu, imageSize, uv_min, uv_max);
|
||||||
|
} else {
|
||||||
|
ImGui::Text("Generating preview...");
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (isGenerating) {
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Cancel")) {
|
||||||
|
cancelGeneration();
|
||||||
|
}
|
||||||
|
// Check for new frames from the generation thread
|
||||||
|
bool hasNewFrame = false;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(state.mutex);
|
||||||
|
if (state.hasNewFrame) {
|
||||||
|
livePreview(state.grid);
|
||||||
|
state.hasNewFrame = false;
|
||||||
|
previewText = "Generating... Frame: " + std::to_string(state.currentFrame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Text(previewText.c_str());
|
||||||
|
|
||||||
|
} else if (textu != 0){
|
||||||
|
//ImGui::EndDisabled();
|
||||||
|
|
||||||
|
ImGui::Text(previewText.c_str());
|
||||||
|
|
||||||
|
if (textu != 0) {
|
||||||
|
ImVec2 imageSize = ImVec2(config.width * 0.5f, config.height * 0.5f);
|
||||||
ImVec2 uv_min = ImVec2(0.0f, 0.0f);
|
ImVec2 uv_min = ImVec2(0.0f, 0.0f);
|
||||||
ImVec2 uv_max = ImVec2(1.0f, 1.0f);
|
ImVec2 uv_max = ImVec2(1.0f, 1.0f);
|
||||||
ImGui::Image((void*)(intptr_t)textu, imageSize, uv_min, uv_max);
|
ImGui::Image((void*)(intptr_t)textu, imageSize, uv_min, uv_max);
|
||||||
@@ -474,5 +522,4 @@ int main() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
//I need this: https://raais.github.io/ImStudio/
|
//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 -lstb `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
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "../vectorlogic/vec4.hpp"
|
#include "../vectorlogic/vec4.hpp"
|
||||||
#include "../timing_decorator.hpp"
|
#include "../timing_decorator.hpp"
|
||||||
#include "../output/frame.hpp"
|
#include "../output/frame.hpp"
|
||||||
|
#include "../noise/pnoise2.hpp"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
@@ -195,16 +196,90 @@ protected:
|
|||||||
SpatialGrid spatialGrid;
|
SpatialGrid spatialGrid;
|
||||||
float spatialCellSize = 2.0f;
|
float spatialCellSize = 2.0f;
|
||||||
|
|
||||||
|
// Default background color for empty spaces
|
||||||
|
Vec4 defaultBackgroundColor = Vec4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
PNoise2 noisegen;
|
||||||
public:
|
public:
|
||||||
bool usable = false;
|
bool usable = false;
|
||||||
|
|
||||||
|
// Set default background color for empty spaces
|
||||||
|
void setDefault(const Vec4& color) {
|
||||||
|
defaultBackgroundColor = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDefault(float r, float g, float b, float a = 0.0f) {
|
||||||
|
defaultBackgroundColor = Vec4(r, g, b, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get current default background color
|
||||||
|
Vec4 getDefaultBackgroundColor() const {
|
||||||
|
return defaultBackgroundColor;
|
||||||
|
}
|
||||||
|
|
||||||
//get position from id
|
//get position from id
|
||||||
Vec2 getPositionID(size_t id) const {
|
Vec2 getPositionID(size_t id) const {
|
||||||
Vec2 it = Positions.at(id);
|
Vec2 it = Positions.at(id);
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Grid2 noiseGenGrid(size_t minx,size_t miny, size_t maxx, size_t maxy
|
||||||
|
, float minChance = 0.1f, float maxChance = 1.0f, bool color = true) {
|
||||||
|
std::vector<Vec2> poses;
|
||||||
|
std::vector<Vec4> colors;
|
||||||
|
std::vector<float> sizes;
|
||||||
|
for (int x = minx; x < maxx; x++) {
|
||||||
|
for (int y = miny; y < maxy; y++) {
|
||||||
|
Vec2 pos = Vec2(x,y);
|
||||||
|
float alpha = noisegen.permute(Vec2(x,y));
|
||||||
|
if (alpha > minChance && alpha < maxChance) {
|
||||||
|
if (color) {
|
||||||
|
float red = noisegen.permute(pos);
|
||||||
|
float green = noisegen.permute(pos);
|
||||||
|
float blue = noisegen.permute(pos);
|
||||||
|
Vec4 newc = Vec4(red,green,blue,alpha);
|
||||||
|
colors.push_back(newc);
|
||||||
|
poses.push_back(pos);
|
||||||
|
sizes.push_back(1.0f);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Vec4 newc = Vec4(alpha,alpha,alpha,alpha);
|
||||||
|
colors.push_back(newc);
|
||||||
|
poses.push_back(pos);
|
||||||
|
sizes.push_back(1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bulkAddObjects(poses,colors,sizes);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t NoiseGenPointB(const Vec2& pos) {
|
||||||
|
float grayc = noisegen.permute(pos);
|
||||||
|
Vec4 newc = Vec4(grayc,grayc,grayc,grayc);
|
||||||
|
return addObject(pos,newc,1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t NoiseGenPointRGB(const Vec2& pos) {
|
||||||
|
float red = noisegen.permute(pos);
|
||||||
|
float green = noisegen.permute(pos);
|
||||||
|
float blue = noisegen.permute(pos);
|
||||||
|
Vec4 newc = Vec4(red,green,blue,1);
|
||||||
|
return addObject(pos,newc,1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t NoiseGenPointRGBA(const Vec2& pos) {
|
||||||
|
float red = noisegen.permute(pos);
|
||||||
|
float green = noisegen.permute(pos);
|
||||||
|
float blue = noisegen.permute(pos);
|
||||||
|
float alpha = noisegen.permute(pos);
|
||||||
|
Vec4 newc = Vec4(red,green,blue,alpha);
|
||||||
|
return addObject(pos,newc,1.0);
|
||||||
|
}
|
||||||
|
|
||||||
//get id from position (optional radius, picks first found. radius of 0 becomes epsilon if none are found)
|
//get id from position (optional radius, picks first found. radius of 0 becomes epsilon if none are found)
|
||||||
size_t getPositionVec(const Vec2& pos, float radius = 0.0f) {
|
size_t getPositionVec(const Vec2& pos, float radius = 0.0f) const {
|
||||||
TIME_FUNCTION;
|
TIME_FUNCTION;
|
||||||
if (radius == 0.0f) {
|
if (radius == 0.0f) {
|
||||||
// Exact match - use spatial grid to find the cell
|
// Exact match - use spatial grid to find the cell
|
||||||
@@ -227,12 +302,41 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t getPositionVec(float x, float y, float radius = 0.0f) {
|
size_t getOrCreatePositionVec(const Vec2& pos, float radius = 0.0f, bool create = false) {
|
||||||
|
TIME_FUNCTION;
|
||||||
|
if (radius == 0.0f) {
|
||||||
|
// Exact match - use spatial grid to find the cell
|
||||||
|
Vec2 gridPos = spatialGrid.worldToGrid(pos);
|
||||||
|
auto cellIt = spatialGrid.grid.find(gridPos);
|
||||||
|
if (cellIt != spatialGrid.grid.end()) {
|
||||||
|
for (size_t id : cellIt->second) {
|
||||||
|
if (Positions.at(id) == pos) {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (create) {
|
||||||
|
return addObject(pos, defaultBackgroundColor, 1.0f);
|
||||||
|
}
|
||||||
|
throw std::out_of_range("Position not found");
|
||||||
|
} else {
|
||||||
|
auto results = getPositionVecRegion(pos, radius);
|
||||||
|
if (!results.empty()) {
|
||||||
|
return results[0]; // Return first found
|
||||||
|
}
|
||||||
|
if (create) {
|
||||||
|
return addObject(pos, defaultBackgroundColor, 1.0f);
|
||||||
|
}
|
||||||
|
throw std::out_of_range("No positions found in radius");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t getPositionVec(float x, float y, float radius = 0.0f) const {
|
||||||
return getPositionVec(Vec2(x,y), radius);
|
return getPositionVec(Vec2(x,y), radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
//get all id in region
|
//get all id in region
|
||||||
std::vector<size_t> getPositionVecRegion(const Vec2& pos, float radius = 1.0f) {
|
std::vector<size_t> getPositionVecRegion(const Vec2& pos, float radius = 1.0f) const {
|
||||||
TIME_FUNCTION;
|
TIME_FUNCTION;
|
||||||
float searchRadius = (radius == 0.0f) ? std::numeric_limits<float>::epsilon() : radius;
|
float searchRadius = (radius == 0.0f) ? std::numeric_limits<float>::epsilon() : radius;
|
||||||
|
|
||||||
@@ -483,7 +587,6 @@ public:
|
|||||||
void getGridRegionAsRGB(const Vec2& minCorner, const Vec2& maxCorner,
|
void getGridRegionAsRGB(const Vec2& minCorner, const Vec2& maxCorner,
|
||||||
int& width, int& height, std::vector<uint8_t>& rgbData) const {
|
int& width, int& height, std::vector<uint8_t>& rgbData) const {
|
||||||
TIME_FUNCTION;
|
TIME_FUNCTION;
|
||||||
// std::cout << "excessdebug g2.483" << std::endl;
|
|
||||||
// Calculate dimensions
|
// Calculate dimensions
|
||||||
width = static_cast<int>(maxCorner.x - minCorner.x);
|
width = static_cast<int>(maxCorner.x - minCorner.x);
|
||||||
height = static_cast<int>(maxCorner.y - minCorner.y);
|
height = static_cast<int>(maxCorner.y - minCorner.y);
|
||||||
@@ -494,14 +597,19 @@ public:
|
|||||||
rgbData.shrink_to_fit();
|
rgbData.shrink_to_fit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// std::cout << "excessdebug g2.494" << std::endl;
|
|
||||||
|
|
||||||
// Initialize RGB data (3 bytes per pixel: R, G, B)
|
// Initialize RGB data with default background color
|
||||||
std::vector<Vec4> rgbaBuffer(width * height, Vec4(0.0f, 0.0f, 0.0f, 0.0f));
|
std::vector<Vec4> rgbaBuffer(width * height, Vec4(0,0,0,0));
|
||||||
|
|
||||||
|
// for (int x = minCorner.x; x < maxCorner.x; x++) {
|
||||||
|
// for (int y = minCorner.y; x < maxCorner.y; y++){
|
||||||
|
// Vec2 pos = Vec2(x,y);
|
||||||
|
// size_t posID = getPositionVec(pos, 1.0f, false);
|
||||||
|
|
||||||
|
// }
|
||||||
|
// }
|
||||||
// For each position in the grid, find the corresponding pixel
|
// For each position in the grid, find the corresponding pixel
|
||||||
for (const auto& [id, pos] : Positions) {
|
for (const auto& [id, pos] : Positions) {
|
||||||
// std::cout << "excessdebug g2.501." << id << std::endl;
|
|
||||||
size_t size = Sizes.at(id);
|
size_t size = Sizes.at(id);
|
||||||
|
|
||||||
// Calculate pixel coordinates
|
// Calculate pixel coordinates
|
||||||
@@ -514,65 +622,69 @@ public:
|
|||||||
pixelXM = std::min(width - 1, pixelXM);
|
pixelXM = std::min(width - 1, pixelXM);
|
||||||
pixelYm = std::max(0, pixelYm);
|
pixelYm = std::max(0, pixelYm);
|
||||||
pixelYM = std::min(height - 1, pixelYM);
|
pixelYM = std::min(height - 1, pixelYM);
|
||||||
// std::cout << "excessdebug g2.514." << id << std::endl;
|
|
||||||
|
|
||||||
// Ensure within bounds
|
// Ensure within bounds
|
||||||
if (pixelXM >= minCorner.x && pixelXm < width && pixelYM >= minCorner.y && pixelYm < height) {
|
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);
|
const Vec4& color = Colors.at(id);
|
||||||
float srcAlpha = color.a;
|
float srcAlpha = color.a;
|
||||||
float invSrcAlpha = 1.0f - srcAlpha;
|
float invSrcAlpha = 1.0f - srcAlpha;
|
||||||
for (int py = pixelYm; py <= pixelYM; ++py){
|
for (int py = pixelYm; py <= pixelYM; ++py){
|
||||||
for (int px = pixelXm; px <= pixelXM; ++px){
|
for (int px = pixelXm; px <= pixelXM; ++px){
|
||||||
// std::cout << "excessdebug g2.524." << id << " - (" << py << "," << px << ")" << std::endl;
|
|
||||||
int index = (py * width + px);
|
int index = (py * width + px);
|
||||||
Vec4 dest = rgbaBuffer[index];
|
Vec4 dest = rgbaBuffer[index];
|
||||||
|
|
||||||
dest.r = color.r * srcAlpha + dest.r; // * invSrcAlpha;
|
// Alpha blending: new_color = src * src_alpha + dest * (1 - src_alpha)
|
||||||
dest.g = color.g * srcAlpha + dest.g; // * invSrcAlpha;
|
dest.r = color.r * srcAlpha + dest.r * invSrcAlpha;
|
||||||
dest.b = color.b * srcAlpha + dest.b; // * invSrcAlpha;
|
dest.g = color.g * srcAlpha + dest.g * invSrcAlpha;
|
||||||
dest.a = srcAlpha + dest.a; // * invSrcAlpha;
|
dest.b = color.b * srcAlpha + dest.b * invSrcAlpha;
|
||||||
|
dest.a = srcAlpha + dest.a * invSrcAlpha;
|
||||||
rgbaBuffer[index] = dest;
|
rgbaBuffer[index] = dest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert to RGB bytes
|
||||||
rgbData.resize(rgbaBuffer.size() * 3);
|
rgbData.resize(rgbaBuffer.size() * 3);
|
||||||
for (int i = 0; i < rgbaBuffer.size(); ++i) {
|
for (int i = 0; i < rgbaBuffer.size(); ++i) {
|
||||||
const Vec4& color = rgbaBuffer[i];
|
Vec4& color = rgbaBuffer[i];
|
||||||
int bgrIndex = i * 3;
|
int rgbIndex = i * 3;
|
||||||
|
float alpha = color.a;
|
||||||
|
|
||||||
|
if (alpha < 1.0) {
|
||||||
|
float invalpha = 1.0 - alpha;
|
||||||
|
color.r = defaultBackgroundColor.r * alpha + color.r * invalpha;
|
||||||
|
color.g = defaultBackgroundColor.g * alpha + color.g * invalpha;
|
||||||
|
color.b = defaultBackgroundColor.b * alpha + color.b * invalpha;
|
||||||
|
}
|
||||||
|
|
||||||
// Convert from [0,1] to [0,255] and store as RGB
|
// Convert from [0,1] to [0,255] and store as RGB
|
||||||
rgbData[bgrIndex + 0] = static_cast<unsigned char>(color.r * 255);
|
rgbData[rgbIndex + 0] = static_cast<unsigned char>(color.r * 255);
|
||||||
rgbData[bgrIndex + 1] = static_cast<unsigned char>(color.g * 255);
|
rgbData[rgbIndex + 1] = static_cast<unsigned char>(color.g * 255);
|
||||||
rgbData[bgrIndex + 2] = static_cast<unsigned char>(color.b * 255);
|
rgbData[rgbIndex + 2] = static_cast<unsigned char>(color.b * 255);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get region as BGR
|
// Get region as BGR
|
||||||
void getGridRegionAsBGR(const Vec2& minCorner, const Vec2& maxCorner,
|
void getGridRegionAsBGR(const Vec2& minCorner, const Vec2& maxCorner,
|
||||||
int& width, int& height, std::vector<uint8_t>& rgbData) const {
|
int& width, int& height, std::vector<uint8_t>& bgrData) const {
|
||||||
TIME_FUNCTION;
|
TIME_FUNCTION;
|
||||||
// std::cout << "excessdebug g2.483" << std::endl;
|
|
||||||
// Calculate dimensions
|
// Calculate dimensions
|
||||||
width = static_cast<int>(maxCorner.x - minCorner.x);
|
width = static_cast<int>(maxCorner.x - minCorner.x);
|
||||||
height = static_cast<int>(maxCorner.y - minCorner.y);
|
height = static_cast<int>(maxCorner.y - minCorner.y);
|
||||||
|
|
||||||
if (width <= 0 || height <= 0) {
|
if (width <= 0 || height <= 0) {
|
||||||
width = height = 0;
|
width = height = 0;
|
||||||
rgbData.clear();
|
bgrData.clear();
|
||||||
rgbData.shrink_to_fit();
|
bgrData.shrink_to_fit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// std::cout << "excessdebug g2.494" << std::endl;
|
|
||||||
|
|
||||||
// Initialize RGB data (3 bytes per pixel: R, G, B)
|
// Initialize RGB data with default background color
|
||||||
std::vector<Vec4> rgbaBuffer(width * height, Vec4(0.0f, 0.0f, 0.0f, 0.0f));
|
std::vector<Vec4> rgbaBuffer(width * height, defaultBackgroundColor);
|
||||||
|
|
||||||
// For each position in the grid, find the corresponding pixel
|
// For each position in the grid, find the corresponding pixel
|
||||||
for (const auto& [id, pos] : Positions) {
|
for (const auto& [id, pos] : Positions) {
|
||||||
// std::cout << "excessdebug g2.501." << id << std::endl;
|
|
||||||
size_t size = Sizes.at(id);
|
size_t size = Sizes.at(id);
|
||||||
|
|
||||||
// Calculate pixel coordinates
|
// Calculate pixel coordinates
|
||||||
@@ -585,68 +697,61 @@ public:
|
|||||||
pixelXM = std::min(width - 1, pixelXM);
|
pixelXM = std::min(width - 1, pixelXM);
|
||||||
pixelYm = std::max(0, pixelYm);
|
pixelYm = std::max(0, pixelYm);
|
||||||
pixelYM = std::min(height - 1, pixelYM);
|
pixelYM = std::min(height - 1, pixelYM);
|
||||||
// std::cout << "excessdebug g2.514." << id << std::endl;
|
|
||||||
|
|
||||||
// Ensure within bounds
|
// Ensure within bounds
|
||||||
if (pixelXM >= minCorner.x && pixelXm < width && pixelYM >= minCorner.y && pixelYm < height) {
|
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);
|
const Vec4& color = Colors.at(id);
|
||||||
float srcAlpha = color.a;
|
float srcAlpha = color.a;
|
||||||
float invSrcAlpha = 1.0f - srcAlpha;
|
float invSrcAlpha = 1.0f - srcAlpha;
|
||||||
for (int py = pixelYm; py <= pixelYM; ++py){
|
for (int py = pixelYm; py <= pixelYM; ++py){
|
||||||
for (int px = pixelXm; px <= pixelXM; ++px){
|
for (int px = pixelXm; px <= pixelXM; ++px){
|
||||||
// std::cout << "excessdebug g2.524." << id << " - (" << py << "," << px << ")" << std::endl;
|
|
||||||
int index = (py * width + px);
|
int index = (py * width + px);
|
||||||
Vec4 dest = rgbaBuffer[index];
|
Vec4 dest = rgbaBuffer[index];
|
||||||
|
|
||||||
dest.r = color.r * srcAlpha + dest.r; // * invSrcAlpha;
|
// Alpha blending: new_color = src * src_alpha + dest * (1 - src_alpha)
|
||||||
dest.g = color.g * srcAlpha + dest.g; // * invSrcAlpha;
|
dest.r = color.r * srcAlpha + dest.r * invSrcAlpha;
|
||||||
dest.b = color.b * srcAlpha + dest.b; // * invSrcAlpha;
|
dest.g = color.g * srcAlpha + dest.g * invSrcAlpha;
|
||||||
dest.a = srcAlpha + dest.a; // * invSrcAlpha;
|
dest.b = color.b * srcAlpha + dest.b * invSrcAlpha;
|
||||||
|
dest.a = srcAlpha + dest.a * invSrcAlpha;
|
||||||
rgbaBuffer[index] = dest;
|
rgbaBuffer[index] = dest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rgbData.resize(rgbaBuffer.size() * 3);
|
|
||||||
|
// Convert to BGR bytes
|
||||||
|
bgrData.resize(rgbaBuffer.size() * 3);
|
||||||
for (int i = 0; i < rgbaBuffer.size(); ++i) {
|
for (int i = 0; i < rgbaBuffer.size(); ++i) {
|
||||||
const Vec4& color = rgbaBuffer[i];
|
const Vec4& color = rgbaBuffer[i];
|
||||||
int bgrIndex = i * 3;
|
int bgrIndex = i * 3;
|
||||||
|
|
||||||
// Convert from [0,1] to [0,255] and store as RGB
|
// Convert from [0,1] to [0,255] and store as BGR
|
||||||
// rgbData.push_back(color.r);
|
bgrData[bgrIndex + 2] = static_cast<unsigned char>(color.r * 255);
|
||||||
// rgbData.push_back(color.g);
|
bgrData[bgrIndex + 1] = static_cast<unsigned char>(color.g * 255);
|
||||||
// rgbData.push_back(color.b);
|
bgrData[bgrIndex + 0] = static_cast<unsigned char>(color.b * 255);
|
||||||
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);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void getGridRegionAsRGBA(const Vec2& minCorner, const Vec2& maxCorner,
|
void getGridRegionAsRGBA(const Vec2& minCorner, const Vec2& maxCorner,
|
||||||
int& width, int& height, std::vector<uint8_t>& rgbData) const {
|
int& width, int& height, std::vector<uint8_t>& rgbaData) const {
|
||||||
TIME_FUNCTION;
|
TIME_FUNCTION;
|
||||||
// std::cout << "excessdebug g2.483" << std::endl;
|
|
||||||
// Calculate dimensions
|
// Calculate dimensions
|
||||||
width = static_cast<int>(maxCorner.x - minCorner.x);
|
width = static_cast<int>(maxCorner.x - minCorner.x);
|
||||||
height = static_cast<int>(maxCorner.y - minCorner.y);
|
height = static_cast<int>(maxCorner.y - minCorner.y);
|
||||||
|
|
||||||
if (width <= 0 || height <= 0) {
|
if (width <= 0 || height <= 0) {
|
||||||
width = height = 0;
|
width = height = 0;
|
||||||
rgbData.clear();
|
rgbaData.clear();
|
||||||
rgbData.shrink_to_fit();
|
rgbaData.shrink_to_fit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// std::cout << "excessdebug g2.494" << std::endl;
|
|
||||||
|
|
||||||
// Initialize RGB data (3 bytes per pixel: R, G, B)
|
// Initialize RGBA data with default background color
|
||||||
std::vector<Vec4> rgbaBuffer(width * height, Vec4(0.0f, 0.0f, 0.0f, 0.0f));
|
std::vector<Vec4> rgbaBuffer(width * height, defaultBackgroundColor);
|
||||||
|
|
||||||
// For each position in the grid, find the corresponding pixel
|
// For each position in the grid, find the corresponding pixel
|
||||||
for (const auto& [id, pos] : Positions) {
|
for (const auto& [id, pos] : Positions) {
|
||||||
// std::cout << "excessdebug g2.501." << id << std::endl;
|
|
||||||
size_t size = Sizes.at(id);
|
size_t size = Sizes.at(id);
|
||||||
|
|
||||||
// Calculate pixel coordinates
|
// Calculate pixel coordinates
|
||||||
@@ -659,40 +764,39 @@ public:
|
|||||||
pixelXM = std::min(width - 1, pixelXM);
|
pixelXM = std::min(width - 1, pixelXM);
|
||||||
pixelYm = std::max(0, pixelYm);
|
pixelYm = std::max(0, pixelYm);
|
||||||
pixelYM = std::min(height - 1, pixelYM);
|
pixelYM = std::min(height - 1, pixelYM);
|
||||||
// std::cout << "excessdebug g2.514." << id << std::endl;
|
|
||||||
|
|
||||||
// Ensure within bounds
|
// Ensure within bounds
|
||||||
if (pixelXM >= minCorner.x && pixelXm < width && pixelYM >= minCorner.y && pixelYm < height) {
|
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);
|
const Vec4& color = Colors.at(id);
|
||||||
float srcAlpha = color.a;
|
float srcAlpha = color.a;
|
||||||
float invSrcAlpha = 1.0f - srcAlpha;
|
float invSrcAlpha = 1.0f - srcAlpha;
|
||||||
for (int py = pixelYm; py <= pixelYM; ++py){
|
for (int py = pixelYm; py <= pixelYM; ++py){
|
||||||
for (int px = pixelXm; px <= pixelXM; ++px){
|
for (int px = pixelXm; px <= pixelXM; ++px){
|
||||||
// std::cout << "excessdebug g2.524." << id << " - (" << py << "," << px << ")" << std::endl;
|
|
||||||
int index = (py * width + px);
|
int index = (py * width + px);
|
||||||
Vec4 dest = rgbaBuffer[index];
|
Vec4 dest = rgbaBuffer[index];
|
||||||
|
|
||||||
dest.r = color.r * srcAlpha + dest.r; // * invSrcAlpha;
|
// Alpha blending: new_color = src * src_alpha + dest * (1 - src_alpha)
|
||||||
dest.g = color.g * srcAlpha + dest.g; // * invSrcAlpha;
|
dest.r = color.r * srcAlpha + dest.r * invSrcAlpha;
|
||||||
dest.b = color.b * srcAlpha + dest.b; // * invSrcAlpha;
|
dest.g = color.g * srcAlpha + dest.g * invSrcAlpha;
|
||||||
dest.a = srcAlpha + dest.a; // * invSrcAlpha;
|
dest.b = color.b * srcAlpha + dest.b * invSrcAlpha;
|
||||||
|
dest.a = srcAlpha + dest.a * invSrcAlpha;
|
||||||
rgbaBuffer[index] = dest;
|
rgbaBuffer[index] = dest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rgbData.resize(rgbaBuffer.size() * 4);
|
|
||||||
|
// Convert to RGBA bytes
|
||||||
|
rgbaData.resize(rgbaBuffer.size() * 4);
|
||||||
for (int i = 0; i < rgbaBuffer.size(); ++i) {
|
for (int i = 0; i < rgbaBuffer.size(); ++i) {
|
||||||
const Vec4& color = rgbaBuffer[i];
|
const Vec4& color = rgbaBuffer[i];
|
||||||
int bgrIndex = i * 4;
|
int rgbaIndex = i * 4;
|
||||||
|
|
||||||
// Convert from [0,1] to [0,255] and store as RGB
|
// Convert from [0,1] to [0,255] and store as RGBA
|
||||||
rgbData[bgrIndex + 0] = static_cast<unsigned char>(color.r * 255);
|
rgbaData[rgbaIndex + 0] = static_cast<unsigned char>(color.r * 255);
|
||||||
rgbData[bgrIndex + 1] = static_cast<unsigned char>(color.g * 255);
|
rgbaData[rgbaIndex + 1] = static_cast<unsigned char>(color.g * 255);
|
||||||
rgbData[bgrIndex + 2] = static_cast<unsigned char>(color.b * 255);
|
rgbaData[rgbaIndex + 2] = static_cast<unsigned char>(color.b * 255);
|
||||||
rgbData[bgrIndex + 2] = static_cast<unsigned char>(color.a * 255);
|
rgbaData[rgbaIndex + 3] = static_cast<unsigned char>(color.a * 255);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -724,11 +828,11 @@ public:
|
|||||||
frame getGridRegionAsFrameRGBA(const Vec2& minCorner, const Vec2& maxCorner) const {
|
frame getGridRegionAsFrameRGBA(const Vec2& minCorner, const Vec2& maxCorner) const {
|
||||||
TIME_FUNCTION;
|
TIME_FUNCTION;
|
||||||
int width, height;
|
int width, height;
|
||||||
std::vector<uint8_t> rgbData;
|
std::vector<uint8_t> rgbaData;
|
||||||
getGridRegionAsRGBA(minCorner, maxCorner, width, height, rgbData);
|
getGridRegionAsRGBA(minCorner, maxCorner, width, height, rgbaData);
|
||||||
|
|
||||||
frame resultFrame(width, height, frame::colormap::RGB);
|
frame resultFrame(width, height, frame::colormap::RGBA);
|
||||||
resultFrame.setData(rgbData);
|
resultFrame.setData(rgbaData);
|
||||||
return resultFrame;
|
return resultFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -837,6 +941,8 @@ public:
|
|||||||
Colors.rehash(0);
|
Colors.rehash(0);
|
||||||
Sizes.rehash(0);
|
Sizes.rehash(0);
|
||||||
neighborMap.rehash(0);
|
neighborMap.rehash(0);
|
||||||
|
// Reset to default background color
|
||||||
|
defaultBackgroundColor = Vec4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// neighbor map
|
// neighbor map
|
||||||
|
|||||||
@@ -20,17 +20,58 @@ public:
|
|||||||
permutation[i] = i;
|
permutation[i] = i;
|
||||||
}
|
}
|
||||||
std::ranges::shuffle(permutation, rng);
|
std::ranges::shuffle(permutation, rng);
|
||||||
TR = permutation[permutation[1]+1];
|
permutation.insert(permutation.end(),permutation.begin(),permutation.end());
|
||||||
TR = permutation[permutation[0]+1];
|
|
||||||
TR = permutation[permutation[1]+0];
|
|
||||||
TR = permutation[permutation[0]+0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec2 GetConstantVector(Vec2 v) {
|
float permute(Vec2 point) {
|
||||||
Vec2 h = v & 3;
|
float x = point.x;
|
||||||
|
float y = point.y;
|
||||||
|
int X = (int)floor(x);
|
||||||
|
int xmod = X & 255;
|
||||||
|
int Y = (int)floor(point.y);
|
||||||
|
int ymod = Y & 255;
|
||||||
|
float xf = point.x - X;
|
||||||
|
float yf = point.y - Y;
|
||||||
|
|
||||||
|
Vec2 TR = Vec2(xf-1, yf-1);
|
||||||
|
Vec2 TL = Vec2(xf-0, yf-1);
|
||||||
|
Vec2 BR = Vec2(xf-1, yf-0);
|
||||||
|
Vec2 BL = Vec2(xf-0, yf-0);
|
||||||
|
|
||||||
|
int vTR = permutation[permutation[xmod+1]+ymod+1];
|
||||||
|
int vTL = permutation[permutation[xmod+0]+ymod+1];
|
||||||
|
int vBR = permutation[permutation[xmod+1]+ymod+0];
|
||||||
|
int vBL = permutation[permutation[xmod+0]+ymod+0];
|
||||||
|
|
||||||
|
float dTR = TR.dot(GetConstantVector(vTR));
|
||||||
|
float dTL = TL.dot(GetConstantVector(vTL));
|
||||||
|
float dBR = BR.dot(GetConstantVector(vBR));
|
||||||
|
float dBL = BL.dot(GetConstantVector(vBL));
|
||||||
|
|
||||||
|
float u = Fade(xf);
|
||||||
|
float v = Fade(yf);
|
||||||
|
|
||||||
|
return lerp(u,lerp(v,dBL,dTL),lerp(v,dBR,dTR));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
float lerp(float t, float a1, float a2) {
|
||||||
|
return a1 + t * (a2 - a1);
|
||||||
|
}
|
||||||
|
|
||||||
|
float Fade(float t) {
|
||||||
|
return (((6 * t - 15)* t + 10) * t * t * t);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 GetConstantVector(float v) {
|
||||||
|
int h = (int)v & 3;
|
||||||
|
if (h == 0) return Vec2(1,1);
|
||||||
|
else if (h == 1) return Vec2(-1,1);
|
||||||
|
else if (h == 2) return Vec2(-1,-1);
|
||||||
|
else return Vec2(1,-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
//https://rtouti.github.io/graphics/perlin-noise-algorithm
|
//https://rtouti.github.io/graphics/perlin-noise-algorithm
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ public:
|
|||||||
x = y = z = w = scalar;
|
x = y = z = w = scalar;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec4& operator+=(const Vec4& other) {
|
Vec4& operator+=(const Vec4& other) {
|
||||||
x += other.x;
|
x += other.x;
|
||||||
y += other.y;
|
y += other.y;
|
||||||
|
|||||||
Reference in New Issue
Block a user