summaryrefslogtreecommitdiff
path: root/src/engine/actors/Text.h
blob: 8d981828ca4f058742cb460679fdfd41e45a74c8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#pragma once

#include <libultraship.h>
#include "engine/registry/RegisterContent.h"
#include "engine/Actor.h"
#include "src/textures.h"
#include "engine/CoreMath.h"

class AText : public AActor {
public:
    enum TextMode : int16_t {
        STATIONARY,
        FOLLOW_PLAYER
    };

    enum FadeMode : int16_t {
        NO_FADE,
        FADE_IN,
        FADE_OUT
    };

    enum DistanceProps : int16_t {
        TOO_CLOSE,
        ACTIVE,
        TOO_FAR
    };

    DistanceProps Dist = ACTIVE;
    DistanceProps PrevState = ACTIVE;
    FadeMode FadeState = NO_FADE;

    struct CharacterList {
        const char* Texture;
        f32 column;
        f32 row;
        u32 width;
        u32 height;
        s32 mode;
        Vtx vtx[4];
    };

    std::vector<CharacterList> TextureList;

    std::string Text; // The text to be displayed
    TextMode Mode;
    uint32_t PlayerIndex;
    float WidthOffset = 0.0f;
    float HeightOffset = 8.0f; // Place text above player
    f32 ScaleX = 1.0f;
    f32 LetterSpacing = 1.0f;
    f32 Far = 14000.0f;
    f32 Close = 350.0f;

    bool FaceCamera = true;
    bool Animate = false;
    bool SingleColour = true; // Only used for imGUI to show more colour options
    // 1 colour for each of the 4 vtx
    // This allows setting each vtx colour individually
    RGBA8 TextColour[4];

    // Constructor
    AText(const SpawnParams& params);
    virtual ~AText() {
        _count--;
    };

    static size_t GetCount() {
        return _count;
    }

    /**
     * This is simply a helper function to keep Spawning code clean
     * Main parameters usage:
     * 
     * PlayerIndex is only used if textMode is FOLLOW_PLAYER
     * 
     * Other available options:
     * 
     * TextColour<RGBA8>      - Colour of the text (1 colour for each vertex)
     * ScaleX<float>          - Font scale Y
     * LetterSpacing<float>   - Space between letters
     * HeightOffset<float>    - Height above player when in FOLLOW_PLAYER mode
     * WidthOffset<float>     - Left/right offset of the text when in FOLLOW_PLAYER mode
     * Far<float>             - Skip rendering if camera is too far away
     * Close<float>           - Skip rendering if too close to the camera
     * Animate<bool>          - Cycle colours similar to the grand prix title text
     * 
     * Other options usage:
     * 
     * AText* text = AText::Spawn("Hello World", FVector(0, 0, 0), etc.);
     * text->Animate = true;
     * text->Far = 14000.0f;
     * text->ScaleX = 0.1f; // Recommend in the range of 0-2.0f. Default 1.0f
     * text->LetterSpacing = 1.0f; // Default 1.0f
     * 
     * For one single colour, set all vertices to the same colour.
     * text->TextColour[0] = {255, 0, 0, 255}; // Red
     * text->TextColour[1] = {0, 255, 0, 255}; // Green
     * text->TextColour[2] = {0, 0, 255, 255}; // Blue
     * text->TextColour[3] = {255, 255, 0, 255}; // Yellow
     * 
     * The above will result in a gradient between red, green, blue, and yellow
     * For transparency {0, 0, 0, 100} <-- alpha value of 100 will render semi-transparent black text.
     *
     */
    static AText* Spawn(std::string text, FVector pos, FVector scale, AText::TextMode textMode, int16_t playerIndex) {
        SpawnParams params = {
            .Name = "hm:text",
            .Type = static_cast<int16_t>(textMode),
            .Behaviour = playerIndex,
            .Skin = text,
            .Location = pos,
            .Scale = scale,
        };
        return dynamic_cast<AText*>(AddActorToWorld<AText>(params));
    }

    // Virtual functions to be overridden by derived classes
    virtual void Tick() override;
    virtual void Draw(Camera* camera) override;
    virtual void SetSpawnParams(SpawnParams& params) override;
    virtual bool IsMod() override;
    virtual void DrawEditorProperties() override;
      void DrawColourEditor(bool* updated);
    void FollowPlayer();

    void SetText(std::string text);
    std::string ValidateString(const std::string_view& text);
    void Refresh();
    void Print3D(char* text, s32 tracking, s32 mode);
    void PrintLetter3D(MenuTexture* glyphTexture, f32 column, f32 row, s32 mode);
    void SetupVtx();
    void DrawText3D(Camera* camera); // Based on func_80095BD0
    void AnimateColour(Vtx* vtx); // Animate the vtx colours
    void FadeIn(Vtx* vtx);
    void FadeOut(Vtx* vtx);

    inline uint8_t FloatToU8(float v) {
        return (uint8_t)(v * 255.0f);
    }

    Vtx myVtx[12] = { // D_02007BB8
        {{{ 0, 16, 0}, 0, {   0, 0}, {0xff, 0xff, 0xff, 0xff}}},
        {{{26, 16, 0}, 0, {1600, 0}, {0xff, 0xff, 0xff, 0xff}}},
        {{{26, 0, 0}, 0, {1600, 960}, {0xff, 0xff, 0xff, 0xff}}},
        {{{ 0, 0, 0}, 0, {   0, 960}, {0xff, 0xff, 0xff, 0xff}}},
        {{{ 0, 16, 0}, 0, {  0, 0}, {0xff, 0xff, 0xff, 0xff}}},
        {{{16, 16, 0}, 0, {960, 0}, {0xff, 0xff, 0xff, 0xff}}},
        {{{16, 0, 0}, 0, {960, 960}, {0xff, 0xff, 0xff, 0xff}}},
        {{{ 0, 0, 0}, 0, {  0, 960}, {0xff, 0xff, 0xff, 0xff}}},
        {{{ 0, 32, 0}, 0, {   0, 0}, {0xff, 0xff, 0xff, 0xff}}},
        {{{30, 32, 0}, 0, {1856, 0}, {0xff, 0xff, 0xff, 0xff}}},
        {{{30, 0, 0}, 0, {1856, 1984}, {0xff, 0xff, 0xff, 0xff}}},
        {{{ 0, 0, 0}, 0, {   0, 1984}, {0xff, 0xff, 0xff, 0xff}}},
    };
private:
    static size_t _count;
    size_t _idx;
};