|
|
|
//
|
|
|
|
// Created by Matthew on 2024/1/4.
|
|
|
|
//
|
|
|
|
|
|
|
|
#ifndef MICROPHOTO_TEXTPAINT_H
|
|
|
|
#define MICROPHOTO_TEXTPAINT_H
|
|
|
|
|
|
|
|
#include <ft2build.h>
|
|
|
|
#include FT_FREETYPE_H
|
|
|
|
#include FT_STROKER_H
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
#include <fstream>
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
#define MIN __min
|
|
|
|
#define MAX __max
|
|
|
|
#else
|
|
|
|
#define MIN std::min
|
|
|
|
#define MAX std::max
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace puttext
|
|
|
|
{
|
|
|
|
|
|
|
|
// Define some fixed size types.
|
|
|
|
|
|
|
|
typedef unsigned char uint8;
|
|
|
|
typedef unsigned short uint16;
|
|
|
|
typedef unsigned int uint32;
|
|
|
|
|
|
|
|
|
|
|
|
// Try to figure out what endian this machine is using. Note that the test
|
|
|
|
// below might fail for cross compilation; additionally, multi-byte
|
|
|
|
// characters are implementation-defined in C preprocessors.
|
|
|
|
|
|
|
|
#if (('1234' >> 24) == '1')
|
|
|
|
#elif (('4321' >> 24) == '1')
|
|
|
|
#define BIG_ENDIAN
|
|
|
|
#else
|
|
|
|
#error "Couldn't determine the endianness!"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
union Pixel32
|
|
|
|
{
|
|
|
|
Pixel32()
|
|
|
|
: integer(0) { }
|
|
|
|
Pixel32(uint8 bi, uint8 gi, uint8 ri, uint8 ai = 255)
|
|
|
|
{
|
|
|
|
b = bi;
|
|
|
|
g = gi;
|
|
|
|
r = ri;
|
|
|
|
a = ai;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 integer;
|
|
|
|
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
#ifdef BIG_ENDIAN
|
|
|
|
uint8 a, r, g, b;
|
|
|
|
#else // BIG_ENDIAN
|
|
|
|
uint8 b, g, r, a;
|
|
|
|
#endif // BIG_ENDIAN
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct Vec2
|
|
|
|
{
|
|
|
|
Vec2() { }
|
|
|
|
Vec2(float a, float b)
|
|
|
|
: x(a), y(b) { }
|
|
|
|
|
|
|
|
float x, y;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct Rect
|
|
|
|
{
|
|
|
|
Rect() { }
|
|
|
|
Rect(float left, float top, float right, float bottom)
|
|
|
|
: xmin(left), xmax(right), ymin(top), ymax(bottom) { }
|
|
|
|
|
|
|
|
void Include(const Vec2 &r)
|
|
|
|
{
|
|
|
|
xmin = MIN(xmin, r.x);
|
|
|
|
ymin = MIN(ymin, r.y);
|
|
|
|
xmax = MAX(xmax, r.x);
|
|
|
|
ymax = MAX(ymax, r.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
float Width() const { return xmax - xmin + 1; }
|
|
|
|
float Height() const { return ymax - ymin + 1; }
|
|
|
|
|
|
|
|
float xmin, xmax, ymin, ymax;
|
|
|
|
};
|
|
|
|
|
|
|
|
// A horizontal pixel span generated by the FreeType renderer.
|
|
|
|
|
|
|
|
struct Span
|
|
|
|
{
|
|
|
|
Span() { }
|
|
|
|
Span(int _x, int _y, int _width, int _coverage)
|
|
|
|
: x(_x), y(_y), width(_width), coverage(_coverage) { }
|
|
|
|
|
|
|
|
int x, y, width, coverage;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef std::vector<Span> Spans;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Each time the renderer calls us back we just push another span entry on
|
|
|
|
// our list.
|
|
|
|
|
|
|
|
void RasterCallback(const int y, const int count, const FT_Span * const spans, void * const user);
|
|
|
|
|
|
|
|
|
|
|
|
// Set up the raster parameters and render the outline.
|
|
|
|
|
|
|
|
void RenderSpans(FT_Library &library, FT_Outline * const outline, Spans *spans);
|
|
|
|
|
|
|
|
// Render the specified character as a colored glyph with a colored outline
|
|
|
|
// and dump it to a TGA.
|
|
|
|
|
|
|
|
class TextPaint
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
TextPaint();
|
|
|
|
~TextPaint();
|
|
|
|
|
|
|
|
bool LoadFont(const char* fontFilePath);
|
|
|
|
|
|
|
|
bool DrawText(Pixel32 *pxl, const wchar_t* str, int size, const Pixel32 &fontCol, const Pixel32& outlineCol, float outlineWidth);
|
|
|
|
|
|
|
|
private:
|
|
|
|
FT_Library library;
|
|
|
|
FT_Face face;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace puttext
|
|
|
|
|
|
|
|
#endif //MICROPHOTO_TEXTPAINT_H
|