Overlapped atlas storage and EC testing

This commit is contained in:
Chlumsky 2024-06-02 11:34:00 +02:00
parent c27de5988d
commit c4e45732ce
7 changed files with 211 additions and 3 deletions

View File

@ -0,0 +1,37 @@
#pragma once
#include "AtlasStorage.h"
namespace msdf_atlas {
/** An implementation of AtlasStorage represented by a bitmap in memory (msdfgen::Bitmap)
* which has improved handling of partially overlapping glyph rectangles
*/
template <typename T, int N>
class BitmapOverlappedAtlasStorage {
public:
BitmapOverlappedAtlasStorage();
BitmapOverlappedAtlasStorage(int width, int height);
BitmapOverlappedAtlasStorage(const BitmapOverlappedAtlasStorage<T, N> &orig, int width, int height);
operator msdfgen::BitmapConstRef<T, N>() const;
operator msdfgen::BitmapRef<T, N>();
operator msdfgen::Bitmap<T, N>() &&;
template <typename S>
void put(int x, int y, const msdfgen::BitmapConstRef<S, N> &subBitmap);
void get(int x, int y, const msdfgen::BitmapRef<T, N> &subBitmap) const;
private:
msdfgen::Bitmap<T, N> bitmap;
msdfgen::Bitmap<byte, 1> stencil;
void blend(const msdfgen::BitmapRef<byte, N> &dst, const msdfgen::BitmapConstRef<byte, N> &src, int dx, int dy, int sx, int sy, int w, int h);
void blend(const msdfgen::BitmapRef<byte, N> &dst, const msdfgen::BitmapConstRef<float, N> &src, int dx, int dy, int sx, int sy, int w, int h);
void blend(const msdfgen::BitmapRef<float, N> &dst, const msdfgen::BitmapConstRef<float, N> &src, int dx, int dy, int sx, int sy, int w, int h);
};
}
#include "BitmapOverlappedAtlasStorage.hpp"

View File

@ -0,0 +1,143 @@
#include "BitmapOverlappedAtlasStorage.h"
#include <cstring>
#include <algorithm>
#include "bitmap-blit.h"
namespace msdf_atlas {
template <typename T>
T minPxVal();
template <>
byte minPxVal() {
return 0;
}
template <>
float minPxVal() {
return -FLT_MAX;
}
template <typename T, int N>
BitmapOverlappedAtlasStorage<T, N>::BitmapOverlappedAtlasStorage() { }
template <typename T, int N>
BitmapOverlappedAtlasStorage<T, N>::BitmapOverlappedAtlasStorage(int width, int height) : bitmap(width, height), stencil(width, height) {
for (T *cur = (T *) bitmap, *end = cur+N*width*height; cur < end; ++cur)
*cur = minPxVal<T>();
memset((byte *) stencil, 0, sizeof(byte)*width*height);
}
template <typename T, int N>
BitmapOverlappedAtlasStorage<T, N>::BitmapOverlappedAtlasStorage(const BitmapOverlappedAtlasStorage<T, N> &orig, int width, int height) : bitmap(width, height) {
for (T *cur = (T *) bitmap, *end = cur+N*width*height; cur < end; ++cur)
*cur = minPxVal<T>();
memset((byte *) stencil, 0, sizeof(byte)*width*height);
blit(bitmap, orig.bitmap, 0, 0, 0, 0, std::min(width, orig.bitmap.width()), std::min(height, orig.bitmap.height()));
blit(stencil, orig.stencil, 0, 0, 0, 0, std::min(width, orig.bitmap.width()), std::min(height, orig.bitmap.height()));
}
template <typename T, int N>
BitmapOverlappedAtlasStorage<T, N>::operator msdfgen::BitmapConstRef<T, N>() const {
return bitmap;
}
template <typename T, int N>
BitmapOverlappedAtlasStorage<T, N>::operator msdfgen::BitmapRef<T, N>() {
return bitmap;
}
template <typename T, int N>
BitmapOverlappedAtlasStorage<T, N>::operator msdfgen::Bitmap<T, N>() && {
return (msdfgen::Bitmap<T, N> &&) bitmap;
}
template <typename T, int N>
template <typename S>
void BitmapOverlappedAtlasStorage<T, N>::put(int x, int y, const msdfgen::BitmapConstRef<S, N> &subBitmap) {
blend((msdfgen::BitmapRef<T, N>) bitmap, subBitmap, x, y, 0, 0, subBitmap.width, subBitmap.height);
}
template <typename T, int N>
void BitmapOverlappedAtlasStorage<T, N>::get(int x, int y, const msdfgen::BitmapRef<T, N> &subBitmap) const {
blit(subBitmap, bitmap, 0, 0, x, y, subBitmap.width, subBitmap.height);
}
#define MSDF_ATLAS_BITMAP_OVERLAPPED_ATLAS_STORAGE_BOUND_AREA() { \
if (dx < 0) w += dx, sx -= dx, dx = 0; \
if (dy < 0) h += dy, sy -= dy, dy = 0; \
if (sx < 0) w += sx, dx -= sx, sx = 0; \
if (sy < 0) h += sy, dy -= sy, sy = 0; \
w = std::max(0, std::min(w, std::min(dst.width-dx, src.width-sx))); \
h = std::max(0, std::min(h, std::min(dst.height-dy, src.height-sy))); \
}
template <typename T, int N>
void BitmapOverlappedAtlasStorage<T, N>::blend(const msdfgen::BitmapRef<byte, N> &dst, const msdfgen::BitmapConstRef<byte, N> &src, int dx, int dy, int sx, int sy, int w, int h) {
MSDF_ATLAS_BITMAP_OVERLAPPED_ATLAS_STORAGE_BOUND_AREA();
for (int y = 0; y < h; ++y) {
byte *dstPixel = dst(dx, dy+y);
const byte *srcPixel = src(sx, sy+y);
byte *stencilPixel = stencil(dx, dy+y);
for (int x = 0; x < w; ++x) {
for (int i = 0; i < N; ++i, ++dstPixel, ++srcPixel) {
if (*dstPixel != *srcPixel) {
if (*stencilPixel)
*dstPixel = minPxVal<byte>();
else
*dstPixel = *srcPixel;
}
}
*stencilPixel++ = 1;
}
}
}
template <typename T, int N>
void BitmapOverlappedAtlasStorage<T, N>::blend(const msdfgen::BitmapRef<byte, N> &dst, const msdfgen::BitmapConstRef<float, N> &src, int dx, int dy, int sx, int sy, int w, int h) {
MSDF_ATLAS_BITMAP_OVERLAPPED_ATLAS_STORAGE_BOUND_AREA();
for (int y = 0; y < h; ++y) {
byte *dstPixel = dst(dx, dy+y);
const float *srcPixel = src(sx, sy+y);
byte *stencilPixel = stencil(dx, dy+y);
for (int x = 0; x < w; ++x) {
for (int i = 0; i < N; ++i, ++dstPixel, ++srcPixel) {
byte srcByte = msdfgen::pixelFloatToByte(*srcPixel);
if (*dstPixel != srcByte) {
if (*stencilPixel)
*dstPixel = minPxVal<byte>();
else
*dstPixel = srcByte;
}
}
*stencilPixel++ = 1;
}
}
}
template <typename T, int N>
void BitmapOverlappedAtlasStorage<T, N>::blend(const msdfgen::BitmapRef<float, N> &dst, const msdfgen::BitmapConstRef<float, N> &src, int dx, int dy, int sx, int sy, int w, int h) {
MSDF_ATLAS_BITMAP_OVERLAPPED_ATLAS_STORAGE_BOUND_AREA();
for (int y = 0; y < h; ++y) {
float *dstPixel = dst(dx, dy+y);
const float *srcPixel = src(sx, sy+y);
byte *stencilPixel = stencil(dx, dy+y);
for (int x = 0; x < w; ++x) {
for (int i = 0; i < N; ++i, ++dstPixel, ++srcPixel) {
if (*dstPixel != *srcPixel) {
if (*stencilPixel)
*dstPixel = minPxVal<float>();
else
*dstPixel = *srcPixel;
}
}
*stencilPixel++ = 1;
}
}
}
#undef MSDF_ATLAS_BITMAP_OVERLAPPED_ATLAS_STORAGE_BOUND_AREA
}

View File

@ -31,6 +31,7 @@ public:
void setThreadCount(int threadCount);
/// Allows access to the underlying AtlasStorage
const AtlasStorage &atlasStorage() const;
AtlasStorage &atlasStorage();
/// Returns the layout of the contained glyphs as a list of GlyphBoxes
const std::vector<GlyphBox> &getLayout() const;

View File

@ -78,6 +78,11 @@ const AtlasStorage &ImmediateAtlasGenerator<T, N, GEN_FN, AtlasStorage>::atlasSt
return storage;
}
template <typename T, int N, GeneratorFunction<T, N> GEN_FN, class AtlasStorage>
AtlasStorage &ImmediateAtlasGenerator<T, N, GEN_FN, AtlasStorage>::atlasStorage() {
return storage;
}
template <typename T, int N, GeneratorFunction<T, N> GEN_FN, class AtlasStorage>
const std::vector<GlyphBox> &ImmediateAtlasGenerator<T, N, GEN_FN, AtlasStorage>::getLayout() const {
return layout;

View File

@ -329,12 +329,33 @@ struct Configuration {
const char *shadronPreviewText;
};
template <typename T, int N>
struct CondEC {
static void condEC(const msdfgen::BitmapRef<T, N> &sdf, msdfgen::Range pxRange, double minDeviationRatio) { }
};
template <>
struct CondEC<float, 3> {
static void condEC(const msdfgen::BitmapRef<float, 3> &sdf, msdfgen::Range pxRange, double minDeviationRatio) {
puts("EC activated");
msdfgen::msdfFastEdgeErrorCorrection(sdf, pxRange, minDeviationRatio);
}
};
template <>
struct CondEC<float, 4> {
static void condEC(const msdfgen::BitmapRef<float, 4> &sdf, msdfgen::Range pxRange, double minDeviationRatio) {
puts("EC activated");
msdfgen::msdfFastEdgeErrorCorrection(sdf, pxRange, minDeviationRatio);
}
};
template <typename T, typename S, int N, GeneratorFunction<S, N> GEN_FN>
static bool makeAtlas(const std::vector<GlyphGeometry> &glyphs, const std::vector<FontGeometry> &fonts, const Configuration &config) {
ImmediateAtlasGenerator<S, N, GEN_FN, BitmapAtlasStorage<T, N> > generator(config.width, config.height);
ImmediateAtlasGenerator<S, N, GEN_FN, BitmapOverlappedAtlasStorage<T, N> > generator(config.width, config.height);
generator.setAttributes(config.generatorAttributes);
generator.setThreadCount(config.threadCount);
generator.generate(glyphs.data(), glyphs.size());
CondEC<T, N>::condEC((msdfgen::BitmapRef<T, N>) generator.atlasStorage(), config.pxRange, config.generatorAttributes.config.errorCorrection.minDeviationRatio);
msdfgen::BitmapConstRef<T, N> bitmap = (msdfgen::BitmapConstRef<T, N>) generator.atlasStorage();
bool success = true;
@ -1064,7 +1085,7 @@ int main(int argc, const char *const *argv) {
config.imageFormat == ImageFormat::BINARY_FLOAT_BE
);
// TODO: In this case (if spacing is -1), the border pixels of each glyph are black, but still computed. For floating-point output, this may play a role.
int spacing = config.imageType == ImageType::MSDF || config.imageType == ImageType::MTSDF ? 0 : -1;
int spacing = -1;
double uniformOriginX, uniformOriginY;
// Load fonts

View File

@ -26,6 +26,7 @@
#include "bitmap-blit.h"
#include "AtlasStorage.h"
#include "BitmapAtlasStorage.h"
#include "BitmapOverlappedAtlasStorage.h"
#include "TightAtlasPacker.h"
#include "GridAtlasPacker.h"
#include "AtlasGenerator.h"

@ -1 +1 @@
Subproject commit 85e8b3d47b3d1a42e4a5ebda0a24fb1cc2e669e0
Subproject commit 755c45b4445baa12bfead90fa7d4d2259f2a14c4