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
 
2
 
3
 ## OpenRaider (0.1.3) xythobuz <xythobuz@xythobuz.de>
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
     [ 20140810 ]
9
     [ 20140810 ]
6
     * Removed recursive Folder access method implementations
10
     * Removed recursive Folder access method implementations
7
       into their own file
11
       into their own file

+ 10
- 14
include/Font.h View File

8
 #ifndef _FONT_H_
8
 #ifndef _FONT_H_
9
 #define _FONT_H_
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
  * \brief Font interface
14
  * \brief Font interface
33
 
25
 
34
     virtual int initialize() = 0;
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
     virtual void drawText(unsigned int x, unsigned int y, float scale,
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
     virtual void drawTextCentered(unsigned int x, unsigned int y, float scale,
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
 protected:
42
 protected:
47
     bool mFontInit;
43
     bool mFontInit;

+ 9
- 1
include/FontManager.h View File

27
 
27
 
28
     virtual int initialize();
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
 private:
40
 private:
33
 
41
 

+ 9
- 1
include/FontSDL.h View File

30
 
30
 
31
     virtual int initialize();
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
 private:
43
 private:
36
     TTF_Font *mFont;
44
     TTF_Font *mFont;

+ 11
- 2
include/FontTRLE.h View File

28
 
28
 
29
     virtual int initialize();
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
 private:
41
 private:
34
 
42
 
35
     void loadLPS(const char *f);
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
     unsigned int mFontTexture;
47
     unsigned int mFontTexture;
39
 
48
 

+ 12
- 1
include/Menu.h View File

8
 #ifndef _MENU_H_
8
 #ifndef _MENU_H_
9
 #define _MENU_H_
9
 #define _MENU_H_
10
 
10
 
11
+#include <functional>
11
 #include <memory>
12
 #include <memory>
12
 
13
 
13
 #include "utils/Folder.h"
14
 #include "utils/Folder.h"
46
 
47
 
47
 private:
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
     bool mVisible;
56
     bool mVisible;
52
     long mCursor;
57
     long mCursor;
54
 
59
 
55
     Folder *mapFolder;
60
     Folder *mapFolder;
56
     bool hiddenState;
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
 Menu &getMenu();
70
 Menu &getMenu();

+ 5
- 4
src/Console.cpp View File

65
     }
65
     }
66
 
66
 
67
     // Draw status line
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
     // Draw output log
72
     // Draw output log
72
     long end = lineCount;
73
     long end = lineCount;
81
 
82
 
82
     for (int i = 0; i < end; i++) {
83
     for (int i = 0; i < end; i++) {
83
         getFont().drawText(10, (unsigned int)((i + drawOffset) * lineSteps) + firstLine,
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
     // Draw current input
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
 void Console::handleKeyboard(KeyboardButton key, bool pressed) {
92
 void Console::handleKeyboard(KeyboardButton key, bool pressed) {

+ 2
- 54
src/Font.cpp View File

5
  * \author xythobuz
5
  * \author xythobuz
6
  */
6
  */
7
 
7
 
8
-#include <stdio.h>
9
-#include <stdarg.h>
10
-
11
 #include "global.h"
8
 #include "global.h"
12
 #include "utils/strings.h"
9
 #include "utils/strings.h"
13
 #include "Window.h"
10
 #include "Window.h"
26
     mFontName = fullPath(font, 0);
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
 void Font::drawTextCentered(unsigned int x, unsigned int y, float scale,
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
     return fonts.at(font)->initialize();
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
     assert(font != -1);
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
     return 0;
49
     return 0;
50
 }
50
 }
51
 
51
 
52
-void FontSDL::writeString(FontString &s) {
52
+unsigned int FontSDL::widthText(float scale, std::string s) {
53
     assert(mFontInit == true);
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
     if (surface == NULL) {
75
     if (surface == NULL) {
64
         printf("TTF_RenderUTF8_Blended Error: %s\n", TTF_GetError());
76
         printf("TTF_RenderUTF8_Blended Error: %s\n", TTF_GetError());
65
         return;
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
     GLenum textureFormat;
161
     GLenum textureFormat;
72
     if (surface->format->BytesPerPixel == 4) {
162
     if (surface->format->BytesPerPixel == 4) {
87
     glTexImage2D(GL_TEXTURE_2D, 0, surface->format->BytesPerPixel, surface->w, surface->h, 0, textureFormat, GL_UNSIGNED_BYTE, surface->pixels);
177
     glTexImage2D(GL_TEXTURE_2D, 0, surface->format->BytesPerPixel, surface->w, surface->h, 0, textureFormat, GL_UNSIGNED_BYTE, surface->pixels);
88
     SDL_FreeSurface(surface);
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
     glBegin(GL_QUADS);
187
     glBegin(GL_QUADS);
98
     glTexCoord2f(0.0f, 0.0f);
188
     glTexCoord2f(0.0f, 0.0f);

+ 104
- 19
src/FontTRLE.cpp View File

94
 
94
 
95
 #define SCALING 2.0f
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
     // screen coordinates
105
     // screen coordinates
103
     int xMin = xDraw;
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
     int xMax = xMin + width;
108
     int xMax = xMin + width;
106
     int yMax = yMin + height;
109
     int yMax = yMin + height;
107
 
110
 
113
 
116
 
114
     // draw
117
     // draw
115
     glBindTexture(GL_TEXTURE_2D, mFontTexture);
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
     glBegin(GL_QUADS);
120
     glBegin(GL_QUADS);
118
     glTexCoord2f(txMin, tyMin);
121
     glTexCoord2f(txMin, tyMin);
119
     glVertex2i(xMin, yMin);
122
     glVertex2i(xMin, yMin);
126
     glEnd();
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
     assert(mFontInit == true);
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
         // index into offset table
182
         // index into offset table
138
-        int index = s.text[i] - '!';
183
+        int index = s[i] - '!';
139
 
184
 
140
         if (index == -1) // space
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
         if ((index < 0) || (index > 105))
188
         if ((index < 0) || (index > 105))
144
             continue; // skip unprintable chars
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
     mMin = 0;
23
     mMin = 0;
24
     mapFolder = nullptr;
24
     mapFolder = nullptr;
25
     hiddenState = false;
25
     hiddenState = false;
26
+    dialogState = false;
26
 }
27
 }
27
 
28
 
28
 Menu::~Menu() {
29
 Menu::~Menu() {
83
     if (!mVisible)
84
     if (!mVisible)
84
         return;
85
         return;
85
 
86
 
86
-    // Draw half-transparent *overlay*
87
+    // Draw half-transparent overlay
87
     glColor4f(0.0f, 0.0f, 0.0f, 0.75f);
88
     glColor4f(0.0f, 0.0f, 0.0f, 0.75f);
88
     glDisable(GL_TEXTURE_2D);
89
     glDisable(GL_TEXTURE_2D);
89
     glRecti(0, 0, (GLint)getWindow().getWidth(), (GLint)getWindow().getHeight());
90
     glRecti(0, 0, (GLint)getWindow().getWidth(), (GLint)getWindow().getHeight());
90
     glEnable(GL_TEXTURE_2D);
91
     glEnable(GL_TEXTURE_2D);
91
 
92
 
92
     // Draw heading
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
     // Estimate displayable number of items
96
     // Estimate displayable number of items
96
     int items = (getWindow().getHeight() - 60) / 25;
97
     int items = (getWindow().getHeight() - 60) / 25;
102
             getFont().drawText(25, 50, 0.75f, (mCursor == i) ? RED : BLUE, "..");
103
             getFont().drawText(25, 50, 0.75f, (mCursor == i) ? RED : BLUE, "..");
103
         } else {
104
         } else {
104
             getFont().drawText(25, (unsigned int)(50 + (25 * (i - mMin))), 0.75f,
105
             getFont().drawText(25, (unsigned int)(50 + (25 * (i - mMin))), 0.75f,
105
-                (mCursor == i) ? RED : BLUE, "%s",
106
+                (mCursor == i) ? RED : BLUE,
106
                 ((i - 1) < mapFolder->folderCount()) ?
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
     if (mCursor == 0) {
117
     if (mCursor == 0) {
115
         if (initialize(mapFolder->getParent().getPath()) != 0) {
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
     } else if ((mCursor - 1) < mapFolder->folderCount()) {
121
     } else if ((mCursor - 1) < mapFolder->folderCount()) {
119
         if (initialize(mapFolder->getFolder(mCursor - 1).getPath()) != 0) {
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
     } else {
125
     } else {
123
         std::string tmp = "load ";
126
         std::string tmp = "load ";
125
         if (getOpenRaider().command(tmp.c_str()) == 0) {
128
         if (getOpenRaider().command(tmp.c_str()) == 0) {
126
             setVisible(false);
129
             setVisible(false);
127
         } else {
130
         } else {
128
-            //! \todo Display something if an error occurs
131
+            showDialog("Error loading map!", "OK", "");
129
         }
132
         }
130
     }
133
     }
131
 }
134
 }
134
     if (!pressed)
137
     if (!pressed)
135
         return;
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
     assert(mapFolder != nullptr);
161
     assert(mapFolder != nullptr);
138
     int items = (getWindow().getHeight() - 60) / 25;
162
     int items = (getWindow().getHeight() - 60) / 25;
139
 
163
 
148
         else
172
         else
149
             mCursor = 0;
173
             mCursor = 0;
150
     } else if (key == enterKey) {
174
     } else if (key == enterKey) {
151
-        play();
175
+        loadOrOpen();
152
     } else if (key == dotKey) {
176
     } else if (key == dotKey) {
153
         hiddenState = !hiddenState;
177
         hiddenState = !hiddenState;
154
         initialize(mapFolder->getPath());
178
         initialize(mapFolder->getPath());
167
     if (released || (button != leftmouseKey))
191
     if (released || (button != leftmouseKey))
168
         return;
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
         y -= 50;
201
         y -= 50;
172
         if (mCursor == (mMin + (y / 25)))
202
         if (mCursor == (mMin + (y / 25)))
173
-            play();
203
+            loadOrOpen();
174
         else
204
         else
175
             mCursor = mMin + (y / 25);
205
             mCursor = mMin + (y / 25);
176
     }
206
     }
177
 }
207
 }
178
 
208
 
179
 void Menu::handleMouseScroll(int xrel, int yrel) {
209
 void Menu::handleMouseScroll(int xrel, int yrel) {
210
+    if (dialogText.length() > 0)
211
+        return;
212
+
180
     assert((xrel != 0) || (yrel != 0));
213
     assert((xrel != 0) || (yrel != 0));
181
     assert(mapFolder != nullptr);
214
     assert(mapFolder != nullptr);
182
     int items = (getWindow().getHeight() - 60) / 25;
215
     int items = (getWindow().getHeight() - 60) / 25;
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
 
7
 
8
 #include <cstdio>
8
 #include <cstdio>
9
 #include <cstring>
9
 #include <cstring>
10
+#include <sstream>
10
 
11
 
11
 #include "global.h"
12
 #include "global.h"
12
 #include "Console.h"
13
 #include "Console.h"
135
     getMenu().display();
136
     getMenu().display();
136
 
137
 
137
     // Draw FPS counter
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
 #ifdef DEBUG
145
 #ifdef DEBUG
142
     // Draw debug infos
146
     // Draw debug infos
143
     if (getGame().isLoaded() && (!getMenu().isVisible())) {
147
     if (getGame().isLoaded() && (!getMenu().isVisible())) {
144
         for (int i = 0; i < 3; i++) {
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
 #endif
154
 #endif

Loading…
Cancel
Save