135 lines
4.8 KiB
C++
135 lines
4.8 KiB
C++
#include "../Gen.h"
|
|
#include "../Log.h"
|
|
#include "Dither.h"
|
|
|
|
#include "bx/math.h"
|
|
|
|
using namespace Gen;
|
|
|
|
void DitherGen(DitherData& data, int32_t recursion)
|
|
{
|
|
data.Points[0] = {0.0f, 0.0f};
|
|
data.Points[1] = {0.5f, 0.5f};
|
|
data.Points[2] = {0.5f, 0.0f};
|
|
data.Points[3] = {0.0f, 0.5f};
|
|
data.PointCount = 4;
|
|
for (int32_t i = 0; i < data.BrightnessBucketCount; ++i)
|
|
data.BrightnessBuckets[i] = 0;
|
|
|
|
// add "subdivided" beyer matrix layers
|
|
for (int32_t recursionLevel = 0; recursionLevel < recursion - 1; ++recursionLevel)
|
|
{
|
|
int32_t startCount = data.PointCount;
|
|
float offset = bx::pow(0.5f, recursionLevel + 1);
|
|
for (int32_t i = 1; i < 4; ++i)
|
|
{
|
|
for (int32_t j = 0; j < startCount; ++j)
|
|
{
|
|
data.Points[data.PointCount] = data.Points[j] + data.Points[i] * offset;
|
|
data.PointCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Texture info setup
|
|
uint64_t dotsPerSide = bx::round(bx::pow(2, recursion));
|
|
data.DitherTexDepth = dotsPerSide * dotsPerSide;
|
|
data.DitherTexWH = 16 * dotsPerSide;
|
|
uint64_t texPixelCount = data.DitherTexWH * data.DitherTexWH * data.DitherTexDepth;
|
|
|
|
if (BX_COUNTOF(DitherData::DitherTex) < texPixelCount)
|
|
{
|
|
LOG_ERROR("Too many pixels: %llu", texPixelCount);
|
|
return;
|
|
}
|
|
|
|
// What does this do?
|
|
float invRes = 1.0f / data.DitherTexWH;
|
|
for (int32_t z = 0; z < data.DitherTexDepth; ++z)
|
|
{
|
|
int32_t dotCount = z + 1;
|
|
float dotArea = 0.5f / dotCount;
|
|
float dotRadius = bx::sqrt(dotArea / bx::kPi);
|
|
|
|
int32_t zOffset = z * data.DitherTexWH * data.DitherTexWH;
|
|
for (int32_t y = 0; y < data.DitherTexWH; ++y)
|
|
{
|
|
int32_t yOffset = y * data.DitherTexWH;
|
|
for (int32_t x = 0; x < data.DitherTexWH; ++x)
|
|
{
|
|
Vec2 point{(x + 0.5f) * invRes, (y + 0.5f) * invRes};
|
|
float dist = bx::kFloatInfinity;
|
|
for (int32_t i = 0; i < dotCount; ++i)
|
|
{
|
|
Vec2 vec = point - data.Points[i];
|
|
float wrapX = bx::wrap(vec.x + 0.5f, 1.0f) - 0.5f;
|
|
float wrapY = bx::wrap(vec.y + 0.5f, 1.0f) - 0.5f;
|
|
Vec2 wrappedVec = {wrapX, wrapY};
|
|
float curDist = Magnitude(wrappedVec);
|
|
dist = bx::min(dist, curDist);
|
|
}
|
|
|
|
dist = dist / (dotRadius * 2.4f);
|
|
float val = bx::clamp(1.0f - dist, 0.0f, 1.0f);
|
|
data.DitherTex[x + yOffset + zOffset] = Vec4{val, val, val, 1.0f};
|
|
int32_t bucket = bx::clamp(
|
|
uint32_t(val * DitherData::BrightnessBucketCount), 0, DitherData::BrightnessBucketCount - 1);
|
|
data.BrightnessBuckets[bucket] += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Brightness ramp
|
|
int32_t sum = 0;
|
|
for (int32_t i = 0; i < data.BrightnessBucketCount; ++i)
|
|
{
|
|
sum += data.BrightnessBuckets[data.BrightnessBucketCount - 1 - i];
|
|
data.BrightnessRamp[i + 1] = sum / (float)texPixelCount;
|
|
}
|
|
|
|
// Upload textures
|
|
CleanupDitherData(data);
|
|
const bgfx::Memory* memPreview = bgfx::makeRef(data.DitherTex, texPixelCount * sizeof(Vec4));
|
|
const bgfx::Memory* memFinal = bgfx::makeRef(data.DitherTex, texPixelCount * sizeof(Vec4));
|
|
const bgfx::Memory* memRamp = bgfx::makeRef(data.BrightnessRamp, sizeof(data.BrightnessRamp));
|
|
data.PreviewTex = bgfx::createTexture2D(data.DitherTexWH,
|
|
data.DitherTexWH * data.DitherTexDepth,
|
|
false,
|
|
false,
|
|
bgfx::TextureFormat::RGBA32F,
|
|
0,
|
|
memPreview);
|
|
data.FinalTex = bgfx::createTexture3D(
|
|
data.DitherTexWH, data.DitherTexWH, data.DitherTexDepth, false, bgfx::TextureFormat::RGBA32F, 0, memFinal);
|
|
data.RampTex =
|
|
bgfx::createTexture2D(BX_COUNTOF(data.BrightnessRamp), 1, false, 1, bgfx::TextureFormat::R32F, 0, memRamp);
|
|
|
|
if (!isValid(data.DitherSampler))
|
|
{
|
|
data.DitherSampler = bgfx::createUniform("s_ditherSampler", bgfx::UniformType::Sampler);
|
|
}
|
|
if (!isValid(data.RampSampler))
|
|
{
|
|
data.RampSampler = bgfx::createUniform("s_rampSampler", bgfx::UniformType::Sampler);
|
|
}
|
|
}
|
|
|
|
void CleanupDitherData(DitherData& data)
|
|
{
|
|
if (isValid(data.PreviewTex))
|
|
{
|
|
bgfx::destroy(data.PreviewTex);
|
|
data.PreviewTex = BGFX_INVALID_HANDLE;
|
|
}
|
|
if (isValid(data.FinalTex))
|
|
{
|
|
bgfx::destroy(data.FinalTex);
|
|
data.FinalTex = BGFX_INVALID_HANDLE;
|
|
}
|
|
if (isValid(data.RampTex))
|
|
{
|
|
bgfx::destroy(data.RampTex);
|
|
data.RampTex = BGFX_INVALID_HANDLE;
|
|
}
|
|
}
|