Browse Source

Now using stb_truetype instead of SDL2-TTF.

Thomas Buck 9 years ago
parent
commit
3c66d229bf

+ 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
+    [ 20150106 ]
6
+    * Removed SDL2-TTF Font implementation
7
+    * Added new Font implementation using stb_truetype
8
+
5 9
     [ 20150104 ]
6 10
     * FontImGui has started to be useful (larger text, proper size calculation).
7 11
 

+ 1
- 3
README.md View File

@@ -44,12 +44,11 @@ Basically, OpenRaider depends on the following:
44 44
 * GLM (>= 0.9.6)
45 45
 * zlib
46 46
 * SDL2 or GLFW
47
-* SDL2-TTF (optional, doesn’t work with GLFW, needed if you want to use TTF fonts)
48 47
 * OpenAL & ALUT (optional, needed for sound output)
49 48
 
50 49
 On Mac OS X 10.9 / 10.10 with [XCode](https://developer.apple.com/xcode/) and [MacPorts](http://www.macports.org) installed, the following should be enough to get all dependencies that are available as port:
51 50
 
52
-    sudo port install cmake zlib glm libsdl2 libsdl2_ttf
51
+    sudo port install cmake zlib glm libsdl2
53 52
 
54 53
 A similar command for the package manager of your favorite Linux Distribution should do the trick.
55 54
 
@@ -175,7 +174,6 @@ There are some included cmake scripts:
175 174
 
176 175
 * [FindALUT](https://github.com/rpavlik/cmake-modules/blob/master/FindALUT.cmake)
177 176
 * [FindSDL2](https://github.com/dhewm/dhewm3/blob/master/neo/sys/cmake/FindSDL2.cmake)
178
-* [FindSDL2TTF](https://github.com/Deraen/ohj2710/blob/master/cmake_modules/FindSDL2TTF.cmake)
179 177
 * [FindSSE](https://gitorious.org/vc/vc/source/a1d8b9fc31060d870386613cc72319546c850b87:cmake/FindSSE.cmake)
180 178
 * [GetGitRevisionDescription.cmake](https://github.com/rpavlik/cmake-modules/blob/master/GetGitRevisionDescription.cmake)
181 179
 * [GetGitRevisionDescription.cmake.in](https://github.com/rpavlik/cmake-modules/blob/master/GetGitRevisionDescription.cmake.in)

+ 0
- 114
cmake/FindSDL2TTF.cmake View File

@@ -1,114 +0,0 @@
1
-# Locate SDL2 library
2
-# This module defines
3
-# SDL2_LIBRARY, the name of the library to link against
4
-# SDL2_FOUND, if false, do not try to link to SDL2
5
-# SDL2_INCLUDE_DIR, where to find SDL.h
6
-#
7
-# This module responds to the the flag:
8
-# SDL2_BUILDING_LIBRARY
9
-# If this is defined, then no SDL2main will be linked in because
10
-# only applications need main().
11
-# Otherwise, it is assumed you are building an application and this
12
-# module will attempt to locate and set the the proper link flags
13
-# as part of the returned SDL2_LIBRARY variable.
14
-#
15
-# Don't forget to include SDLmain.h and SDLmain.m your project for the
16
-# OS X framework based version. (Other versions link to -lSDL2main which
17
-# this module will try to find on your behalf.) Also for OS X, this
18
-# module will automatically add the -framework Cocoa on your behalf.
19
-#
20
-#
21
-# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration
22
-# and no SDL2_LIBRARY, it means CMake did not find your SDL2 library
23
-# (SDL2.dll, libsdl2.so, SDL2.framework, etc).
24
-# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again.
25
-# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value
26
-# as appropriate. These values are used to generate the final SDL2_LIBRARY
27
-# variable, but when these values are unset, SDL2_LIBRARY does not get created.
28
-#
29
-#
30
-# $SDL2DIR is an environment variable that would
31
-# correspond to the ./configure --prefix=$SDL2DIR
32
-# used in building SDL2.
33
-# l.e.galup  9-20-02
34
-#
35
-# Modified by Eric Wing.
36
-# Added code to assist with automated building by using environmental variables
37
-# and providing a more controlled/consistent search behavior.
38
-# Added new modifications to recognize OS X frameworks and
39
-# additional Unix paths (FreeBSD, etc).
40
-# Also corrected the header search path to follow "proper" SDL guidelines.
41
-# Added a search for SDL2main which is needed by some platforms.
42
-# Added a search for threads which is needed by some platforms.
43
-# Added needed compile switches for MinGW.
44
-#
45
-# On OSX, this will prefer the Framework version (if found) over others.
46
-# People will have to manually change the cache values of
47
-# SDL2_LIBRARY to override this selection or set the CMake environment
48
-# CMAKE_INCLUDE_PATH to modify the search paths.
49
-#
50
-# Note that the header path has changed from SDL2/SDL.h to just SDL.h
51
-# This needed to change because "proper" SDL convention
52
-# is #include "SDL.h", not <SDL2/SDL.h>. This is done for portability
53
-# reasons because not all systems place things in SDL2/ (see FreeBSD).
54
-#
55
-# =============================================================================
56
-# Copyright 2003-2009 Kitware, Inc.
57
-#
58
-# Redistribution and use in source and binary forms, with or without
59
-# modification, are permitted provided that the following conditions are met: 
60
-# 
61
-# 1. Redistributions of source code must retain the above copyright notice, this
62
-#    list of conditions and the following disclaimer. 
63
-# 2. Redistributions in binary form must reproduce the above copyright notice,
64
-#    this list of conditions and the following disclaimer in the documentation
65
-#    and/or other materials provided with the distribution. 
66
-# 
67
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
68
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
69
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
70
-# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
71
-# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
72
-# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
73
-# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
74
-# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
75
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
76
-# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
77
-# =============================================================================
78
-
79
-SET(SDL2TTF_SEARCH_PATHS
80
-	~/Library/Frameworks
81
-	/Library/Frameworks
82
-	/usr/local
83
-	/usr
84
-	/sw # Fink
85
-	/opt/local # DarwinPorts
86
-	/opt/csw # Blastwave
87
-	/opt
88
-)
89
-
90
-FIND_PATH(SDL2TTF_INCLUDE_DIR SDL_ttf.h
91
-	HINTS
92
-	$ENV{SDL2TTFDIR}
93
-	PATH_SUFFIXES include/SDL2 include
94
-	PATHS ${SDL2TTF_SEARCH_PATHS}
95
-)
96
-
97
-FIND_LIBRARY(SDL2TTF_LIBRARY_TEMP
98
-	NAMES SDL2_ttf
99
-	HINTS
100
-	$ENV{SDL2TTFDIR}
101
-	PATH_SUFFIXES lib64 lib
102
-	PATHS ${SDL2TTF_SEARCH_PATHS}
103
-)
104
-
105
-IF(SDL2TTF_LIBRARY_TEMP)
106
-	# Set the final string here so the GUI reflects the final state.
107
-	SET(SDL2TTF_LIBRARY ${SDL2TTF_LIBRARY_TEMP} CACHE STRING "Where the SDL2TTF Library can be found")
108
-	# Set the temp variable to INTERNAL so it is not seen in the CMake GUI
109
-	SET(SDL2TTF_LIBRARY_TEMP "${SDL2TTF_LIBRARY_TEMP}" CACHE INTERNAL "")
110
-ENDIF(SDL2TTF_LIBRARY_TEMP)
111
-
112
-INCLUDE(FindPackageHandleStandardArgs)
113
-
114
-FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2TTF REQUIRED_VARS SDL2TTF_LIBRARY SDL2TTF_INCLUDE_DIR)

+ 0
- 1
include/config.h.in View File

@@ -20,7 +20,6 @@ extern const char* INSTALL_PREFIX;
20 20
 
21 21
 #cmakedefine USING_AL
22 22
 #cmakedefine USING_SDL
23
-#cmakedefine USING_SDL_FONT
24 23
 #cmakedefine USING_GLFW
25 24
 
26 25
 #cmakedefine HAVE_EXECINFO_H

+ 0
- 41
include/system/FontSDL.h View File

@@ -1,41 +0,0 @@
1
-/*!
2
- * \file include/system/FontSDL.h
3
- * \brief SDL Font implementation
4
- *
5
- * \author xythobuz
6
- */
7
-
8
-#ifndef _FONT_SDL_H_
9
-#define _FONT_SDL_H_
10
-
11
-#include "SDL_ttf.h"
12
-
13
-/*!
14
- * \brief SDL Font implementation
15
- */
16
-class FontSDL {
17
-  public:
18
-    static void shutdown();
19
-
20
-    static int initialize(std::string font);
21
-
22
-    static unsigned int widthText(float scale, std::string s);
23
-
24
-    static unsigned int heightText(float scale, unsigned int maxWidth, std::string s);
25
-
26
-    static void drawText(unsigned int x, unsigned int y, float scale,
27
-                         const unsigned char color[4], std::string s);
28
-
29
-    static void drawTextWrapped(unsigned int x, unsigned int y, float scale,
30
-                                const unsigned char color[4], unsigned int maxWidth, std::string s);
31
-
32
-  private:
33
-    static bool mFontInit;
34
-    static TTF_Font* mFont;
35
-    static unsigned int mFontTexture;
36
-    static ShaderBuffer vertexBuffer;
37
-    static ShaderBuffer uvBuffer;
38
-};
39
-
40
-#endif
41
-

+ 58
- 0
include/system/FontTTF.h View File

@@ -0,0 +1,58 @@
1
+/*!
2
+ * \file include/system/FontTTF.h
3
+ * \brief TrueType Font implementation
4
+ *
5
+ * \author xythobuz
6
+ */
7
+
8
+#ifndef _FONT_TTF_H_
9
+#define _FONT_TTF_H_
10
+
11
+#include <string>
12
+#include <vector>
13
+
14
+#include "stb/stb_truetype.h"
15
+#include "system/Shader.h"
16
+
17
+class FontMapTTF {
18
+  public:
19
+    FontMapTTF();
20
+    FontMapTTF(FontMapTTF&& other);
21
+    ~FontMapTTF();
22
+
23
+    int initialize(unsigned char* fontData, int firstChar);
24
+    bool contains(int c);
25
+    int getTexture() { return texture; }
26
+    void getQuad(int c, float* xpos, float* ypos, stbtt_aligned_quad *quad);
27
+
28
+  private:
29
+    int begin;
30
+    int texture;
31
+    stbtt_packedchar* charInfo;
32
+};
33
+
34
+class FontTTF {
35
+  public:
36
+    static int initialize(std::string f);
37
+    static void shutdown();
38
+
39
+    static unsigned int widthText(float scale, std::string s);
40
+    static unsigned int heightText(float scale, unsigned int maxWidth, std::string s);
41
+
42
+    static void drawText(unsigned int x, unsigned int y, float scale,
43
+                         const unsigned char color[4], std::string s);
44
+    static void drawTextWrapped(unsigned int x, unsigned int y, float scale,
45
+                                const unsigned char color[4], unsigned int maxWidth, std::string s);
46
+
47
+  private:
48
+    static int charIsMapped(int c);
49
+    static int getQuad(int c, float* xpos, float* ypos, stbtt_aligned_quad *quad);
50
+
51
+    static unsigned char* fontData;
52
+    static std::vector<FontMapTTF> maps;
53
+    static ShaderBuffer vertexBuffer;
54
+    static ShaderBuffer uvBuffer;
55
+};
56
+
57
+#endif
58
+

+ 1
- 0
include/utils/pixel.h View File

@@ -17,6 +17,7 @@ void argb2rgba32(unsigned char* image, unsigned int w, unsigned int h);
17 17
 
18 18
 // Returns newly allocated buffer
19 19
 unsigned char* argb16to32(unsigned char* image, unsigned int w, unsigned int h);
20
+unsigned char* grayscale2rgba(unsigned char* image, unsigned int w, unsigned int h);
20 21
 
21 22
 unsigned char* scaleBuffer(unsigned char* image, unsigned int* w, unsigned int* h,
22 23
                            unsigned int bpp);

+ 0
- 13
src/CMakeLists.txt View File

@@ -17,13 +17,6 @@ find_package (SDL2)
17 17
 if (SDL2_FOUND AND NOT FORCE_GLFW)
18 18
     include_directories (SYSTEM ${SDL2_INCLUDE_DIR})
19 19
     set (LIBS ${LIBS} ${SDL2_LIBRARY})
20
-
21
-    # Add SDL2_ttf Library
22
-    find_package (SDL2TTF)
23
-    if (SDL2TTF_FOUND)
24
-        include_directories (SYSTEM ${SDL2TTF_INCLUDE_DIR})
25
-        set (LIBS ${LIBS} ${SDL2TTF_LIBRARY})
26
-    endif (SDL2TTF_FOUND)
27 20
 else (SDL2_FOUND AND NOT FORCE_GLFW)
28 21
     find_package (GLFW)
29 22
     if (GLFW_FOUND)
@@ -90,14 +83,8 @@ endif (OPENAL_FOUND AND ALUT_FOUND AND ENABLE_AUDIO)
90 83
 if (SDL2_FOUND AND NOT FORCE_GLFW)
91 84
     set (USING_GLFW FALSE)
92 85
     set (USING_SDL TRUE)
93
-    if (SDL2TTF_FOUND)
94
-        set (USING_SDL_FONT TRUE)
95
-    else (SDL2TTF_FOUND)
96
-        set (USING_SDL_FONT FALSE)
97
-    endif (SDL2TTF_FOUND)
98 86
 else (SDL2_FOUND AND NOT FORCE_GLFW)
99 87
     set (USING_SDL FALSE)
100
-    set (USING_SDL_FONT FALSE)
101 88
     if (GLFW_FOUND)
102 89
         set (USING_GLFW TRUE)
103 90
     else (GLFW_FOUND)

+ 1
- 1
src/TextureManager.cpp View File

@@ -114,7 +114,7 @@ int TextureManager::loadBufferSlot(unsigned char* image,
114 114
            || (mode ==  ColorMode::BGRA));
115 115
     assert((bpp == 8) || (bpp == 24) || (bpp == 32));
116 116
 
117
-    if (slot == -1)
117
+    if (slot < 0)
118 118
         slot = getIds(s).size();
119 119
 
120 120
     while (getIds(s).size() <= slot) {

+ 1
- 1
src/deps/CMakeLists.txt View File

@@ -1,7 +1,7 @@
1 1
 # Source files
2 2
 set (DEPS_SRCS ${DEPS_SRCS} "commander/commander.c" "commander/commander.h")
3 3
 set (DEPS_SRCS ${DEPS_SRCS} "imgui/imgui.cpp" "imgui/imgui.h" "imgui/imconfig.h" "imgui/stb_textedit.h")
4
-set (DEPS_SRCS ${DEPS_SRCS} "stb/stb.cpp" "stb/stb_image.h" "stb/stb_image_write.h")
4
+set (DEPS_SRCS ${DEPS_SRCS} "stb/stb.cpp" "stb/stb_image.h" "stb/stb_image_write.h" "stb/stb_truetype.h")
5 5
 
6 6
 # Add library
7 7
 add_library (OpenRaider_deps OBJECT ${DEPS_SRCS})

+ 8
- 0
src/deps/stb/stb.cpp View File

@@ -14,3 +14,11 @@
14 14
 #define STB_IMAGE_WRITE_IMPLEMENTATION
15 15
 #include "stb/stb_image_write.h"
16 16
 
17
+#define STB_RECT_PACK_IMPLEMENTATION
18
+#define STBRP_ASSERT assert
19
+#include "stb/stb_rect_pack.h"
20
+
21
+#define STB_TRUETYPE_IMPLEMENTATION
22
+#define STBTT_assert(x) assert(x)
23
+#include "stb/stb_truetype.h"
24
+

+ 546
- 0
src/deps/stb/stb_rect_pack.h View File

@@ -0,0 +1,546 @@
1
+// stb_rect_pack.h - v0.05 - public domain - rectangle packing
2
+// Sean Barrett 2014
3
+//
4
+// Useful for e.g. packing rectangular textures into an atlas.
5
+// Does not do rotation.
6
+//
7
+// Not necessarily the awesomest packing method, but better than
8
+// the totally naive one in stb_truetype (which is primarily what
9
+// this is meant to replace).
10
+//
11
+// Has only had a few tests run, may have issues.
12
+//
13
+// More docs to come.
14
+//
15
+// No memory allocations; uses qsort() and assert() from stdlib.
16
+//
17
+// This library currently uses the Skyline Bottom-Left algorithm.
18
+//
19
+// Please note: better rectangle packers are welcome! Please
20
+// implement them to the same API, but with a different init
21
+// function.
22
+//
23
+// Version history:
24
+//
25
+//     0.05:  added STBRP_ASSERT to allow replacing assert
26
+//     0.04:  fixed minor bug in STBRP_LARGE_RECTS support
27
+//     0.01:  initial release
28
+
29
+//////////////////////////////////////////////////////////////////////////////
30
+//
31
+//       INCLUDE SECTION
32
+//
33
+
34
+#ifndef STB_INCLUDE_STB_RECT_PACK_H
35
+#define STB_INCLUDE_STB_RECT_PACK_H
36
+
37
+#define STB_RECT_PACK_VERSION  1
38
+
39
+#ifdef STBRP_STATIC
40
+#define STBRP_DEF static
41
+#else
42
+#define STBRP_DEF extern
43
+#endif
44
+
45
+#ifdef __cplusplus
46
+extern "C" {
47
+#endif
48
+
49
+typedef struct stbrp_context stbrp_context;
50
+typedef struct stbrp_node    stbrp_node;
51
+typedef struct stbrp_rect    stbrp_rect;
52
+
53
+#ifdef STBRP_LARGE_RECTS
54
+typedef int            stbrp_coord;
55
+#else
56
+typedef unsigned short stbrp_coord;
57
+#endif
58
+
59
+STBRP_DEF void stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
60
+// Assign packed locations to rectangles. The rectangles are of type
61
+// 'stbrp_rect' defined below, stored in the array 'rects', and there
62
+// are 'num_rects' many of them.
63
+//
64
+// Rectangles which are successfully packed have the 'was_packed' flag
65
+// set to a non-zero value and 'x' and 'y' store the minimum location
66
+// on each axis (i.e. bottom-left in cartesian coordinates, top-left
67
+// if you imagine y increasing downwards). Rectangles which do not fit
68
+// have the 'was_packed' flag set to 0.
69
+//
70
+// You should not try to access the 'rects' array from another thread
71
+// while this function is running, as the function temporarily reorders
72
+// the array while it executes.
73
+//
74
+// To pack into another rectangle, you need to call stbrp_init_target
75
+// again. To continue packing into the same rectangle, you can call
76
+// this function again. Calling this multiple times with multiple rect
77
+// arrays will probably produce worse packing results than calling it
78
+// a single time with the full rectangle array, but the option is
79
+// available.
80
+
81
+struct stbrp_rect
82
+{
83
+   // reserved for your use:
84
+   int            id;
85
+
86
+   // input:
87
+   stbrp_coord    w, h;
88
+
89
+   // output:
90
+   stbrp_coord    x, y;
91
+   int            was_packed;  // non-zero if valid packing
92
+
93
+}; // 16 bytes, nominally
94
+
95
+
96
+STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
97
+// Initialize a rectangle packer to:
98
+//    pack a rectangle that is 'width' by 'height' in dimensions
99
+//    using temporary storage provided by the array 'nodes', which is 'num_nodes' long
100
+//
101
+// You must call this function every time you start packing into a new target.
102
+//
103
+// There is no "shutdown" function. The 'nodes' memory must stay valid for
104
+// the following stbrp_pack_rects() call (or calls), but can be freed after
105
+// the call (or calls) finish.
106
+//
107
+// Note: to guarantee best results, either:
108
+//       1. make sure 'num_nodes' >= 'width'
109
+//   or  2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
110
+//
111
+// If you don't do either of the above things, widths will be quantized to multiples
112
+// of small integers to guarantee the algorithm doesn't run out of temporary storage.
113
+//
114
+// If you do #2, then the non-quantized algorithm will be used, but the algorithm
115
+// may run out of temporary storage and be unable to pack some rectangles.
116
+
117
+STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
118
+// Optionally call this function after init but before doing any packing to
119
+// change the handling of the out-of-temp-memory scenario, described above.
120
+// If you call init again, this will be reset to the default (false).
121
+
122
+
123
+STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
124
+// Optionally select which packing heuristic the library should use. Different
125
+// heuristics will produce better/worse results for different data sets.
126
+// If you call init again, this will be reset to the default.
127
+
128
+enum
129
+{
130
+   STBRP_HEURISTIC_Skyline_default=0,
131
+   STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
132
+   STBRP_HEURISTIC_Skyline_BF_sortHeight,
133
+};
134
+
135
+
136
+//////////////////////////////////////////////////////////////////////////////
137
+//
138
+// the details of the following structures don't matter to you, but they must
139
+// be visible so you can handle the memory allocations for them
140
+
141
+struct stbrp_node
142
+{
143
+   stbrp_coord  x,y;
144
+   stbrp_node  *next;
145
+};
146
+
147
+struct stbrp_context
148
+{
149
+   int width;
150
+   int height;
151
+   int align;
152
+   int init_mode;
153
+   int heuristic;
154
+   int num_nodes;
155
+   stbrp_node *active_head;
156
+   stbrp_node *free_head;
157
+   stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
158
+};
159
+
160
+#ifdef __cplusplus
161
+}
162
+#endif
163
+
164
+#endif
165
+
166
+//////////////////////////////////////////////////////////////////////////////
167
+//
168
+//     IMPLEMENTATION SECTION
169
+//
170
+
171
+#ifdef STB_RECT_PACK_IMPLEMENTATION
172
+#include <stdlib.h>
173
+
174
+#ifndef STBRP_ASSERT
175
+#include <assert.h>
176
+#define STBRP_ASSERT assert
177
+#endif
178
+
179
+enum
180
+{
181
+   STBRP__INIT_skyline = 1,
182
+};
183
+
184
+STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
185
+{
186
+   switch (context->init_mode) {
187
+      case STBRP__INIT_skyline:
188
+         STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
189
+         context->heuristic = heuristic;
190
+         break;
191
+      default:
192
+         STBRP_ASSERT(0);
193
+   }
194
+}
195
+
196
+STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
197
+{
198
+   if (allow_out_of_mem)
199
+      // if it's ok to run out of memory, then don't bother aligning them;
200
+      // this gives better packing, but may fail due to OOM (even though
201
+      // the rectangles easily fit). @TODO a smarter approach would be to only
202
+      // quantize once we've hit OOM, then we could get rid of this parameter.
203
+      context->align = 1;
204
+   else {
205
+      // if it's not ok to run out of memory, then quantize the widths
206
+      // so that num_nodes is always enough nodes.
207
+      //
208
+      // I.e. num_nodes * align >= width
209
+      //                  align >= width / num_nodes
210
+      //                  align = ceil(width/num_nodes)
211
+
212
+      context->align = (context->width + context->num_nodes-1) / context->num_nodes;
213
+   }
214
+}
215
+
216
+STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
217
+{
218
+   int i;
219
+#ifndef STBRP_LARGE_RECTS
220
+   STBRP_ASSERT(width <= 0xffff && height <= 0xffff);
221
+#endif
222
+
223
+   for (i=0; i < num_nodes-1; ++i)
224
+      nodes[i].next = &nodes[i+1];
225
+   nodes[i].next = NULL;
226
+   context->init_mode = STBRP__INIT_skyline;
227
+   context->heuristic = STBRP_HEURISTIC_Skyline_default;
228
+   context->free_head = &nodes[0];
229
+   context->active_head = &context->extra[0];
230
+   context->width = width;
231
+   context->height = height;
232
+   context->num_nodes = num_nodes;
233
+   stbrp_setup_allow_out_of_mem(context, 0);
234
+
235
+   // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
236
+   context->extra[0].x = 0;
237
+   context->extra[0].y = 0;
238
+   context->extra[0].next = &context->extra[1];
239
+   context->extra[1].x = (stbrp_coord) width;
240
+#ifdef STBRP_LARGE_RECTS
241
+   context->extra[1].y = (1<<30);
242
+#else
243
+   context->extra[1].y = 65535;
244
+#endif
245
+   context->extra[1].next = NULL;
246
+}
247
+
248
+// find minimum y position if it starts at x1
249
+static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
250
+{
251
+   stbrp_node *node = first;
252
+   int x1 = x0 + width;
253
+   int min_y, visited_width, waste_area;
254
+   STBRP_ASSERT(first->x <= x0);
255
+
256
+   #if 0
257
+   // skip in case we're past the node
258
+   while (node->next->x <= x0)
259
+      ++node;
260
+   #else
261
+   STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
262
+   #endif
263
+
264
+   STBRP_ASSERT(node->x <= x0);
265
+
266
+   min_y = 0;
267
+   waste_area = 0;
268
+   visited_width = 0;
269
+   while (node->x < x1) {
270
+      if (node->y > min_y) {
271
+         // raise min_y higher.
272
+         // we've accounted for all waste up to min_y,
273
+         // but we'll now add more waste for everything we've visted
274
+         waste_area += visited_width * (node->y - min_y);
275
+         min_y = node->y;
276
+         // the first time through, visited_width might be reduced
277
+         if (node->x < x0)
278
+            visited_width += node->next->x - x0;
279
+         else
280
+            visited_width += node->next->x - node->x;
281
+      } else {
282
+         // add waste area
283
+         int under_width = node->next->x - node->x;
284
+         if (under_width + visited_width > width)
285
+            under_width = width - visited_width;
286
+         waste_area += under_width * (min_y - node->y);
287
+         visited_width += under_width;
288
+      }
289
+      node = node->next;
290
+   }
291
+
292
+   *pwaste = waste_area;
293
+   return min_y;
294
+}
295
+
296
+typedef struct
297
+{
298
+   int x,y;
299
+   stbrp_node **prev_link;
300
+} stbrp__findresult;
301
+
302
+static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
303
+{
304
+   int best_waste = (1<<30), best_x, best_y = (1 << 30);
305
+   stbrp__findresult fr;
306
+   stbrp_node **prev, *node, *tail, **best = NULL;
307
+
308
+   // align to multiple of c->align
309
+   width = (width + c->align - 1);
310
+   width -= width % c->align;
311
+   STBRP_ASSERT(width % c->align == 0);
312
+
313
+   node = c->active_head;
314
+   prev = &c->active_head;
315
+   while (node->x + width <= c->width) {
316
+      int y,waste;
317
+      y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
318
+      if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
319
+         // bottom left
320
+         if (y < best_y) {
321
+            best_y = y;
322
+            best = prev;
323
+         }
324
+      } else {
325
+         // best-fit
326
+         if (y + height <= c->height) {
327
+            // can only use it if it first vertically
328
+            if (y < best_y || (y == best_y && waste < best_waste)) {
329
+               best_y = y;
330
+               best_waste = waste;
331
+               best = prev;
332
+            }
333
+         }
334
+      }
335
+      prev = &node->next;
336
+      node = node->next;
337
+   }
338
+
339
+   best_x = (best == NULL) ? 0 : (*best)->x;
340
+
341
+   // if doing best-fit (BF), we also have to try aligning right edge to each node position
342
+   //
343
+   // e.g, if fitting
344
+   //
345
+   //     ____________________
346
+   //    |____________________|
347
+   //
348
+   //            into
349
+   //
350
+   //   |                         |
351
+   //   |             ____________|
352
+   //   |____________|
353
+   //
354
+   // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
355
+   //
356
+   // This makes BF take about 2x the time
357
+
358
+   if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
359
+      tail = c->active_head;
360
+      node = c->active_head;
361
+      prev = &c->active_head;
362
+      // find first node that's admissible
363
+      while (tail->x < width)
364
+         tail = tail->next;
365
+      while (tail) {
366
+         int xpos = tail->x - width;
367
+         int y,waste;
368
+         STBRP_ASSERT(xpos >= 0);
369
+         // find the left position that matches this
370
+         while (node->next->x <= xpos) {
371
+            prev = &node->next;
372
+            node = node->next;
373
+         }
374
+         STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
375
+         y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
376
+         if (y + height < c->height) {
377
+            if (y <= best_y) {
378
+               if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
379
+                  best_x = xpos;
380
+                  STBRP_ASSERT(y <= best_y);
381
+                  best_y = y;
382
+                  best_waste = waste;
383
+                  best = prev;
384
+               }
385
+            }
386
+         }
387
+         tail = tail->next;
388
+      }
389
+   }
390
+
391
+   fr.prev_link = best;
392
+   fr.x = best_x;
393
+   fr.y = best_y;
394
+   return fr;
395
+}
396
+
397
+static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
398
+{
399
+   // find best position according to heuristic
400
+   stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
401
+   stbrp_node *node, *cur;
402
+
403
+   // bail if:
404
+   //    1. it failed
405
+   //    2. the best node doesn't fit (we don't always check this)
406
+   //    3. we're out of memory
407
+   if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
408
+      res.prev_link = NULL;
409
+      return res;
410
+   }
411
+
412
+   // on success, create new node
413
+   node = context->free_head;
414
+   node->x = (stbrp_coord) res.x;
415
+   node->y = (stbrp_coord) (res.y + height);
416
+
417
+   context->free_head = node->next;
418
+
419
+   // insert the new node into the right starting point, and
420
+   // let 'cur' point to the remaining nodes needing to be
421
+   // stiched back in
422
+
423
+   cur = *res.prev_link;
424
+   if (cur->x < res.x) {
425
+      // preserve the existing one, so start testing with the next one
426
+      stbrp_node *next = cur->next;
427
+      cur->next = node;
428
+      cur = next;
429
+   } else {
430
+      *res.prev_link = node;
431
+   }
432
+
433
+   // from here, traverse cur and free the nodes, until we get to one
434
+   // that shouldn't be freed
435
+   while (cur->next && cur->next->x <= res.x + width) {
436
+      stbrp_node *next = cur->next;
437
+      // move the current node to the free list
438
+      cur->next = context->free_head;
439
+      context->free_head = cur;
440
+      cur = next;
441
+   }
442
+
443
+   // stitch the list back in
444
+   node->next = cur;
445
+
446
+   if (cur->x < res.x + width)
447
+      cur->x = (stbrp_coord) (res.x + width);
448
+
449
+#ifdef _DEBUG
450
+   cur = context->active_head;
451
+   while (cur->x < context->width) {
452
+      STBRP_ASSERT(cur->x < cur->next->x);
453
+      cur = cur->next;
454
+   }
455
+   STBRP_ASSERT(cur->next == NULL);
456
+
457
+   {
458
+      stbrp_node *L1 = NULL, *L2 = NULL;
459
+      int count=0;
460
+      cur = context->active_head;
461
+      while (cur) {
462
+         L1 = cur;
463
+         cur = cur->next;
464
+         ++count;
465
+      }
466
+      cur = context->free_head;
467
+      while (cur) {
468
+         L2 = cur;
469
+         cur = cur->next;
470
+         ++count;
471
+      }
472
+      STBRP_ASSERT(count == context->num_nodes+2);
473
+   }
474
+#endif
475
+
476
+   return res;
477
+}
478
+
479
+static int rect_height_compare(const void *a, const void *b)
480
+{
481
+   stbrp_rect *p = (stbrp_rect *) a;
482
+   stbrp_rect *q = (stbrp_rect *) b;
483
+   if (p->h > q->h)
484
+      return -1;
485
+   if (p->h < q->h)
486
+      return  1;
487
+   return (p->w > q->w) ? -1 : (p->w < q->w);
488
+}
489
+
490
+static int rect_width_compare(const void *a, const void *b)
491
+{
492
+   stbrp_rect *p = (stbrp_rect *) a;
493
+   stbrp_rect *q = (stbrp_rect *) b;
494
+   if (p->w > q->w)
495
+      return -1;
496
+   if (p->w < q->w)
497
+      return  1;
498
+   return (p->h > q->h) ? -1 : (p->h < q->h);
499
+}
500
+
501
+static int rect_original_order(const void *a, const void *b)
502
+{
503
+   stbrp_rect *p = (stbrp_rect *) a;
504
+   stbrp_rect *q = (stbrp_rect *) b;
505
+   return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
506
+}
507
+
508
+#ifdef STBRP_LARGE_RECTS
509
+#define STBRP__MAXVAL  0xffffffff
510
+#else
511
+#define STBRP__MAXVAL  0xffff
512
+#endif
513
+
514
+STBRP_DEF void stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
515
+{
516
+   int i;
517
+
518
+   // we use the 'was_packed' field internally to allow sorting/unsorting
519
+   for (i=0; i < num_rects; ++i) {
520
+      rects[i].was_packed = i;
521
+      #ifndef STBRP_LARGE_RECTS
522
+      STBRP_ASSERT(rects[i].w <= 0xffff && rects[i].h <= 0xffff);
523
+      #endif
524
+   }
525
+
526
+   // sort according to heuristic
527
+   qsort(rects, num_rects, sizeof(rects[0]), rect_height_compare);
528
+
529
+   for (i=0; i < num_rects; ++i) {
530
+      stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
531
+      if (fr.prev_link) {
532
+         rects[i].x = (stbrp_coord) fr.x;
533
+         rects[i].y = (stbrp_coord) fr.y;
534
+      } else {
535
+         rects[i].x = rects[i].y = STBRP__MAXVAL;
536
+      }
537
+   }
538
+
539
+   // unsort
540
+   qsort(rects, num_rects, sizeof(rects[0]), rect_original_order);
541
+
542
+   // set was_packed flags
543
+   for (i=0; i < num_rects; ++i)
544
+      rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
545
+}
546
+#endif

+ 2612
- 0
src/deps/stb/stb_truetype.h
File diff suppressed because it is too large
View File


+ 1
- 4
src/system/CMakeLists.txt View File

@@ -2,6 +2,7 @@
2 2
 set (SYS_SRCS ${SYS_SRCS} "Font.cpp" "../../include/system/Font.h")
3 3
 set (SYS_SRCS ${SYS_SRCS} "FontImGui.cpp" "../../include/system/FontImGui.h")
4 4
 set (SYS_SRCS ${SYS_SRCS} "FontTRLE.cpp" "../../include/system/FontTRLE.h")
5
+set (SYS_SRCS ${SYS_SRCS} "FontTTF.cpp" "../../include/system/FontTTF.h")
5 6
 set (SYS_SRCS ${SYS_SRCS} "Shader.cpp" "../../include/system/Shader.h")
6 7
 set (SYS_SRCS ${SYS_SRCS} "Sound.cpp" "../../include/system/Sound.h")
7 8
 set (SYS_SRCS ${SYS_SRCS} "Window.cpp" "../../include/system/Window.h")
@@ -17,10 +18,6 @@ if (USING_SDL)
17 18
     set (SYS_SRCS ${SYS_SRCS} "WindowSDL.cpp" "../../include/system/WindowSDL.h")
18 19
 endif (USING_SDL)
19 20
 
20
-if (USING_SDL_FONT)
21
-    set (SYS_SRCS ${SYS_SRCS} "FontSDL.cpp" "../../include/system/FontSDL.h")
22
-endif (USING_SDL_FONT)
23
-
24 21
 if (USING_GLFW)
25 22
     set (SYS_SRCS ${SYS_SRCS} "WindowGLFW.cpp" "../../include/system/WindowGLFW.h")
26 23
 endif (USING_GLFW)

+ 8
- 23
src/system/Font.cpp View File

@@ -9,32 +9,25 @@
9 9
 #include "Log.h"
10 10
 #include "utils/strings.h"
11 11
 #include "system/Window.h"
12
-#include "system/Font.h"
13 12
 #include "system/FontImGui.h"
14 13
 #include "system/FontTRLE.h"
15
-
16
-#ifdef USING_SDL_FONT
17
-#include "system/FontSDL.h"
18
-#endif
14
+#include "system/FontTTF.h"
15
+#include "system/Font.h"
19 16
 
20 17
 bool Font::isInit = false;
21 18
 std::string Font::fontName;
22 19
 
23 20
 void Font::shutdown() {
24 21
     FontTRLE::shutdown();
25
-#ifdef USING_SDL_FONT
26
-    FontSDL::shutdown();
27
-#endif
22
+    FontTTF::shutdown();
28 23
 }
29 24
 
30 25
 int Font::initialize(std::string font) {
31 26
     fontName = font;
32 27
     if (stringEndsWith(fontName, ".pc")) {
33 28
         return FontTRLE::initialize(fontName);
34
-#ifdef USING_SDL_FONT
35 29
     } else if (stringEndsWith(fontName, ".ttf")) {
36
-        return FontSDL::initialize(fontName);
37
-#endif
30
+        return FontTTF::initialize(fontName);
38 31
     }
39 32
 
40 33
     if (font != "") {
@@ -48,10 +41,8 @@ int Font::initialize(std::string font) {
48 41
 unsigned int Font::widthText(float scale, std::string s) {
49 42
     if (stringEndsWith(fontName, ".pc")) {
50 43
         return FontTRLE::widthText(scale, s);
51
-#ifdef USING_SDL_FONT
52 44
     } else if (stringEndsWith(fontName, ".ttf")) {
53
-        return FontSDL::widthText(scale, s);
54
-#endif
45
+        return FontTTF::widthText(scale, s);
55 46
     } else {
56 47
         return FontImGui::widthText(scale, s);
57 48
     }
@@ -60,10 +51,8 @@ unsigned int Font::widthText(float scale, std::string s) {
60 51
 unsigned int Font::heightText(float scale, unsigned int maxWidth, std::string s) {
61 52
     if (stringEndsWith(fontName, ".pc")) {
62 53
         return FontTRLE::heightText(scale, maxWidth, s);
63
-#ifdef USING_SDL_FONT
64 54
     } else if (stringEndsWith(fontName, ".ttf")) {
65
-        return FontSDL::heightText(scale, maxWidth, s);
66
-#endif
55
+        return FontTTF::heightText(scale, maxWidth, s);
67 56
     } else {
68 57
         return FontImGui::heightText(scale, maxWidth, s);
69 58
     }
@@ -73,10 +62,8 @@ void Font::drawText(unsigned int x, unsigned int y, float scale,
73 62
                     const unsigned char color[4], std::string s) {
74 63
     if (stringEndsWith(fontName, ".pc")) {
75 64
         FontTRLE::drawText(x, y, scale, color, s);
76
-#ifdef USING_SDL_FONT
77 65
     } else if (stringEndsWith(fontName, ".ttf")) {
78
-        FontSDL::drawText(x, y, scale, color, s);
79
-#endif
66
+        FontTTF::drawText(x, y, scale, color, s);
80 67
     } else {
81 68
         FontImGui::drawText(x, y, scale, color, s);
82 69
     }
@@ -86,10 +73,8 @@ void Font::drawTextWrapped(unsigned int x, unsigned int y, float scale,
86 73
                            const unsigned char color[4], unsigned int maxWidth, std::string s) {
87 74
     if (stringEndsWith(fontName, ".pc")) {
88 75
         FontTRLE::drawTextWrapped(x, y, scale, color, maxWidth, s);
89
-#ifdef USING_SDL_FONT
90 76
     } else if (stringEndsWith(fontName, ".ttf")) {
91
-        FontSDL::drawTextWrapped(x, y, scale, color, maxWidth, s);
92
-#endif
77
+        FontTTF::drawTextWrapped(x, y, scale, color, maxWidth, s);
93 78
     } else {
94 79
         FontImGui::drawTextWrapped(x, y, scale, color, maxWidth, s);
95 80
     }

+ 0
- 222
src/system/FontSDL.cpp View File

@@ -1,222 +0,0 @@
1
-/*!
2
- * \file src/system/FontSDL.cpp
3
- * \brief SDL Font implementation
4
- *
5
- * \author xythobuz
6
- */
7
-
8
-#include <iostream>
9
-
10
-#include "global.h"
11
-#include "TextureManager.h"
12
-#include "system/Shader.h"
13
-#include "system/FontSDL.h"
14
-
15
-bool FontSDL::mFontInit = false;
16
-TTF_Font* FontSDL::mFont = nullptr;
17
-unsigned int FontSDL::mFontTexture = -1;
18
-ShaderBuffer FontSDL::vertexBuffer;
19
-ShaderBuffer FontSDL::uvBuffer;
20
-
21
-void FontSDL::shutdown() {
22
-    if (mFont != nullptr)
23
-        TTF_CloseFont(mFont);
24
-    mFont = nullptr;
25
-
26
-    if (mFontInit) {
27
-        TTF_Quit();
28
-        mFontInit = false;
29
-    }
30
-}
31
-
32
-int FontSDL::initialize(std::string font) {
33
-    if (!mFontInit) {
34
-        if (TTF_Init() != 0) {
35
-            std::cout << "Could not initialize SDL-TTF!" << std::endl;
36
-            return -1;
37
-        }
38
-
39
-        // Reserve slot
40
-        mFontTexture = TextureManager::loadBufferSlot(nullptr, 256, 256,
41
-                                                      ColorMode::RGBA, 32,
42
-                                                      TextureStorage::SYSTEM);
43
-
44
-        mFontInit = true;
45
-    }
46
-
47
-    if (mFont != nullptr)
48
-        TTF_CloseFont(mFont);
49
-
50
-    mFont = TTF_OpenFont(font.c_str(), 24);
51
-    if (mFont == nullptr) {
52
-        std::cout << "TTF_OpenFont Error: " << TTF_GetError() << std::endl;
53
-        return -2;
54
-    }
55
-
56
-    return 0;
57
-}
58
-
59
-unsigned int FontSDL::widthText(float scale, std::string s) {
60
-    assert(mFontInit == true);
61
-    assert(mFont != nullptr);
62
-
63
-    int w;
64
-    if (TTF_SizeUTF8(mFont, s.c_str(), &w, nullptr) != 0) {
65
-        std::cout << "TTF_SizeUTF8 Error: " << TTF_GetError() << std::endl;
66
-        return s.length() * 15 * scale;
67
-    }
68
-    return w * scale;
69
-}
70
-
71
-void FontSDL::drawText(unsigned int x, unsigned int y, float scale,
72
-                       const unsigned char color[4], std::string s) {
73
-    assert(mFontInit == true);
74
-    assert(mFont != nullptr);
75
-    assert(s.length() > 0);
76
-
77
-    SDL_Color col;
78
-    col.r = color[0];
79
-    col.g = color[1];
80
-    col.b = color[2];
81
-    col.a = color[3];
82
-
83
-    SDL_Surface* surface = TTF_RenderUTF8_Blended(mFont, s.c_str(), col);
84
-    if (surface == nullptr) {
85
-        std::cout << "TTF_RenderUTF8_Blended Error: " << TTF_GetError() << std::endl;
86
-        return;
87
-    }
88
-
89
-    int w = (int)((float)surface->w * scale);
90
-    int h = (int)((float)surface->h * scale);
91
-
92
-    ColorMode textureFormat;
93
-    unsigned int bpp = 0;
94
-    if (surface->format->BytesPerPixel == 4) {
95
-        if (surface->format->Rmask == 0x000000FF)
96
-            textureFormat = ColorMode::RGBA;
97
-        else
98
-            textureFormat = ColorMode::BGRA;
99
-        bpp = 32;
100
-    } else {
101
-        if (surface->format->Rmask == 0x000000FF)
102
-            textureFormat = ColorMode::RGB;
103
-        else
104
-            textureFormat = ColorMode::BGR;
105
-        bpp = 24;
106
-    }
107
-
108
-    TextureManager::loadBufferSlot(static_cast<unsigned char*>(surface->pixels),
109
-                                   surface->w, surface->h, textureFormat, bpp,
110
-                                   TextureStorage::SYSTEM, mFontTexture);
111
-    SDL_FreeSurface(surface);
112
-
113
-    std::vector<glm::vec2> vertices;
114
-    std::vector<glm::vec2> uvs;
115
-
116
-    vertices.push_back(glm::vec2(x, y + h));
117
-    vertices.push_back(glm::vec2(x, y));
118
-    vertices.push_back(glm::vec2(x + w, y + h));
119
-
120
-    vertices.push_back(glm::vec2(x + w, y));
121
-    vertices.push_back(glm::vec2(x + w, y + h));
122
-    vertices.push_back(glm::vec2(x, y));
123
-
124
-    uvs.push_back(glm::vec2(0.0f, 1.0f));
125
-    uvs.push_back(glm::vec2(0.0f, 0.0f));
126
-    uvs.push_back(glm::vec2(1.0f, 1.0f));
127
-
128
-    uvs.push_back(glm::vec2(1.0f, 0.0f));
129
-    uvs.push_back(glm::vec2(1.0f, 1.0f));
130
-    uvs.push_back(glm::vec2(0.0f, 0.0f));
131
-
132
-    vertexBuffer.bufferData(vertices);
133
-    uvBuffer.bufferData(uvs);
134
-    Shader::drawGL(vertexBuffer, uvBuffer, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f),
135
-                   mFontTexture, TextureStorage::SYSTEM);
136
-}
137
-
138
-unsigned int FontSDL::heightText(float scale, unsigned int maxWidth, std::string s) {
139
-    assert(mFontInit == true);
140
-    assert(mFont != nullptr);
141
-    assert(s.length() > 0);
142
-    assert(maxWidth > 0);
143
-
144
-    SDL_Color col;
145
-    SDL_Surface* surface = TTF_RenderUTF8_Blended_Wrapped(mFont, s.c_str(), col, maxWidth);
146
-    if (surface == nullptr) {
147
-        std::cout << "TTF_RenderUTF8_Blended_Wrapped Error: " << TTF_GetError() << std::endl;
148
-        return 0;
149
-    }
150
-    int h = surface->h * scale;
151
-    SDL_FreeSurface(surface);
152
-    return h;
153
-}
154
-
155
-void FontSDL::drawTextWrapped(unsigned int x, unsigned int y, float scale,
156
-                              const unsigned char color[4], unsigned int maxWidth, std::string s) {
157
-    assert(mFontInit == true);
158
-    assert(mFont != nullptr);
159
-    assert(s.length() > 0);
160
-    assert(maxWidth > 0);
161
-
162
-    SDL_Color col;
163
-    col.r = color[0];
164
-    col.g = color[1];
165
-    col.b = color[2];
166
-    col.a = color[3];
167
-
168
-    SDL_Surface* surface = TTF_RenderUTF8_Blended_Wrapped(mFont, s.c_str(), col, maxWidth);
169
-    if (surface == nullptr) {
170
-        std::cout << "TTF_RenderUTF8_Blended_Wrapped Error: " << TTF_GetError() << std::endl;
171
-        return;
172
-    }
173
-
174
-    int w = (int)((float)surface->w * scale);
175
-    int h = (int)((float)surface->h * scale);
176
-
177
-    ColorMode textureFormat;
178
-    unsigned int bpp = 0;
179
-    if (surface->format->BytesPerPixel == 4) {
180
-        if (surface->format->Rmask == 0x000000FF)
181
-            textureFormat = ColorMode::RGBA;
182
-        else
183
-            textureFormat = ColorMode::BGRA;
184
-        bpp = 32;
185
-    } else {
186
-        if (surface->format->Rmask == 0x000000FF)
187
-            textureFormat = ColorMode::RGB;
188
-        else
189
-            textureFormat = ColorMode::BGR;
190
-        bpp = 24;
191
-    }
192
-
193
-    TextureManager::loadBufferSlot(static_cast<unsigned char*>(surface->pixels),
194
-                                   surface->w, surface->h, textureFormat, bpp,
195
-                                   TextureStorage::SYSTEM, mFontTexture);
196
-    SDL_FreeSurface(surface);
197
-
198
-    std::vector<glm::vec2> vertices;
199
-    std::vector<glm::vec2> uvs;
200
-
201
-    vertices.push_back(glm::vec2(x, y + h));
202
-    vertices.push_back(glm::vec2(x, y));
203
-    vertices.push_back(glm::vec2(x + w, y + h));
204
-
205
-    vertices.push_back(glm::vec2(x + w, y));
206
-    vertices.push_back(glm::vec2(x + w, y + h));
207
-    vertices.push_back(glm::vec2(x, y));
208
-
209
-    uvs.push_back(glm::vec2(0.0f, 1.0f));
210
-    uvs.push_back(glm::vec2(0.0f, 0.0f));
211
-    uvs.push_back(glm::vec2(1.0f, 1.0f));
212
-
213
-    uvs.push_back(glm::vec2(1.0f, 0.0f));
214
-    uvs.push_back(glm::vec2(1.0f, 1.0f));
215
-    uvs.push_back(glm::vec2(0.0f, 0.0f));
216
-
217
-    vertexBuffer.bufferData(vertices);
218
-    uvBuffer.bufferData(uvs);
219
-    Shader::drawGL(vertexBuffer, uvBuffer, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f),
220
-                   mFontTexture, TextureStorage::SYSTEM);
221
-}
222
-

+ 1
- 1
src/system/FontTRLE.cpp View File

@@ -1,6 +1,6 @@
1 1
 /*!
2 2
  * \file src/system/FontTRLE.cpp
3
- * \brief SDL Font implementation
3
+ * \brief Tomb Raider Level Editor Font loader
4 4
  *
5 5
  * \author xythobuz
6 6
  */

+ 327
- 0
src/system/FontTTF.cpp View File

@@ -0,0 +1,327 @@
1
+/*!
2
+ * \file src/system/FontTTF.cpp
3
+ * \brief TrueType Font implementation
4
+ *
5
+ * \author xythobuz
6
+ */
7
+
8
+#include <fstream>
9
+
10
+#include "global.h"
11
+#include "Log.h"
12
+#include "TextureManager.h"
13
+#include "utils/pixel.h"
14
+#include "system/FontTTF.h"
15
+
16
+#define MAP_WIDTH 512
17
+#define MAP_HEIGHT 512
18
+#define FONT_SIZE 30
19
+#define MAP_NUM_CHARS 50
20
+
21
+FontMapTTF::FontMapTTF() : begin(-1), texture(-1), charInfo(nullptr) { }
22
+
23
+FontMapTTF::FontMapTTF(FontMapTTF&& other) {
24
+    begin = other.begin;
25
+    texture = other.texture;
26
+    other.begin = other.texture = -1;
27
+    charInfo = other.charInfo;
28
+    other.charInfo = nullptr;
29
+}
30
+
31
+FontMapTTF::~FontMapTTF() {
32
+    if (charInfo != nullptr) {
33
+        delete [] charInfo;
34
+    }
35
+
36
+    if (texture > -1) {
37
+        //! \todo _Free_ the TextureManager buffer slot
38
+    }
39
+}
40
+
41
+int FontMapTTF::initialize(unsigned char* fontData, int firstChar) {
42
+    stbtt_pack_context context;
43
+    unsigned char* pixels = new unsigned char[MAP_WIDTH * MAP_HEIGHT];
44
+    if (!stbtt_PackBegin(&context, pixels, MAP_WIDTH, MAP_HEIGHT, 0, 1, nullptr)) {
45
+        delete [] pixels;
46
+        getLog() << "Error initializing font map in stbtt_PackBegin!" << Log::endl;
47
+        return -1;
48
+    }
49
+
50
+    stbtt_PackSetOversampling(&context, 2, 2);
51
+
52
+    if (charInfo != nullptr)
53
+        delete [] charInfo;
54
+
55
+    charInfo = new stbtt_packedchar[MAP_NUM_CHARS];
56
+    if (!stbtt_PackFontRange(&context, fontData, 0, FONT_SIZE, firstChar, MAP_NUM_CHARS, charInfo)) {
57
+        stbtt_PackEnd(&context);
58
+        delete [] pixels;
59
+        delete [] charInfo;
60
+        charInfo = nullptr;
61
+        getLog() << "Error packing font map!" << Log::endl;
62
+        return -2;
63
+    }
64
+
65
+    stbtt_PackEnd(&context);
66
+    unsigned char* rgb = grayscale2rgba(pixels, MAP_WIDTH, MAP_HEIGHT);
67
+    delete [] pixels;
68
+
69
+    texture = TextureManager::loadBufferSlot(rgb, MAP_WIDTH, MAP_HEIGHT, ColorMode::RGBA,
70
+                                             32, TextureStorage::SYSTEM, texture);
71
+    delete [] rgb;
72
+    if (texture < 0) {
73
+        delete [] charInfo;
74
+        charInfo = nullptr;
75
+        getLog() << "Error loading new font map texture!" << Log::endl;
76
+        return -3;
77
+    }
78
+
79
+    begin = firstChar;
80
+    return 0;
81
+}
82
+
83
+bool FontMapTTF::contains(int c) {
84
+    assert(begin >= 0);
85
+    return (begin >= 0) && (c >= begin) && (c < (begin + MAP_NUM_CHARS));
86
+}
87
+
88
+void FontMapTTF::getQuad(int c, float* xpos, float* ypos, stbtt_aligned_quad *quad) {
89
+    assert(contains(c));
90
+    stbtt_GetPackedQuad(charInfo, MAP_WIDTH, MAP_HEIGHT, c - begin, xpos, ypos, quad, 0);
91
+}
92
+
93
+// ----------------------------------------------------------------------------
94
+
95
+unsigned char* FontTTF::fontData = nullptr;
96
+std::vector<FontMapTTF> FontTTF::maps;
97
+ShaderBuffer FontTTF::vertexBuffer;
98
+ShaderBuffer FontTTF::uvBuffer;
99
+
100
+int FontTTF::initialize(std::string f) {
101
+    assert(f.length() > 0);
102
+
103
+    std::ifstream file(f, std::ios::binary);
104
+    if (!file) {
105
+        getLog() << "Couldn't open file \"" << f << "\"!" << Log::endl;
106
+        return -1;
107
+    }
108
+
109
+    file.seekg(0, std::ios::end);
110
+    auto size = file.tellg();
111
+    assert(size > 0);
112
+    file.seekg(0);
113
+
114
+    maps.clear();
115
+    if (fontData != nullptr) {
116
+        delete [] fontData;
117
+        fontData = nullptr;
118
+    }
119
+
120
+    fontData = new unsigned char[size];
121
+    if (!file.read(reinterpret_cast<char*>(fontData), size)) {
122
+        getLog() << "Couldn't read data in \"" << f << "\"" << Log::endl;
123
+        delete [] fontData;
124
+        fontData = nullptr;
125
+        return -2;
126
+    }
127
+
128
+    maps.emplace_back();
129
+    if (maps.at(0).initialize(fontData, ' ') < 0) {
130
+        delete [] fontData;
131
+        fontData = nullptr;
132
+        return -3;
133
+    }
134
+
135
+    return 0;
136
+}
137
+
138
+void FontTTF::shutdown() {
139
+    if (fontData != nullptr) {
140
+        delete [] fontData;
141
+        fontData = nullptr;
142
+    }
143
+
144
+    maps.clear();
145
+}
146
+
147
+unsigned int FontTTF::widthText(float scale, std::string s) {
148
+    float x = 0.0f, y = 0.0f;
149
+    stbtt_aligned_quad q;
150
+    for (int i = 0; i < s.length(); i++) {
151
+        if ((s[i] < 0x20) || (s[i] == 0x7F)) {
152
+            continue;
153
+        }
154
+
155
+        getQuad(s[i], &x, &y, &q);
156
+    }
157
+    return x * scale;
158
+}
159
+
160
+void FontTTF::drawText(unsigned int x, unsigned int y, float scale,
161
+                       const unsigned char color[4], std::string s) {
162
+    glm::vec4 col(color[0] / 256.0f, color[1] / 256.0f, color[2] / 256.0f, color[3] / 256.0f);
163
+    std::vector<glm::vec2> vertices;
164
+    std::vector<glm::vec2> uvs;
165
+    int texture = -1;
166
+    float xpos = x, ypos = y + (FONT_SIZE * scale);
167
+    for (int i = 0; i < s.length(); i++) {
168
+        if ((s[i] < 0x20) || (s[i] == 0x7F)) {
169
+            continue;
170
+        }
171
+
172
+        stbtt_aligned_quad quad;
173
+        int tex = getQuad(s[i], &xpos, &ypos, &quad);
174
+
175
+        if ((texture != tex) && (texture != -1)) {
176
+            vertexBuffer.bufferData(vertices);
177
+            uvBuffer.bufferData(uvs);
178
+            Shader::drawGL(vertexBuffer, uvBuffer, col, texture);
179
+            vertices.clear();
180
+            uvs.clear();
181
+        }
182
+
183
+        texture = tex;
184
+
185
+        glm::vec2 v1(quad.x0, quad.y0);
186
+        glm::vec2 v2(quad.x0, quad.y0 + ((quad.y1 - quad.y0) * scale));
187
+        glm::vec2 v3(quad.x0 + ((quad.x1 - quad.x0) * scale), quad.y0 + ((quad.y1 - quad.y0) * scale));
188
+        glm::vec2 v4(quad.x0 + ((quad.x1 - quad.x0) * scale), quad.y0);
189
+        glm::vec2 u1(quad.s0, quad.t0);
190
+        glm::vec2 u2(quad.s0, quad.t1);
191
+        glm::vec2 u3(quad.s1, quad.t1);
192
+        glm::vec2 u4(quad.s1, quad.t0);
193
+
194
+        vertices.push_back(v1);
195
+        vertices.push_back(v2);
196
+        vertices.push_back(v3);
197
+        vertices.push_back(v4);
198
+        vertices.push_back(v1);
199
+        vertices.push_back(v3);
200
+
201
+        uvs.push_back(u1);
202
+        uvs.push_back(u2);
203
+        uvs.push_back(u3);
204
+        uvs.push_back(u4);
205
+        uvs.push_back(u1);
206
+        uvs.push_back(u3);
207
+    }
208
+
209
+    vertexBuffer.bufferData(vertices);
210
+    uvBuffer.bufferData(uvs);
211
+    Shader::drawGL(vertexBuffer, uvBuffer, col, texture);
212
+}
213
+
214
+unsigned int FontTTF::heightText(float scale, unsigned int maxWidth, std::string s) {
215
+    float x = 0.0f, y = FONT_SIZE;
216
+    stbtt_aligned_quad q;
217
+    for (int i = 0; i < s.length(); i++) {
218
+        if ((s[i] < 0x20) || (s[i] == 0x7F)) {
219
+            continue;
220
+        }
221
+
222
+        getQuad(s[i], &x, &y, &q);
223
+        if (x > maxWidth) {
224
+            x = 0.0f;
225
+            y += FONT_SIZE;
226
+        }
227
+    }
228
+    return y * scale;
229
+}
230
+
231
+void FontTTF::drawTextWrapped(unsigned int x, unsigned int y, float scale,
232
+                              const unsigned char color[4], unsigned int maxWidth, std::string s) {
233
+    glm::vec4 col(color[0] / 256.0f, color[1] / 256.0f, color[2] / 256.0f, color[3] / 256.0f);
234
+    std::vector<glm::vec2> vertices;
235
+    std::vector<glm::vec2> uvs;
236
+    int texture = -1;
237
+    float xpos = x, ypos = y + (FONT_SIZE * scale);
238
+    for (int i = 0; i < s.length(); i++) {
239
+        if ((s[i] < 0x20) || (s[i] == 0x7F)) {
240
+            continue;
241
+        }
242
+
243
+        stbtt_aligned_quad quad;
244
+        int tex = getQuad(s[i], &xpos, &ypos, &quad);
245
+
246
+        if (xpos > (x + maxWidth)) {
247
+            xpos = x;
248
+            ypos += FONT_SIZE * scale;
249
+            if (s[i] != ' ')
250
+                i--;
251
+            continue;
252
+        }
253
+
254
+        if ((texture != tex) && (texture != -1)) {
255
+            vertexBuffer.bufferData(vertices);
256
+            uvBuffer.bufferData(uvs);
257
+            Shader::drawGL(vertexBuffer, uvBuffer, col, texture);
258
+            vertices.clear();
259
+            uvs.clear();
260
+        }
261
+
262
+        texture = tex;
263
+
264
+        glm::vec2 v1(quad.x0, quad.y0);
265
+        glm::vec2 v2(quad.x0, quad.y0 + ((quad.y1 - quad.y0) * scale));
266
+        glm::vec2 v3(quad.x0 + ((quad.x1 - quad.x0) * scale), quad.y0 + ((quad.y1 - quad.y0) * scale));
267
+        glm::vec2 v4(quad.x0 + ((quad.x1 - quad.x0) * scale), quad.y0);
268
+        glm::vec2 u1(quad.s0, quad.t0);
269
+        glm::vec2 u2(quad.s0, quad.t1);
270
+        glm::vec2 u3(quad.s1, quad.t1);
271
+        glm::vec2 u4(quad.s1, quad.t0);
272
+
273
+        vertices.push_back(v1);
274
+        vertices.push_back(v2);
275
+        vertices.push_back(v3);
276
+        vertices.push_back(v4);
277
+        vertices.push_back(v1);
278
+        vertices.push_back(v3);
279
+
280
+        uvs.push_back(u1);
281
+        uvs.push_back(u2);
282
+        uvs.push_back(u3);
283
+        uvs.push_back(u4);
284
+        uvs.push_back(u1);
285
+        uvs.push_back(u3);
286
+    }
287
+
288
+    vertexBuffer.bufferData(vertices);
289
+    uvBuffer.bufferData(uvs);
290
+    Shader::drawGL(vertexBuffer, uvBuffer, col, texture);
291
+}
292
+
293
+int FontTTF::charIsMapped(int c) {
294
+    for (int i = 0; i < maps.size(); i++) {
295
+        if (maps.at(i).contains(c)) {
296
+            return i;
297
+        }
298
+    }
299
+
300
+    int begin = c;
301
+    if (c >= (MAP_NUM_CHARS / 2))
302
+        begin -= (MAP_NUM_CHARS / 2);
303
+
304
+    getLog() << "Unmapped character " << c << ", new map from " << begin << " to "
305
+             << begin + MAP_NUM_CHARS - 1 << "..." << Log::endl;
306
+
307
+    int p = maps.size();
308
+    maps.emplace_back();
309
+    if (maps.at(p).initialize(fontData, begin) < 0) {
310
+        return -1;
311
+    }
312
+
313
+    return p;
314
+}
315
+
316
+int FontTTF::getQuad(int c, float* xpos, float* ypos, stbtt_aligned_quad *quad) {
317
+    if (c < 0) {
318
+        //! \todo This has nothing to do with proper UTF8 support...
319
+        c += 128;
320
+    }
321
+
322
+    int map = charIsMapped(c);
323
+    assert(map >= 0);
324
+    maps.at(map).getQuad(c, xpos, ypos, quad);
325
+    return maps.at(map).getTexture();
326
+}
327
+

+ 15
- 0
src/utils/pixel.cpp View File

@@ -86,6 +86,21 @@ unsigned char* argb16to32(unsigned char* image, unsigned int w, unsigned int h)
86 86
     return img;
87 87
 }
88 88
 
89
+unsigned char* grayscale2rgba(unsigned char* image, unsigned int w, unsigned int h) {
90
+    assert(image != nullptr);
91
+    assert(w > 0);
92
+    assert(h > 0);
93
+
94
+    unsigned char* img = new unsigned char[w * h * 4];
95
+    for (unsigned int i = 0; i < (w * h); i++) {
96
+        img[i * 4] = image[i];
97
+        img[(i * 4) + 1] = image[i];
98
+        img[(i * 4) + 2] = image[i];
99
+        img[(i * 4) + 3] = (image[i] == 0) ? 0 : 255;
100
+    }
101
+    return img;
102
+}
103
+
89 104
 #define NEXT_POWER(x) do {        \
90 105
     unsigned int i;               \
91 106
     for (i = 1; i < (x); i *= 2); \

Loading…
Cancel
Save