Browse Source

Wrapped Text Rendering. Menu dialogs.

Thomas Buck 9 years ago
parent
commit
ba9e86cd4c
13 changed files with 460 additions and 129 deletions
  1. 4
    0
      ChangeLog.md
  2. 10
    14
      include/Font.h
  3. 9
    1
      include/FontManager.h
  4. 9
    1
      include/FontSDL.h
  5. 11
    2
      include/FontTRLE.h
  6. 12
    1
      include/Menu.h
  7. 5
    4
      src/Console.cpp
  8. 2
    54
      src/Font.cpp
  9. 19
    2
      src/FontManager.cpp
  10. 105
    15
      src/FontSDL.cpp
  11. 104
    19
      src/FontTRLE.cpp
  12. 161
    12
      src/Menu.cpp
  13. 9
    4
      src/OpenRaider.cpp

+ 4
- 0
ChangeLog.md View File

@@ -2,6 +2,10 @@
2 2
 
3 3
 ## OpenRaider (0.1.3) xythobuz <xythobuz@xythobuz.de>
4 4
 
5
+    [ 20140811 ]
6
+    * New Font API, allows drawing strings with line-wrapping
7
+    * Added ability to Menu to show info dialogs
8
+
5 9
     [ 20140810 ]
6 10
     * Removed recursive Folder access method implementations
7 11
       into their own file

+ 10
- 14
include/Font.h View File

@@ -8,15 +8,7 @@
8 8
 #ifndef _FONT_H_
9 9
 #define _FONT_H_
10 10
 
11
-typedef struct {
12
-    char *text;
13
-    unsigned int x;
14
-    unsigned int y;
15
-    int w;
16
-    int h;
17
-    float scale;
18
-    unsigned char color[4];
19
-} FontString;
11
+#include  <string>
20 12
 
21 13
 /*!
22 14
  * \brief Font interface
@@ -33,15 +25,19 @@ public:
33 25
 
34 26
     virtual int initialize() = 0;
35 27
 
36
-    virtual void writeString(FontString &s) = 0;
28
+    virtual unsigned int widthText(float scale, std::string s) = 0;
37 29
 
38 30
     virtual void drawText(unsigned int x, unsigned int y, float scale,
39
-            const unsigned char color[4], const char *s, ...)
40
-            __attribute__((format(printf, 6, 0)));
31
+            const unsigned char color[4], std::string s) = 0;
41 32
 
33
+    virtual unsigned int heightText(float scale, unsigned int maxWidth, std::string s) = 0;
34
+
35
+    virtual void drawTextWrapped(unsigned int x, unsigned int y, float scale,
36
+            const unsigned char color[4], unsigned int maxWidth, std::string s) = 0;
37
+
38
+    // Implemented in Font.cpp using widthText & drawText
42 39
     virtual void drawTextCentered(unsigned int x, unsigned int y, float scale,
43
-            const unsigned char color[4], unsigned int width, const char *s, ...)
44
-            __attribute__((format(printf, 7, 0)));
40
+            const unsigned char color[4], unsigned int width, std::string s);
45 41
 
46 42
 protected:
47 43
     bool mFontInit;

+ 9
- 1
include/FontManager.h View File

@@ -27,7 +27,15 @@ public:
27 27
 
28 28
     virtual int initialize();
29 29
 
30
-    virtual void writeString(FontString &s);
30
+    virtual unsigned int widthText(float scale, std::string s);
31
+
32
+    virtual void drawText(unsigned int x, unsigned int y, float scale,
33
+            const unsigned char color[4], std::string s);
34
+
35
+    virtual unsigned int heightText(float scale, unsigned int maxWidth, std::string s);
36
+
37
+    virtual void drawTextWrapped(unsigned int x, unsigned int y, float scale,
38
+            const unsigned char color[4], unsigned int maxWidth, std::string s);
31 39
 
32 40
 private:
33 41
 

+ 9
- 1
include/FontSDL.h View File

@@ -30,7 +30,15 @@ public:
30 30
 
31 31
     virtual int initialize();
32 32
 
33
-    virtual void writeString(FontString &s);
33
+    virtual unsigned int widthText(float scale, std::string s);
34
+
35
+    virtual void drawText(unsigned int x, unsigned int y, float scale,
36
+            const unsigned char color[4], std::string s);
37
+
38
+    virtual unsigned int heightText(float scale, unsigned int maxWidth, std::string s);
39
+
40
+    virtual void drawTextWrapped(unsigned int x, unsigned int y, float scale,
41
+            const unsigned char color[4], unsigned int maxWidth, std::string s);
34 42
 
35 43
 private:
36 44
     TTF_Font *mFont;

+ 11
- 2
include/FontTRLE.h View File

@@ -28,12 +28,21 @@ public:
28 28
 
29 29
     virtual int initialize();
30 30
 
31
-    virtual void writeString(FontString &s);
31
+    virtual unsigned int widthText(float scale, std::string s);
32
+
33
+    virtual void drawText(unsigned int x, unsigned int y, float scale,
34
+            const unsigned char color[4], std::string s);
35
+
36
+    virtual unsigned int heightText(float scale, unsigned int maxWidth, std::string s);
37
+
38
+    virtual void drawTextWrapped(unsigned int x, unsigned int y, float scale,
39
+            const unsigned char color[4], unsigned int maxWidth, std::string s);
32 40
 
33 41
 private:
34 42
 
35 43
     void loadLPS(const char *f);
36
-    void writeChar(unsigned int index, unsigned int xDraw, FontString &s);
44
+    void writeChar(unsigned int index, unsigned int xDraw, unsigned int yDraw,
45
+            float scale, const unsigned char color[4]);
37 46
 
38 47
     unsigned int mFontTexture;
39 48
 

+ 12
- 1
include/Menu.h View File

@@ -8,6 +8,7 @@
8 8
 #ifndef _MENU_H_
9 9
 #define _MENU_H_
10 10
 
11
+#include <functional>
11 12
 #include <memory>
12 13
 
13 14
 #include "utils/Folder.h"
@@ -46,7 +47,11 @@ public:
46 47
 
47 48
 private:
48 49
 
49
-    void play();
50
+    void loadOrOpen();
51
+    void showDialog(std::string msg, std::string btn1, std::string btn2,
52
+            std::function<int (bool state)> callback = std::function<int (bool)>());
53
+    void ackDialog();
54
+    void displayDialog();
50 55
 
51 56
     bool mVisible;
52 57
     long mCursor;
@@ -54,6 +59,12 @@ private:
54 59
 
55 60
     Folder *mapFolder;
56 61
     bool hiddenState;
62
+
63
+    std::string dialogText;
64
+    std::string dialogButton1;
65
+    std::string dialogButton2;
66
+    bool dialogState;
67
+    std::function<int (bool state)> dialogFunction;
57 68
 };
58 69
 
59 70
 Menu &getMenu();

+ 5
- 4
src/Console.cpp View File

@@ -65,8 +65,9 @@ void Console::display() {
65 65
     }
66 66
 
67 67
     // Draw status line
68
-    getFont().drawText(10, 10, 0.70f, BLUE,
69
-            "%s uptime %lus scroll %d%%", VERSION, systemTimerGet() / 1000, scrollIndicator);
68
+    std::ostringstream status;
69
+    status << VERSION << " uptime " << (systemTimerGet() / 1000) << "s scroll " << scrollIndicator << "%";
70
+    getFont().drawText(10, 10, 0.70f, BLUE, status.str());
70 71
 
71 72
     // Draw output log
72 73
     long end = lineCount;
@@ -81,11 +82,11 @@ void Console::display() {
81 82
 
82 83
     for (int i = 0; i < end; i++) {
83 84
         getFont().drawText(10, (unsigned int)((i + drawOffset) * lineSteps) + firstLine,
84
-                0.75f, BLUE, "%s", mHistory[i + historyOffset - mLineOffset].c_str());
85
+                0.75f, BLUE, mHistory.at(i + historyOffset - mLineOffset));
85 86
     }
86 87
 
87 88
     // Draw current input
88
-    getFont().drawText(10, inputLine, 0.75f, BLUE, "> %s", (mInputBuffer + mPartialInput).c_str());
89
+    getFont().drawText(10, inputLine, 0.75f, BLUE, "> " + mInputBuffer + mPartialInput);
89 90
 }
90 91
 
91 92
 void Console::handleKeyboard(KeyboardButton key, bool pressed) {

+ 2
- 54
src/Font.cpp View File

@@ -5,9 +5,6 @@
5 5
  * \author xythobuz
6 6
  */
7 7
 
8
-#include <stdio.h>
9
-#include <stdarg.h>
10
-
11 8
 #include "global.h"
12 9
 #include "utils/strings.h"
13 10
 #include "Window.h"
@@ -26,57 +23,8 @@ void Font::setFont(const char *font) {
26 23
     mFontName = fullPath(font, 0);
27 24
 }
28 25
 
29
-void Font::drawText(unsigned int x, unsigned int y, float scale,
30
-        const unsigned char color[4], const char *s, ...) {
31
-    FontString tempText;
32
-    va_list args;
33
-    va_start(args, s);
34
-
35
-    tempText.text = new char[256];
36
-    tempText.scale = scale;
37
-    tempText.w = 0;
38
-    tempText.h = 0;
39
-    tempText.x = x;
40
-    tempText.y = y;
41
-    tempText.color[0] = color[0];
42
-    tempText.color[1] = color[1];
43
-    tempText.color[2] = color[2];
44
-    tempText.color[3] = color[3];
45
-
46
-    vsnprintf(tempText.text, 256, s, args);
47
-    tempText.text[255] = '\0';
48
-    writeString(tempText);
49
-
50
-    delete [] tempText.text;
51
-    va_end(args);
52
-}
53
-
54 26
 void Font::drawTextCentered(unsigned int x, unsigned int y, float scale,
55
-        const unsigned char color[4], unsigned int width, const char *s, ...) {
56
-    FontString tempText;
57
-    va_list args;
58
-    va_start(args, s);
59
-
60
-    tempText.text = new char[256];
61
-    tempText.scale = scale;
62
-    tempText.w = 0;
63
-    tempText.h = 0;
64
-    tempText.x = x;
65
-    tempText.y = y + getWindow().getHeight(); //! \fixme Ugly hack to hide first draw
66
-    tempText.color[0] = color[0];
67
-    tempText.color[1] = color[1];
68
-    tempText.color[2] = color[2];
69
-    tempText.color[3] = color[3];
70
-
71
-    vsnprintf(tempText.text, 256, s, args);
72
-    tempText.text[255] = '\0';
73
-    writeString(tempText);
74
-
75
-    tempText.x = (width / 2) - ((unsigned int)(tempText.w / 2));
76
-    tempText.y = y;
77
-    writeString(tempText);
78
-
79
-    delete [] tempText.text;
80
-    va_end(args);
27
+        const unsigned char color[4], unsigned int width, std::string s) {
28
+    drawText(x + ((width / 2) - (widthText(scale, s) / 2)), y, scale, color, s);
81 29
 }
82 30
 

+ 19
- 2
src/FontManager.cpp View File

@@ -52,8 +52,25 @@ int FontManager::initialize() {
52 52
     return fonts.at(font)->initialize();
53 53
 }
54 54
 
55
-void FontManager::writeString(FontString &s) {
55
+unsigned int FontManager::widthText(float scale, std::string s) {
56 56
     assert(font != -1);
57
-    fonts.at(font)->writeString(s);
57
+    return fonts.at(font)->widthText(scale, s);
58
+}
59
+
60
+void FontManager::drawText(unsigned int x, unsigned int y, float scale,
61
+        const unsigned char color[4], std::string s) {
62
+    assert(font != -1);
63
+    fonts.at(font)->drawText(x, y, scale, color, s);
64
+}
65
+
66
+unsigned int FontManager::heightText(float scale, unsigned int maxWidth, std::string s) {
67
+    assert(font != -1);
68
+    return fonts.at(font)->heightText(scale, maxWidth, s);
69
+}
70
+
71
+void FontManager::drawTextWrapped(unsigned int x, unsigned int y, float scale,
72
+        const unsigned char color[4], unsigned int maxWidth, std::string s) {
73
+    assert(font != -1);
74
+    fonts.at(font)->drawTextWrapped(x, y, scale, color, maxWidth, s);
58 75
 }
59 76
 

+ 105
- 15
src/FontSDL.cpp View File

@@ -49,24 +49,114 @@ int FontSDL::initialize() {
49 49
     return 0;
50 50
 }
51 51
 
52
-void FontSDL::writeString(FontString &s) {
52
+unsigned int FontSDL::widthText(float scale, std::string s) {
53 53
     assert(mFontInit == true);
54
-    assert(s.text != NULL);
55 54
 
56
-    SDL_Color color;
57
-    color.r = s.color[0];
58
-    color.g = s.color[1];
59
-    color.b = s.color[2];
60
-    color.a = s.color[3];
55
+    int w;
56
+    if (TTF_SizeUTF8(mFont, s.c_str(), &w, NULL) != 0) {
57
+        printf("TTF_SizeUTF8 Error: %s\n", TTF_GetError());
58
+        return s.length() * 15 * scale;
59
+    }
60
+    return w * scale;
61
+}
62
+
63
+void FontSDL::drawText(unsigned int x, unsigned int y, float scale,
64
+        const unsigned char color[4], std::string s) {
65
+    assert(mFontInit == true);
66
+    assert(s.length() > 0);
61 67
 
62
-    SDL_Surface *surface = TTF_RenderUTF8_Blended(mFont, s.text, color);
68
+    SDL_Color col;
69
+    col.r = color[0];
70
+    col.g = color[1];
71
+    col.b = color[2];
72
+    col.a = color[3];
73
+
74
+    SDL_Surface *surface = TTF_RenderUTF8_Blended(mFont, s.c_str(), col);
63 75
     if (surface == NULL) {
64 76
         printf("TTF_RenderUTF8_Blended Error: %s\n", TTF_GetError());
65 77
         return;
66 78
     }
67 79
 
68
-    s.w = (int)((float)surface->w * s.scale);
69
-    s.h = (int)((float)surface->h * s.scale);
80
+    int w = (int)((float)surface->w * scale);
81
+    int h = (int)((float)surface->h * scale);
82
+
83
+    GLenum textureFormat;
84
+    if (surface->format->BytesPerPixel == 4) {
85
+        if (surface->format->Rmask == 0x000000FF)
86
+            textureFormat = GL_RGBA;
87
+        else
88
+            textureFormat = GL_BGRA_EXT;
89
+    } else {
90
+        if (surface->format->Rmask == 0x000000FF)
91
+            textureFormat = GL_RGB;
92
+        else
93
+            textureFormat = GL_BGR_EXT;
94
+    }
95
+
96
+    glBindTexture(GL_TEXTURE_2D, mFontTexture);
97
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
98
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
99
+    glTexImage2D(GL_TEXTURE_2D, 0, surface->format->BytesPerPixel, surface->w, surface->h, 0, textureFormat, GL_UNSIGNED_BYTE, surface->pixels);
100
+    SDL_FreeSurface(surface);
101
+
102
+    GLuint xMin = x;
103
+    GLuint yMin = y;
104
+    GLuint xMax = xMin + w;
105
+    GLuint yMax = yMin + h;
106
+
107
+    glColor4ubv(color);
108
+
109
+    glBegin(GL_QUADS);
110
+    glTexCoord2f(0.0f, 0.0f);
111
+    glVertex2i(xMin, yMin);
112
+
113
+    glTexCoord2f(0.0f, 1.0f);
114
+    glVertex2i(xMin, yMax);
115
+
116
+    glTexCoord2f(1.0f, 1.0f);
117
+    glVertex2i(xMax, yMax);
118
+
119
+    glTexCoord2f(1.0f, 0.0f);
120
+    glVertex2i(xMax, yMin);
121
+    glEnd();
122
+}
123
+
124
+unsigned int FontSDL::heightText(float scale, unsigned int maxWidth, std::string s) {
125
+    assert(mFontInit == true);
126
+    assert(s.length() > 0);
127
+    assert(maxWidth > 0);
128
+
129
+    SDL_Color col;
130
+    SDL_Surface *surface = TTF_RenderUTF8_Blended_Wrapped(mFont, s.c_str(), col, maxWidth);
131
+    if (surface == NULL) {
132
+        printf("TTF_RenderUTF8_Blended_Wrapped Error: %s\n", TTF_GetError());
133
+        return 0;
134
+    }
135
+    int h = surface->h * scale;
136
+    SDL_FreeSurface(surface);
137
+    return h;
138
+}
139
+
140
+void FontSDL::drawTextWrapped(unsigned int x, unsigned int y, float scale,
141
+        const unsigned char color[4], unsigned int maxWidth, std::string s) {
142
+    assert(mFontInit == true);
143
+    assert(s.length() > 0);
144
+    assert(maxWidth > 0);
145
+
146
+    SDL_Color col;
147
+    col.r = color[0];
148
+    col.g = color[1];
149
+    col.b = color[2];
150
+    col.a = color[3];
151
+
152
+    SDL_Surface *surface = TTF_RenderUTF8_Blended_Wrapped(mFont, s.c_str(), col, maxWidth);
153
+    if (surface == NULL) {
154
+        printf("TTF_RenderUTF8_Blended_Wrapped Error: %s\n", TTF_GetError());
155
+        return;
156
+    }
157
+
158
+    int w = (int)((float)surface->w * scale);
159
+    int h = (int)((float)surface->h * scale);
70 160
 
71 161
     GLenum textureFormat;
72 162
     if (surface->format->BytesPerPixel == 4) {
@@ -87,12 +177,12 @@ void FontSDL::writeString(FontString &s) {
87 177
     glTexImage2D(GL_TEXTURE_2D, 0, surface->format->BytesPerPixel, surface->w, surface->h, 0, textureFormat, GL_UNSIGNED_BYTE, surface->pixels);
88 178
     SDL_FreeSurface(surface);
89 179
 
90
-    GLuint xMin = s.x;
91
-    GLuint yMin = s.y;
92
-    GLuint xMax = xMin + s.w;
93
-    GLuint yMax = yMin + s.h;
180
+    GLuint xMin = x;
181
+    GLuint yMin = y;
182
+    GLuint xMax = xMin + w;
183
+    GLuint yMax = yMin + h;
94 184
 
95
-    glColor4ubv(s.color);
185
+    glColor4ubv(color);
96 186
 
97 187
     glBegin(GL_QUADS);
98 188
     glTexCoord2f(0.0f, 0.0f);

+ 104
- 19
src/FontTRLE.cpp View File

@@ -94,14 +94,17 @@ void FontTRLE::loadLPS(const char *f) {
94 94
 
95 95
 #define SCALING 2.0f
96 96
 
97
-void FontTRLE::writeChar(unsigned int index, unsigned int xDraw, FontString &s) {
98
-    int width = (int)(((float)offsets[index][2]) * s.scale * SCALING);
99
-    int height = (int)(((float)offsets[index][3]) * s.scale * SCALING);
100
-    int offset = (int)(((float)offsets[index][4]) * s.scale * SCALING);
97
+void FontTRLE::writeChar(unsigned int index, unsigned int xDraw, unsigned int yDraw,
98
+        float scale, const unsigned char color[4]) {
99
+    assert(mFontInit == true);
100
+
101
+    int width = (int)(((float)offsets[index][2]) * scale * SCALING);
102
+    int height = (int)(((float)offsets[index][3]) * scale * SCALING);
103
+    int offset = (int)(((float)offsets[index][4]) * scale * SCALING);
101 104
 
102 105
     // screen coordinates
103 106
     int xMin = xDraw;
104
-    int yMin = s.y + offset + (int)(10.0f * s.scale * SCALING);
107
+    int yMin = ((int)yDraw) + offset + (int)(10.0f * scale * SCALING);
105 108
     int xMax = xMin + width;
106 109
     int yMax = yMin + height;
107 110
 
@@ -113,7 +116,7 @@ void FontTRLE::writeChar(unsigned int index, unsigned int xDraw, FontString &s)
113 116
 
114 117
     // draw
115 118
     glBindTexture(GL_TEXTURE_2D, mFontTexture);
116
-    glColor4f(s.color[0] * 256.0f, s.color[1] * 256.0f, s.color[2] * 256.0f, s.color[3] * 256.0f);
119
+    glColor4f(color[0] * 256.0f, color[1] * 256.0f, color[2] * 256.0f, color[3] * 256.0f);
117 120
     glBegin(GL_QUADS);
118 121
     glTexCoord2f(txMin, tyMin);
119 122
     glVertex2i(xMin, yMin);
@@ -126,31 +129,113 @@ void FontTRLE::writeChar(unsigned int index, unsigned int xDraw, FontString &s)
126 129
     glEnd();
127 130
 }
128 131
 
129
-void FontTRLE::writeString(FontString &s) {
132
+unsigned int FontTRLE::widthText(float scale, std::string s) {
133
+    assert(mFontInit == true);
134
+    assert(s.length() > 0);
135
+
136
+    unsigned int width = 0;
137
+    for (unsigned int i = 0; i < s.length(); i++) {
138
+        // index into offset table
139
+        int index = s[i] - '!';
140
+
141
+        if (index == -1) // space
142
+            width += (unsigned int)(14.0f * scale * SCALING);
143
+
144
+        if ((index < 0) || (index > 105))
145
+            continue; // skip unprintable chars
146
+
147
+        width += (float)(offsets[index][2] + 1) * scale * SCALING; // glyph width
148
+    }
149
+
150
+    return width;
151
+}
152
+
153
+void FontTRLE::drawText(unsigned int x, unsigned int y, float scale,
154
+        const unsigned char color[4], std::string s) {
155
+    assert(mFontInit == true);
156
+    assert(s.length() > 0);
157
+
158
+    for (unsigned int i = 0; i < s.length(); i++) {
159
+        // index into offset table
160
+        int index = s[i] - '!';
161
+
162
+        if (index == -1) // space
163
+            x += (unsigned int)(14.0f * scale * SCALING);
164
+
165
+        if ((index < 0) || (index > 105))
166
+            continue; // skip unprintable chars
167
+
168
+        writeChar((unsigned int)index, x, y, scale, color);
169
+        x += (int)((float)(offsets[index][2] + 1) * scale * SCALING); // width
170
+    }
171
+}
172
+
173
+unsigned int FontTRLE::heightText(float scale, unsigned int maxWidth, std::string s) {
130 174
     assert(mFontInit == true);
131
-    assert(s.text != NULL);
175
+    assert(s.length() > 0);
132 176
 
133
-    unsigned int x = s.x;
134
-    unsigned int y = 0;
177
+    unsigned int x = 0;
178
+    unsigned int yMax = 0;
179
+    unsigned int yReturn = 0;
135 180
 
136
-    for (unsigned int i = 0; s.text[i] != '\0'; i++) {
181
+    for (unsigned int i = 0; i < s.length(); i++) {
137 182
         // index into offset table
138
-        int index = s.text[i] - '!';
183
+        int index = s[i] - '!';
139 184
 
140 185
         if (index == -1) // space
141
-            x += (unsigned int)(14.0f * s.scale * SCALING);
186
+            x += (unsigned int)(14.0f * scale * SCALING);
142 187
 
143 188
         if ((index < 0) || (index > 105))
144 189
             continue; // skip unprintable chars
145 190
 
146
-        writeChar((unsigned int)index, x, s);
147
-        x += (int)((float)(offsets[index][2] + 1) * s.scale * SCALING); // width
191
+        if (yMax < (unsigned int)(((float)offsets[index][3]) * scale * SCALING))
192
+            yMax = (unsigned int)(((float)offsets[index][3]) * scale * SCALING);
148 193
 
149
-        if (y < (unsigned int)(((float)offsets[index][3]) * s.scale * SCALING))
150
-            y = (unsigned int)(((float)offsets[index][3]) * s.scale * SCALING);
194
+        x += (int)((float)(offsets[index][2] + 1) * scale * SCALING); // width
195
+        if (x > maxWidth) {
196
+            // go to the next line
197
+            yReturn += yMax + 2;
198
+            yMax = 0;
199
+            x = (int)((float)(offsets[index][2] + 1) * scale * SCALING);
200
+        }
151 201
     }
152 202
 
153
-    s.w = x - s.x;
154
-    s.h = y;
203
+    return yReturn + yMax + 2;
204
+}
205
+
206
+void FontTRLE::drawTextWrapped(unsigned int x, unsigned int y, float scale,
207
+        const unsigned char color[4], unsigned int maxWidth, std::string s) {
208
+    assert(mFontInit == true);
209
+    assert(s.length() > 0);
210
+
211
+    unsigned int xStart = x;
212
+    unsigned int yMax = 0;
213
+
214
+    for (unsigned int i = 0; i < s.length(); i++) {
215
+        // index into offset table
216
+        int index = s[i] - '!';
217
+
218
+        if (index == -1) // space
219
+            x += (unsigned int)(14.0f * scale * SCALING);
220
+
221
+        if ((index < 0) || (index > 105))
222
+            continue; // skip unprintable chars
223
+
224
+        if (yMax < (unsigned int)(((float)offsets[index][3]) * scale * SCALING))
225
+            yMax = (unsigned int)(((float)offsets[index][3]) * scale * SCALING);
226
+
227
+        x += (int)((float)(offsets[index][2] + 1) * scale * SCALING); // width
228
+        if ((x - xStart) > maxWidth) {
229
+            // go to the next line
230
+            y += yMax + 2;
231
+            yMax = 0;
232
+            x = xStart;
233
+        } else {
234
+            x -= (int)((float)(offsets[index][2] + 1) * scale * SCALING);
235
+        }
236
+
237
+        writeChar((unsigned int)index, x, y, scale, color);
238
+        x += (int)((float)(offsets[index][2] + 1) * scale * SCALING); // width
239
+    }
155 240
 }
156 241
 

+ 161
- 12
src/Menu.cpp View File

@@ -23,6 +23,7 @@ Menu::Menu() {
23 23
     mMin = 0;
24 24
     mapFolder = nullptr;
25 25
     hiddenState = false;
26
+    dialogState = false;
26 27
 }
27 28
 
28 29
 Menu::~Menu() {
@@ -83,14 +84,14 @@ void Menu::display() {
83 84
     if (!mVisible)
84 85
         return;
85 86
 
86
-    // Draw half-transparent *overlay*
87
+    // Draw half-transparent overlay
87 88
     glColor4f(0.0f, 0.0f, 0.0f, 0.75f);
88 89
     glDisable(GL_TEXTURE_2D);
89 90
     glRecti(0, 0, (GLint)getWindow().getWidth(), (GLint)getWindow().getHeight());
90 91
     glEnable(GL_TEXTURE_2D);
91 92
 
92 93
     // Draw heading
93
-    getFont().drawTextCentered(0, 10, 1.2f, BLUE, getWindow().getWidth(), "%s", VERSION);
94
+    getFont().drawTextCentered(0, 10, 1.2f, BLUE, getWindow().getWidth(), VERSION);
94 95
 
95 96
     // Estimate displayable number of items
96 97
     int items = (getWindow().getHeight() - 60) / 25;
@@ -102,22 +103,24 @@ void Menu::display() {
102 103
             getFont().drawText(25, 50, 0.75f, (mCursor == i) ? RED : BLUE, "..");
103 104
         } else {
104 105
             getFont().drawText(25, (unsigned int)(50 + (25 * (i - mMin))), 0.75f,
105
-                (mCursor == i) ? RED : BLUE, "%s",
106
+                (mCursor == i) ? RED : BLUE,
106 107
                 ((i - 1) < mapFolder->folderCount()) ?
107
-                    (mapFolder->getFolder(i - 1).getName() + "/").c_str()
108
-                    : mapFolder->getFile(i - 1 - mapFolder->folderCount()).getName().c_str());
108
+                    (mapFolder->getFolder(i - 1).getName() + "/")
109
+                    : mapFolder->getFile(i - 1 - mapFolder->folderCount()).getName());
109 110
         }
110 111
     }
112
+
113
+    displayDialog();
111 114
 }
112 115
 
113
-void Menu::play() {
116
+void Menu::loadOrOpen() {
114 117
     if (mCursor == 0) {
115 118
         if (initialize(mapFolder->getParent().getPath()) != 0) {
116
-            //! \todo Display something if an error occurs
119
+            showDialog("Error reading parent folder!", "OK", "");
117 120
         }
118 121
     } else if ((mCursor - 1) < mapFolder->folderCount()) {
119 122
         if (initialize(mapFolder->getFolder(mCursor - 1).getPath()) != 0) {
120
-            //! \todo Display something if an error occurs
123
+            showDialog("Error reading subfolder!", "OK", "");
121 124
         }
122 125
     } else {
123 126
         std::string tmp = "load ";
@@ -125,7 +128,7 @@ void Menu::play() {
125 128
         if (getOpenRaider().command(tmp.c_str()) == 0) {
126 129
             setVisible(false);
127 130
         } else {
128
-            //! \todo Display something if an error occurs
131
+            showDialog("Error loading map!", "OK", "");
129 132
         }
130 133
     }
131 134
 }
@@ -134,6 +137,27 @@ void Menu::handleKeyboard(KeyboardButton key, bool pressed) {
134 137
     if (!pressed)
135 138
         return;
136 139
 
140
+    if (dialogText.length() > 0) {
141
+        if (dialogButton2.length() == 0) {
142
+            if (key == enterKey) {
143
+                ackDialog();
144
+            }
145
+        } else {
146
+            if (key == enterKey) {
147
+                ackDialog();
148
+            } else if (key == leftKey) {
149
+                dialogState = !dialogState;
150
+            } else if (key == rightKey) {
151
+                dialogState = !dialogState;
152
+            } else if (key == upKey) {
153
+                dialogState = !dialogState;
154
+            } else if (key == downKey) {
155
+                dialogState = !dialogState;
156
+            }
157
+        }
158
+        return;
159
+    }
160
+
137 161
     assert(mapFolder != nullptr);
138 162
     int items = (getWindow().getHeight() - 60) / 25;
139 163
 
@@ -148,7 +172,7 @@ void Menu::handleKeyboard(KeyboardButton key, bool pressed) {
148 172
         else
149 173
             mCursor = 0;
150 174
     } else if (key == enterKey) {
151
-        play();
175
+        loadOrOpen();
152 176
     } else if (key == dotKey) {
153 177
         hiddenState = !hiddenState;
154 178
         initialize(mapFolder->getPath());
@@ -167,16 +191,25 @@ void Menu::handleMouseClick(unsigned int x, unsigned int y, KeyboardButton butto
167 191
     if (released || (button != leftmouseKey))
168 192
         return;
169 193
 
170
-    if ((y >= 50) && (y <= (unsigned int)(50 + (25 * items)))) {
194
+    if (dialogText.length() > 0) {
195
+        //!< \todo Allow mouse usage of Menu dialogs!
196
+        return;
197
+    }
198
+
199
+    if ((y >= 50) && (y <= (unsigned int)(50 + (25 * items)))
200
+            && ((mMin + (y / 25)) <= (mapFolder->folderCount() + mapFolder->fileCount() + 2))) {
171 201
         y -= 50;
172 202
         if (mCursor == (mMin + (y / 25)))
173
-            play();
203
+            loadOrOpen();
174 204
         else
175 205
             mCursor = mMin + (y / 25);
176 206
     }
177 207
 }
178 208
 
179 209
 void Menu::handleMouseScroll(int xrel, int yrel) {
210
+    if (dialogText.length() > 0)
211
+        return;
212
+
180 213
     assert((xrel != 0) || (yrel != 0));
181 214
     assert(mapFolder != nullptr);
182 215
     int items = (getWindow().getHeight() - 60) / 25;
@@ -198,3 +231,119 @@ void Menu::handleMouseScroll(int xrel, int yrel) {
198 231
     }
199 232
 }
200 233
 
234
+void Menu::showDialog(std::string msg, std::string btn1, std::string btn2,
235
+        std::function<int (bool state)> callback) {
236
+    // Only show one dialog at a time
237
+    assert(dialogText.length() == 0);
238
+    assert(dialogButton1.length() == 0);
239
+    assert(dialogButton2.length() == 0);
240
+
241
+    assert(msg.length() > 0);
242
+    assert(btn1.length() > 0);
243
+
244
+    dialogText = msg;
245
+    dialogButton1 = btn1;
246
+    dialogButton2 = btn2;
247
+    dialogState = false;
248
+    dialogFunction = callback;
249
+
250
+    getConsole() << dialogText << Console::endl;
251
+}
252
+
253
+void Menu::ackDialog() {
254
+    dialogText = "";
255
+    dialogButton1 = "";
256
+    dialogButton2 = "";
257
+
258
+    if (dialogFunction) {
259
+        int error = dialogFunction(dialogState);
260
+        if (error != 0) {
261
+            showDialog("Error processing dialog callback!", "OK", "");
262
+        }
263
+    }
264
+
265
+    dialogState = false;
266
+}
267
+
268
+void Menu::displayDialog() {
269
+    if (dialogText.length() > 0) {
270
+        unsigned int wMax = ((unsigned int)(getWindow().getWidth() * 0.66f));
271
+
272
+        unsigned int w0 = getFont().widthText(1.0f, dialogText) + 20;
273
+        if (w0 > wMax)
274
+            w0 = wMax;
275
+        unsigned int h0 =  getFont().heightText(1.0f, w0, dialogText) + 10;
276
+
277
+        assert(dialogButton1.length() > 0);
278
+        unsigned int w1 = getFont().widthText(1.0f, dialogButton1) + 20;
279
+        if (w1 > wMax)
280
+            w1 = wMax;
281
+        unsigned int h1 = getFont().heightText(1.0f, w1, dialogButton1) + 10;
282
+
283
+        unsigned int wOverlay = wMax, hOverlay, w2 = 0, h2 = 0;
284
+
285
+        if (dialogButton2.length() > 0) {
286
+            // Show text and two buttons
287
+            w2 = getFont().widthText(1.0f, dialogButton2) + 20;
288
+            if (w2 > wMax)
289
+                w2 = wMax;
290
+            h2 = getFont().heightText(1.0f, w2, dialogButton2) + 10;
291
+
292
+            if (w0 > (w1 + w2)) {
293
+                if (w0 < wMax) {
294
+                    wOverlay = w0;
295
+                }
296
+            } else if (w0 < (w1 + w2)) {
297
+                if ((w1 + w2) < wMax) {
298
+                    wOverlay = (w1 + w2);
299
+                }
300
+            }
301
+
302
+            if ((w1 + w2) <= wMax) {
303
+                hOverlay = h0 + ((h1 + h2) / 2);
304
+            } else {
305
+                hOverlay = h0 + h1 + h2;
306
+            }
307
+        } else {
308
+            // Show text and one button
309
+            if (w0 > w1) {
310
+                if (w0 < wMax) {
311
+                    wOverlay = w0;
312
+                }
313
+            } else if (w0 < w1) {
314
+                if (w1 < wMax) {
315
+                    wOverlay = w1;
316
+                }
317
+            }
318
+
319
+            hOverlay = h0 + h1;
320
+        }
321
+
322
+        unsigned int xOverlay = (getWindow().getWidth() - wOverlay) / 2;
323
+        unsigned int yOverlay = (getWindow().getHeight() - hOverlay) / 2;
324
+
325
+        glColor4f(0.0f, 0.0f, 0.0f, 0.75f);
326
+        glDisable(GL_TEXTURE_2D);
327
+        glRecti(xOverlay, yOverlay, xOverlay + wOverlay, yOverlay + hOverlay);
328
+        glEnable(GL_TEXTURE_2D);
329
+
330
+        getFont().drawTextWrapped(xOverlay + 10, yOverlay + 5, 1.0f, BLUE, w0, dialogText);
331
+        if (dialogButton2.length() > 0) {
332
+            if ((w1 + w2) <= wMax) {
333
+                getFont().drawTextWrapped(xOverlay + 10, yOverlay + 10 + h0, 1.0f,
334
+                    dialogState ? BLUE : RED, w1, dialogButton1);
335
+                getFont().drawTextWrapped(xOverlay + 10 + w1, yOverlay + 10 + h0,
336
+                    1.0f, dialogState ? RED : BLUE, w2, dialogButton2);
337
+            } else {
338
+                getFont().drawTextWrapped((getWindow().getWidth() - w1) / 2,
339
+                    yOverlay + 10 + h0, 1.0f, dialogState ? BLUE : RED, w1, dialogButton1);
340
+                getFont().drawTextWrapped((getWindow().getWidth() - w2) / 2,
341
+                    yOverlay + 10 + h0 + h1, 1.0f, dialogState ? RED : BLUE, w2, dialogButton2);
342
+            }
343
+        } else {
344
+            getFont().drawTextWrapped((getWindow().getWidth() - w1) / 2,
345
+                    yOverlay + 10 + h0, 1.0f, RED, w1, dialogButton1);
346
+        }
347
+    }
348
+}
349
+

+ 9
- 4
src/OpenRaider.cpp View File

@@ -7,6 +7,7 @@
7 7
 
8 8
 #include <cstdio>
9 9
 #include <cstring>
10
+#include <sstream>
10 11
 
11 12
 #include "global.h"
12 13
 #include "Console.h"
@@ -135,15 +136,19 @@ void OpenRaider::frame() {
135 136
     getMenu().display();
136 137
 
137 138
     // Draw FPS counter
138
-    if (mFPS)
139
-        getFont().drawText(10, getWindow().getHeight() - 20, 0.5f, BLUE, "%dFPS", fps);
139
+    if (mFPS) {
140
+        std::ostringstream fpsText;
141
+        fpsText << fps << "FPS";
142
+        getFont().drawText(10, getWindow().getHeight() - 20, 0.5f, BLUE, fpsText.str());
143
+    }
140 144
 
141 145
 #ifdef DEBUG
142 146
     // Draw debug infos
143 147
     if (getGame().isLoaded() && (!getMenu().isVisible())) {
144 148
         for (int i = 0; i < 3; i++) {
145
-            getFont().drawText(10, getWindow().getHeight() - ((4 - i) * 20), 0.5f, BLUE, "%.2f (%.2f)",
146
-                getGame().getLara().getPos(i) / 256.0f, getGame().getLara().getAngle(i));
149
+            std::ostringstream axis;
150
+            axis << getGame().getLara().getPos(i) / 256.0f << " (" << getGame().getLara().getAngle(i) << ")";
151
+            getFont().drawText(10, getWindow().getHeight() - ((4 - i) * 20), 0.5f, BLUE, axis.str());
147 152
         }
148 153
     }
149 154
 #endif

Loading…
Cancel
Save