better g2chromatic.cpp
This commit is contained in:
@@ -3,17 +3,19 @@
|
|||||||
#include <random>
|
#include <random>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <tuple>
|
||||||
|
#include <unordered_set>
|
||||||
#include "../util/grid/grid22.hpp"
|
#include "../util/grid/grid22.hpp"
|
||||||
#include "../util/output/aviwriter.hpp"
|
#include "../util/output/aviwriter.hpp"
|
||||||
#include "../util/output/bmpwriter.hpp"
|
#include "../util/output/bmpwriter.hpp"
|
||||||
#include "../util/timing_decorator.cpp"
|
#include "../util/timing_decorator.cpp"
|
||||||
|
|
||||||
struct AnimationConfig {
|
struct AnimationConfig {
|
||||||
int width = 1024;
|
int width = 128;
|
||||||
int height = 1024;
|
int height = 128;
|
||||||
int totalFrames = 480;
|
int totalFrames = 480;
|
||||||
float fps = 30.0f;
|
float fps = 30.0f;
|
||||||
int numSeeds = 1;
|
int numSeeds = 8;
|
||||||
};
|
};
|
||||||
|
|
||||||
Grid2 setup(AnimationConfig config) {
|
Grid2 setup(AnimationConfig config) {
|
||||||
@@ -44,7 +46,7 @@ void Preview(Grid2 grid) {
|
|||||||
bool success = BMPWriter::saveBMP("output/grayscalesource.bmp", rgbData, width, height);
|
bool success = BMPWriter::saveBMP("output/grayscalesource.bmp", rgbData, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::pair<Vec2, Vec4>> pickSeeds(Grid2 grid, AnimationConfig config) {
|
std::vector<std::tuple<size_t, Vec2, Vec4>> pickSeeds(Grid2 grid, AnimationConfig config) {
|
||||||
TIME_FUNCTION;
|
TIME_FUNCTION;
|
||||||
std::random_device rd;
|
std::random_device rd;
|
||||||
std::mt19937 gen(rd());
|
std::mt19937 gen(rd());
|
||||||
@@ -52,39 +54,74 @@ std::vector<std::pair<Vec2, Vec4>> pickSeeds(Grid2 grid, AnimationConfig config)
|
|||||||
std::uniform_int_distribution<> yDist(0, config.height - 1);
|
std::uniform_int_distribution<> yDist(0, config.height - 1);
|
||||||
std::uniform_real_distribution<> colorDist(0.2f, 0.8f);
|
std::uniform_real_distribution<> colorDist(0.2f, 0.8f);
|
||||||
|
|
||||||
std::vector<std::pair<Vec2, Vec4>> seeds;
|
std::vector<std::tuple<size_t, Vec2, Vec4>> seeds;
|
||||||
|
|
||||||
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), colorDist(gen));
|
Vec4 color(colorDist(gen), colorDist(gen), colorDist(gen), 1.0f);
|
||||||
seeds.push_back(std::make_pair(point, color));
|
size_t id = grid.getPositionVec(point);
|
||||||
// Or in C++17 and later, you can use:
|
grid.setColor(id, color);
|
||||||
// seeds.push_back({point, color});
|
seeds.push_back(std::make_tuple(id,point, color));
|
||||||
}
|
|
||||||
for (int i = 0; i < seeds.size(); ++i) {
|
|
||||||
size_t id = grid.getPositionVec(seeds[i].first);
|
|
||||||
grid.setColor(id,seeds[i].second);
|
|
||||||
}
|
}
|
||||||
return seeds;
|
return seeds;
|
||||||
}
|
}
|
||||||
|
|
||||||
void expandPixel(Grid2& grid, AnimationConfig config, std::vector<std::pair<Vec2, Vec4>> seeds) {
|
void expandPixel(Grid2& grid, AnimationConfig config, std::vector<std::tuple<size_t, Vec2, Vec4>>& seeds, std::unordered_set<size_t>& visited) {
|
||||||
TIME_FUNCTION;
|
TIME_FUNCTION;
|
||||||
for (int i = 0; i < seeds.size(); ++i) {
|
std::vector<std::tuple<size_t, Vec2, Vec4>> newseeds;
|
||||||
size_t id = grid.getPositionVec(seeds[i].first);
|
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);
|
std::vector<size_t> neighbors = grid.getNeighbors(id);
|
||||||
for (int j = 0; j < neighbors.size(); ++j) {
|
for (size_t neighbor : neighbors) {
|
||||||
size_t neighbor = neighbors[j];
|
if (visited.find(neighbor) != visited.end()) {
|
||||||
|
continue; // Skip already processed neighbors
|
||||||
|
}
|
||||||
|
visited.insert(neighbor);
|
||||||
|
Vec2 neipos = grid.getPositionID(neighbor);
|
||||||
Vec4 neighborColor = grid.getColor(neighbor);
|
Vec4 neighborColor = grid.getColor(neighbor);
|
||||||
Vec4 newcolor = (neighborColor - seeds[i].second) / float(config.width + config.height - 2);
|
float distance = seedPOS.distance(neipos);
|
||||||
|
float angle = seedPOS.angleTo(neipos);
|
||||||
|
Vec4 newcolor = Vec4(neighborColor.r * ((1.1f + angle) * std::sin(seedColor.r)),
|
||||||
|
neighborColor.g * ((1.1f + angle) * std::sin(seedColor.g)),
|
||||||
|
neighborColor.b * ((1.1f + angle) * std::sin(seedColor.b)),
|
||||||
|
1.0f
|
||||||
|
);
|
||||||
grid.setColor(neighbor, newcolor);
|
grid.setColor(neighbor, newcolor);
|
||||||
|
newseeds.push_back({neighbor, neipos,newcolor});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
seeds = newseeds;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool exportavi(std::vector<std::vector<uint8_t>> frames, AnimationConfig config) {
|
bool exportavi(std::vector<std::vector<uint8_t>> frames, AnimationConfig config) {
|
||||||
TIME_FUNCTION;
|
TIME_FUNCTION;
|
||||||
bool success = AVIWriter::saveAVI("output/g2chromatic.avi", frames, config.width, config.height);
|
std::string filename = "output/chromatic_transformation.avi";
|
||||||
|
|
||||||
|
std::cout << "Frame count: " << frames.size() << std::endl;
|
||||||
|
std::cout << "Frame size: " << (frames.empty() ? 0 : frames[0].size()) << std::endl;
|
||||||
|
std::cout << "Width: " << config.width << ", Height: " << config.height << 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::saveAVI(filename, frames, config.width+1, config.height+1, config.fps);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
// Check if file actually exists
|
||||||
|
if (std::filesystem::exists(filename)) {
|
||||||
|
auto file_size = std::filesystem::file_size(filename);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::cout << "Failed to save AVI file!" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,11 +131,15 @@ int main() {
|
|||||||
Grid2 grid = setup(config);
|
Grid2 grid = setup(config);
|
||||||
grid.updateNeighborMap();
|
grid.updateNeighborMap();
|
||||||
Preview(grid);
|
Preview(grid);
|
||||||
std::vector<std::pair<Vec2, Vec4>> seeds = pickSeeds(grid,config);
|
std::vector<std::tuple<size_t, Vec2, Vec4>> seeds = pickSeeds(grid,config);
|
||||||
std::vector<std::vector<uint8_t>> frames;
|
std::vector<std::vector<uint8_t>> frames;
|
||||||
|
|
||||||
|
//memory aid
|
||||||
|
std::unordered_set<size_t> visited;
|
||||||
|
|
||||||
for (int i = 0; i < config.totalFrames; ++i){
|
for (int i = 0; i < config.totalFrames; ++i){
|
||||||
std::cout << "Processing frame " << i + 1 << "/" << config.totalFrames << std::endl;
|
std::cout << "Processing frame " << i + 1 << "/" << config.totalFrames << std::endl;
|
||||||
expandPixel(grid,config,seeds);
|
expandPixel(grid,config,seeds, visited);
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
std::vector<uint8_t> frame;
|
std::vector<uint8_t> frame;
|
||||||
@@ -106,7 +147,7 @@ int main() {
|
|||||||
frames.push_back(frame);
|
frames.push_back(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exportavi(frames,config);
|
||||||
FunctionTimer::printStats(FunctionTimer::Mode::ENHANCED);
|
FunctionTimer::printStats(FunctionTimer::Mode::ENHANCED);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -90,13 +90,16 @@ public:
|
|||||||
Colors[id] = color;
|
Colors[id] = color;
|
||||||
Sizes[id] = size;
|
Sizes[id] = size;
|
||||||
return id;
|
return id;
|
||||||
|
updateNeighborForID(id);
|
||||||
}
|
}
|
||||||
//set position by id
|
//set position by id
|
||||||
void setPosition(size_t id, const Vec2& position) {
|
void setPosition(size_t id, const Vec2& position) {
|
||||||
Positions.at(id).move(position);
|
Positions.at(id).move(position);
|
||||||
|
updateNeighborForID(id);
|
||||||
}
|
}
|
||||||
void setPosition(size_t id, float x, float y) {
|
void setPosition(size_t id, float x, float y) {
|
||||||
Positions.at(id).move(Vec2(x,y));
|
Positions.at(id).move(Vec2(x,y));
|
||||||
|
updateNeighborForID(id);
|
||||||
}
|
}
|
||||||
//set color by id (by pos same as get color)
|
//set color by id (by pos same as get color)
|
||||||
void setColor(size_t id, const Vec4 color) {
|
void setColor(size_t id, const Vec4 color) {
|
||||||
@@ -140,7 +143,7 @@ public:
|
|||||||
Colors.erase(id);
|
Colors.erase(id);
|
||||||
Sizes.erase(id);
|
Sizes.erase(id);
|
||||||
unassignedIDs.push_back(id);
|
unassignedIDs.push_back(id);
|
||||||
|
updateNeighborForID(id);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
size_t removeID(Vec2 pos) {
|
size_t removeID(Vec2 pos) {
|
||||||
@@ -149,7 +152,7 @@ public:
|
|||||||
Colors.erase(id);
|
Colors.erase(id);
|
||||||
Sizes.erase(id);
|
Sizes.erase(id);
|
||||||
unassignedIDs.push_back(id);
|
unassignedIDs.push_back(id);
|
||||||
|
updateNeighborForID(id);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,6 +165,7 @@ public:
|
|||||||
it->second = newPos;
|
it->second = newPos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
updateNeighborMap();
|
||||||
}
|
}
|
||||||
// Bulk update colors
|
// Bulk update colors
|
||||||
void bulkUpdateColors(const std::unordered_map<size_t, Vec4>& newColors) {
|
void bulkUpdateColors(const std::unordered_map<size_t, Vec4>& newColors) {
|
||||||
|
|||||||
@@ -260,6 +260,11 @@ class Vec2 {
|
|||||||
float angleTo(const Vec2& other) const {
|
float angleTo(const Vec2& other) const {
|
||||||
return std::acos(this->dot(other) / (this->length() * other.length()));
|
return std::acos(this->dot(other) / (this->length() * other.length()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float directionTo(const Vec2& other) const {
|
||||||
|
Vec2 direction = other - *this;
|
||||||
|
return direction.angle();
|
||||||
|
}
|
||||||
|
|
||||||
float& operator[](int index) {
|
float& operator[](int index) {
|
||||||
return (&x)[index];
|
return (&x)[index];
|
||||||
|
|||||||
Reference in New Issue
Block a user