//
// 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
