set up frame to be more useful, minor fixes in grid, added use lod checkbox
This commit is contained in:
@@ -28,6 +28,7 @@ struct defaults {
|
|||||||
int gridSizecube = 10000;
|
int gridSizecube = 10000;
|
||||||
bool slowRender = false;
|
bool slowRender = false;
|
||||||
bool globalIllumination = true;
|
bool globalIllumination = true;
|
||||||
|
bool useLod = true;
|
||||||
int rayCount = 3;
|
int rayCount = 3;
|
||||||
int reflectCount = 3;
|
int reflectCount = 3;
|
||||||
int lodDist = 500;
|
int lodDist = 500;
|
||||||
@@ -408,7 +409,7 @@ void livePreview(Octree<int>& grid, defaults& config, const Camera& cam) {
|
|||||||
grid.setLODMinDistance(config.lodDist);
|
grid.setLODMinDistance(config.lodDist);
|
||||||
grid.setLODFalloff(config.lodDropoff);
|
grid.setLODFalloff(config.lodDropoff);
|
||||||
if (config.slowRender) {
|
if (config.slowRender) {
|
||||||
currentPreviewFrame = grid.renderFrame(cam, config.outWidth, config.outHeight, frame::colormap::RGB, config.rayCount, config.reflectCount, config.globalIllumination);
|
currentPreviewFrame = grid.renderFrame(cam, config.outWidth, config.outHeight, frame::colormap::RGB, config.rayCount, config.reflectCount, config.globalIllumination, config.useLod);
|
||||||
} else {
|
} else {
|
||||||
currentPreviewFrame = grid.fastRenderFrame(cam, config.outWidth, config.outHeight, frame::colormap::RGB);
|
currentPreviewFrame = grid.fastRenderFrame(cam, config.outWidth, config.outHeight, frame::colormap::RGB);
|
||||||
}
|
}
|
||||||
@@ -998,6 +999,7 @@ int main() {
|
|||||||
ImGui::InputFloat("Lod dropoff", &config.lodDropoff);
|
ImGui::InputFloat("Lod dropoff", &config.lodDropoff);
|
||||||
ImGui::InputInt("lod minimum Distance", &config.lodDist);
|
ImGui::InputInt("lod minimum Distance", &config.lodDist);
|
||||||
ImGui::Checkbox("use Global illumination", &config.globalIllumination);
|
ImGui::Checkbox("use Global illumination", &config.globalIllumination);
|
||||||
|
ImGui::Checkbox("use Lod", &config.useLod);
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -502,9 +502,6 @@ private:
|
|||||||
return randomDir;
|
return randomDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
float rgbToGrayscale(const Eigen::Vector3f& color) const {
|
|
||||||
return 0.2126f * color[0] + 0.7152f * color[1] + 0.0722f * color[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
void collectNodesByObjectId(OctreeNode* node, int id, std::vector<std::shared_ptr<NodeData>>& results) const {
|
void collectNodesByObjectId(OctreeNode* node, int id, std::vector<std::shared_ptr<NodeData>>& results) const {
|
||||||
if (!node) return;
|
if (!node) return;
|
||||||
@@ -900,14 +897,14 @@ public:
|
|||||||
if (!pointData->active) continue;
|
if (!pointData->active) continue;
|
||||||
|
|
||||||
float t;
|
float t;
|
||||||
// if (pointData->shape == Shape::SPHERE) {
|
if (pointData->shape == Shape::SPHERE) {
|
||||||
// if (raySphereIntersect(origin, dir, pointData->position, pointData->size, t)) {
|
if (raySphereIntersect(origin, dir, pointData->position, pointData->size, t)) {
|
||||||
// if (t >= 0 && t <= maxDist) {
|
if (t >= 0 && t <= maxDist) {
|
||||||
// hits.emplace_back(pointData);
|
hits.emplace_back(pointData);
|
||||||
// if (stopAtFirstHit) return;
|
if (stopAtFirstHit) return;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// } else {
|
} else {
|
||||||
PointType normal, hitPoint;
|
PointType normal, hitPoint;
|
||||||
if (rayCubeIntersect(origin, dir, pointData.get(), t, normal, hitPoint)) {
|
if (rayCubeIntersect(origin, dir, pointData.get(), t, normal, hitPoint)) {
|
||||||
if (t >= 0 && t <= maxDist) {
|
if (t >= 0 && t <= maxDist) {
|
||||||
@@ -915,7 +912,7 @@ public:
|
|||||||
if (stopAtFirstHit) return;
|
if (stopAtFirstHit) return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < 8; ++i) {
|
for (int i = 0; i < 8; ++i) {
|
||||||
@@ -950,15 +947,8 @@ public:
|
|||||||
PointType right = cam.right();
|
PointType right = cam.right();
|
||||||
|
|
||||||
frame outFrame(width, height, colorformat);
|
frame outFrame(width, height, colorformat);
|
||||||
std::vector<uint8_t> colorBuffer;
|
std::vector<float> colorBuffer;
|
||||||
int channels;
|
int channels = 3;
|
||||||
if (colorformat == frame::colormap::B) {
|
|
||||||
channels = 1;
|
|
||||||
} else if (colorformat == frame::colormap::RGB || colorformat == frame::colormap::BGR) {
|
|
||||||
channels = 3;
|
|
||||||
} else { //BGRA and RGBA
|
|
||||||
channels = 4;
|
|
||||||
}
|
|
||||||
colorBuffer.resize(width * height * channels);
|
colorBuffer.resize(width * height * channels);
|
||||||
|
|
||||||
float aspect = static_cast<float>(width) / height;
|
float aspect = static_cast<float>(width) / height;
|
||||||
@@ -1005,7 +995,6 @@ public:
|
|||||||
hitPoint = rayOrig + rayDir * t;
|
hitPoint = rayOrig + rayDir * t;
|
||||||
normal = (hitPoint - center).normalized();
|
normal = (hitPoint - center).normalized();
|
||||||
} else {
|
} else {
|
||||||
// Cube intersection
|
|
||||||
PointType cubeNormal;
|
PointType cubeNormal;
|
||||||
if (!rayCubeIntersect(rayOrig, rayDir, obj.get(), t, normal, hitPoint)) {
|
if (!rayCubeIntersect(rayOrig, rayDir, obj.get(), t, normal, hitPoint)) {
|
||||||
return globalIllumination ? skylight_ : Eigen::Vector3f::Zero();
|
return globalIllumination ? skylight_ : Eigen::Vector3f::Zero();
|
||||||
@@ -1030,11 +1019,6 @@ public:
|
|||||||
finalColor += obj->color.cwiseProduct(incomingLight) * diffuseProb;
|
finalColor += obj->color.cwiseProduct(incomingLight) * diffuseProb;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (refl > 0.001f) {
|
|
||||||
PointType rDir = (rayDir - 2.0f * rayDir.dot(normal) * normal).normalized();
|
|
||||||
finalColor += traceRay(hitPoint + normal * 0.002f, rDir, bounces + 1, rngState) * refl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (refr > 0.001f) {
|
if (refr > 0.001f) {
|
||||||
float ior = 1.45f;
|
float ior = 1.45f;
|
||||||
float η = 1.0f / ior;
|
float η = 1.0f / ior;
|
||||||
@@ -1084,37 +1068,13 @@ public:
|
|||||||
|
|
||||||
color = color.cwiseMax(0.0f).cwiseMin(1.0f);
|
color = color.cwiseMax(0.0f).cwiseMin(1.0f);
|
||||||
|
|
||||||
switch(colorformat) {
|
colorBuffer[idx ] = color[0];
|
||||||
case frame::colormap::B:
|
colorBuffer[idx + 1] = color[1];
|
||||||
colorBuffer[idx ] = static_cast<uint8_t>(rgbToGrayscale(color) * 255.0f);
|
colorBuffer[idx + 2] = color[2];
|
||||||
break;
|
|
||||||
case frame::colormap::RGB:
|
|
||||||
colorBuffer[idx ] = static_cast<uint8_t>(color[0] * 255.0f);
|
|
||||||
colorBuffer[idx + 1] = static_cast<uint8_t>(color[1] * 255.0f);
|
|
||||||
colorBuffer[idx + 2] = static_cast<uint8_t>(color[2] * 255.0f);
|
|
||||||
break;
|
|
||||||
case frame::colormap::BGR:
|
|
||||||
colorBuffer[idx ] = static_cast<uint8_t>(color[2] * 255.0f);
|
|
||||||
colorBuffer[idx + 1] = static_cast<uint8_t>(color[1] * 255.0f);
|
|
||||||
colorBuffer[idx + 2] = static_cast<uint8_t>(color[0] * 255.0f);
|
|
||||||
break;
|
|
||||||
case frame::colormap::RGBA:
|
|
||||||
colorBuffer[idx ] = static_cast<uint8_t>(color[0] * 255.0f);
|
|
||||||
colorBuffer[idx + 1] = static_cast<uint8_t>(color[1] * 255.0f);
|
|
||||||
colorBuffer[idx + 2] = static_cast<uint8_t>(color[2] * 255.0f);
|
|
||||||
colorBuffer[idx + 3] = 255;
|
|
||||||
break;
|
|
||||||
case frame::colormap::BGRA:
|
|
||||||
colorBuffer[idx ] = static_cast<uint8_t>(color[2] * 255.0f);
|
|
||||||
colorBuffer[idx + 1] = static_cast<uint8_t>(color[1] * 255.0f);
|
|
||||||
colorBuffer[idx + 2] = static_cast<uint8_t>(color[0] * 255.0f);
|
|
||||||
colorBuffer[idx + 3] = 255;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
outFrame.setData(colorBuffer);
|
outFrame.setData(colorBuffer, frame::colormap::RGB);
|
||||||
return outFrame;
|
return outFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1214,15 +1174,9 @@ public:
|
|||||||
PointType right = cam.right();
|
PointType right = cam.right();
|
||||||
|
|
||||||
frame outFrame(width, height, colorformat);
|
frame outFrame(width, height, colorformat);
|
||||||
std::vector<uint8_t> colorBuffer;
|
std::vector<float> colorBuffer;
|
||||||
int channels;
|
int channels;
|
||||||
if (colorformat == frame::colormap::B) {
|
|
||||||
channels = 1;
|
|
||||||
} else if (colorformat == frame::colormap::RGB || colorformat == frame::colormap::BGR) {
|
|
||||||
channels = 3;
|
channels = 3;
|
||||||
} else { //BGRA and RGBA
|
|
||||||
channels = 4;
|
|
||||||
}
|
|
||||||
colorBuffer.resize(width * height * channels);
|
colorBuffer.resize(width * height * channels);
|
||||||
|
|
||||||
float aspect = static_cast<float>(width) / height;
|
float aspect = static_cast<float>(width) / height;
|
||||||
@@ -1262,37 +1216,13 @@ public:
|
|||||||
color = color * lightDot;
|
color = color * lightDot;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(colorformat) {
|
colorBuffer[idx ] = color[0];
|
||||||
case frame::colormap::B:
|
colorBuffer[idx + 1] = color[1];
|
||||||
colorBuffer[idx ] = static_cast<uint8_t>(rgbToGrayscale(color) * 255.0f);
|
colorBuffer[idx + 2] = color[2];
|
||||||
break;
|
|
||||||
case frame::colormap::RGB:
|
|
||||||
colorBuffer[idx ] = static_cast<uint8_t>(color[0] * 255.0f);
|
|
||||||
colorBuffer[idx + 1] = static_cast<uint8_t>(color[1] * 255.0f);
|
|
||||||
colorBuffer[idx + 2] = static_cast<uint8_t>(color[2] * 255.0f);
|
|
||||||
break;
|
|
||||||
case frame::colormap::BGR:
|
|
||||||
colorBuffer[idx ] = static_cast<uint8_t>(color[2] * 255.0f);
|
|
||||||
colorBuffer[idx + 1] = static_cast<uint8_t>(color[1] * 255.0f);
|
|
||||||
colorBuffer[idx + 2] = static_cast<uint8_t>(color[0] * 255.0f);
|
|
||||||
break;
|
|
||||||
case frame::colormap::RGBA:
|
|
||||||
colorBuffer[idx ] = static_cast<uint8_t>(color[0] * 255.0f);
|
|
||||||
colorBuffer[idx + 1] = static_cast<uint8_t>(color[1] * 255.0f);
|
|
||||||
colorBuffer[idx + 2] = static_cast<uint8_t>(color[2] * 255.0f);
|
|
||||||
colorBuffer[idx + 3] = 255;
|
|
||||||
break;
|
|
||||||
case frame::colormap::BGRA:
|
|
||||||
colorBuffer[idx ] = static_cast<uint8_t>(color[2] * 255.0f);
|
|
||||||
colorBuffer[idx + 1] = static_cast<uint8_t>(color[1] * 255.0f);
|
|
||||||
colorBuffer[idx + 2] = static_cast<uint8_t>(color[0] * 255.0f);
|
|
||||||
colorBuffer[idx + 3] = 255;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
outFrame.setData(colorBuffer);
|
outFrame.setData(colorBuffer, frame::colormap::RGB);
|
||||||
return outFrame;
|
return outFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
#include <future>
|
#include <future>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <cmath>
|
||||||
|
#include <iomanip>
|
||||||
#include "../timing_decorator.hpp"
|
#include "../timing_decorator.hpp"
|
||||||
|
|
||||||
class frame {
|
class frame {
|
||||||
@@ -26,7 +28,6 @@ private:
|
|||||||
size_t sourceSize = 0;
|
size_t sourceSize = 0;
|
||||||
size_t width = 0;
|
size_t width = 0;
|
||||||
size_t height = 0;
|
size_t height = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum class colormap {
|
enum class colormap {
|
||||||
RGB,
|
RGB,
|
||||||
@@ -44,7 +45,29 @@ public:
|
|||||||
HUFFMAN,
|
HUFFMAN,
|
||||||
RAW
|
RAW
|
||||||
};
|
};
|
||||||
|
private:
|
||||||
|
size_t getChannels(colormap fmt) const {
|
||||||
|
switch (fmt) {
|
||||||
|
case colormap::RGBA: return 4;
|
||||||
|
case colormap::BGR: return 3;
|
||||||
|
case colormap::BGRA: return 4;
|
||||||
|
case colormap::B: return 1;
|
||||||
|
case colormap::RGB: default: return 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetState(size_t newSize) {
|
||||||
|
cformat = compresstype::RAW;
|
||||||
|
_compressedData.clear();
|
||||||
|
_compressedData.shrink_to_fit();
|
||||||
|
overheadmap.clear();
|
||||||
|
sourceSize = newSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
float rgbToGrayscale(float r, float g, float b) const {
|
||||||
|
return 0.2126f * r + 0.7152f * g + 0.0722f * b;
|
||||||
|
}
|
||||||
|
public:
|
||||||
colormap colorFormat = colormap::RGB;
|
colormap colorFormat = colormap::RGB;
|
||||||
compresstype cformat = compresstype::RAW;
|
compresstype cformat = compresstype::RAW;
|
||||||
|
|
||||||
@@ -58,30 +81,245 @@ public:
|
|||||||
frame() {};
|
frame() {};
|
||||||
frame(size_t w, size_t h, colormap format = colormap::RGB)
|
frame(size_t w, size_t h, colormap format = colormap::RGB)
|
||||||
: width(w), height(h), colorFormat(format), cformat(compresstype::RAW) {
|
: width(w), height(h), colorFormat(format), cformat(compresstype::RAW) {
|
||||||
size_t channels = 3;
|
_data.resize(width * height * getChannels(format));
|
||||||
switch (format) {
|
|
||||||
case colormap::RGBA: channels = 4; break;
|
|
||||||
case colormap::BGR: channels = 3; break;
|
|
||||||
case colormap::BGRA: channels = 4; break;
|
|
||||||
case colormap::B: channels = 1; break;
|
|
||||||
default: channels = 3; break;
|
|
||||||
}
|
|
||||||
_data.resize(width * height * channels);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setData(const std::vector<uint8_t>& data) {
|
void setData(const std::vector<uint8_t>& data) {
|
||||||
_data = data;
|
_data = data;
|
||||||
cformat = compresstype::RAW;
|
resetState(data.size());
|
||||||
_compressedData.clear();
|
}
|
||||||
_compressedData.shrink_to_fit();
|
|
||||||
overheadmap.clear();
|
void setData(const std::vector<uint8_t>& inputData, colormap inputFormat) {
|
||||||
sourceSize = data.size();
|
if (inputFormat == colorFormat) {
|
||||||
|
setData(inputData);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t srcChannels = getChannels(inputFormat);
|
||||||
|
size_t dstChannels = getChannels(colorFormat);
|
||||||
|
size_t numPixels = width * height;
|
||||||
|
|
||||||
|
if (inputData.size() != numPixels * srcChannels) {
|
||||||
|
throw std::runtime_error("Input data size does not match frame dimensions for the specified format.");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> newData;
|
||||||
|
newData.reserve(numPixels * dstChannels);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < numPixels; ++i) {
|
||||||
|
size_t px = i * srcChannels;
|
||||||
|
uint8_t r = 0, g = 0, b = 0, a = 255;
|
||||||
|
|
||||||
|
switch (inputFormat) {
|
||||||
|
case colormap::RGB: {
|
||||||
|
r = inputData[px];
|
||||||
|
g = inputData[px+1];
|
||||||
|
b = inputData[px+2];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case colormap::RGBA:
|
||||||
|
r = inputData[px];
|
||||||
|
g = inputData[px+1];
|
||||||
|
b = inputData[px+2];
|
||||||
|
a = inputData[px+3];
|
||||||
|
break;
|
||||||
|
case colormap::BGR:
|
||||||
|
b = inputData[px];
|
||||||
|
g = inputData[px+1];
|
||||||
|
r = inputData[px+2];
|
||||||
|
break;
|
||||||
|
case colormap::BGRA:
|
||||||
|
b = inputData[px];
|
||||||
|
g = inputData[px+1];
|
||||||
|
r = inputData[px+2];
|
||||||
|
a = inputData[px+3];
|
||||||
|
break;
|
||||||
|
case colormap::B:
|
||||||
|
r = g = b = inputData[px];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (colorFormat) {
|
||||||
|
case colormap::RGB:
|
||||||
|
newData.push_back(r);
|
||||||
|
newData.push_back(g);
|
||||||
|
newData.push_back(b);
|
||||||
|
break;
|
||||||
|
case colormap::RGBA:
|
||||||
|
newData.push_back(r);
|
||||||
|
newData.push_back(g);
|
||||||
|
newData.push_back(b);
|
||||||
|
newData.push_back(a);
|
||||||
|
break;
|
||||||
|
case colormap::BGR:
|
||||||
|
newData.push_back(b);
|
||||||
|
newData.push_back(g);
|
||||||
|
newData.push_back(r);
|
||||||
|
break;
|
||||||
|
case colormap::BGRA:
|
||||||
|
newData.push_back(b);
|
||||||
|
newData.push_back(g);
|
||||||
|
newData.push_back(r);
|
||||||
|
newData.push_back(a);
|
||||||
|
break;
|
||||||
|
case colormap::B:
|
||||||
|
newData.push_back(rgbToGrayscale(r, g, b));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_data = std::move(newData);
|
||||||
|
resetState(_data.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void setData(const std::vector<float>& inputData) {
|
||||||
|
size_t channels = getChannels(colorFormat);
|
||||||
|
|
||||||
|
if (inputData.size() != width * height * channels) {
|
||||||
|
throw std::runtime_error("Input float data size does not match frame dimensions.");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> newData;
|
||||||
|
newData.reserve(inputData.size());
|
||||||
|
|
||||||
|
for (float val : inputData) {
|
||||||
|
// Clamp between 0.0 and 1.0, scale to 255
|
||||||
|
float v = std::max(0.0f, std::min(1.0f, val));
|
||||||
|
newData.push_back(static_cast<uint8_t>(v * 255.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
_data = std::move(newData);
|
||||||
|
resetState(_data.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void setData(const std::vector<float>& inputData, colormap inputFormat) {
|
||||||
|
size_t srcChannels = getChannels(inputFormat);
|
||||||
|
size_t dstChannels = getChannels(colorFormat);
|
||||||
|
size_t numPixels = width * height;
|
||||||
|
|
||||||
|
if (inputData.size() != numPixels * srcChannels) {
|
||||||
|
throw std::runtime_error("Input float data size does not match frame dimensions.");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> newData;
|
||||||
|
newData.reserve(numPixels * dstChannels);
|
||||||
|
|
||||||
|
auto floatToByte = [](float f) -> uint8_t {
|
||||||
|
return static_cast<uint8_t>(std::max(0.0f, std::min(1.0f, f)) * 255.0f);
|
||||||
|
};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < numPixels; ++i) {
|
||||||
|
size_t px = i * srcChannels;
|
||||||
|
uint8_t r = 0, g = 0, b = 0, a = 255;
|
||||||
|
|
||||||
|
// Extract and convert floats to bytes
|
||||||
|
switch (inputFormat) {
|
||||||
|
case colormap::RGB:
|
||||||
|
r = floatToByte(inputData[px]);
|
||||||
|
g = floatToByte(inputData[px+1]);
|
||||||
|
b = floatToByte(inputData[px+2]);
|
||||||
|
break;
|
||||||
|
case colormap::RGBA:
|
||||||
|
r = floatToByte(inputData[px]);
|
||||||
|
g = floatToByte(inputData[px+1]);
|
||||||
|
b = floatToByte(inputData[px+2]);
|
||||||
|
a = floatToByte(inputData[px+3]);
|
||||||
|
break;
|
||||||
|
case colormap::BGR:
|
||||||
|
b = floatToByte(inputData[px]);
|
||||||
|
g = floatToByte(inputData[px+1]);
|
||||||
|
r = floatToByte(inputData[px+2]);
|
||||||
|
break;
|
||||||
|
case colormap::BGRA:
|
||||||
|
b = floatToByte(inputData[px]);
|
||||||
|
g = floatToByte(inputData[px+1]);
|
||||||
|
r = floatToByte(inputData[px+2]);
|
||||||
|
a = floatToByte(inputData[px+3]);
|
||||||
|
break;
|
||||||
|
case colormap::B:
|
||||||
|
r = g = b = floatToByte(inputData[px]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (colorFormat) {
|
||||||
|
case colormap::RGB:
|
||||||
|
newData.push_back(r);
|
||||||
|
newData.push_back(g);
|
||||||
|
newData.push_back(b);
|
||||||
|
break;
|
||||||
|
case colormap::RGBA:
|
||||||
|
newData.push_back(r);
|
||||||
|
newData.push_back(g);
|
||||||
|
newData.push_back(b);
|
||||||
|
newData.push_back(a);
|
||||||
|
break;
|
||||||
|
case colormap::BGR:
|
||||||
|
newData.push_back(b);
|
||||||
|
newData.push_back(g);
|
||||||
|
newData.push_back(r);
|
||||||
|
break;
|
||||||
|
case colormap::BGRA:
|
||||||
|
newData.push_back(b);
|
||||||
|
newData.push_back(g);
|
||||||
|
newData.push_back(r);
|
||||||
|
newData.push_back(a);
|
||||||
|
break;
|
||||||
|
case colormap::B:
|
||||||
|
newData.push_back(rgbToGrayscale(r, g, b));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_data = std::move(newData);
|
||||||
|
resetState(_data.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<uint8_t>& getData() const {
|
const std::vector<uint8_t>& getData() const {
|
||||||
return _data;
|
return _data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> getPixel(size_t x, size_t y) const {
|
||||||
|
if (cformat != compresstype::RAW) {
|
||||||
|
throw std::runtime_error("Cannot get pixel data from a compressed frame. Decompress first.");
|
||||||
|
}
|
||||||
|
if (x >= width || y >= height) {
|
||||||
|
throw std::out_of_range("Pixel coordinates out of bounds.");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t channels = getChannels(colorFormat);
|
||||||
|
size_t index = (y * width + x) * channels;
|
||||||
|
|
||||||
|
std::vector<uint8_t> pixel;
|
||||||
|
pixel.reserve(channels);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < channels; ++i) {
|
||||||
|
pixel.push_back(_data[index + i]);
|
||||||
|
}
|
||||||
|
return pixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPixel(size_t x, size_t y, const std::vector<uint8_t>& values) {
|
||||||
|
if (cformat != compresstype::RAW) {
|
||||||
|
throw std::runtime_error("Cannot set pixel data on a compressed frame. Decompress first.");
|
||||||
|
}
|
||||||
|
if (x >= width || y >= height) {
|
||||||
|
throw std::out_of_range("Pixel coordinates out of bounds.");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t channels = getChannels(colorFormat);
|
||||||
|
if (values.size() != channels) {
|
||||||
|
throw std::invalid_argument("Input value count does not match frame channel count.");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t index = (y * width + x) * channels;
|
||||||
|
for (size_t i = 0; i < channels; ++i) {
|
||||||
|
_data[index + i] = values[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since data changed, previous compression stats are invalid
|
||||||
|
resetState(_data.size());
|
||||||
|
}
|
||||||
|
|
||||||
// Run-Length Encoding (RLE) compression
|
// Run-Length Encoding (RLE) compression
|
||||||
frame& compressFrameRLE() {
|
frame& compressFrameRLE() {
|
||||||
TIME_FUNCTION;
|
TIME_FUNCTION;
|
||||||
@@ -243,13 +481,27 @@ public:
|
|||||||
void printCompressionInfo() const {
|
void printCompressionInfo() const {
|
||||||
std::cout << "Compression Type: ";
|
std::cout << "Compression Type: ";
|
||||||
switch (cformat) {
|
switch (cformat) {
|
||||||
case compresstype::RLE: std::cout << "RLE"; break;
|
case compresstype::RLE:
|
||||||
case compresstype::DIFF: std::cout << "DIFF"; break;
|
std::cout << "RLE";
|
||||||
case compresstype::DIFFRLE: std::cout << "DIFF + RLE"; break;
|
break;
|
||||||
case compresstype::LZ78: std::cout << "LZ78 (kinda)"; break;
|
case compresstype::DIFF:
|
||||||
case compresstype::HUFFMAN: std::cout << "HUFFMAN"; break;
|
std::cout << "DIFF";
|
||||||
case compresstype::RAW: std::cout << "RAW (uncompressed)"; break;
|
break;
|
||||||
default: std::cout << "UNKNOWN"; break;
|
case compresstype::DIFFRLE:
|
||||||
|
std::cout << "DIFF + RLE";
|
||||||
|
break;
|
||||||
|
case compresstype::LZ78:
|
||||||
|
std::cout << "LZ78 (kinda)";
|
||||||
|
break;
|
||||||
|
case compresstype::HUFFMAN:
|
||||||
|
std::cout << "HUFFMAN";
|
||||||
|
break;
|
||||||
|
case compresstype::RAW:
|
||||||
|
std::cout << "RAW (uncompressed)";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
std::cout << "UNKNOWN";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
|
||||||
@@ -503,19 +755,30 @@ private:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, frame& f) {
|
||||||
std::ostream& operator<<(std::ostream& os, frame& f) {
|
|
||||||
os << "Frame[" << f.getWidth() << "x" << f.getHeight() << "] ";
|
os << "Frame[" << f.getWidth() << "x" << f.getHeight() << "] ";
|
||||||
|
|
||||||
// Color format
|
// Color format
|
||||||
os << "Format: ";
|
os << "Format: ";
|
||||||
switch (f.colorFormat) {
|
switch (f.colorFormat) {
|
||||||
case frame::colormap::RGB: os << "RGB"; break;
|
case frame::colormap::RGB:
|
||||||
case frame::colormap::RGBA: os << "RGBA"; break;
|
os << "RGB";
|
||||||
case frame::colormap::BGR: os << "BGR"; break;
|
break;
|
||||||
case frame::colormap::BGRA: os << "BGRA"; break;
|
case frame::colormap::RGBA:
|
||||||
case frame::colormap::B: os << "Grayscale"; break;
|
os << "RGBA";
|
||||||
default: os << "Unknown"; break;
|
break;
|
||||||
|
case frame::colormap::BGR:
|
||||||
|
os << "BGR";
|
||||||
|
break;
|
||||||
|
case frame::colormap::BGRA:
|
||||||
|
os << "BGRA";
|
||||||
|
break;
|
||||||
|
case frame::colormap::B:
|
||||||
|
os << "Grayscale";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
os << "Unknown";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compression info
|
// Compression info
|
||||||
|
|||||||
Reference in New Issue
Block a user