made vec templates.
This commit is contained in:
@@ -56,16 +56,16 @@ struct AnimationConfig {
|
|||||||
Grid3 setup(AnimationConfig config) {
|
Grid3 setup(AnimationConfig config) {
|
||||||
TIME_FUNCTION;
|
TIME_FUNCTION;
|
||||||
Grid3 grid;
|
Grid3 grid;
|
||||||
std::vector<Vec3> pos;
|
std::vector<Vec3f> pos;
|
||||||
std::vector<Vec4> colors;
|
std::vector<Vec4ui8> colors;
|
||||||
for (int x = 0; x < config.height; ++x) {
|
for (int x = 0; x < config.height; ++x) {
|
||||||
float r = (x / config.height) * 255;
|
float r = (x / config.height) * 255;
|
||||||
for (int y = 0; y < config.width; ++y) {
|
for (int y = 0; y < config.width; ++y) {
|
||||||
float g = (y / config.height) * 255;
|
float g = (y / config.height) * 255;
|
||||||
for (int z = 0; z < config.depth; ++z) {
|
for (int z = 0; z < config.depth; ++z) {
|
||||||
float b = (z / config.height) * 255;
|
float b = (z / config.height) * 255;
|
||||||
pos.push_back(Vec3(x,y,z));
|
pos.push_back(Vec3f(x,y,z));
|
||||||
colors.push_back(Vec4(r, g, b, 1.0f));
|
colors.push_back(Vec4ui8(r, g, b, 1.0f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,7 +76,7 @@ Grid3 setup(AnimationConfig config) {
|
|||||||
void Preview(AnimationConfig config, Grid3& grid) {
|
void Preview(AnimationConfig config, Grid3& grid) {
|
||||||
TIME_FUNCTION;
|
TIME_FUNCTION;
|
||||||
|
|
||||||
frame rgbData = grid.getGridAsFrame(Vec2(config.width, config.height), Ray3(Vec3(config.width + 10,config.height + 10,config.depth + 10), Vec3(0)), frame::colormap::RGB);
|
frame rgbData = grid.getGridAsFrame(Vec2(config.width, config.height), Ray3(Vec3f(config.width + 10,config.height + 10,config.depth + 10), Vec3f(0)), frame::colormap::RGB);
|
||||||
std::cout << "Frame looks like: " << rgbData << std::endl;
|
std::cout << "Frame looks like: " << rgbData << std::endl;
|
||||||
bool success = BMPWriter::saveBMP("output/grayscalesource3d.bmp", rgbData);
|
bool success = BMPWriter::saveBMP("output/grayscalesource3d.bmp", rgbData);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@@ -87,7 +87,7 @@ void Preview(AnimationConfig config, Grid3& grid) {
|
|||||||
void livePreview(const Grid3& grid, AnimationConfig config) {
|
void livePreview(const Grid3& grid, AnimationConfig config) {
|
||||||
// std::lock_guard<std::mutex> lock(previewMutex);
|
// std::lock_guard<std::mutex> lock(previewMutex);
|
||||||
|
|
||||||
// currentPreviewFrame = grid.getGridAsFrame(Vec2(config.width, config.height), Ray3(Vec3(config.width + 10,config.height + 10,config.depth + 10), Vec3(0)), frame::colormap::RGBA);
|
// currentPreviewFrame = grid.getGridAsFrame(Vec2(config.width, config.height), Ray3(Vec3f(config.width + 10,config.height + 10,config.depth + 10), Vec3f(0)), frame::colormap::RGBA);
|
||||||
|
|
||||||
// glGenTextures(1, &textu);
|
// glGenTextures(1, &textu);
|
||||||
// glBindTexture(GL_TEXTURE_2D, textu);
|
// glBindTexture(GL_TEXTURE_2D, textu);
|
||||||
@@ -102,7 +102,7 @@ void livePreview(const Grid3& grid, AnimationConfig config) {
|
|||||||
// updatePreview = true;
|
// updatePreview = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::tuple<size_t, Vec3, Vec4>> pickSeeds(Grid3& grid, AnimationConfig config) {
|
std::vector<std::tuple<size_t, Vec3f, Vec4ui8>> pickSeeds(Grid3& grid, AnimationConfig config) {
|
||||||
TIME_FUNCTION;
|
TIME_FUNCTION;
|
||||||
// std::cout << "picking seeds" << std::endl;
|
// std::cout << "picking seeds" << std::endl;
|
||||||
std::random_device rd;
|
std::random_device rd;
|
||||||
@@ -112,11 +112,11 @@ std::vector<std::tuple<size_t, Vec3, Vec4>> pickSeeds(Grid3& grid, AnimationConf
|
|||||||
std::uniform_int_distribution<> zDist(0, config.depth - 1);
|
std::uniform_int_distribution<> zDist(0, config.depth - 1);
|
||||||
std::uniform_real_distribution<> colorDist(0.2f, 0.8f);
|
std::uniform_real_distribution<> colorDist(0.2f, 0.8f);
|
||||||
|
|
||||||
std::vector<std::tuple<size_t, Vec3, Vec4>> seeds;
|
std::vector<std::tuple<size_t, Vec3f, Vec4ui8>> seeds;
|
||||||
|
|
||||||
for (int i = 0; i < config.numSeeds; ++i) {
|
for (int i = 0; i < config.numSeeds; ++i) {
|
||||||
Vec3 point(xDist(gen), yDist(gen), zDist(gen));
|
Vec3f point(xDist(gen), yDist(gen), zDist(gen));
|
||||||
Vec4 color(colorDist(gen), colorDist(gen), colorDist(gen), 255);
|
Vec4ui8 color(colorDist(gen), colorDist(gen), colorDist(gen), 255);
|
||||||
bool foundValidPos;
|
bool foundValidPos;
|
||||||
int maxTries = 0;
|
int maxTries = 0;
|
||||||
while (!foundValidPos && maxTries < 10) {
|
while (!foundValidPos && maxTries < 10) {
|
||||||
@@ -132,10 +132,10 @@ std::vector<std::tuple<size_t, Vec3, Vec4>> pickSeeds(Grid3& grid, AnimationConf
|
|||||||
return seeds;
|
return seeds;
|
||||||
}
|
}
|
||||||
|
|
||||||
void expandPixel(Grid3& grid, AnimationConfig config, std::vector<std::tuple<size_t, Vec3, Vec4>>& seeds) {
|
void expandPixel(Grid3& grid, AnimationConfig config, std::vector<std::tuple<size_t, Vec3f, Vec4ui8>>& seeds) {
|
||||||
TIME_FUNCTION;
|
TIME_FUNCTION;
|
||||||
std::cout << "expanding pixel" << std::endl;
|
std::cout << "expanding pixel" << std::endl;
|
||||||
std::vector<std::tuple<size_t, Vec3, Vec4>> newseeds;
|
std::vector<std::tuple<size_t, Vec3f, Vec4ui8>> newseeds;
|
||||||
|
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
std::unordered_set<size_t> visitedThisFrame;
|
std::unordered_set<size_t> visitedThisFrame;
|
||||||
@@ -144,10 +144,10 @@ void expandPixel(Grid3& grid, AnimationConfig config, std::vector<std::tuple<siz
|
|||||||
}
|
}
|
||||||
|
|
||||||
//std::cout << "counter at: " << counter++ << std::endl;
|
//std::cout << "counter at: " << counter++ << std::endl;
|
||||||
for (const std::tuple<size_t, Vec3, Vec4>& seed : seeds) {
|
for (const std::tuple<size_t, Vec3f, Vec4ui8>& seed : seeds) {
|
||||||
size_t id = std::get<0>(seed);
|
size_t id = std::get<0>(seed);
|
||||||
Vec3 seedPOS = std::get<1>(seed);
|
Vec3f seedPOS = std::get<1>(seed);
|
||||||
Vec4 seedColor = std::get<2>(seed);
|
Vec4ui8 seedColor = std::get<2>(seed);
|
||||||
std::vector<size_t> neighbors = grid.getNeighbors(id);
|
std::vector<size_t> neighbors = grid.getNeighbors(id);
|
||||||
for (size_t neighbor : neighbors) {
|
for (size_t neighbor : neighbors) {
|
||||||
std::cout << "counter at 1: " << counter++ << std::endl;
|
std::cout << "counter at 1: " << counter++ << std::endl;
|
||||||
@@ -155,13 +155,13 @@ void expandPixel(Grid3& grid, AnimationConfig config, std::vector<std::tuple<siz
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3 neipos;
|
Vec3f neipos;
|
||||||
try {
|
try {
|
||||||
neipos = grid.getPositionID(neighbor);
|
neipos = grid.getPositionID(neighbor);
|
||||||
} catch (const std::out_of_range& e) {
|
} catch (const std::out_of_range& e) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Vec4 neighborColor;
|
Vec4ui8 neighborColor;
|
||||||
try {
|
try {
|
||||||
neighborColor = grid.getColor(neighbor);
|
neighborColor = grid.getColor(neighbor);
|
||||||
} catch (const std::out_of_range& e) {
|
} catch (const std::out_of_range& e) {
|
||||||
@@ -170,7 +170,7 @@ void expandPixel(Grid3& grid, AnimationConfig config, std::vector<std::tuple<siz
|
|||||||
}
|
}
|
||||||
visitedThisFrame.insert(neighbor);
|
visitedThisFrame.insert(neighbor);
|
||||||
|
|
||||||
// Vec3 neipos = grid.getPositionID(neighbor);
|
// Vec3f neipos = grid.getPositionID(neighbor);
|
||||||
// Vec4 neighborColor = grid.getColor(neighbor);
|
// Vec4 neighborColor = grid.getColor(neighbor);
|
||||||
float distance = seedPOS.distance(neipos);
|
float distance = seedPOS.distance(neipos);
|
||||||
float angle = seedPOS.directionTo(neipos);
|
float angle = seedPOS.directionTo(neipos);
|
||||||
@@ -179,7 +179,7 @@ void expandPixel(Grid3& grid, AnimationConfig config, std::vector<std::tuple<siz
|
|||||||
float blendFactor = 0.3f + 0.4f * std::sin(normalizedAngle * 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);
|
blendFactor = std::clamp(blendFactor, 0.1f, 0.9f);
|
||||||
//std::cout << "counter at 2: " << counter++ << std::endl;
|
//std::cout << "counter at 2: " << counter++ << std::endl;
|
||||||
Vec4 newcolor = Vec4(
|
Vec4ui8 newcolor = Vec4ui8(
|
||||||
seedColor.r * blendFactor + neighborColor.r * (1.0f - blendFactor),
|
seedColor.r * blendFactor + neighborColor.r * (1.0f - blendFactor),
|
||||||
seedColor.g * (1.0f - blendFactor) + neighborColor.g * blendFactor,
|
seedColor.g * (1.0f - blendFactor) + neighborColor.g * blendFactor,
|
||||||
seedColor.b * (0.5f + 0.5f * std::sin(normalizedAngle * 4.0f * M_PI)),
|
seedColor.b * (0.5f + 0.5f * std::sin(normalizedAngle * 4.0f * M_PI)),
|
||||||
@@ -262,9 +262,9 @@ void mainLogic(const AnimationConfig& config, Shared& state, int gradnoise) {
|
|||||||
if (gradnoise == 0) {
|
if (gradnoise == 0) {
|
||||||
grid = setup(config);
|
grid = setup(config);
|
||||||
} else if (gradnoise == 1) {
|
} else if (gradnoise == 1) {
|
||||||
grid = grid.noiseGenGrid(Vec3(0, 0, 0), Vec3(config.height, config.width, config.depth), 0.01, 1.0, true, config.noisemod);
|
grid = grid.noiseGenGrid(Vec3f(0, 0, 0), Vec3f(config.height, config.width, config.depth), 0.01, 1.0, true, config.noisemod);
|
||||||
}
|
}
|
||||||
grid.setDefault(Vec4(0,0,0,0));
|
grid.setDefault(Vec4ui8(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;
|
||||||
@@ -274,7 +274,7 @@ void mainLogic(const AnimationConfig& config, Shared& state, int gradnoise) {
|
|||||||
std::cout << "generated grid" << std::endl;
|
std::cout << "generated grid" << std::endl;
|
||||||
Preview(config, grid);
|
Preview(config, grid);
|
||||||
std::cout << "generated preview" << std::endl;
|
std::cout << "generated preview" << std::endl;
|
||||||
std::vector<std::tuple<size_t, Vec3, Vec4>> seeds = pickSeeds(grid, config);
|
std::vector<std::tuple<size_t, Vec3f, Vec4ui8>> seeds = pickSeeds(grid, config);
|
||||||
std::vector<frame> frames;
|
std::vector<frame> frames;
|
||||||
|
|
||||||
for (int i = 0; i < config.totalFrames; ++i){
|
for (int i = 0; i < config.totalFrames; ++i){
|
||||||
@@ -294,7 +294,7 @@ void mainLogic(const AnimationConfig& config, Shared& state, int gradnoise) {
|
|||||||
//if (i % 10 == 0 ) {
|
//if (i % 10 == 0 ) {
|
||||||
frame bgrframe;
|
frame bgrframe;
|
||||||
std::cout << "Processing frame " << i + 1 << "/" << config.totalFrames << std::endl;
|
std::cout << "Processing frame " << i + 1 << "/" << config.totalFrames << std::endl;
|
||||||
bgrframe = grid.getGridAsFrame(Vec2(config.width,config.height), Ray3(Vec3(config.width + 10,config.height + 10,config.depth + 10), Vec3(0)), frame::colormap::BGR);
|
bgrframe = grid.getGridAsFrame(Vec2(config.width,config.height), Ray3(Vec3f(config.width + 10,config.height + 10,config.depth + 10), Vec3f(0)), frame::colormap::BGR);
|
||||||
frames.push_back(bgrframe);
|
frames.push_back(bgrframe);
|
||||||
// BMPWriter::saveBMP(std::format("output/grayscalesource3d.{}.bmp", i), bgrframe);
|
// BMPWriter::saveBMP(std::format("output/grayscalesource3d.{}.bmp", i), bgrframe);
|
||||||
bgrframe.compressFrameLZ78();
|
bgrframe.compressFrameLZ78();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#define GRID3_HPP
|
#define GRID3_HPP
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include "../vectorlogic/vec3.hpp"
|
#include "../vectorlogic/Vec3.hpp"
|
||||||
#include "../vectorlogic/vec4.hpp"
|
#include "../vectorlogic/vec4.hpp"
|
||||||
#include "../timing_decorator.hpp"
|
#include "../timing_decorator.hpp"
|
||||||
#include "../output/frame.hpp"
|
#include "../output/frame.hpp"
|
||||||
@@ -20,41 +20,41 @@ constexpr int CHUNK_SIZE = 16;
|
|||||||
class GenericVoxel {
|
class GenericVoxel {
|
||||||
protected:
|
protected:
|
||||||
size_t id;
|
size_t id;
|
||||||
Vec4 color;
|
Vec4ui8 color;
|
||||||
Vec3 pos;
|
Vec3f pos;
|
||||||
public:
|
public:
|
||||||
//constructors
|
//constructors
|
||||||
GenericVoxel(size_t id, Vec4 color, Vec3 pos) : id(id), color(color), pos(pos) {};
|
GenericVoxel(size_t id, Vec4ui8 color, Vec3f pos) : id(id), color(color), pos(pos) {};
|
||||||
GenericVoxel() : id(0), color(Vec4()), pos(Vec3()) {};
|
GenericVoxel() : id(0), color(Vec4ui8()), pos(Vec3f()) {};
|
||||||
|
|
||||||
//getters
|
//getters
|
||||||
size_t getId() const {
|
size_t getId() const {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
Vec3 getPos() const {
|
Vec3f getPos() const {
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec4 getColor() const {
|
Vec4ui8 getColor() const {
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
//setters
|
//setters
|
||||||
void setColor(Vec4 newColor) {
|
void setColor(Vec4ui8 newColor) {
|
||||||
color = newColor;
|
color = newColor;
|
||||||
}
|
}
|
||||||
void setPos(Vec3 newPos) {
|
void setPos(Vec3f newPos) {
|
||||||
pos = newPos;
|
pos = newPos;
|
||||||
}
|
}
|
||||||
void setId(size_t newId) {
|
void setId(size_t newId) {
|
||||||
id = newId;
|
id = newId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void move(Vec3 newPos) {
|
void move(Vec3f newPos) {
|
||||||
pos = newPos;
|
pos = newPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void recolor(Vec4 newColor) {
|
void recolor(Vec4ui8 newColor) {
|
||||||
color.recolor(newColor);
|
color.recolor(newColor);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -63,33 +63,33 @@ public:
|
|||||||
/// @details Maintains two hashmaps to allow O(1) lookup in either direction.
|
/// @details Maintains two hashmaps to allow O(1) lookup in either direction.
|
||||||
class reverselookupassistant3 {
|
class reverselookupassistant3 {
|
||||||
private:
|
private:
|
||||||
std::unordered_map<size_t, Vec3> Positions;
|
std::unordered_map<size_t, Vec3f> Positions;
|
||||||
/// "Positions" reversed - stores the reverse mapping from Vec3 to ID.
|
/// "Positions" reversed - stores the reverse mapping from Vec3f to ID.
|
||||||
std::unordered_map<Vec3, size_t, Vec3::Hash> ƨnoiƚiƨoꟼ;
|
std::unordered_map<Vec3f, size_t, Vec3f::Hash> ƨnoiƚiƨoꟼ;
|
||||||
size_t next_id;
|
size_t next_id;
|
||||||
public:
|
public:
|
||||||
/// @brief Get the Position associated with a specific ID.
|
/// @brief Get the Position associated with a specific ID.
|
||||||
/// @throws std::out_of_range if the ID does not exist.
|
/// @throws std::out_of_range if the ID does not exist.
|
||||||
Vec3 at(size_t id) const {
|
Vec3f at(size_t id) const {
|
||||||
auto it = Positions.at(id);
|
auto it = Positions.at(id);
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Get the ID associated with a specific Position.
|
/// @brief Get the ID associated with a specific Position.
|
||||||
/// @throws std::out_of_range if the Position does not exist.
|
/// @throws std::out_of_range if the Position does not exist.
|
||||||
size_t at(const Vec3& pos) const {
|
size_t at(const Vec3f& pos) const {
|
||||||
size_t id = ƨnoiƚiƨoꟼ.at(pos);
|
size_t id = ƨnoiƚiƨoꟼ.at(pos);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Finds a position by ID (Wrapper for at).
|
/// @brief Finds a position by ID (Wrapper for at).
|
||||||
Vec3 find(size_t id) {
|
Vec3f find(size_t id) {
|
||||||
return Positions.at(id);
|
return Positions.at(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Registers a new position and assigns it a unique ID.
|
/// @brief Registers a new position and assigns it a unique ID.
|
||||||
/// @return The newly generated ID.
|
/// @return The newly generated ID.
|
||||||
size_t set(const Vec3& pos) {
|
size_t set(const Vec3f& pos) {
|
||||||
size_t id = next_id++;
|
size_t id = next_id++;
|
||||||
Positions[id] = pos;
|
Positions[id] = pos;
|
||||||
ƨnoiƚiƨoꟼ[pos] = id;
|
ƨnoiƚiƨoꟼ[pos] = id;
|
||||||
@@ -98,14 +98,14 @@ public:
|
|||||||
|
|
||||||
/// @brief Removes an entry by ID.
|
/// @brief Removes an entry by ID.
|
||||||
size_t remove(size_t id) {
|
size_t remove(size_t id) {
|
||||||
Vec3& pos = Positions[id];
|
Vec3f& pos = Positions[id];
|
||||||
Positions.erase(id);
|
Positions.erase(id);
|
||||||
ƨnoiƚiƨoꟼ.erase(pos);
|
ƨnoiƚiƨoꟼ.erase(pos);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Removes an entry by Position.
|
/// @brief Removes an entry by Position.
|
||||||
size_t remove(const Vec3& pos) {
|
size_t remove(const Vec3f& pos) {
|
||||||
size_t id = ƨnoiƚiƨoꟼ[pos];
|
size_t id = ƨnoiƚiƨoꟼ[pos];
|
||||||
Positions.erase(id);
|
Positions.erase(id);
|
||||||
ƨnoiƚiƨoꟼ.erase(pos);
|
ƨnoiƚiƨoꟼ.erase(pos);
|
||||||
@@ -141,8 +141,8 @@ public:
|
|||||||
next_id = 0;
|
next_id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
using iterator = typename std::unordered_map<size_t, Vec3>::iterator;
|
using iterator = typename std::unordered_map<size_t, Vec3f>::iterator;
|
||||||
using const_iterator = typename std::unordered_map<size_t, Vec3>::const_iterator;
|
using const_iterator = typename std::unordered_map<size_t, Vec3f>::const_iterator;
|
||||||
|
|
||||||
iterator begin() {
|
iterator begin() {
|
||||||
return Positions.begin();
|
return Positions.begin();
|
||||||
@@ -167,31 +167,51 @@ public:
|
|||||||
return (Positions.find(id) != Positions.end());
|
return (Positions.find(id) != Positions.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool contains(const Vec3& pos) const {
|
bool contains(const Vec3f& pos) const {
|
||||||
return (ƨnoiƚiƨoꟼ.find(pos) != ƨnoiƚiƨoꟼ.end());
|
return (ƨnoiƚiƨoꟼ.find(pos) != ƨnoiƚiƨoꟼ.end());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Chunk3 : GenericVoxel {
|
class Chunk3 : public GenericVoxel {
|
||||||
private:
|
private:
|
||||||
Vec3 chunkCoord;
|
Vec3f chunkCoord;
|
||||||
std::unordered_set<size_t> voxelIDs;
|
std::unordered_set<size_t> voxelIDs;
|
||||||
std::vector<GenericVoxel> storedValues;
|
|
||||||
bool isCompressed = false;
|
bool isCompressed = false;
|
||||||
int detailLevel;
|
int detailLevel;
|
||||||
std::vector<GenericVoxel> fullVoxels;
|
std::vector<GenericVoxel> fullVoxels;
|
||||||
|
std::vector<uint16_t> compressedVoxels;
|
||||||
public:
|
public:
|
||||||
Chunk3(const Vec3& coord) : chunkCoord(coord) {}
|
//overload GenericVoxel
|
||||||
|
Vec4ui8 getColor() {
|
||||||
|
if (isCompressed) {
|
||||||
|
return color;
|
||||||
|
} else {
|
||||||
|
if (fullVoxels.empty()) {
|
||||||
|
return Vec4ui8();
|
||||||
|
}
|
||||||
|
|
||||||
Vec3 getCoord() const { return chunkCoord; }
|
Vec4ui8 accumulatedColor(0, 0, 0, 0);
|
||||||
|
|
||||||
std::pair<Vec3, Vec3> getBounds() const {
|
for (const auto& voxel : fullVoxels) {
|
||||||
Vec3 minBound(
|
accumulatedColor = accumulatedColor + voxel.getColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
float count = static_cast<float>(fullVoxels.size());
|
||||||
|
return accumulatedColor / count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Chunk3(const Vec3f& coord) : chunkCoord(coord) {}
|
||||||
|
|
||||||
|
Vec3f getCoord() const { return chunkCoord; }
|
||||||
|
|
||||||
|
std::pair<Vec3f, Vec3f> getBounds() const {
|
||||||
|
Vec3f minBound(
|
||||||
chunkCoord.x*CHUNK_SIZE,
|
chunkCoord.x*CHUNK_SIZE,
|
||||||
chunkCoord.y*CHUNK_SIZE,
|
chunkCoord.y*CHUNK_SIZE,
|
||||||
chunkCoord.z*CHUNK_SIZE
|
chunkCoord.z*CHUNK_SIZE
|
||||||
);
|
);
|
||||||
Vec3 maxBound(
|
Vec3f maxBound(
|
||||||
minBound.x+CHUNK_SIZE,
|
minBound.x+CHUNK_SIZE,
|
||||||
minBound.y+CHUNK_SIZE,
|
minBound.y+CHUNK_SIZE,
|
||||||
minBound.z+CHUNK_SIZE
|
minBound.z+CHUNK_SIZE
|
||||||
@@ -199,14 +219,14 @@ public:
|
|||||||
return {minBound, maxBound};
|
return {minBound, maxBound};
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3 worldToChunkPos(const Vec3& worldPos) const {
|
Vec3f worldToChunkPos(const Vec3f& worldPos) const {
|
||||||
auto [minBound, _] = getBounds();
|
auto [minBound, _] = getBounds();
|
||||||
return worldPos - minBound;
|
return worldPos - minBound;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> compress() {
|
std::vector<uint8_t> compress() {
|
||||||
for (auto value : storedValues) {
|
for (auto value : fullVoxels) {
|
||||||
Vec4 sc = value.getColor() / CHUNK_SIZE;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -217,26 +237,26 @@ class SpatialGrid3 {
|
|||||||
private:
|
private:
|
||||||
float cellSize;
|
float cellSize;
|
||||||
public:
|
public:
|
||||||
std::unordered_map<Vec3, std::unordered_set<size_t>, Vec3::Hash> grid;
|
std::unordered_map<Vec3f, std::unordered_set<size_t>, Vec3f::Hash> grid;
|
||||||
|
|
||||||
/// @brief Initializes the spatial grid.
|
/// @brief Initializes the spatial grid.
|
||||||
/// @param cellSize The dimension of the spatial buckets. Larger cells mean more items per bucket but fewer buckets.
|
/// @param cellSize The dimension of the spatial buckets. Larger cells mean more items per bucket but fewer buckets.
|
||||||
SpatialGrid3(float cellSize = 2.0f) : cellSize(cellSize) {}
|
SpatialGrid3(float cellSize = 2.0f) : cellSize(cellSize) {}
|
||||||
|
|
||||||
/// @brief Converts world coordinates to spatial grid coordinates.
|
/// @brief Converts world coordinates to spatial grid coordinates.
|
||||||
Vec3 worldToGrid(const Vec3& worldPos) const {
|
Vec3f worldToGrid(const Vec3f& worldPos) const {
|
||||||
return (worldPos / cellSize).floor();
|
return (worldPos / cellSize).floor();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Adds an object ID to the spatial index at the given position.
|
/// @brief Adds an object ID to the spatial index at the given position.
|
||||||
void insert(size_t id, const Vec3& pos) {
|
void insert(size_t id, const Vec3f& pos) {
|
||||||
Vec3 gridPos = worldToGrid(pos);
|
Vec3f gridPos = worldToGrid(pos);
|
||||||
grid[gridPos].insert(id);
|
grid[gridPos].insert(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Removes an object ID from the spatial index.
|
/// @brief Removes an object ID from the spatial index.
|
||||||
void remove(size_t id, const Vec3& pos) {
|
void remove(size_t id, const Vec3f& pos) {
|
||||||
Vec3 gridPos = worldToGrid(pos);
|
Vec3f gridPos = worldToGrid(pos);
|
||||||
auto cellIt = grid.find(gridPos);
|
auto cellIt = grid.find(gridPos);
|
||||||
if (cellIt != grid.end()) {
|
if (cellIt != grid.end()) {
|
||||||
cellIt->second.erase(id);
|
cellIt->second.erase(id);
|
||||||
@@ -247,9 +267,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Moves an object within the spatial index (removes from old cell, adds to new if changed).
|
/// @brief Moves an object within the spatial index (removes from old cell, adds to new if changed).
|
||||||
void update(size_t id, const Vec3& oldPos, const Vec3& newPos) {
|
void update(size_t id, const Vec3f& oldPos, const Vec3f& newPos) {
|
||||||
Vec3 oldGridPos = worldToGrid(oldPos);
|
Vec3f oldGridPos = worldToGrid(oldPos);
|
||||||
Vec3 newGridPos = worldToGrid(newPos);
|
Vec3f newGridPos = worldToGrid(newPos);
|
||||||
|
|
||||||
if (oldGridPos != newGridPos) {
|
if (oldGridPos != newGridPos) {
|
||||||
remove(id, oldPos);
|
remove(id, oldPos);
|
||||||
@@ -258,7 +278,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Returns all IDs located in the specific grid cell containing 'center'.
|
/// @brief Returns all IDs located in the specific grid cell containing 'center'.
|
||||||
std::unordered_set<size_t> find(const Vec3& center) const {
|
std::unordered_set<size_t> find(const Vec3f& center) const {
|
||||||
auto cellIt = grid.find(worldToGrid(center));
|
auto cellIt = grid.find(worldToGrid(center));
|
||||||
if (cellIt != grid.end()) {
|
if (cellIt != grid.end()) {
|
||||||
return cellIt->second;
|
return cellIt->second;
|
||||||
@@ -270,13 +290,13 @@ public:
|
|||||||
/// @param center The world position center.
|
/// @param center The world position center.
|
||||||
/// @param radius The search radius (defines the bounds of grid cells to check).
|
/// @param radius The search radius (defines the bounds of grid cells to check).
|
||||||
/// @return A vector of candidate IDs (Note: this returns objects in valid grid cells, further distance checks may be required).
|
/// @return A vector of candidate IDs (Note: this returns objects in valid grid cells, further distance checks may be required).
|
||||||
std::vector<size_t> queryRange(const Vec3& center, float radius) const {
|
std::vector<size_t> queryRange(const Vec3f& center, float radius) const {
|
||||||
std::vector<size_t> results;
|
std::vector<size_t> results;
|
||||||
float radiusSq = radius * radius;
|
float radiusSq = radius * radius;
|
||||||
|
|
||||||
// Calculate grid bounds for the query
|
// Calculate grid bounds for the query
|
||||||
Vec3 minGrid = worldToGrid(center - Vec3(radius, radius, radius));
|
Vec3f minGrid = worldToGrid(center - Vec3f(radius, radius, radius));
|
||||||
Vec3 maxGrid = worldToGrid(center + Vec3(radius, radius, radius));
|
Vec3f maxGrid = worldToGrid(center + Vec3f(radius, radius, radius));
|
||||||
|
|
||||||
size_t estimatedSize = (maxGrid.x - minGrid.x + 1) * (maxGrid.y - minGrid.y + 1) * (maxGrid.z - minGrid.z + 1) * 10;
|
size_t estimatedSize = (maxGrid.x - minGrid.x + 1) * (maxGrid.y - minGrid.y + 1) * (maxGrid.z - minGrid.z + 1) * 10;
|
||||||
results.reserve(estimatedSize);
|
results.reserve(estimatedSize);
|
||||||
@@ -285,7 +305,7 @@ public:
|
|||||||
for (int x = minGrid.x; x <= maxGrid.x; ++x) {
|
for (int x = minGrid.x; x <= maxGrid.x; ++x) {
|
||||||
for (int y = minGrid.y; y <= maxGrid.y; ++y) {
|
for (int y = minGrid.y; y <= maxGrid.y; ++y) {
|
||||||
for (int z = minGrid.z; z <= minGrid.z; ++z) {
|
for (int z = minGrid.z; z <= minGrid.z; ++z) {
|
||||||
auto cellIt = grid.find(Vec3(x, y, z));
|
auto cellIt = grid.find(Vec3f(x, y, z));
|
||||||
if (cellIt != grid.end()) {
|
if (cellIt != grid.end()) {
|
||||||
results.insert(results.end(), cellIt->second.begin(), cellIt->second.end());
|
results.insert(results.end(), cellIt->second.begin(), cellIt->second.end());
|
||||||
}
|
}
|
||||||
@@ -316,40 +336,40 @@ protected:
|
|||||||
float spatialCellSize = neighborRadius * 1.5f;
|
float spatialCellSize = neighborRadius * 1.5f;
|
||||||
|
|
||||||
// Default background color for empty spaces
|
// Default background color for empty spaces
|
||||||
Vec4 defaultBackgroundColor = Vec4(0.0f, 0.0f, 0.0f, 0.0f);
|
Vec4ui8 defaultBackgroundColor = Vec4ui8(0, 0, 0, 0);
|
||||||
PNoise2 noisegen;
|
PNoise2 noisegen;
|
||||||
|
|
||||||
bool regenpreventer = false;
|
bool regenpreventer = false;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Grid3& noiseGenGrid(Vec3 min, Vec3 max, float minChance = 0.1f
|
Grid3& noiseGenGrid(Vec3f min, Vec3f max, float minChance = 0.1f
|
||||||
, float maxChance = 1.0f, bool color = true, int noisemod = 42) {
|
, float maxChance = 1.0f, bool color = true, int noisemod = 42) {
|
||||||
TIME_FUNCTION;
|
TIME_FUNCTION;
|
||||||
noisegen = PNoise2(noisemod);
|
noisegen = PNoise2(noisemod);
|
||||||
std::cout << "generating a noise grid with the following: "<< min << " by " << max << "chance min: " << minChance
|
std::cout << "generating a noise grid with the following: "<< min << " by " << max << "chance min: " << minChance
|
||||||
<< " max: " << maxChance << " gen colors: " << color << std::endl;
|
<< " max: " << maxChance << " gen colors: " << color << std::endl;
|
||||||
std::vector<Vec3> poses;
|
std::vector<Vec3f> poses;
|
||||||
std::vector<Vec4> colors;
|
std::vector<Vec4ui8> colors;
|
||||||
for (int x = min.x; x < max.x; x++) {
|
for (int x = min.x; x < max.x; x++) {
|
||||||
for (int y = min.y; y < max.y; y++) {
|
for (int y = min.y; y < max.y; y++) {
|
||||||
for (int z = min.z; z < max.z; z++) {
|
for (int z = min.z; z < max.z; z++) {
|
||||||
float nx = (x+noisemod)/(max.x+EPSILON)/0.1;
|
float nx = (x+noisemod)/(max.x+EPSILON)/0.1;
|
||||||
float ny = (y+noisemod)/(max.y+EPSILON)/0.1;
|
float ny = (y+noisemod)/(max.y+EPSILON)/0.1;
|
||||||
float nz = (z+noisemod)/(max.z+EPSILON)/0.1;
|
float nz = (z+noisemod)/(max.z+EPSILON)/0.1;
|
||||||
Vec3 pos = Vec3(nx,ny,nz);
|
Vec3f pos = Vec3f(nx,ny,nz);
|
||||||
float alpha = noisegen.permute(pos);
|
float alpha = noisegen.permute(pos);
|
||||||
if (alpha > minChance && alpha < maxChance) {
|
if (alpha > minChance && alpha < maxChance) {
|
||||||
if (color) {
|
if (color) {
|
||||||
float red = noisegen.permute(Vec3(nx, ny, nz)*0.3);
|
float red = noisegen.permute(Vec3f(nx, ny, nz)*0.3);
|
||||||
float green = noisegen.permute(Vec3(nx, ny, nz)*0.6);
|
float green = noisegen.permute(Vec3f(nx, ny, nz)*0.6);
|
||||||
float blue = noisegen.permute(Vec3(nx, ny, nz)*0.9);
|
float blue = noisegen.permute(Vec3f(nx, ny, nz)*0.9);
|
||||||
Vec4 newc = Vec4(red,green,blue,1.0);
|
Vec4 newc = Vec4ui8(red,green,blue,1.0);
|
||||||
colors.push_back(newc);
|
colors.push_back(newc);
|
||||||
poses.push_back(Vec3(x,y,z));
|
poses.push_back(Vec3f(x,y,z));
|
||||||
} else {
|
} else {
|
||||||
Vec4 newc = Vec4(alpha,alpha,alpha,1.0);
|
Vec4 newc = Vec4ui8(alpha,alpha,alpha,1.0);
|
||||||
colors.push_back(newc);
|
colors.push_back(newc);
|
||||||
poses.push_back(Vec3(x,y,z));
|
poses.push_back(Vec3f(x,y,z));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -360,7 +380,7 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t addObject(const Vec3& pos, const Vec4& color, float size = 1.0f) {
|
size_t addObject(const Vec3f& pos, const Vec4ui8& color, float size = 1.0f) {
|
||||||
size_t id = Positions.set(pos);
|
size_t id = Positions.set(pos);
|
||||||
Pixels.emplace(id, GenericVoxel(id, color, pos));
|
Pixels.emplace(id, GenericVoxel(id, color, pos));
|
||||||
spatialGrid.insert(id, pos);
|
spatialGrid.insert(id, pos);
|
||||||
@@ -368,19 +388,19 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Sets the default background color.
|
/// @brief Sets the default background color.
|
||||||
void setDefault(const Vec4& color) {
|
void setDefault(const Vec4ui8& color) {
|
||||||
defaultBackgroundColor = color;
|
defaultBackgroundColor = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Moves an object to a new position and updates spatial indexing.
|
/// @brief Moves an object to a new position and updates spatial indexing.
|
||||||
void setPosition(size_t id, const Vec3& newPosition) {
|
void setPosition(size_t id, const Vec3f& newPosition) {
|
||||||
Vec3 oldPosition = Positions.at(id);
|
Vec3f oldPosition = Positions.at(id);
|
||||||
Pixels.at(id).move(newPosition);
|
Pixels.at(id).move(newPosition);
|
||||||
spatialGrid.update(id, oldPosition, newPosition);
|
spatialGrid.update(id, oldPosition, newPosition);
|
||||||
Positions.at(id).move(newPosition);
|
Positions.at(id).move(newPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setColor(size_t id, const Vec4 color) {
|
void setColor(size_t id, const Vec4ui8 color) {
|
||||||
Pixels.at(id).recolor(color);
|
Pixels.at(id).recolor(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,20 +409,20 @@ public:
|
|||||||
//optimizeSpatialGrid();
|
//optimizeSpatialGrid();
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec4 getDefaultBackgroundColor() const {
|
Vec4ui8 getDefaultBackgroundColor() const {
|
||||||
return defaultBackgroundColor;
|
return defaultBackgroundColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3 getPositionID(size_t id) const {
|
Vec3f getPositionID(size_t id) const {
|
||||||
Vec3 it = Positions.at(id);
|
Vec3f it = Positions.at(id);
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t getPositionVec(const Vec3& pos, float radius = 0.0f) const {
|
size_t getPositionVec(const Vec3f& 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
|
||||||
Vec3 gridPos = spatialGrid.worldToGrid(pos);
|
Vec3f gridPos = spatialGrid.worldToGrid(pos);
|
||||||
auto cellIt = spatialGrid.grid.find(gridPos);
|
auto cellIt = spatialGrid.grid.find(gridPos);
|
||||||
if (cellIt != spatialGrid.grid.end()) {
|
if (cellIt != spatialGrid.grid.end()) {
|
||||||
for (size_t id : cellIt->second) {
|
for (size_t id : cellIt->second) {
|
||||||
@@ -421,10 +441,10 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t getOrCreatePositionVec(const Vec3& pos, float radius = 0.0f, bool create = true) {
|
size_t getOrCreatePositionVec(const Vec3f& pos, float radius = 0.0f, bool create = true) {
|
||||||
//TIME_FUNCTION; //called too many times and average time is less than 0.0000001 so ignore it.
|
//TIME_FUNCTION; //called too many times and average time is less than 0.0000001 so ignore it.
|
||||||
if (radius == 0.0f) {
|
if (radius == 0.0f) {
|
||||||
Vec3 gridPos = spatialGrid.worldToGrid(pos);
|
Vec3f gridPos = spatialGrid.worldToGrid(pos);
|
||||||
auto cellIt = spatialGrid.grid.find(gridPos);
|
auto cellIt = spatialGrid.grid.find(gridPos);
|
||||||
if (cellIt != spatialGrid.grid.end()) {
|
if (cellIt != spatialGrid.grid.end()) {
|
||||||
for (size_t id : cellIt->second) {
|
for (size_t id : cellIt->second) {
|
||||||
@@ -449,7 +469,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<size_t> getPositionVecRegion(const Vec3& pos, float radius = 1.0f) const {
|
std::vector<size_t> getPositionVecRegion(const Vec3f& 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;
|
||||||
|
|
||||||
@@ -469,16 +489,16 @@ public:
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec4 getColor(size_t id) {
|
Vec4ui8 getColor(size_t id) {
|
||||||
return Pixels.at(id).getColor();
|
return Pixels.at(id).getColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<Vec3,Vec3> getBoundingBox(Vec3& minCorner, Vec3& maxCorner) const {
|
std::pair<Vec3f,Vec3f> getBoundingBox(Vec3f& minCorner, Vec3f& maxCorner) const {
|
||||||
TIME_FUNCTION;
|
TIME_FUNCTION;
|
||||||
if (Positions.empty()) {
|
if (Positions.empty()) {
|
||||||
std::cout << "empty" << std::endl;
|
std::cout << "empty" << std::endl;
|
||||||
minCorner = Vec3(0, 0, 0);
|
minCorner = Vec3f(0, 0, 0);
|
||||||
maxCorner = Vec3(0, 0, 0);
|
maxCorner = Vec3f(0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize with first position
|
// Initialize with first position
|
||||||
@@ -499,8 +519,8 @@ public:
|
|||||||
return std::make_pair(minCorner, maxCorner);
|
return std::make_pair(minCorner, maxCorner);
|
||||||
}
|
}
|
||||||
|
|
||||||
frame getGridRegionAsFrame(const Vec3& minCorner, const Vec3& maxCorner, const Vec2& res,
|
frame getGridRegionAsFrame(const Vec3f& minCorner, const Vec3f& maxCorner, const Vec2& res,
|
||||||
const Ray3& View, frame::colormap outChannels = frame::colormap::RGB) const {
|
const Ray3<float>& View, frame::colormap outChannels = frame::colormap::RGB) const {
|
||||||
TIME_FUNCTION;
|
TIME_FUNCTION;
|
||||||
|
|
||||||
// Calculate volume dimensions
|
// Calculate volume dimensions
|
||||||
@@ -520,8 +540,8 @@ public:
|
|||||||
|
|
||||||
frame outframe(outputWidth, outputHeight, outChannels);
|
frame outframe(outputWidth, outputHeight, outChannels);
|
||||||
|
|
||||||
std::unordered_map<Vec2, Vec4> colorBuffer;
|
std::unordered_map<Vec2, Vec4ui8> colorBuffer;
|
||||||
std::unordered_map<Vec2, Vec4> colorAccumBuffer;
|
std::unordered_map<Vec2, Vec4ui8> colorAccumBuffer;
|
||||||
std::unordered_map<Vec2, int> countBuffer;
|
std::unordered_map<Vec2, int> countBuffer;
|
||||||
std::unordered_map<Vec2, float> depthBuffer;
|
std::unordered_map<Vec2, float> depthBuffer;
|
||||||
|
|
||||||
@@ -531,11 +551,11 @@ public:
|
|||||||
countBuffer.reserve(bufferSize);
|
countBuffer.reserve(bufferSize);
|
||||||
depthBuffer.reserve(bufferSize);
|
depthBuffer.reserve(bufferSize);
|
||||||
|
|
||||||
Vec3 viewDirection = View.direction;
|
Vec3f viewDirection = View.direction;
|
||||||
Vec3 viewOrigin = View.origin;
|
Vec3f viewOrigin = View.origin;
|
||||||
|
|
||||||
Vec3 viewRight = Vec3(1, 0, 0);
|
Vec3f viewRight = Vec3f(1, 0, 0);
|
||||||
Vec3 viewUp = Vec3(0, 1, 0);
|
Vec3f viewUp = Vec3f(0, 1, 0);
|
||||||
|
|
||||||
float xScale = outputWidth / width;
|
float xScale = outputWidth / width;
|
||||||
float yScale = outputHeight / height;
|
float yScale = outputHeight / height;
|
||||||
@@ -553,10 +573,10 @@ public:
|
|||||||
float relY = pos.y - minCorner.y;
|
float relY = pos.y - minCorner.y;
|
||||||
float relZ = pos.z - minCorner.z;
|
float relZ = pos.z - minCorner.z;
|
||||||
|
|
||||||
Vec3 toVoxel = pos - viewOrigin;
|
Vec3f toVoxel = pos - viewOrigin;
|
||||||
float distance = toVoxel.length();
|
float distance = toVoxel.length();
|
||||||
|
|
||||||
Vec3 viewPlanePos = pos - (toVoxel.dot(viewDirection)) * viewDirection;
|
Vec3f viewPlanePos = pos - (toVoxel.dot(viewDirection)) * viewDirection;
|
||||||
|
|
||||||
float screenX = viewPlanePos.dot(viewRight);
|
float screenX = viewPlanePos.dot(viewRight);
|
||||||
float screenY = viewPlanePos.dot(viewUp);
|
float screenY = viewPlanePos.dot(viewUp);
|
||||||
@@ -569,7 +589,7 @@ public:
|
|||||||
|
|
||||||
Vec2 pixelPos(pixX, pixY);
|
Vec2 pixelPos(pixX, pixY);
|
||||||
|
|
||||||
Vec4 voxelColor = Pixels.at(id).getColor();
|
Vec4ui8 voxelColor = Pixels.at(id).getColor();
|
||||||
|
|
||||||
float depth = relZ;
|
float depth = relZ;
|
||||||
|
|
||||||
@@ -603,7 +623,7 @@ public:
|
|||||||
Vec2 pixelPos(x, y);
|
Vec2 pixelPos(x, y);
|
||||||
size_t index = (y * outputWidth + x) * 4;
|
size_t index = (y * outputWidth + x) * 4;
|
||||||
|
|
||||||
Vec4 finalColor;
|
Vec4ui8 finalColor;
|
||||||
auto countIt = countBuffer.find(pixelPos);
|
auto countIt = countBuffer.find(pixelPos);
|
||||||
|
|
||||||
if (countIt != countBuffer.end() && countIt->second > 0) {
|
if (countIt != countBuffer.end() && countIt->second > 0) {
|
||||||
@@ -633,7 +653,7 @@ public:
|
|||||||
Vec2 pixelPos(x, y);
|
Vec2 pixelPos(x, y);
|
||||||
size_t index = (y * outputWidth + x) * 3;
|
size_t index = (y * outputWidth + x) * 3;
|
||||||
|
|
||||||
Vec4 finalColor;
|
Vec4ui8 finalColor;
|
||||||
auto countIt = countBuffer.find(pixelPos);
|
auto countIt = countBuffer.find(pixelPos);
|
||||||
|
|
||||||
if (countIt != countBuffer.end() && countIt->second > 0) {
|
if (countIt != countBuffer.end() && countIt->second > 0) {
|
||||||
@@ -663,7 +683,7 @@ public:
|
|||||||
Vec2 pixelPos(x, y);
|
Vec2 pixelPos(x, y);
|
||||||
size_t index = (y * outputWidth + x) * 3;
|
size_t index = (y * outputWidth + x) * 3;
|
||||||
|
|
||||||
Vec4 finalColor;
|
Vec4ui8 finalColor;
|
||||||
auto countIt = countBuffer.find(pixelPos);
|
auto countIt = countBuffer.find(pixelPos);
|
||||||
|
|
||||||
if (countIt != countBuffer.end() && countIt->second > 0) {
|
if (countIt != countBuffer.end() && countIt->second > 0) {
|
||||||
@@ -688,16 +708,16 @@ public:
|
|||||||
return outframe;
|
return outframe;
|
||||||
}
|
}
|
||||||
|
|
||||||
frame getGridAsFrame(const Vec2& res, const Ray3& View, frame::colormap outChannels = frame::colormap::RGB) const {
|
frame getGridAsFrame(const Vec2& res, const Ray3<float>& View, frame::colormap outChannels = frame::colormap::RGB) const {
|
||||||
Vec3 Min;
|
Vec3f Min;
|
||||||
Vec3 Max;
|
Vec3f Max;
|
||||||
auto a = getBoundingBox(Min, Max);
|
auto a = getBoundingBox(Min, Max);
|
||||||
|
|
||||||
return getGridRegionAsFrame(a.first, a.second, res, View, outChannels);
|
return getGridRegionAsFrame(a.first, a.second, res, View, outChannels);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t removeID(size_t id) {
|
size_t removeID(size_t id) {
|
||||||
Vec3 oldPosition = Positions.at(id);
|
Vec3f oldPosition = Positions.at(id);
|
||||||
Positions.remove(id);
|
Positions.remove(id);
|
||||||
Pixels.erase(id);
|
Pixels.erase(id);
|
||||||
unassignedIDs.push_back(id);
|
unassignedIDs.push_back(id);
|
||||||
@@ -705,17 +725,17 @@ public:
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bulkUpdatePositions(const std::unordered_map<size_t, Vec3>& newPositions) {
|
void bulkUpdatePositions(const std::unordered_map<size_t, Vec3f>& newPositions) {
|
||||||
TIME_FUNCTION;
|
TIME_FUNCTION;
|
||||||
for (const auto& [id, newPos] : newPositions) {
|
for (const auto& [id, newPos] : newPositions) {
|
||||||
Vec3 oldPosition = Positions.at(id);
|
Vec3f oldPosition = Positions.at(id);
|
||||||
Positions.at(id).move(newPos);
|
Positions.at(id).move(newPos);
|
||||||
Pixels.at(id).move(newPos);
|
Pixels.at(id).move(newPos);
|
||||||
spatialGrid.update(id, oldPosition, newPos);
|
spatialGrid.update(id, oldPosition, newPos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<size_t> bulkAddObjects(const std::vector<Vec3> poses, std::vector<Vec4> colors) {
|
std::vector<size_t> bulkAddObjects(const std::vector<Vec3f> poses, std::vector<Vec4ui8> colors) {
|
||||||
TIME_FUNCTION;
|
TIME_FUNCTION;
|
||||||
std::vector<size_t> ids;
|
std::vector<size_t> ids;
|
||||||
ids.reserve(poses.size());
|
ids.reserve(poses.size());
|
||||||
@@ -749,7 +769,7 @@ public:
|
|||||||
Pixels.clear();
|
Pixels.clear();
|
||||||
spatialGrid.clear();
|
spatialGrid.clear();
|
||||||
Pixels.rehash(0);
|
Pixels.rehash(0);
|
||||||
defaultBackgroundColor = Vec4(0.0f, 0.0f, 0.0f, 0.0f);
|
defaultBackgroundColor = Vec4ui8(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void optimizeSpatialGrid() {
|
void optimizeSpatialGrid() {
|
||||||
@@ -766,7 +786,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<size_t> getNeighbors(size_t id) const {
|
std::vector<size_t> getNeighbors(size_t id) const {
|
||||||
Vec3 pos = Positions.at(id);
|
Vec3f pos = Positions.at(id);
|
||||||
std::vector<size_t> candidates = spatialGrid.queryRange(pos, neighborRadius);
|
std::vector<size_t> candidates = spatialGrid.queryRange(pos, neighborRadius);
|
||||||
std::vector<size_t> neighbors;
|
std::vector<size_t> neighbors;
|
||||||
float radiusSq = neighborRadius * neighborRadius;
|
float radiusSq = neighborRadius * neighborRadius;
|
||||||
@@ -787,7 +807,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<size_t> getNeighborsRange(size_t id, float dist) const {
|
std::vector<size_t> getNeighborsRange(size_t id, float dist) const {
|
||||||
Vec3 pos = Positions.at(id);
|
Vec3f pos = Positions.at(id);
|
||||||
std::vector<size_t> candidates = spatialGrid.queryRange(pos, neighborRadius);
|
std::vector<size_t> candidates = spatialGrid.queryRange(pos, neighborRadius);
|
||||||
|
|
||||||
std::vector<size_t> neighbors;
|
std::vector<size_t> neighbors;
|
||||||
@@ -804,17 +824,17 @@ public:
|
|||||||
|
|
||||||
Grid3& backfillGrid() {
|
Grid3& backfillGrid() {
|
||||||
TIME_FUNCTION;
|
TIME_FUNCTION;
|
||||||
Vec3 Min;
|
Vec3f Min;
|
||||||
Vec3 Max;
|
Vec3f Max;
|
||||||
getBoundingBox(Min, Max);
|
getBoundingBox(Min, Max);
|
||||||
std::vector<Vec3> newPos;
|
std::vector<Vec3f> newPos;
|
||||||
std::vector<Vec4> newColors;
|
std::vector<Vec4ui8> newColors;
|
||||||
for (size_t x = Min.x; x < Max.x; x++) {
|
for (size_t x = Min.x; x < Max.x; x++) {
|
||||||
for (size_t y = Min.y; y < Max.y; y++) {
|
for (size_t y = Min.y; y < Max.y; y++) {
|
||||||
for (size_t z = Min.z; z < Max.z; z++) {
|
for (size_t z = Min.z; z < Max.z; z++) {
|
||||||
Vec3 pos = Vec3(x,y,z);
|
Vec3f pos = Vec3f(x,y,z);
|
||||||
if (Positions.contains(pos)) continue;
|
if (Positions.contains(pos)) continue;
|
||||||
Vec4 color = defaultBackgroundColor;
|
Vec4ui8 color = defaultBackgroundColor;
|
||||||
float size = 0.1;
|
float size = 0.1;
|
||||||
newPos.push_back(pos);
|
newPos.push_back(pos);
|
||||||
newColors.push_back(color);
|
newColors.push_back(color);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include "../vectorlogic/vec2.hpp"
|
#include "../vectorlogic/vec2.hpp"
|
||||||
#include "../vectorlogic/vec3.hpp"
|
#include "../vectorlogic/Vec3.hpp"
|
||||||
#include "../timing_decorator.hpp"
|
#include "../timing_decorator.hpp"
|
||||||
|
|
||||||
class PNoise2 {
|
class PNoise2 {
|
||||||
@@ -31,16 +31,16 @@ private:
|
|||||||
else return Vec2(1,-1);
|
else return Vec2(1,-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3 GetConstantVector3(int v) {
|
Vec3ui8 GetConstantVector3(int v) {
|
||||||
int h = v & 7;
|
int h = v & 7;
|
||||||
if (h == 0) return Vec3(1,1,1);
|
if (h == 0) return Vec3ui8(1,1,1);
|
||||||
else if (h == 1) return Vec3(-1,1, 1);
|
else if (h == 1) return Vec3ui8(-1,1, 1);
|
||||||
else if (h == 2) return Vec3(-1,-1, 1);
|
else if (h == 2) return Vec3ui8(-1,-1, 1);
|
||||||
else if (h == 3) return Vec3(-1,-1, 1);
|
else if (h == 3) return Vec3ui8(-1,-1, 1);
|
||||||
else if (h == 4) return Vec3(-1,-1,-1);
|
else if (h == 4) return Vec3ui8(-1,-1,-1);
|
||||||
else if (h == 5) return Vec3(-1,-1, -1);
|
else if (h == 5) return Vec3ui8(-1,-1, -1);
|
||||||
else if (h == 6) return Vec3(-1,-1, -1);
|
else if (h == 6) return Vec3ui8(-1,-1, -1);
|
||||||
else return Vec3(1,-1, -1);
|
else return Vec3ui8(1,-1, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static double grad(int hash, double x, double y, double z = 0.0) {
|
static double grad(int hash, double x, double y, double z = 0.0) {
|
||||||
@@ -106,7 +106,8 @@ public:
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
float permute(Vec3 point) {
|
template<typename T>
|
||||||
|
float permute(Vec3<T> point) {
|
||||||
TIME_FUNCTION;
|
TIME_FUNCTION;
|
||||||
int X = (int)floor(point.x) & 255;
|
int X = (int)floor(point.x) & 255;
|
||||||
int Y = (int)floor(point.y) & 255;
|
int Y = (int)floor(point.y) & 255;
|
||||||
@@ -115,15 +116,15 @@ public:
|
|||||||
float yf = point.y - Y;
|
float yf = point.y - Y;
|
||||||
float zf = point.z - Z;
|
float zf = point.z - Z;
|
||||||
|
|
||||||
Vec3 FBL = Vec3(xf-0, yf-0, zf-0);
|
Vec3ui8 FBL = Vec3ui8(xf-0, yf-0, zf-0);
|
||||||
Vec3 FBR = Vec3(xf-1, yf-0, zf-0);
|
Vec3ui8 FBR = Vec3ui8(xf-1, yf-0, zf-0);
|
||||||
Vec3 FTL = Vec3(xf-0, yf-1, zf-0);
|
Vec3ui8 FTL = Vec3ui8(xf-0, yf-1, zf-0);
|
||||||
Vec3 FTR = Vec3(xf-1, yf-1, zf-0);
|
Vec3ui8 FTR = Vec3ui8(xf-1, yf-1, zf-0);
|
||||||
|
|
||||||
Vec3 RBL = Vec3(xf-0, yf-0, zf-1);
|
Vec3ui8 RBL = Vec3ui8(xf-0, yf-0, zf-1);
|
||||||
Vec3 RBR = Vec3(xf-1, yf-0, zf-1);
|
Vec3ui8 RBR = Vec3ui8(xf-1, yf-0, zf-1);
|
||||||
Vec3 RTL = Vec3(xf-0, yf-1, zf-1);
|
Vec3ui8 RTL = Vec3ui8(xf-0, yf-1, zf-1);
|
||||||
Vec3 RTR = Vec3(xf-1, yf-1, zf-1);
|
Vec3ui8 RTR = Vec3ui8(xf-1, yf-1, zf-1);
|
||||||
|
|
||||||
int vFBL = permutation[permutation[permutation[Z+0]+X+0]+Y+0];
|
int vFBL = permutation[permutation[permutation[Z+0]+X+0]+Y+0];
|
||||||
int vFBR = permutation[permutation[permutation[Z+0]+X+1]+Y+0];
|
int vFBR = permutation[permutation[permutation[Z+0]+X+1]+Y+0];
|
||||||
@@ -166,4 +167,3 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
//https://rtouti.github.io/graphics/perlin-noise-algorithm
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include "../vectorlogic/vec3.hpp"
|
#include "../vectorlogic/Vec3.hpp"
|
||||||
#include "frame.hpp"
|
#include "frame.hpp"
|
||||||
|
|
||||||
class BMPWriter {
|
class BMPWriter {
|
||||||
@@ -49,9 +49,9 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Save a 2D vector of Vec3 (RGB) colors as BMP
|
// Save a 2D vector of Vec3ui8 (RGB) colors as BMP
|
||||||
// Vec3 components: x = red, y = green, z = blue (values in range [0,1])
|
// Vec3ui8 components: x = red, y = green, z = blue (values in range [0,1])
|
||||||
static bool saveBMP(const std::string& filename, const std::vector<std::vector<Vec3>>& pixels) {
|
static bool saveBMP(const std::string& filename, const std::vector<std::vector<Vec3ui8>>& pixels) {
|
||||||
if (pixels.empty() || pixels[0].empty()) {
|
if (pixels.empty() || pixels[0].empty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -70,13 +70,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Alternative interface with width/height and flat vector (row-major order)
|
// Alternative interface with width/height and flat vector (row-major order)
|
||||||
static bool saveBMP(const std::string& filename, const std::vector<Vec3>& pixels, int width, int height) {
|
static bool saveBMP(const std::string& filename, const std::vector<Vec3ui8>& pixels, int width, int height) {
|
||||||
if (pixels.size() != width * height) {
|
if (pixels.size() != width * height) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to 2D vector format
|
// Convert to 2D vector format
|
||||||
std::vector<std::vector<Vec3>> pixels2D(height, std::vector<Vec3>(width));
|
std::vector<std::vector<Vec3ui8>> pixels2D(height, std::vector<Vec3ui8>(width));
|
||||||
for (int y = 0; y < height; ++y) {
|
for (int y = 0; y < height; ++y) {
|
||||||
for (int x = 0; x < width; ++x) {
|
for (int x = 0; x < width; ++x) {
|
||||||
pixels2D[y][x] = pixels[y * width + x];
|
pixels2D[y][x] = pixels[y * width + x];
|
||||||
@@ -157,7 +157,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool saveBMP(const std::string& filename, const std::vector<std::vector<Vec3>>& pixels, int width, int height) {
|
static bool saveBMP(const std::string& filename, const std::vector<std::vector<Vec3ui8>>& pixels, int width, int height) {
|
||||||
// Create directory if needed
|
// Create directory if needed
|
||||||
if (!createDirectoryIfNeeded(filename)) {
|
if (!createDirectoryIfNeeded(filename)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -186,7 +186,7 @@ private:
|
|||||||
std::vector<uint8_t> row(rowSize, 0);
|
std::vector<uint8_t> row(rowSize, 0);
|
||||||
for (int y = height - 1; y >= 0; --y) {
|
for (int y = height - 1; y >= 0; --y) {
|
||||||
for (int x = 0; x < width; ++x) {
|
for (int x = 0; x < width; ++x) {
|
||||||
const Vec3& color = pixels[y][x];
|
const Vec3ui8& color = pixels[y][x];
|
||||||
|
|
||||||
// Convert from [0,1] float to [0,255] uint8_t
|
// Convert from [0,1] float to [0,255] uint8_t
|
||||||
uint8_t r = static_cast<uint8_t>(std::clamp(color.x * 255.0f, 0.0f, 255.0f));
|
uint8_t r = static_cast<uint8_t>(std::clamp(color.x * 255.0f, 0.0f, 255.0f));
|
||||||
|
|||||||
@@ -1,31 +1,32 @@
|
|||||||
#ifndef RAY3_HPP
|
#ifndef RAY3_HPP
|
||||||
#define RAY3_HPP
|
#define RAY3_HPP
|
||||||
|
|
||||||
#include "vectorlogic/vec3.hpp"
|
#include "vectorlogic/Vec3.hpp"
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
class Ray3 {
|
class Ray3 {
|
||||||
public:
|
public:
|
||||||
Vec3 origin;
|
Vec3<T> origin;
|
||||||
Vec3 direction;
|
Vec3<T> direction;
|
||||||
|
|
||||||
Ray3() : origin(Vec3()), direction(Vec3(1, 0, 0)) {}
|
Ray3() : origin(Vec3<T>()), direction(Vec3<T>(1, 0, 0)) {}
|
||||||
Ray3(const Vec3& origin, const Vec3& direction)
|
Ray3(const Vec3<T>& origin, const Vec3<T>& direction)
|
||||||
: origin(origin), direction(direction.normalized()) {}
|
: origin(origin), direction(direction.normalized()) {}
|
||||||
|
|
||||||
// Get point at parameter t along the ray
|
// Get point at parameter t along the ray
|
||||||
Vec3 at(float t) const {
|
Vec3<T> at(float t) const {
|
||||||
return origin + direction * t;
|
return origin + direction * t;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reflect ray off a surface with given normal
|
// Reflect ray off a surface with given normal
|
||||||
Ray3 reflect(const Vec3& point, const Vec3& normal) const {
|
Ray3 reflect(const Vec3<T>& point, const Vec3<T>& normal) const {
|
||||||
Vec3 reflectedDir = direction.reflect(normal);
|
Vec3<T> reflectedDir = direction.reflect(normal);
|
||||||
return Ray3(point, reflectedDir);
|
return Ray3(point, reflectedDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if ray intersects with a sphere
|
// Check if ray intersects with a sphere
|
||||||
bool intersectsSphere(const Vec3& center, float radius, float& t1, float& t2) const {
|
bool intersectsSphere(const Vec3<T>& center, T radius, T& t1, T& t2) const {
|
||||||
Vec3 oc = origin - center;
|
Vec3<T> oc = origin - center;
|
||||||
float a = direction.dot(direction);
|
float a = direction.dot(direction);
|
||||||
float b = 2.0f * oc.dot(direction);
|
float b = 2.0f * oc.dot(direction);
|
||||||
float c = oc.dot(oc) - radius * radius;
|
float c = oc.dot(oc) - radius * radius;
|
||||||
@@ -44,7 +45,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if ray intersects with a plane (defined by point and normal)
|
// Check if ray intersects with a plane (defined by point and normal)
|
||||||
bool intersectsPlane(const Vec3& planePoint, const Vec3& planeNormal, float& t) const {
|
bool intersectsPlane(const Vec3<T>& planePoint, const Vec3<T>& planeNormal, T& t) const {
|
||||||
float denom = planeNormal.dot(direction);
|
float denom = planeNormal.dot(direction);
|
||||||
|
|
||||||
if (std::abs(denom) < 1e-10f) {
|
if (std::abs(denom) < 1e-10f) {
|
||||||
@@ -56,9 +57,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the distance from a point to this ray
|
// Get the distance from a point to this ray
|
||||||
float distanceToPoint(const Vec3& point) const {
|
float distanceToPoint(const Vec3<T>& point) const {
|
||||||
Vec3 pointToOrigin = point - origin;
|
Vec3<T> pointToOrigin = point - origin;
|
||||||
Vec3 crossProduct = direction.cross(pointToOrigin);
|
Vec3<T> crossProduct = direction.cross(pointToOrigin);
|
||||||
return crossProduct.length() / direction.length();
|
return crossProduct.length() / direction.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,17 +6,18 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
class Vec3 {
|
class Vec3 {
|
||||||
public:
|
public:
|
||||||
float x, y, z;
|
T x, y, z;
|
||||||
|
|
||||||
Vec3() : x(0), y(0), z(0) {}
|
Vec3() : x(0), y(0), z(0) {}
|
||||||
Vec3(float x, float y, float z) : x(x), y(y), z(z) {}
|
Vec3(T x, T y, T z) : x(x), y(y), z(z) {}
|
||||||
Vec3(float scalar) : x(scalar), y(scalar), z(scalar) {}
|
Vec3(T scalar) : x(scalar), y(scalar), z(scalar) {}
|
||||||
|
|
||||||
Vec3(const class Vec2& vec2, float z = 0.0f);
|
Vec3(const class Vec2& vec2, T z = 0);
|
||||||
|
|
||||||
Vec3& move(const Vec3 newpos) {
|
Vec3& move(const Vec3& newpos) {
|
||||||
x = newpos.x;
|
x = newpos.x;
|
||||||
y = newpos.y;
|
y = newpos.y;
|
||||||
z = newpos.z;
|
z = newpos.z;
|
||||||
@@ -40,11 +41,11 @@ public:
|
|||||||
return Vec3(x / other.x, y / other.y, z / other.z);
|
return Vec3(x / other.x, y / other.y, z / other.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3 operator+(float scalar) const {
|
Vec3 operator+(T scalar) const {
|
||||||
return Vec3(x + scalar, y + scalar, z + scalar);
|
return Vec3(x + scalar, y + scalar, z + scalar);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3 operator-(float scalar) const {
|
Vec3 operator-(T scalar) const {
|
||||||
return Vec3(x - scalar, y - scalar, z - scalar);
|
return Vec3(x - scalar, y - scalar, z - scalar);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,15 +53,15 @@ public:
|
|||||||
return Vec3(-x, -y, -z);
|
return Vec3(-x, -y, -z);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3 operator*(float scalar) const {
|
Vec3 operator*(T scalar) const {
|
||||||
return Vec3(x * scalar, y * scalar, z * scalar);
|
return Vec3(x * scalar, y * scalar, z * scalar);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3 operator/(float scalar) const {
|
Vec3 operator/(T scalar) const {
|
||||||
return Vec3(x / scalar, y / scalar, z / scalar);
|
return Vec3(x / scalar, y / scalar, z / scalar);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3& operator=(float scalar) {
|
Vec3& operator=(T scalar) {
|
||||||
x = y = z = scalar;
|
x = y = z = scalar;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -93,28 +94,28 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3& operator+=(float scalar) {
|
Vec3& operator+=(T scalar) {
|
||||||
x += scalar;
|
x += scalar;
|
||||||
y += scalar;
|
y += scalar;
|
||||||
z += scalar;
|
z += scalar;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3& operator-=(float scalar) {
|
Vec3& operator-=(T scalar) {
|
||||||
x -= scalar;
|
x -= scalar;
|
||||||
y -= scalar;
|
y -= scalar;
|
||||||
z -= scalar;
|
z -= scalar;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3& operator*=(float scalar) {
|
Vec3& operator*=(T scalar) {
|
||||||
x *= scalar;
|
x *= scalar;
|
||||||
y *= scalar;
|
y *= scalar;
|
||||||
z *= scalar;
|
z *= scalar;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3& operator/=(float scalar) {
|
Vec3& operator/=(T scalar) {
|
||||||
x /= scalar;
|
x /= scalar;
|
||||||
y /= scalar;
|
y /= scalar;
|
||||||
z /= scalar;
|
z /= scalar;
|
||||||
@@ -125,7 +126,7 @@ public:
|
|||||||
return x * other.x + y * other.y + z * other.z;
|
return x * other.x + y * other.y + z * other.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3 cross(const Vec3& other) const {
|
Vec3& cross(const Vec3& other) const {
|
||||||
return Vec3(
|
return Vec3(
|
||||||
y * other.z - z * other.y,
|
y * other.z - z * other.y,
|
||||||
z * other.x - x * other.z,
|
z * other.x - x * other.z,
|
||||||
@@ -133,25 +134,25 @@ public:
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
float length() const {
|
T length() const {
|
||||||
return std::sqrt(x * x + y * y + z * z);
|
return static_cast<T>(std::sqrt(static_cast<double>(x * x + y * y + z * z)));
|
||||||
}
|
}
|
||||||
|
|
||||||
float lengthSquared() const {
|
T lengthSquared() const {
|
||||||
return x * x + y * y + z * z;
|
return x * x + y * y + z * z;
|
||||||
}
|
}
|
||||||
|
|
||||||
float distance(const Vec3& other) const {
|
T distance(const Vec3& other) const {
|
||||||
return (*this - other).length();
|
return (*this - other).length();
|
||||||
}
|
}
|
||||||
|
|
||||||
float distanceSquared(const Vec3& other) const {
|
T distanceSquared(const Vec3& other) const {
|
||||||
Vec3 diff = *this - other;
|
Vec3 diff = *this - other;
|
||||||
return diff.x * diff.x + diff.y * diff.y + diff.z * diff.z;
|
return diff.x * diff.x + diff.y * diff.y + diff.z * diff.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3 normalized() const {
|
Vec3 normalized() const {
|
||||||
float len = length();
|
T len = length();
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
return *this / len;
|
return *this / len;
|
||||||
}
|
}
|
||||||
@@ -222,7 +223,7 @@ public:
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3 clamp(float minVal, float maxVal) const {
|
Vec3 clamp(T minVal, T maxVal) const {
|
||||||
return Vec3(
|
return Vec3(
|
||||||
std::clamp(x, minVal, maxVal),
|
std::clamp(x, minVal, maxVal),
|
||||||
std::clamp(y, minVal, maxVal),
|
std::clamp(y, minVal, maxVal),
|
||||||
@@ -240,19 +241,19 @@ public:
|
|||||||
std::abs(z - other.z) < epsilon;
|
std::abs(z - other.z) < epsilon;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend Vec3 operator+(float scalar, const Vec3& vec) {
|
friend Vec3 operator+(T scalar, const Vec3& vec) {
|
||||||
return Vec3(scalar + vec.x, scalar + vec.y, scalar + vec.z);
|
return Vec3(scalar + vec.x, scalar + vec.y, scalar + vec.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend Vec3 operator-(float scalar, const Vec3& vec) {
|
friend Vec3 operator-(T scalar, const Vec3& vec) {
|
||||||
return Vec3(scalar - vec.x, scalar - vec.y, scalar - vec.z);
|
return Vec3(scalar - vec.x, scalar - vec.y, scalar - vec.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend Vec3 operator*(float scalar, const Vec3& vec) {
|
friend Vec3 operator*(T scalar, const Vec3& vec) {
|
||||||
return Vec3(scalar * vec.x, scalar * vec.y, scalar * vec.z);
|
return Vec3(scalar * vec.x, scalar * vec.y, scalar * vec.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend Vec3 operator/(float scalar, const Vec3& vec) {
|
friend Vec3 operator/(T scalar, const Vec3& vec) {
|
||||||
return Vec3(scalar / vec.x, scalar / vec.y, scalar / vec.z);
|
return Vec3(scalar / vec.x, scalar / vec.y, scalar / vec.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,17 +261,17 @@ public:
|
|||||||
return *this - 2.0f * this->dot(normal) * normal;
|
return *this - 2.0f * this->dot(normal) * normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3 lerp(const Vec3& other, float t) const {
|
Vec3 lerp(const Vec3& other, T t) const {
|
||||||
t = std::clamp(t, 0.0f, 1.0f);
|
t = std::clamp(t, 0.0f, 1.0f);
|
||||||
return *this + (other - *this) * t;
|
return *this + (other - *this) * t;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3 slerp(const Vec3& other, float t) const {
|
Vec3 slerp(const Vec3& other, T t) const {
|
||||||
t = std::clamp(t, 0.0f, 1.0f);
|
t = std::clamp(t, 0.0f, 1.0f);
|
||||||
float dot = this->dot(other);
|
T dot = this->dot(other);
|
||||||
dot = std::clamp(dot, -1.0f, 1.0f);
|
dot = std::clamp(dot, -1.0f, 1.0f);
|
||||||
|
|
||||||
float theta = std::acos(dot) * t;
|
T theta = std::acos(dot) * t;
|
||||||
Vec3 relative = other - *this * dot;
|
Vec3 relative = other - *this * dot;
|
||||||
relative = relative.normalized();
|
relative = relative.normalized();
|
||||||
|
|
||||||
@@ -326,11 +327,11 @@ public:
|
|||||||
return direction.angleTo(other);
|
return direction.angleTo(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
float& operator[](int index) {
|
T& operator[](int index) {
|
||||||
return (&x)[index];
|
return (&x)[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
const float& operator[](int index) const {
|
const T& operator[](int index) const {
|
||||||
return (&x)[index];
|
return (&x)[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -345,16 +346,22 @@ public:
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::ostream& operator<<(std::ostream& os, const Vec3& vec) {
|
using Vec3f = Vec3<float>;
|
||||||
|
using Vec3d = Vec3<double>;
|
||||||
|
using Vec3i = Vec3<int>;
|
||||||
|
using Vec3ui8 = Vec3<uint8_t>;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, const Vec3<T>& vec) {
|
||||||
os << vec.toString();
|
os << vec.toString();
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
template<>
|
template<typename T>
|
||||||
struct hash<Vec3> {
|
struct hash<Vec3<T>> {
|
||||||
size_t operator()(const Vec3& v) const {
|
size_t operator()(const Vec3<T>& v) const {
|
||||||
return hash<float>()(v.x) ^ (hash<float>()(v.y) << 1) ^ (hash<float>()(v.z) << 2);
|
return hash<T>()(v.x) ^ (hash<T>()(v.y) << 1) ^ (hash<T>()(v.z) << 2);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,24 +8,25 @@
|
|||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
class Vec4 {
|
class Vec4 {
|
||||||
public:
|
public:
|
||||||
union {
|
union {
|
||||||
struct { float x, y, z, w; };
|
struct { T x, y, z, w; };
|
||||||
struct { float r, g, b, a; };
|
struct { T r, g, b, a; };
|
||||||
struct { float s, t, p, q; }; // For texture coordinates
|
struct { T s, t, p, q; }; // For texture coordinates
|
||||||
};
|
};
|
||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
Vec4() : x(0), y(0), z(0), w(0) {}
|
Vec4() : x(0), y(0), z(0), w(0) {}
|
||||||
Vec4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {}
|
Vec4(T x, T y, T z, T w) : x(x), y(y), z(z), w(w) {}
|
||||||
Vec4(float scalar) : x(scalar), y(scalar), z(scalar), w(scalar) {}
|
Vec4(T scalar) : x(scalar), y(scalar), z(scalar), w(scalar) {}
|
||||||
|
|
||||||
Vec4(const Vec3& rgb, float w = 1.0f) : x(rgb.x), y(rgb.y), z(rgb.z), w(w) {}
|
Vec4(const Vec3<T>& rgb, T w = 1) : x(rgb.x), y(rgb.y), z(rgb.z), w(w) {}
|
||||||
static Vec4 RGB(float r, float g, float b, float a = 1.0f) { return Vec4(r, g, b, a); }
|
static Vec4 RGB(T r, T g, T b, T a = 1) { return Vec4(r, g, b, a); }
|
||||||
static Vec4 RGBA(float r, float g, float b, float a) { return Vec4(r, g, b, a); }
|
static Vec4 RGBA(T r, T g, T b, T a) { return Vec4(r, g, b, a); }
|
||||||
|
|
||||||
Vec4& recolor(const Vec4 newColor) {
|
Vec4& recolor(const Vec4& newColor) {
|
||||||
r = newColor.r;
|
r = newColor.r;
|
||||||
g = newColor.g;
|
g = newColor.g;
|
||||||
b = newColor.b;
|
b = newColor.b;
|
||||||
@@ -53,11 +54,11 @@ public:
|
|||||||
return Vec4(x / other.x, y / other.y, z / other.z, w / other.w);
|
return Vec4(x / other.x, y / other.y, z / other.z, w / other.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec4 operator+(float scalar) const {
|
Vec4 operator+(T scalar) const {
|
||||||
return Vec4(x + scalar, y + scalar, z + scalar, w + scalar);
|
return Vec4(x + scalar, y + scalar, z + scalar, w + scalar);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec4 operator-(float scalar) const {
|
Vec4 operator-(T scalar) const {
|
||||||
return Vec4(x - scalar, y - scalar, z - scalar, w - scalar);
|
return Vec4(x - scalar, y - scalar, z - scalar, w - scalar);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,15 +66,15 @@ public:
|
|||||||
return Vec4(-x, -y, -z, -w);
|
return Vec4(-x, -y, -z, -w);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec4 operator*(float scalar) const {
|
Vec4 operator*(T scalar) const {
|
||||||
return Vec4(x * scalar, y * scalar, z * scalar, w * scalar);
|
return Vec4(x * scalar, y * scalar, z * scalar, w * scalar);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec4 operator/(float scalar) const {
|
Vec4 operator/(T scalar) const {
|
||||||
return Vec4(x / scalar, y / scalar, z / scalar, w / scalar);
|
return Vec4(x / scalar, y / scalar, z / scalar, w / scalar);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec4& operator=(float scalar) {
|
Vec4& operator=(T scalar) {
|
||||||
x = y = z = w = scalar;
|
x = y = z = w = scalar;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -110,7 +111,7 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec4& operator+=(float scalar) {
|
Vec4& operator+=(T scalar) {
|
||||||
x += scalar;
|
x += scalar;
|
||||||
y += scalar;
|
y += scalar;
|
||||||
z += scalar;
|
z += scalar;
|
||||||
@@ -118,7 +119,7 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec4& operator-=(float scalar) {
|
Vec4& operator-=(T scalar) {
|
||||||
x -= scalar;
|
x -= scalar;
|
||||||
y -= scalar;
|
y -= scalar;
|
||||||
z -= scalar;
|
z -= scalar;
|
||||||
@@ -126,7 +127,7 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec4& operator*=(float scalar) {
|
Vec4& operator*=(T scalar) {
|
||||||
x *= scalar;
|
x *= scalar;
|
||||||
y *= scalar;
|
y *= scalar;
|
||||||
z *= scalar;
|
z *= scalar;
|
||||||
@@ -134,7 +135,7 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec4& operator/=(float scalar) {
|
Vec4& operator/=(T scalar) {
|
||||||
x /= scalar;
|
x /= scalar;
|
||||||
y /= scalar;
|
y /= scalar;
|
||||||
z /= scalar;
|
z /= scalar;
|
||||||
@@ -142,50 +143,50 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
float dot(const Vec4& other) const {
|
T dot(const Vec4& other) const {
|
||||||
return x * other.x + y * other.y + z * other.z + w * other.w;
|
return x * other.x + y * other.y + z * other.z + w * other.w;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4D cross product (returns vector perpendicular to 3 given vectors in 4D space)
|
// 4D cross product (returns vector perpendicular to 3 given vectors in 4D space)
|
||||||
Vec4 cross(const Vec4& v1, const Vec4& v2, const Vec4& v3) const {
|
Vec4 cross(const Vec4& v1, const Vec4& v2, const Vec4& v3) const {
|
||||||
float a = v1.y * (v2.z * v3.w - v2.w * v3.z) -
|
T a = v1.y * (v2.z * v3.w - v2.w * v3.z) -
|
||||||
v1.z * (v2.y * v3.w - v2.w * v3.y) +
|
v1.z * (v2.y * v3.w - v2.w * v3.y) +
|
||||||
v1.w * (v2.y * v3.z - v2.z * v3.y);
|
v1.w * (v2.y * v3.z - v2.z * v3.y);
|
||||||
|
|
||||||
float b = -v1.x * (v2.z * v3.w - v2.w * v3.z) +
|
T b = -v1.x * (v2.z * v3.w - v2.w * v3.z) +
|
||||||
v1.z * (v2.x * v3.w - v2.w * v3.x) -
|
v1.z * (v2.x * v3.w - v2.w * v3.x) -
|
||||||
v1.w * (v2.x * v3.z - v2.z * v3.x);
|
v1.w * (v2.x * v3.z - v2.z * v3.x);
|
||||||
|
|
||||||
float c = v1.x * (v2.y * v3.w - v2.w * v3.y) -
|
T c = v1.x * (v2.y * v3.w - v2.w * v3.y) -
|
||||||
v1.y * (v2.x * v3.w - v2.w * v3.x) +
|
v1.y * (v2.x * v3.w - v2.w * v3.x) +
|
||||||
v1.w * (v2.x * v3.y - v2.y * v3.x);
|
v1.w * (v2.x * v3.y - v2.y * v3.x);
|
||||||
|
|
||||||
float d = -v1.x * (v2.y * v3.z - v2.z * v3.y) +
|
T d = -v1.x * (v2.y * v3.z - v2.z * v3.y) +
|
||||||
v1.y * (v2.x * v3.z - v2.z * v3.x) -
|
v1.y * (v2.x * v3.z - v2.z * v3.x) -
|
||||||
v1.z * (v2.x * v3.y - v2.y * v3.x);
|
v1.z * (v2.x * v3.y - v2.y * v3.x);
|
||||||
|
|
||||||
return Vec4(a, b, c, d);
|
return Vec4(a, b, c, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
float length() const {
|
T length() const {
|
||||||
return std::sqrt(x * x + y * y + z * z + w * w);
|
return static_cast<T>(std::sqrt(static_cast<double>(x * x + y * y + z * z + w * w)));
|
||||||
}
|
}
|
||||||
|
|
||||||
float lengthSquared() const {
|
T lengthSquared() const {
|
||||||
return x * x + y * y + z * z + w * w;
|
return x * x + y * y + z * z + w * w;
|
||||||
}
|
}
|
||||||
|
|
||||||
float distance(const Vec4& other) const {
|
T distance(const Vec4& other) const {
|
||||||
return (*this - other).length();
|
return (*this - other).length();
|
||||||
}
|
}
|
||||||
|
|
||||||
float distanceSquared(const Vec4& other) const {
|
T distanceSquared(const Vec4& other) const {
|
||||||
Vec4 diff = *this - other;
|
Vec4 diff = *this - other;
|
||||||
return diff.x * diff.x + diff.y * diff.y + diff.z * diff.z + diff.w * diff.w;
|
return diff.x * diff.x + diff.y * diff.y + diff.z * diff.z + diff.w * diff.w;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec4 normalized() const {
|
Vec4 normalized() const {
|
||||||
float len = length();
|
T len = length();
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
return *this / len;
|
return *this / len;
|
||||||
}
|
}
|
||||||
@@ -194,8 +195,8 @@ public:
|
|||||||
|
|
||||||
// Homogeneous normalization (divide by w)
|
// Homogeneous normalization (divide by w)
|
||||||
Vec4 homogenized() const {
|
Vec4 homogenized() const {
|
||||||
if (w != 0.0f) {
|
if (w != 0) {
|
||||||
return Vec4(x / w, y / w, z / w, 1.0f);
|
return Vec4(x / w, y / w, z / w, 1);
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -203,36 +204,45 @@ public:
|
|||||||
// Clamp values between 0 and 1
|
// Clamp values between 0 and 1
|
||||||
Vec4 clamped() const {
|
Vec4 clamped() const {
|
||||||
return Vec4(
|
return Vec4(
|
||||||
std::clamp(r, 0.0f, 1.0f),
|
std::clamp(r, static_cast<T>(0), static_cast<T>(1)),
|
||||||
std::clamp(g, 0.0f, 1.0f),
|
std::clamp(g, static_cast<T>(0), static_cast<T>(1)),
|
||||||
std::clamp(b, 0.0f, 1.0f),
|
std::clamp(b, static_cast<T>(0), static_cast<T>(1)),
|
||||||
std::clamp(a, 0.0f, 1.0f)
|
std::clamp(a, static_cast<T>(0), static_cast<T>(1))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to Vec3 (ignoring alpha)
|
// Convert to Vec3 (ignoring alpha)
|
||||||
Vec3 toVec3() const {
|
Vec3<T> toVec3() const {
|
||||||
return Vec3(r, g, b);
|
return Vec3<T>(r, g, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to 8-bit color values
|
// Convert to 8-bit color values
|
||||||
void toUint8(uint8_t& red, uint8_t& green, uint8_t& blue, uint8_t& alpha) const {
|
template<typename U = T>
|
||||||
red = static_cast<uint8_t>(std::clamp(r, 0.0f, 1.0f) * 255);
|
typename std::enable_if<std::is_floating_point<U>::value>::type
|
||||||
green = static_cast<uint8_t>(std::clamp(g, 0.0f, 1.0f) * 255);
|
toUint8(uint8_t& red, uint8_t& green, uint8_t& blue, uint8_t& alpha) const {
|
||||||
blue = static_cast<uint8_t>(std::clamp(b, 0.0f, 1.0f) * 255);
|
red = static_cast<uint8_t>(std::clamp(r, static_cast<T>(0), static_cast<T>(1)) * 255);
|
||||||
alpha = static_cast<uint8_t>(std::clamp(a, 0.0f, 1.0f) * 255);
|
green = static_cast<uint8_t>(std::clamp(g, static_cast<T>(0), static_cast<T>(1)) * 255);
|
||||||
|
blue = static_cast<uint8_t>(std::clamp(b, static_cast<T>(0), static_cast<T>(1)) * 255);
|
||||||
|
alpha = static_cast<uint8_t>(std::clamp(a, static_cast<T>(0), static_cast<T>(1)) * 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
void toUint8(uint8_t& red, uint8_t& green, uint8_t& blue) const {
|
template<typename U = T>
|
||||||
red = static_cast<uint8_t>(std::clamp(r, 0.0f, 1.0f) * 255);
|
typename std::enable_if<std::is_floating_point<U>::value>::type
|
||||||
green = static_cast<uint8_t>(std::clamp(g, 0.0f, 1.0f) * 255);
|
toUint8(uint8_t& red, uint8_t& green, uint8_t& blue) const {
|
||||||
blue = static_cast<uint8_t>(std::clamp(b, 0.0f, 1.0f) * 255);
|
red = static_cast<uint8_t>(std::clamp(r, static_cast<T>(0), static_cast<T>(1)) * 255);
|
||||||
|
green = static_cast<uint8_t>(std::clamp(g, static_cast<T>(0), static_cast<T>(1)) * 255);
|
||||||
|
blue = static_cast<uint8_t>(std::clamp(b, static_cast<T>(0), static_cast<T>(1)) * 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get XYZ components as Vec3
|
// Get XYZ components as Vec3
|
||||||
class Vec3 xyz() const;
|
Vec3<T> xyz() const {
|
||||||
|
return Vec3<T>(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
// Get RGB components as Vec3
|
// Get RGB components as Vec3
|
||||||
class Vec3 rgb() const;
|
Vec3<T> rgb() const {
|
||||||
|
return Vec3<T>(r, g, b);
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==(const Vec4& other) const {
|
bool operator==(const Vec4& other) const {
|
||||||
return x == other.x && y == other.y && z == other.z && w == other.w;
|
return x == other.x && y == other.y && z == other.z && w == other.w;
|
||||||
@@ -296,7 +306,7 @@ public:
|
|||||||
std::max(z, other.z), std::max(w, other.w));
|
std::max(z, other.z), std::max(w, other.w));
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec4 clamp(float minVal, float maxVal) const {
|
Vec4 clamp(T minVal, T maxVal) const {
|
||||||
return Vec4(
|
return Vec4(
|
||||||
std::clamp(x, minVal, maxVal),
|
std::clamp(x, minVal, maxVal),
|
||||||
std::clamp(y, minVal, maxVal),
|
std::clamp(y, minVal, maxVal),
|
||||||
@@ -315,54 +325,58 @@ public:
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isZero(float epsilon = 1e-10f) const {
|
bool isZero(T epsilon = static_cast<T>(1e-10)) const {
|
||||||
return std::abs(x) < epsilon && std::abs(y) < epsilon &&
|
return std::abs(x) < epsilon && std::abs(y) < epsilon &&
|
||||||
std::abs(z) < epsilon && std::abs(w) < epsilon;
|
std::abs(z) < epsilon && std::abs(w) < epsilon;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool equals(const Vec4& other, float epsilon = 1e-10f) const {
|
bool equals(const Vec4& other, T epsilon = static_cast<T>(1e-10)) const {
|
||||||
return std::abs(x - other.x) < epsilon &&
|
return std::abs(x - other.x) < epsilon &&
|
||||||
std::abs(y - other.y) < epsilon &&
|
std::abs(y - other.y) < epsilon &&
|
||||||
std::abs(z - other.z) < epsilon &&
|
std::abs(z - other.z) < epsilon &&
|
||||||
std::abs(w - other.w) < epsilon;
|
std::abs(w - other.w) < epsilon;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend Vec4 operator+(float scalar, const Vec4& vec) {
|
friend Vec4 operator+(T scalar, const Vec4& vec) {
|
||||||
return Vec4(scalar + vec.x, scalar + vec.y, scalar + vec.z, scalar + vec.w);
|
return Vec4(scalar + vec.x, scalar + vec.y, scalar + vec.z, scalar + vec.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend Vec4 operator-(float scalar, const Vec4& vec) {
|
friend Vec4 operator-(T scalar, const Vec4& vec) {
|
||||||
return Vec4(scalar - vec.x, scalar - vec.y, scalar - vec.z, scalar - vec.w);
|
return Vec4(scalar - vec.x, scalar - vec.y, scalar - vec.z, scalar - vec.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend Vec4 operator*(float scalar, const Vec4& vec) {
|
friend Vec4 operator*(T scalar, const Vec4& vec) {
|
||||||
return Vec4(scalar * vec.x, scalar * vec.y, scalar * vec.z, scalar * vec.w);
|
return Vec4(scalar * vec.x, scalar * vec.y, scalar * vec.z, scalar * vec.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend Vec4 operator/(float scalar, const Vec4& vec) {
|
friend Vec4 operator/(T scalar, const Vec4& vec) {
|
||||||
return Vec4(scalar / vec.x, scalar / vec.y, scalar / vec.z, scalar / vec.w);
|
return Vec4(scalar / vec.x, scalar / vec.y, scalar / vec.z, scalar / vec.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec4 lerp(const Vec4& other, float t) const {
|
Vec4 lerp(const Vec4& other, T t) const {
|
||||||
t = std::clamp(t, 0.0f, 1.0f);
|
t = std::clamp(t, static_cast<T>(0), static_cast<T>(1));
|
||||||
return *this + (other - *this) * t;
|
return *this + (other - *this) * t;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to grayscale using standard RGB weights
|
// Convert to grayscale using standard RGB weights (only valid for float/double)
|
||||||
float grayscale() const {
|
template<typename U = T>
|
||||||
return r * 0.299f + g * 0.587f + b * 0.114f;
|
typename std::enable_if<std::is_floating_point<U>::value, T>::type grayscale() const {
|
||||||
|
return r * static_cast<T>(0.299) + g * static_cast<T>(0.587) + b * static_cast<T>(0.114);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Color inversion (1.0 - color)
|
// Color inversion (1.0 - color) (only valid for float/double)
|
||||||
Vec4 inverted() const {
|
template<typename U = T>
|
||||||
return Vec4(1.0f - r, 1.0f - g, 1.0f - b, a);
|
typename std::enable_if<std::is_floating_point<U>::value, Vec4>::type
|
||||||
|
inverted() const {
|
||||||
|
return Vec4(static_cast<T>(1) - r, static_cast<T>(1) - g,
|
||||||
|
static_cast<T>(1) - b, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
float& operator[](int index) {
|
T& operator[](int index) {
|
||||||
return (&x)[index];
|
return (&x)[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
const float& operator[](int index) const {
|
const T& operator[](int index) const {
|
||||||
return (&x)[index];
|
return (&x)[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,29 +385,40 @@ public:
|
|||||||
std::to_string(z) + ", " + std::to_string(w) + ")";
|
std::to_string(z) + ", " + std::to_string(w) + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string toColorString() const {
|
template<typename U = T>
|
||||||
|
typename std::enable_if<std::is_floating_point<U>::value, std::string>::type
|
||||||
|
toColorString() const {
|
||||||
return "RGBA(" + std::to_string(r) + ", " + std::to_string(g) + ", " +
|
return "RGBA(" + std::to_string(r) + ", " + std::to_string(g) + ", " +
|
||||||
std::to_string(b) + ", " + std::to_string(a) + ")";
|
std::to_string(b) + ", " + std::to_string(a) + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Hash {
|
struct Hash {
|
||||||
std::size_t operator()(const Vec4& v) const {
|
std::size_t operator()(const Vec4& v) const {
|
||||||
return std::hash<float>()(v.x) ^ (std::hash<float>()(v.y) << 1) ^ (std::hash<float>()(v.z) << 2) ^ (std::hash<float>()(v.w) << 3);
|
return std::hash<T>()(v.x) ^ (std::hash<T>()(v.y) << 1) ^
|
||||||
|
(std::hash<T>()(v.z) << 2) ^ (std::hash<T>()(v.w) << 3);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::ostream& operator<<(std::ostream& os, const Vec4& vec) {
|
// Type aliases for common use cases
|
||||||
|
using Vec4f = Vec4<float>;
|
||||||
|
using Vec4d = Vec4<double>;
|
||||||
|
using Vec4i = Vec4<int>;
|
||||||
|
using Vec4u = Vec4<unsigned int>;
|
||||||
|
using Vec4ui8 = Vec4<uint8_t>;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, const Vec4<T>& vec) {
|
||||||
os << vec.toString();
|
os << vec.toString();
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
template<>
|
template<typename T>
|
||||||
struct hash<Vec4> {
|
struct hash<Vec4<T>> {
|
||||||
size_t operator()(const Vec4& v) const {
|
size_t operator()(const Vec4<T>& v) const {
|
||||||
return hash<float>()(v.x) ^ (hash<float>()(v.y) << 1) ^
|
return hash<T>()(v.x) ^ (hash<T>()(v.y) << 1) ^
|
||||||
(hash<float>()(v.z) << 2) ^ (hash<float>()(v.w) << 3);
|
(hash<T>()(v.z) << 2) ^ (hash<T>()(v.w) << 3);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user