Codebase list blockattack / fedd855
New upstream version 2.2.0 Markus Koschany 5 years ago
87 changed file(s) with 3542 addition(s) and 4942 deletion(s). Raw diff Collapse all Expand all
44 Makefile
55 CMakeCache.txt
66 CMakeFiles
7 CPack*
66 winicon.res
77 nbproject
88 .*
9 -.travis.yml
10 -.gitignore
9 !.travis.yml
10 !.gitignore
1111 !.editorconfig
1212 !.dockerignore
1313 *.patch
22 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${blockattack_SOURCE_DIR}/source/misc/cmake")
33 set(BIN_DIR ${blockattack_SOURCE_DIR}/Game)
44
5 SET(CPACK_PACKAGE_VERSION "2.1.2")
5 SET(CPACK_PACKAGE_VERSION "2.2.0")
66 SET(CPACK_PACKAGE_VERSION_MAJOR "2")
7 SET(CPACK_PACKAGE_VERSION_MINOR "1")
8 SET(CPACK_PACKAGE_VERSION_PATCH "2")
7 SET(CPACK_PACKAGE_VERSION_MINOR "2")
8 SET(CPACK_PACKAGE_VERSION_PATCH "0")
99 SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Block Attack - Rise of the Blocks ${CPACK_PACKAGE_VERSION}")
1010 SET(CPACK_PACKAGE_VENDOR "Poul Sander")
1111 INCLUDE(CPack)
3434 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=i686")
3535 endif()
3636
37 if (NOT WIN32)
37 if (NOT WIN32 AND NOT STANDALONE)
3838 #The path to the data dir must be compiled into the binary
3939 add_definitions(-DSHAREDIR=\"${CMAKE_INSTALL_PREFIX}/${INSTALL_DATA_DIR}\")
4040 add_definitions(-DLOCALEDIR=\"${CMAKE_INSTALL_PREFIX}/${INSTALL_LOCALE_DIR}\")
4444 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -std=c++11")
4545 set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_DEBUG} -g -DDEBUG")
4646 set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE} -O2")
47
48 #Newer versions of gcc fails for Cereal.
49 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-implicit-fallthrough")
4750
4851 #Setup SDL2
4952 find_package(SDL2 REQUIRED)
0 ../../../source/code/AUTHORS
529529 "width" : 50,
530530 "number_of_frames" : 1,
531531 "frame_time" : 1
532 },
533 "help_controller" : {
534 "texture" : "help_controller",
535 "topx" : 0,
536 "topy" : 0,
537 "height" : 310,
538 "width" : 479
532539 }
533540
534541 }
0 # blockattack-game [![Build Status](https://travis-ci.org/blockattack/blockattack-game.svg?branch=master)](https://travis-ci.org/blockattack/blockattack-game) [![Coverity Status](https://scan.coverity.com/projects/8278/badge.svg)](https://scan.coverity.com/projects/8278) [![license](https://img.shields.io/github/license/blockattack/blockattack-game.svg)]()
0 # blockattack-game [![Build Status](https://travis-ci.org/blockattack/blockattack-game.svg?branch=master)](https://travis-ci.org/blockattack/blockattack-game) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/0dfba60f2ce9484a828bd7c112f50089)](https://www.codacy.com/app/github_43/blockattack-game?utm_source=github.com&utm_medium=referral&utm_content=blockattack/blockattack-game&utm_campaign=Badge_Grade) [![Coverity Status](https://scan.coverity.com/projects/8278/badge.svg)](https://scan.coverity.com/projects/8278) [![license](https://img.shields.io/github/license/blockattack/blockattack-game.svg)]()
11 Block Attack - Rise of the Blocks - the game<br/>
22 A Tetris Attack Clone under the GPL.
33
7171 * Game - The output is placed here
7272 * man - The manual file and the script to generate it. May be moved to source/misc at some point
7373 * source/code/ - The source code
74 * source/code/Libs - External libs that are compiled into the project because they are either header only (Cereal) or not designed for use as a shared library (NFont).
74 * source/code/Libs - External libs that are compiled into the project because they are either header only (Cereal) or not designed for use as a shared library.
7575 * source/code/sago - Source code. Not designed to be specific to Block Attack - Rise of the Blocks
7676 * source/assets - Source for the assets if relevant. For instance svg source for the graphics.
7777 * source/misc - Misc stuff. Code related tool that are used for development but not part of the final product.
+0
-39
ReleaseNotes-2.1.1.txt less more
0 This is Block Attack - Rise of the Blocks - version 2.1.1
1
2 This has the first gameplay change in a long time. In the previous version the rise would stop
3 while clearing. It could stop for several seconds. This is no longer the case. The time is now
4 bound and will lower as the game progresses.
5
6 The update of the model has also been changed. This should make it more smooth in some of the
7 high speed Stage Clear levels.
8
9 Changes since 2.0.1:
10 * There is now an upper limit on how long the rise will stop
11 * The internal updated of the game has been updated from 20 times a second to 100 times a second
12 * Menu fonts have been changed
13 * Window is now resizeable by default
14 * jsoncpp removed as a dependency
15 * Other code cleanup
16 * Docker files are now provided to make compiling even easier
17 * Translation strings changed and are now more
18 * Updated libraries
19
20 About the resize of the window:
21
22 The normal resize will simply resize the whole screen. This unfortunately makes the fonts hard to read.
23 The size of the screen is not saved!
24 You can use the command line argument "--no-auto-scale" to not scale the whole image. Screen size will
25 also be saved in this mode and remembered for the next startup.
26
27 Known issues:
28 * Windows 10 with HighDPI: Fonts becomes unreadable. https://github.com/blockattack/blockattack-game/issues/5
29 * The translation does not work with the shortcuts created by the Windows installer due to a wrong startup path.
30 I have not been able to figure out why
31
32
33 Thank you
34 Thanks to the people that have provided patches or feedback for this release: Paul Wise, mstraube and scootergrisen
35 Especially mstraube that discovered a fatal problem just hours after the release of 2.1.0.
36
37
38 Feedback can be given on http://www.blockattack.net or https://github.com/blockattack/blockattack-game
+0
-4
ReleaseNotes-2.1.2.txt less more
0 This is Block Attack - Rise of the Blocks - version 2.1.2
1
2 This version only fixes one single bug. The Windows version would not save correctly if "My Games" did not already exist in the Documents folder.
3 No changes to anything else
0 This is Block Attack - Rise of the Blocks - version 2.2.0
1
2 The primary change in this version is the font handling but I have also added a few help pages.
3
4 While an updated font handling may at first glance not seem so interesting the effect is actually quite bug. Most importantly the scaling is now a lot better. This is important as computer screens has gotten smaller and smaller in the past years. Another change is that the game now runs out of the box on Windows machines with high resolution displays.
5
6 Changes since 2.1.2:
7 * New font system
8 * Better scaling
9 * Works out of the box on Windows with high resolution displays
10 * New help menu with rule explanations
11
12 Known issues:
13 * Some string like "winner", "loser" and "draw" are not translatable.
14 * Keyboard key names are not translatable either
15 * A few screens like the "name" screen does not have gamepad support
16 * Only gamepads connected on startup can be used
17
18 Feedback can be given on https://blockattack.net or https://github.com/blockattack/blockattack-game
0 .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4.
1 .TH BLOCKATTACK "6" "July 2017" "blockattack 2.1.2" "Games"
0 .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6.
1 .TH BLOCKATTACK "6" "May 2018" "blockattack 2.2.0" "Games"
22 .SH NAME
33 blockattack \- a puzzle game inspired by Tetris Attack
44 .SH SYNOPSIS
55 .B blockattack
66 [\fI\,OPTION\/\fR]...
77 .SH DESCRIPTION
8 Block Attack \- Rise of the blocks 2.1.2
8 Block Attack \- Rise of the blocks 2.2.0
99 .PP
1010 Block Attack \- Rise of the Blocks is a puzzle/blockfall game inspired by Tetris Attack for the SNES.
1111 .PP
2626 .TP
2727 \fB\-\-priority\fR
2828 Causes the game to not sleep between frames.
29 .TP
30 \fB\-\-software\-renderer\fR
31 Asks SDL2 to use software renderer
2932 .TP
3033 \fB\-\-verbose\-basic\fR
3134 Enables basic verbose messages
5760 .TP
5861 blockattack \-\-nosound
5962 Start the game without sound. Can be used if sound problems prevents the game from starting
63 .TP
64 blockattack \-\-puzzle\-level\-file puzzle.levels \-\-puzzle\-single\-level 3
65 Start the game with the default puzzles in level 3
66 .TP
67 blockattack \-\-bind\-text\-domain /dev/null
68 Disables translations
6069 .SH "REPORTING BUGS"
6170 Report bugs to the issue tracker here: <https://github.com/blockattack/blockattack\-game/issues>
6271 .SH COPYRIGHT
00 #!/bin/bash
11 set -e
2 zip -9rj Game/blockattack.data source/AUTH
2 zip -9rjX Game/blockattack.data source/AUTH
33 cd Game/data
4 zip -9r ../blockattack.data * -x \*svn*
4 zip -9rX ../blockattack.data * -x \*svn*
55 cd ../../man
66 gzip -9 -c blockattack.man > blockattack.6.gz
77 cd ../source/misc/translation/
5959 garbage_tr.png qubodup
6060 green.png qubodup
6161 grey.png qubodup
62 help_controller.png nicefrog (https://opengameart.org/content/generic-gamepad-template)
6263 i_check_box_area.png Poul Sander
6364 icon.png Poul Sander
6465 i_draw.png Poul Sander
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!-- Created with Inkscape (http://www.inkscape.org/) -->
2
3 <svg
4 xmlns:dc="http://purl.org/dc/elements/1.1/"
5 xmlns:cc="http://creativecommons.org/ns#"
6 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
7 xmlns:svg="http://www.w3.org/2000/svg"
8 xmlns="http://www.w3.org/2000/svg"
9 xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
10 xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
11 width="546.73724"
12 height="367.63187"
13 id="svg2"
14 version="1.1"
15 inkscape:version="0.48.4 r9939"
16 sodipodi:docname="controller.svg">
17 <defs
18 id="defs4" />
19 <sodipodi:namedview
20 id="base"
21 pagecolor="#ffffff"
22 bordercolor="#666666"
23 borderopacity="1.0"
24 inkscape:pageopacity="0.0"
25 inkscape:pageshadow="2"
26 inkscape:zoom="1.28"
27 inkscape:cx="571.3369"
28 inkscape:cy="104.84448"
29 inkscape:document-units="px"
30 inkscape:current-layer="g3802"
31 showgrid="false"
32 inkscape:window-width="1920"
33 inkscape:window-height="975"
34 inkscape:window-x="-8"
35 inkscape:window-y="-8"
36 inkscape:window-maximized="1"
37 fit-margin-top="20"
38 fit-margin-left="20"
39 fit-margin-right="20"
40 fit-margin-bottom="20" />
41 <metadata
42 id="metadata7">
43 <rdf:RDF>
44 <cc:Work
45 rdf:about="">
46 <dc:format>image/svg+xml</dc:format>
47 <dc:type
48 rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
49 <dc:title />
50 </cc:Work>
51 </rdf:RDF>
52 </metadata>
53 <g
54 inkscape:label="Layer 1"
55 inkscape:groupmode="layer"
56 id="layer1"
57 style="display:inline"
58 transform="translate(-154.99045,-304.71875)" />
59 <g
60 inkscape:groupmode="layer"
61 id="layer2"
62 inkscape:label="Layer"
63 style="display:inline"
64 transform="translate(-154.99045,-304.71875)">
65 <g
66 id="g3793"
67 transform="translate(58.719552,141.85595)"
68 style="display:inline">
69 <g
70 id="g3788">
71 <path
72 style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
73 d="m 263.57143,419.50504 c -28.03572,56.42858 -80.49928,92.08847 -100.73276,90.44683 -20.23348,-1.64165 -48.23687,-25.58484 -45.92365,-67.64816 4.55975,-82.91401 73.58785,-221.40908 83.79926,-229.94153 10.21141,-8.53244 18.78619,-14.07754 71.22999,-14.52433 41.022,-0.34948 55.19859,-2.26138 52.34145,25.95291"
74 id="path2985"
75 inkscape:connector-curvature="0"
76 sodipodi:nodetypes="csszsc" />
77 <path
78 style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
79 d="m 473.50901,365.07965 c 0,0 0.73545,8.10393 -6.7986,8.0934 -7.53405,-0.0105 -70.34884,0.0366 -77.88289,0.0261 -7.53405,-0.0105 -5.72717,-8.24589 -5.72717,-8.24589"
80 id="path3838"
81 inkscape:connector-curvature="0"
82 transform="translate(-58.719552,-141.85595)"
83 sodipodi:nodetypes="czzc" />
84 </g>
85 <path
86 transform="matrix(0.87614083,0,0,0.87046633,35.919161,50.685326)"
87 d="m 344.28571,391.29074 c 0,30.17842 -24.30454,54.64286 -54.28571,54.64286 -29.98117,0 -54.28571,-24.46444 -54.28571,-54.64286 0,-30.17842 24.30454,-54.64286 54.28571,-54.64286 29.98117,0 54.28571,24.46444 54.28571,54.64286 z"
88 sodipodi:ry="54.642857"
89 sodipodi:rx="54.285713"
90 sodipodi:cy="391.29074"
91 sodipodi:cx="290"
92 id="path2994"
93 style="fill:#ffffff;stroke:#000000"
94 sodipodi:type="arc" />
95 <path
96 transform="matrix(1.1409547,0,0,1.1717896,-48.580202,-61.679814)"
97 d="m 331.42858,309.14789 c 0,36.49024 -30.38067,66.07142 -67.85714,66.07142 -37.47646,0 -67.85714,-29.58118 -67.85714,-66.07142 0,-36.49024 30.38068,-66.07143 67.85714,-66.07143 37.47647,0 67.85714,29.58119 67.85714,66.07143 z"
98 sodipodi:ry="66.071426"
99 sodipodi:rx="67.85714"
100 sodipodi:cy="309.14789"
101 sodipodi:cx="263.57144"
102 id="path3766"
103 style="fill:#ffffff;stroke:#000000"
104 sodipodi:type="arc" />
105 <path
106 inkscape:connector-curvature="0"
107 id="path3776"
108 d="m 312.76848,350.62183 c -3.15673,-1.86247 -3.15673,-1.86247 -3.15673,-1.86247 l 0,0"
109 style="fill:none;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
110 <path
111 inkscape:connector-curvature="0"
112 id="path3778"
113 d="m 245.06697,378.85772 0.40178,-2.36608"
114 style="fill:none;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
115 </g>
116 <rect
117 style="fill:#ffffff;stroke:#ffffff"
118 id="rect3834"
119 width="65.535683"
120 height="34.46431"
121 x="304.64285"
122 y="492.36218" />
123 </g>
124 <g
125 style="display:inline"
126 inkscape:label="Layer copy"
127 id="g3802"
128 inkscape:groupmode="layer"
129 transform="translate(-154.99045,-304.71875)">
130 <g
131 id="g3804"
132 transform="matrix(-1,0,0,1,797.99858,141.85595)">
133 <g
134 id="g3806">
135 <path
136 sodipodi:nodetypes="csszsc"
137 inkscape:connector-curvature="0"
138 id="path3808"
139 d="m 263.57143,419.50504 c -28.03572,56.42858 -80.49928,92.08847 -100.73276,90.44683 -20.23348,-1.64165 -48.23687,-25.58484 -45.92365,-67.64816 4.55975,-82.91401 73.58785,-221.40908 83.79926,-229.94153 10.21141,-8.53244 18.78619,-14.07754 71.22999,-14.52433 41.022,-0.34948 55.19859,-2.26138 52.34145,25.95291"
140 style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
141 </g>
142 <path
143 sodipodi:type="arc"
144 style="fill:#ffffff;stroke:#000000"
145 id="path3810"
146 sodipodi:cx="290"
147 sodipodi:cy="391.29074"
148 sodipodi:rx="54.285713"
149 sodipodi:ry="54.642857"
150 d="m 344.28571,391.29074 c 0,30.17842 -24.30454,54.64286 -54.28571,54.64286 -29.98117,0 -54.28571,-24.46444 -54.28571,-54.64286 0,-30.17842 24.30454,-54.64286 54.28571,-54.64286 29.98117,0 54.28571,24.46444 54.28571,54.64286 z"
151 transform="matrix(0.87614083,0,0,0.87046633,35.919161,50.685326)" />
152 <path
153 sodipodi:type="arc"
154 style="fill:#ffffff;stroke:#000000"
155 id="path3812"
156 sodipodi:cx="263.57144"
157 sodipodi:cy="309.14789"
158 sodipodi:rx="67.85714"
159 sodipodi:ry="66.071426"
160 d="m 331.42858,309.14789 c 0,36.49024 -30.38067,66.07142 -67.85714,66.07142 -37.47646,0 -67.85714,-29.58118 -67.85714,-66.07142 0,-36.49024 30.38068,-66.07143 67.85714,-66.07143 37.47647,0 67.85714,29.58119 67.85714,66.07143 z"
161 transform="matrix(1.1409547,0,0,1.1717896,-48.580202,-61.679814)" />
162 <path
163 style="fill:none;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
164 d="m 312.76848,350.62183 c -3.15673,-1.86247 -3.15673,-1.86247 -3.15673,-1.86247 l 0,0"
165 id="path3814"
166 inkscape:connector-curvature="0" />
167 <path
168 style="fill:none;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
169 d="m 245.06697,378.85772 0.40178,-2.36608"
170 id="path3816"
171 inkscape:connector-curvature="0" />
172 <rect
173 style="fill:#ffffff;stroke:#ffffff;stroke-width:0.98766255"
174 id="rect3830"
175 width="65.695984"
176 height="33.636066"
177 x="-311.72412"
178 y="350.62634"
179 transform="scale(-1,1)" />
180 <path
181 style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
182 d="m 395.71429,539.50504 64.82142,0.0893"
183 id="path3836"
184 inkscape:connector-curvature="0"
185 transform="matrix(-1,0,0,1,797.99858,-141.85595)"
186 sodipodi:nodetypes="cc" />
187 </g>
188 <text
189 xml:space="preserve"
190 style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Induction;-inkscape-font-specification:Induction"
191 x="541.78571"
192 y="465.93362"
193 id="text4345"
194 sodipodi:linespacing="125%"><tspan
195 sodipodi:role="line"
196 id="tspan4347"
197 x="541.78571"
198 y="465.93362" /></text>
199 <text
200 xml:space="preserve"
201 style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#338000;fill-opacity:1;stroke:none;font-family:Induction;-inkscape-font-specification:Induction"
202 x="542.85712"
203 y="468.07648"
204 id="text4349"
205 sodipodi:linespacing="125%"><tspan
206 sodipodi:role="line"
207 id="tspan4351"
208 x="542.85712"
209 y="468.07648" /></text>
210 <text
211 xml:space="preserve"
212 style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Induction;-inkscape-font-specification:Induction"
213 x="540"
214 y="474.50504"
215 id="text4353"
216 sodipodi:linespacing="125%"><tspan
217 sodipodi:role="line"
218 id="tspan4355"
219 x="540"
220 y="474.50504" /></text>
221 <text
222 xml:space="preserve"
223 style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Induction;-inkscape-font-specification:Induction"
224 x="547.3764"
225 y="453.65738"
226 id="text4357"
227 sodipodi:linespacing="125%"><tspan
228 sodipodi:role="line"
229 id="tspan4359"
230 x="547.3764"
231 y="453.65738" /></text>
232 </g>
233 <g
234 inkscape:groupmode="layer"
235 id="layer5"
236 inkscape:label="dpad"
237 transform="translate(-154.99045,-304.71875)">
238 <path
239 sodipodi:type="arc"
240 style="fill:#ffffff;stroke:#000000"
241 id="path3845"
242 sodipodi:cx="309.10669"
243 sodipodi:cy="438.94705"
244 sodipodi:rx="36.36549"
245 sodipodi:ry="46.214478"
246 d="m 345.47218,438.94705 c 0,25.52355 -16.28139,46.21448 -36.36549,46.21448 -20.08411,0 -36.36549,-20.69093 -36.36549,-46.21448 0,-25.52355 16.28138,-46.21448 36.36549,-46.21448 20.0841,0 36.36549,20.69093 36.36549,46.21448 z"
247 transform="matrix(1.3583623,0,0,1.0688757,-109.76203,-28.21247)" />
248 <path
249 style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
250 d="m 300.13896,392.88521 c 0,0 0.21752,6.21345 0.31578,9.66211 -0.55737,11.95566 2.83194,22.26427 -5.30375,27.18421 -5.89285,3.44866 -19.27082,1.58089 -33.02082,1.58089"
251 id="path3847"
252 inkscape:connector-curvature="0"
253 sodipodi:nodetypes="cccc" />
254 <path
255 style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
256 d="m 357.8672,430.52556 c 0,0 -6.21345,0.21752 -9.66211,0.31578 -11.95566,-0.55737 -22.26427,2.83194 -27.18421,-5.30375 -3.44866,-5.89285 -1.58089,-19.27082 -1.58089,-33.02082"
257 id="path3847-1"
258 inkscape:connector-curvature="0"
259 sodipodi:nodetypes="cccc" />
260 <path
261 style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
262 d="m 299.92758,489.2228 c 0,0 0.21752,-6.21345 0.31578,-9.66211 -0.55737,-11.95566 2.83194,-22.26427 -5.30375,-27.18421 -5.89285,-3.44866 -19.27082,-1.58089 -33.02082,-1.58089"
263 id="path3847-7"
264 inkscape:connector-curvature="0"
265 sodipodi:nodetypes="cccc" />
266 <path
267 style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
268 d="m 357.9195,451.1566 c 0,0 -6.21345,-0.21752 -9.66211,-0.31578 -11.95566,0.55737 -22.26427,-2.83194 -27.18421,5.30375 -3.44866,5.89285 -1.58089,19.27082 -1.58089,33.02082"
269 id="path3847-4"
270 inkscape:connector-curvature="0"
271 sodipodi:nodetypes="cccc" />
272 <path
273 sodipodi:type="arc"
274 style="fill:#ffffff;stroke:#000000"
275 id="path3892"
276 sodipodi:cx="349.76532"
277 sodipodi:cy="530.61841"
278 sodipodi:rx="19.950512"
279 sodipodi:ry="25.75889"
280 d="m 369.71583,530.61841 c 0,14.22624 -8.93215,25.75889 -19.95051,25.75889 -11.01836,0 -19.95051,-11.53265 -19.95051,-25.75889 0,-14.22624 8.93215,-25.75889 19.95051,-25.75889 11.01836,0 19.95051,11.53265 19.95051,25.75889 z"
281 transform="matrix(1.8336949,0,0,1.4280878,-291.53629,-223.11064)" />
282 <path
283 sodipodi:type="arc"
284 style="fill:#ffffff;stroke:#000000"
285 id="path3892-9"
286 sodipodi:cx="349.76532"
287 sodipodi:cy="530.61841"
288 sodipodi:rx="19.950512"
289 sodipodi:ry="25.75889"
290 d="m 369.71583,530.61841 c 0,14.22624 -8.93215,25.75889 -19.95051,25.75889 -11.01836,0 -19.95051,-11.53265 -19.95051,-25.75889 0,-14.22624 8.93215,-25.75889 19.95051,-25.75889 11.01836,0 19.95051,11.53265 19.95051,25.75889 z"
291 transform="matrix(1.8336949,0,0,1.4280878,-133.86288,-223.62178)" />
292 </g>
293 <g
294 inkscape:groupmode="layer"
295 id="layer6"
296 inkscape:label="buttons"
297 transform="translate(-154.99045,-304.71875)">
298 <rect
299 style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
300 id="rect3922"
301 width="20.355255"
302 height="11.251501"
303 x="441.53503"
304 y="418.69357"
305 ry="5.2401662" />
306 <path
307 style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
308 d="m 446.67683,421.20625 -3e-5,6.43972 10.6066,-3.21987 z"
309 id="path4104"
310 inkscape:connector-curvature="0"
311 sodipodi:nodetypes="cccc" />
312 <rect
313 style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
314 id="rect3922-8"
315 width="20.355255"
316 height="11.251501"
317 x="395.04974"
318 y="418.94559"
319 ry="5.2401662" />
320 <path
321 style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
322 d="m 409.99564,421.45878 3e-5,6.43972 -10.6066,-3.21987 z"
323 id="path4104-8"
324 inkscape:connector-curvature="0"
325 sodipodi:nodetypes="cccc" />
326 <path
327 style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
328 d="m 497.41072,339.41575 0,-8.30357 5.08928,-5.89286 55.00001,0.17857 4.82143,5.71429 -1e-5,9.91071"
329 id="path4171"
330 inkscape:connector-curvature="0"
331 sodipodi:nodetypes="cccccc" />
332 <path
333 style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
334 d="m 362.40015,339.55448 0,-8.30357 -5.08928,-5.89286 -55.00001,0.17857 -4.82143,5.71429 10e-6,9.91071"
335 id="path4171-2"
336 inkscape:connector-curvature="0"
337 sodipodi:nodetypes="cccccc" />
338 </g>
339 <g
340 inkscape:groupmode="layer"
341 id="layer7"
342 inkscape:label="face_buttons"
343 transform="translate(-154.99045,-304.71875)">
344 <path
345 sodipodi:type="arc"
346 style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
347 id="path4212-1"
348 sodipodi:cx="512.90497"
349 sodipodi:cy="442.10379"
350 sodipodi:rx="12.879445"
351 sodipodi:ry="8.7125654"
352 d="m 525.78441,442.10379 a 12.879445,8.7125654 0 1 1 -25.75889,0 12.879445,8.7125654 0 1 1 25.75889,0 z"
353 transform="matrix(1.3351132,0,0,1.9720704,-96.78891,-432.50229)" />
354 <path
355 sodipodi:type="arc"
356 style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
357 id="path4212-5-4"
358 sodipodi:cx="512.90497"
359 sodipodi:cy="442.10379"
360 sodipodi:rx="12.879445"
361 sodipodi:ry="8.7125654"
362 d="m 525.78441,442.10379 a 12.879445,8.7125654 0 1 1 -25.75889,0 12.879445,8.7125654 0 1 1 25.75889,0 z"
363 transform="matrix(1.3351132,0,0,1.9720704,-96.70624,-434.05825)" />
364 <path
365 sodipodi:type="arc"
366 style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
367 id="path4212-2"
368 sodipodi:cx="512.90497"
369 sodipodi:cy="442.10379"
370 sodipodi:rx="12.879445"
371 sodipodi:ry="8.7125654"
372 d="m 525.78441,442.10379 a 12.879445,8.7125654 0 1 1 -25.75889,0 12.879445,8.7125654 0 1 1 25.75889,0 z"
373 transform="matrix(1.3351132,0,0,1.9720704,-136.51444,-397.50229)" />
374 <path
375 sodipodi:type="arc"
376 style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
377 id="path4212-5-3"
378 sodipodi:cx="512.90497"
379 sodipodi:cy="442.10379"
380 sodipodi:rx="12.879445"
381 sodipodi:ry="8.7125654"
382 d="m 525.78441,442.10379 a 12.879445,8.7125654 0 1 1 -25.75889,0 12.879445,8.7125654 0 1 1 25.75889,0 z"
383 transform="matrix(1.3351132,0,0,1.9720704,-136.78891,-399.05825)" />
384 <path
385 sodipodi:type="arc"
386 style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
387 id="path4212-22"
388 sodipodi:cx="512.90497"
389 sodipodi:cy="442.10379"
390 sodipodi:rx="12.879445"
391 sodipodi:ry="8.7125654"
392 d="m 525.78441,442.10379 a 12.879445,8.7125654 0 1 1 -25.75889,0 12.879445,8.7125654 0 1 1 25.75889,0 z"
393 transform="matrix(1.3351132,0,0,1.9720704,-136.78891,-472.50229)" />
394 <path
395 sodipodi:type="arc"
396 style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
397 id="path4212-5-1"
398 sodipodi:cx="512.90497"
399 sodipodi:cy="442.10379"
400 sodipodi:rx="12.879445"
401 sodipodi:ry="8.7125654"
402 d="m 525.78441,442.10379 a 12.879445,8.7125654 0 1 1 -25.75889,0 12.879445,8.7125654 0 1 1 25.75889,0 z"
403 transform="matrix(1.3351132,0,0,1.9720704,-136.70624,-474.05825)" />
404 <path
405 sodipodi:type="arc"
406 style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
407 id="path4212"
408 sodipodi:cx="512.90497"
409 sodipodi:cy="442.10379"
410 sodipodi:rx="12.879445"
411 sodipodi:ry="8.7125654"
412 d="m 525.78441,442.10379 a 12.879445,8.7125654 0 1 1 -25.75889,0 12.879445,8.7125654 0 1 1 25.75889,0 z"
413 transform="matrix(1.3351132,0,0,1.9720704,-176.78891,-432.50229)" />
414 <path
415 sodipodi:type="arc"
416 style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
417 id="path4212-5"
418 sodipodi:cx="512.90497"
419 sodipodi:cy="442.10379"
420 sodipodi:rx="12.879445"
421 sodipodi:ry="8.7125654"
422 d="m 525.78441,442.10379 a 12.879445,8.7125654 0 1 1 -25.75889,0 12.879445,8.7125654 0 1 1 25.75889,0 z"
423 transform="matrix(1.3351132,0,0,1.9720704,-176.70624,-434.05825)" />
424 <path
425 style="fill:#00ff66;stroke:#000000;stroke-width:0.29228577;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
426 d="m 547.26452,454.96682 c -8.99466,0.14886 -17.15195,8.1631 -17.09419,17.40605 -0.4705,8.75652 6.52899,16.7924 14.94723,18.03231 8.1379,1.44809 16.88935,-3.49526 19.67598,-11.4751 2.5451,-6.81932 0.42098,-15.13904 -5.24513,-19.69002 -3.37564,-2.93548 -7.85236,-4.46284 -12.28389,-4.27324 z"
427 id="path4325"
428 inkscape:connector-curvature="0" />
429 <path
430 style="fill:#00ccff;stroke:#000000;stroke-width:0.29228571;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
431 d="m 507.34719,419.96682 c -8.99466,0.14886 -17.15195,8.1631 -17.09419,17.40605 -0.47048,8.75651 6.52898,16.7924 14.94722,18.03231 8.13791,1.44809 16.88936,-3.49528 19.67598,-11.47511 2.54511,-6.81931 0.42099,-15.13903 -5.24512,-19.69003 -3.37566,-2.93548 -7.85238,-4.46282 -12.28389,-4.27322 z"
432 id="path4333"
433 inkscape:connector-curvature="0" />
434 <path
435 style="fill:#ff2a2a;stroke:#000000;stroke-width:0.29228565;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
436 d="m 587.34719,419.96682 c -8.99466,0.14886 -17.15194,8.16312 -17.09419,17.40606 -0.47048,8.75651 6.529,16.7924 14.94722,18.03231 8.13791,1.44808 16.88936,-3.49528 19.67598,-11.47511 2.54511,-6.81931 0.42099,-15.13903 -5.24512,-19.69002 -3.37564,-2.93548 -7.85238,-4.46282 -12.28389,-4.27324 z"
437 id="path4337"
438 inkscape:connector-curvature="0" />
439 <path
440 style="fill:#ff7f2a;stroke:#000000;stroke-width:0.29228565;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
441 d="m 547.34719,379.96682 c -8.99465,0.14886 -17.15194,8.1631 -17.09418,17.40606 -0.47048,8.75651 6.52898,16.7924 14.94722,18.03231 8.1379,1.44808 16.88936,-3.49528 19.67598,-11.47511 2.54511,-6.81931 0.42099,-15.13903 -5.24512,-19.69002 -3.37566,-2.93548 -7.85238,-4.46282 -12.2839,-4.27324 z"
442 id="path4341"
443 inkscape:connector-curvature="0" />
444 </g>
445 <g
446 inkscape:groupmode="layer"
447 id="layer8"
448 inkscape:label="face_buttons_text_layer"
449 transform="translate(-154.99045,-304.71875)">
450 <text
451 xml:space="preserve"
452 style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Induction;-inkscape-font-specification:Induction"
453 x="549.27045"
454 y="452.33157"
455 id="text4362"
456 sodipodi:linespacing="125%"><tspan
457 sodipodi:role="line"
458 id="tspan4364"
459 x="549.27045"
460 y="452.33157" /></text>
461 <text
462 xml:space="preserve"
463 style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Mycalc;-inkscape-font-specification:Sans Bold"
464 x="542.42029"
465 y="480.00809"
466 id="text4370"
467 sodipodi:linespacing="125%"><tspan
468 sodipodi:role="line"
469 id="tspan4372"
470 x="542.42029"
471 y="480.00809"
472 style="font-size:18px;font-weight:normal;fill:#225500;-inkscape-font-specification:Mycalc">A</tspan></text>
473 <text
474 xml:space="preserve"
475 style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#550000;fill-opacity:1;stroke:none;font-family:Mycalc;-inkscape-font-specification:Sans Bold"
476 x="582.77081"
477 y="445.09735"
478 id="text4374"
479 sodipodi:linespacing="125%"><tspan
480 sodipodi:role="line"
481 id="tspan4376"
482 x="582.77081"
483 y="445.09735"
484 style="font-size:18px">B</tspan></text>
485 <text
486 xml:space="preserve"
487 style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#164450;fill-opacity:1;stroke:none;font-family:Mycalc;-inkscape-font-specification:Sans Bold"
488 x="503.0386"
489 y="444.56168"
490 id="text4378"
491 sodipodi:linespacing="125%"><tspan
492 sodipodi:role="line"
493 id="tspan4380"
494 x="503.0386"
495 y="444.56168"
496 style="font-size:18px">X</tspan></text>
497 <text
498 xml:space="preserve"
499 style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#552200;fill-opacity:1;stroke:none;font-family:Mycalc;-inkscape-font-specification:Sans Bold"
500 x="543.57434"
501 y="404.47235"
502 id="text4382"
503 sodipodi:linespacing="125%"><tspan
504 sodipodi:role="line"
505 id="tspan4384"
506 x="543.57434"
507 y="404.47235"
508 style="font-size:18px">Y</tspan></text>
509 <path
510 style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
511 d="m 562.27679,331.06754 21.5625,-0.0447 3.83928,3.30357 -0.0446,13.12499"
512 id="path3057"
513 inkscape:connector-curvature="0"
514 sodipodi:nodetypes="cccc" />
515 <path
516 style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
517 d="m 297.58938,331.24662 -21.5625,-0.0447 -3.83928,3.30357 0.0446,11.60713"
518 id="path3057-1"
519 inkscape:connector-curvature="0"
520 sodipodi:nodetypes="cccc" />
521 </g>
522 </svg>
00 Block Attack - Rise of the Blocks by
11 Poul Sander <blockattack@poulsander.com>
2 http://blockattack.net
2 https://blockattack.net
33
44 Gonéri Le Bouder
55 Done some work for making it work with SHAREDIR and all Scons scripts
66
7 Jonathan Dearborn
8 NFont library
9
10 Jordà Polo
11 Two patches
12
137 A lot of the 1.4.0 graphics is by
148 Iwan Gabovitch aka qubodup
9
10 Also:
11 Paul Wise, Jordà Polo, mstraube and scootergrisen for patches and bug reports
1512
1613 This does not cover non-embedded libraries.
1714
2929 #define BLOCKFALL 10000
3030 #define GARBAGE 1000000
3131 #define CHAINPLACE 10000000
32
33 // The game uses a very special base-10 pack system
34 // int 999999999999
35 // YYYYYGWBHTTC
36 // YYYY = Chain
37 // G = Garbage, 1= NORMAL, 2=GRAY
38 // W = Waiting (A bomb is on it)
39 // B = 1 if the block is falling
40 // H = Block is hanging after garbage (Get Ready text on it)
41 // TT = Time (in steps) until something happens
42 // C = color
43
44 static bool block_isFalling(int block) {
45 return (block/BLOCKFALL)%10;
46 }
47
48 static void block_setFalling(int& block, bool value) {
49 if (value) {
50 if (!block_isFalling(block)) {
51 block += BLOCKFALL;
52 }
53 }
54 else {
55 if (block_isFalling(block)) {
56 block -= BLOCKFALL;
57 }
58 }
59 }
3260
3361 #include "BlockGame.hpp"
3462 #include "puzzlehandler.hpp"
723751 bool faaling = false;
724752 for (int j=0; j<30; j++) {
725753 if ((faaling)&&(board[i][j]>-1)&&(board[i][j]%10000000<7)) {
726 board[i][j]+=BLOCKFALL;
754 block_setFalling(board[i][j], true);
727755 }
728756 if ((!faaling)&&((board[i][j]/BLOCKFALL)%10==1)) {
729 board[i][j]-=BLOCKFALL;
757 block_setFalling(board[i][j], false);
730758 }
731759 if (!((board[i][j]>-1)&&(board[i][j]%10000000<7))) {
732760 faaling=true;
904932 if (toBeCleared[j][i]) {
905933 if (!dead) {
906934 dead=true;
907 string tempS = std::to_string(chainSize[chain]);
908935 if (chainSize[chain]>1) {
909 AddText(j, i, tempS, 1000);
936 AddText(j, i, chainSize[chain], 1000);
910937 }
911938 }
912939 }
9841011 bool faaling = false; //In the beginning we are NOT falling
9851012 for (int j=0; j<30; j++) {
9861013 if ((faaling)&&(board[i][j]>-1)&&(board[i][j]<7)) {
987 board[i][j]+=BLOCKFALL;
988 }
989 if ((!faaling)&&((board[i][j]/BLOCKFALL)%10==1)) {
990 board[i][j]-=BLOCKFALL;
1014 block_setFalling(board[i][j], true);
1015 }
1016 if (!faaling) {
1017 block_setFalling(board[i][j], false);
9911018 }
9921019 if ((!faaling)&&(board[i][j]>0)&&(board[i][j]/10000000!=0)&&((board[i][j]/BLOCKWAIT)%10!=1)&&((board[i][j]/BLOCKHANG)%10!=1)) {
9931020 if (chainSize[board[i][j]/10000000]>chainSize[chain]) {
12791306 int BlockGame::horiInLine(int line) {
12801307 //cout << "Start_ hori in line" << "\n";
12811308 int nrOfType[7] = {0, 0, 0, 0, 0, 0, 0};
1282 int iTemp;
12831309 int max = 0;
12841310 for (int i=0; i<6; i++) {
1285 iTemp = board[i][line];
1311 int iTemp = board[i][line];
12861312 if ((iTemp>-1)&&(iTemp<7)) {
12871313 nrOfType[iTemp]++;
12881314 }
145145 int nrPushedPixel = 0;
146146 int nrFellDown = 0;
147147 unsigned int nrStops = 0;
148 bool garbageToBeCleared[7][30];
148 bool garbageToBeCleared[7][30] = {};
149149 unsigned int lastAImove = 0;
150150
151151 int AI_LineOffset = 0; //how many lines have changed since command
218218
219219 int getAIlevel() const;
220220
221 virtual void AddText(int, int, const std::string&, int) const {}
221 virtual void AddText(int, int, unsigned int, int) const {}
222222 virtual void AddBall(int, int, bool, int) const {}
223223 virtual void AddExplosion(int, int) const {}
224224 virtual void PlayerWonEvent() const {}
1616 along with this program. If not, see http://www.gnu.org/licenses/
1717
1818 Source information and contacts persons can be found at
19 http://www.blockattack.net
19 https://blockattack.net
2020 ===========================================================================
2121 */
2222
2323 #include "BlockGame.hpp"
2424 #include "global.hpp"
25
25 #include "sago/SagoTextField.hpp"
26
27 static void setScoreboardFont(const sago::SagoDataHolder* holder, sago::SagoTextField& field, const char* text){
28 field.SetHolder(holder);
29 field.SetFont("penguinattack");
30 field.SetColor({255,255,255,255});
31 field.SetFontSize(20);
32 field.SetText(text);
33 }
34
35 static void setButtonFont(const sago::SagoDataHolder* holder, sago::SagoTextField& field, const char* text){
36 field.SetHolder(holder);
37 field.SetFont("freeserif");
38 field.SetColor({255,255,255,255});
39 field.SetFontSize(24);
40 field.SetOutline(1, {64,64,64,255});
41 field.SetText(text);
42 }
2643
2744 class BlockGameSdl : public BlockGame {
2845 public:
29 BlockGameSdl(int tx, int ty) {
46 BlockGameSdl(int tx, int ty, const sago::SagoDataHolder* holder) {
3047 topx = tx;
3148 topy = ty;
49 setScoreboardFont(holder, scoreLabel, _("Score:"));
50 setScoreboardFont(holder, timeLabel, _("Time:"));
51 setScoreboardFont(holder, chainLabel, _("Chain:"));
52 setScoreboardFont(holder, speedLabel, _("Speed:"));
53 setButtonFont(holder, buttonNext, _("Next"));
54 setButtonFont(holder, buttonRetry, _("Retry"));
55 setButtonFont(holder, buttonSkip, _("Skip"));
56 setButtonFont(holder, stopIntField, "");
3257 }
3358
3459
4065 DrawIMG_Bounded(img, globalData.screen, x+topx, y+topy, topx, topy, topx + backBoard.GetWidth(), topy + backBoard.GetHeight());
4166 }
4267
43 void PrintTextCenteredBoard(int x, int y, const char* text) {
44 globalData.nf_button_font.draw(globalData.screen, x+topx+60, y+topy+10, NFont::CENTER, "%s", text);
45 }
46
47 void PrintIntRightAlignedBoard(int x, int y, int number) {
48 globalData.nf_button_font.draw(globalData.screen, x+topx+60, y+topy+10, NFont::RIGHT, "%d", number);
68 void PrintTextCenteredBoard(int x, int y, sago::SagoTextField& field) {
69 field.Draw(globalData.screen, x+topx+60, y+topy+20,
70 sago::SagoTextField::Alignment::center, sago::SagoTextField::VerticalAlignment::center);
4971 }
5072
5173 void SetTopXY(int tx, int ty) {
92114 return true;
93115 }
94116
95 void AddText(int x, int y, const std::string& text, int time) const override {
117 void AddText(int x, int y, unsigned int text, int time) const override {
96118 globalData.theTextManager.addText(topx-10+x*bsize, topy+12*bsize-y*bsize, text, time);
97119 }
98120
108130 if (!globalData.SoundEnabled) {
109131 return;
110132 }
111 Mix_PlayChannel(1, applause, 0);
133 Mix_PlayChannel(1, applause.get(), 0);
112134 }
113135
114136 void DrawEvent() const override {
119141 if (!globalData.SoundEnabled) {
120142 return;
121143 }
122 Mix_PlayChannel(0, boing, 0);
144 Mix_PlayChannel(0, boing.get(), 0);
123145 }
124146
125147 void LongChainDoneEvent() const override {
126148 if (!globalData.SoundEnabled) {
127149 return;
128150 }
129 Mix_PlayChannel(1, applause, 0);
151 Mix_PlayChannel(1, applause.get(), 0);
130152 }
131153
132154 void TimeTrialEndEvent() const override {
133155 if (!globalData.NoSound && globalData.SoundEnabled) {
134 Mix_PlayChannel(1,counterFinalChunk,0);
156 Mix_PlayChannel(1,counterFinalChunk.get(),0);
135157 }
136158 }
137159
139161 if (!globalData.SoundEnabled) {
140162 return;
141163 }
142 Mix_PlayChannel(1, applause, 0);
164 Mix_PlayChannel(1, applause.get(), 0);
143165 }
144166 private:
145167 //Draws all the bricks to the board (including garbage)
289311 void DoPaintJob() {
290312 DrawIMG(boardBackBack,globalData.screen,this->GetTopX()-60,this->GetTopY()-68);
291313
292 globalData.nf_scoreboard_font.draw(globalData.screen, this->GetTopX()+310,this->GetTopY()-68+148,_("Score:") );
293 globalData.nf_scoreboard_font.draw(globalData.screen, this->GetTopX()+310,this->GetTopY()-68+197,_("Time:") );
294 globalData.nf_scoreboard_font.draw(globalData.screen, this->GetTopX()+310,this->GetTopY()-68+246,_("Chain:") );
295 globalData.nf_scoreboard_font.draw(globalData.screen, this->GetTopX()+310,this->GetTopY()-68+295,_("Speed:") );
314 this->scoreLabel.Draw(globalData.screen, this->GetTopX()+310,this->GetTopY()-68+148);
315 this->timeLabel.Draw(globalData.screen, this->GetTopX()+310,this->GetTopY()-68+197);
316 this->chainLabel.Draw(globalData.screen, this->GetTopX()+310,this->GetTopY()-68+246);
317 this->speedLabel.Draw(globalData.screen, this->GetTopX()+310,this->GetTopY()-68+295);
296318 DrawImgBoard(backBoard, 0, 0);
297319
298320 PaintBricks();
302324 if (puzzleMode&&(!bGameOver)) {
303325 //We need to write nr. of moves left!
304326 strHolder = _("Moves left: ") + std::to_string(MovesLeft);
305 globalData.nf_standard_blue_font.draw(globalData.screen, topx+5, topy+5, "%s", strHolder.c_str());
327 static sago::SagoTextField movesPuzzleLabel;
328 sagoTextSetHelpFont(movesPuzzleLabel);
329 movesPuzzleLabel.SetText(strHolder);
330 movesPuzzleLabel.Draw(globalData.screen, topx+5, topy+5);
306331
307332 }
308333 if (puzzleMode && stageButtonStatus == SBpuzzleMode) {
309334 DrawImgBoard(bRetry, cordRetryButton.x, cordRetryButton.y);
310 PrintTextCenteredBoard(cordRetryButton.x, cordRetryButton.y, _("Retry"));
335 PrintTextCenteredBoard(cordRetryButton.x, cordRetryButton.y, buttonRetry);
311336 if (getLevel()<PuzzleGetNumberOfPuzzles()-1) {
312337 if (hasWonTheGame) {
313338 DrawImgBoard(globalData.bNext, cordNextButton.x, cordNextButton.y);
314 PrintTextCenteredBoard(cordNextButton.x, cordNextButton.y, _("Next"));
339 PrintTextCenteredBoard(cordNextButton.x, cordNextButton.y, buttonNext);
315340 }
316341 else {
317342 DrawImgBoard(bSkip,cordNextButton.x, cordNextButton.y);
318 PrintTextCenteredBoard(cordNextButton.x, cordNextButton.y, _("Skip"));
343 PrintTextCenteredBoard(cordNextButton.x, cordNextButton.y, buttonSkip);
319344 }
320345 }
321346 else {
322 strHolder = "Last puzzle";
323 globalData.nf_standard_blue_font.draw(globalData.screen, topx+5, topy+5, "%s",strHolder.c_str());
347 static sago::SagoTextField lastPuzzleLabel;
348 sagoTextSetHelpFont(lastPuzzleLabel);
349 lastPuzzleLabel.SetText(_("Last puzzle"));
350 lastPuzzleLabel.Draw(globalData.screen, topx+5, topy+5);
324351 }
325352 }
326353 if (stageClear && stageButtonStatus == SBstageClear) {
327354 DrawImgBoard(bRetry, cordRetryButton.x, cordRetryButton.y);
328 PrintTextCenteredBoard(cordRetryButton.x, cordRetryButton.y, _("Retry"));
355 PrintTextCenteredBoard(cordRetryButton.x, cordRetryButton.y, buttonRetry);
329356 if (getLevel()<50-1) {
330357 if (hasWonTheGame) {
331358 DrawImgBoard(globalData.bNext, cordNextButton.x, cordNextButton.y);
332 PrintTextCenteredBoard(cordNextButton.x, cordNextButton.y, _("Next"));
359 PrintTextCenteredBoard(cordNextButton.x, cordNextButton.y, buttonNext);
333360 }
334361 else {
335362 DrawImgBoard(bSkip,cordNextButton.x, cordNextButton.y);
336 PrintTextCenteredBoard(cordNextButton.x, cordNextButton.y, _("Skip"));
363 PrintTextCenteredBoard(cordNextButton.x, cordNextButton.y, buttonSkip);
337364 }
338365 }
339366 else {
340 strHolder = "Last stage";
341 globalData.nf_standard_blue_font.draw(globalData.screen, topx+5, topy+5, "%s",strHolder.c_str());
367 static sago::SagoTextField lastStageLabel;
368 sagoTextSetHelpFont(lastStageLabel);
369 lastStageLabel.SetText(_("Last stage"));
370 lastStageLabel.Draw(globalData.screen, topx+5, topy+5);
342371 }
343372 }
344373 if (!bGameOver && stop > 20) {
345 PrintIntRightAlignedBoard(240, -40, stop/10);
374 stopIntField.SetText(std::to_string(stop/10));
375 stopIntField.Draw(globalData.screen, 240+topx, -40+topy);
346376 }
347377
348378 #if DEBUG
349379 if (AI_Enabled&&(!bGameOver)) {
380 sagoTextSetBlueFont(aiStatusField);
350381 strHolder = "AI_status: " + std::to_string(AIstatus)+ ", "+ std::to_string(AIlineToClear);
351 //NFont_Write( 5, 5, strHolder.c_str());
352 globalData.nf_standard_blue_font.draw(globalData.screen, topx+5, topy+5, "%s",strHolder.c_str());
382 aiStatusField.SetText(strHolder);
383 aiStatusField.Draw(globalData.screen, topx+5, topy+5);
353384 }
354385 #endif
355386 if (!bGameOver) {
361392 DrawImgBoard(globalData.spriteHolder->GetSprite("touchcursor"),mx*bsize, 11*bsize-my*bsize-pixels);
362393 }
363394 else {
364 DrawImgBoard(cursor,cursorx*bsize-4,11*bsize-cursory*bsize-pixels-4);
395 DrawImgBoard(cursor,cursorx*bsize,11*bsize-cursory*bsize-pixels);
365396 }
366397 }
367398 if (ticks<gameStartedAt) {
368399 int currentCounter = abs((int)ticks-(int)gameStartedAt)/1000;
369400 if ( (currentCounter!=lastCounter) && (globalData.SoundEnabled)&&(!globalData.NoSound)) {
370 Mix_PlayChannel(1,counterChunk,0);
401 Mix_PlayChannel(1, counterChunk.get(), 0);
371402 }
372403 lastCounter = currentCounter;
373404 switch (currentCounter) {
389420 int currentCounter = (ticks-(int)gameStartedAt)/1000;
390421 if (currentCounter!=lastCounter) {
391422 if (currentCounter>115 && currentCounter<120) {
392 Mix_PlayChannel(1,counterChunk,0);
423 Mix_PlayChannel(1, counterChunk.get(), 0);
393424 }
394425 }
395426 lastCounter = currentCounter;
396427 }
397428 else {
398429 if ( (0==lastCounter) && (globalData.SoundEnabled)&&(!globalData.NoSound)) {
399 Mix_PlayChannel(1, counterFinalChunk, 0);
430 Mix_PlayChannel(1, counterFinalChunk.get(), 0);
400431 }
401432 lastCounter = -1;
402433 }
403434 }
404435
405 if ((bGameOver)&&(!editorMode)) {
436 if (bGameOver) {
406437 if (hasWonTheGame) {
407438 DrawImgBoard(iWinner, 0, 5*bsize);
408439 }
419450
420451 private:
421452 int topx, topy;
453 sago::SagoTextField scoreLabel;
454 sago::SagoTextField timeLabel;
455 sago::SagoTextField chainLabel;
456 sago::SagoTextField speedLabel;
457 sago::SagoTextField buttonSkip;
458 sago::SagoTextField buttonRetry;
459 sago::SagoTextField buttonNext;
460 sago::SagoTextField stopIntField;
461 #if DEBUG
462 sago::SagoTextField aiStatusField;
463 #endif
422464 };
423465
424466
2525 #include "common.h"
2626 #include "ReadKeyboard.h"
2727
28 static void NFont_Write(SDL_Renderer* target, int x, int y, const std::string& text) {
29 globalData.nf_standard_blue_font.draw(target, x, y, "%s", text.c_str());
28 static void setButtonFont(const sago::SagoDataHolder* holder, sago::SagoTextField& field, const char* text) {
29 field.SetHolder(holder);
30 field.SetFont("freeserif");
31 field.SetColor({255,255,255,255});
32 field.SetFontSize(24);
33 field.SetOutline(1, {0,0,0,255});
34 field.SetText(text);
3035 }
3136
3237 static void DrawRect(SDL_Renderer* target, int topx, int topy, int height, int width, const std::string& name) {
6368 DrawRect(target, topx, topy, height, width, name);
6469 }
6570
66 static void DrawRectYellow(SDL_Renderer* target, int topx, int topy, int height, int width) {
71 void DrawRectYellow(SDL_Renderer* target, int topx, int topy, int height, int width) {
6772 std::string name = "ui_rect_yellow_";
6873 DrawRect(target, topx, topy, height, width, name);
6974 }
8287 this->x = x;
8388 this->y = y;
8489 SetName(name);
90 setButtonFont(&globalData.spriteHolder->GetDataHolder(), headerLabel, header.c_str());
91 setButtonFont(&globalData.spriteHolder->GetDataHolder(), enterLabel, _("Enter to accept"));
92 setButtonFont(&globalData.spriteHolder->GetDataHolder(), cancelLabel, _("Esc to cancel"));
93 sagoTextSetBlueFont(textField);
94 sagoTextSetBlueFont(cursorLabel);
95 cursorLabel.SetText("|");
8596 }
8697
8798
98109 this->x = globalData.xsize/2-300;
99110 this->y = globalData.ysize/2-100;
100111 DrawRectYellow(target, x, y, 200, 600);
101 globalData.nf_button_font.draw(target, x+300, y+20, NFont::CENTER, "%s", header.c_str());
102 globalData.nf_button_font.draw(target, x+150, y+140, NFont::CENTER, _("Enter to accept"));
103 globalData.nf_button_font.draw(target, x+450, y+140, NFont::CENTER, _("Esc to cancel"));
112 headerLabel.Draw(target, x+300, y+20, sago::SagoTextField::Alignment::center);
113 enterLabel.Draw(target, x+150, y+140, sago::SagoTextField::Alignment::center);
114 cancelLabel.Draw(target, x+450, y+140, sago::SagoTextField::Alignment::center);
104115 DrawRectWhite(target, x+26, y+64, 54, 600-2*26);
105 NFont_Write(target, x+40, y+76,rk->GetString());
116 textField.SetText(rk->GetString());
117 textField.Draw(target, x+40, y+76);
106118 std::string strHolder = rk->GetString();
107119 strHolder.erase((int)rk->CharsBeforeCursor());
108120
109121 if (((SDL_GetTicks()/600)%2)==1) {
110 NFont_Write(target, x+40+globalData.nf_standard_blue_font.getWidth( "%s", strHolder.c_str()),y+76,"|");
122 int width = 0;
123 textField.GetRenderedSize( strHolder.c_str(), &width);
124 width -= 2;
125 cursorLabel.Draw(target, x+40+width,y+76);
111126 }
112127 }
113128
114129 void DialogBox::ProcessInput(const SDL_Event& event, bool& processed) {
115130 if (event.type == SDL_TEXTINPUT) {
116131 if ((rk->ReadKey(event))&&(globalData.SoundEnabled)&&(!globalData.NoSound)) {
117 Mix_PlayChannel(1, globalData.typingChunk, 0);
132 Mix_PlayChannel(1, globalData.typingChunk.get(), 0);
118133 }
119134 }
120135
129144 }
130145 else {
131146 if ((rk->ReadKey(event))&&(globalData.SoundEnabled)&&(!globalData.NoSound)) {
132 Mix_PlayChannel(1, globalData.typingChunk, 0);
147 Mix_PlayChannel(1, globalData.typingChunk.get(), 0);
133148 }
134149 }
135150 }
5151 std::string header;
5252 bool updated = false;
5353 SDL_TextInput textInputScope;
54 sago::SagoTextField headerLabel;
55 sago::SagoTextField enterLabel;
56 sago::SagoTextField cancelLabel;
57 sago::SagoTextField textField;
58 sago::SagoTextField cursorLabel;
5459 };
5560
5661 #endif /* DIALOGBOX_HPP */
0 /*
1 ===========================================================================
2 blockattack - Block Attack - Rise of the Blocks
3 Copyright (C) 2005-2018 Poul Sander
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see http://www.gnu.org/licenses/
17
18 Source information and contacts persons can be found at
19 https://blockattack.net
20 ===========================================================================
21 */
22
23 #include "HelpAboutState.hpp"
24 #include "global.hpp"
25 #include "common.h"
26 #include "MenuSystem.h"
27 #include "sstream"
28 #include "version.h"
29
30 const int xsize = 1024;
31 const int ysize = 768;
32 const int buttonOffset = 160;
33 extern sago::SagoSprite bExit;
34
35
36
37 static void setHelpGamepadFont(const sago::SagoDataHolder* holder, sago::SagoTextField& field, const char* text) {
38 field.SetHolder(holder);
39 field.SetFont("freeserif");
40 field.SetColor({255,255,255,255});
41 field.SetFontSize(30);
42 field.SetOutline(1, {128,128,128,255});
43 field.SetText(text);
44 }
45
46 static void setHelpGamepadFont(const sago::SagoDataHolder* holder, sago::SagoTextBox& field, const char* text) {
47 field.SetHolder(holder);
48 field.SetFont("freeserif");
49 field.SetColor({255,255,255,255});
50 field.SetColor({0,0,0,255});
51 field.SetFontSize(20);
52 field.SetOutline(0, {0,0,0,255});
53 field.SetText(text);
54 }
55
56 static SDL_RendererInfo renderInfo;
57
58 HelpAboutState::HelpAboutState() {
59 SDL_GetRendererInfo(globalData.screen, &renderInfo);
60 std::stringstream infoStream;
61 infoStream << _("Name:") << " " << _("Block Attack - Rise of the Blocks") << "\n";
62 infoStream << _("Original name:") << " Block Attack - Rise of the Blocks" << "\n";
63 infoStream << _("Version:") << " " << VERSION_NUMBER << "\n";
64 infoStream << _("Homepage:") << " " << "https://blockattack.net\n";
65 infoStream << _("Github page:") << " " << "https://github.com/blockattack/blockattack-game\n";
66 infoStream << _("SDL render:") << " " << renderInfo.name << "\n";
67 infoStream << _("Save folder:") << " " << PHYSFS_getWriteDir() << "\n";
68 infoStream << _("Locale:") << " " << setlocale( LC_CTYPE, nullptr ) << "\n";
69 setHelpGamepadFont(&globalData.spriteHolder->GetDataHolder(), titleField, _("About"));
70 setHelpGamepadFont(&globalData.spriteHolder->GetDataHolder(), infoBox, infoStream.str().c_str());
71 }
72
73 HelpAboutState::~HelpAboutState() {
74 }
75
76 bool HelpAboutState::IsActive() {
77 return isActive;
78 }
79
80 void HelpAboutState::ProcessInput(const SDL_Event& event, bool& processed) {
81
82 UpdateMouseCoordinates(event, globalData.mousex, globalData.mousey);
83
84 if (isConfirmEvent(event) || isEscapeEvent(event)) {
85 isActive = false;
86 processed = true;
87 }
88 }
89
90 extern void DrawRectYellow(SDL_Renderer* target, int topx, int topy, int height, int width);
91
92 void HelpAboutState::Draw(SDL_Renderer* target) {
93 DrawBackground(target);
94 titleField.Draw(target, 50, 50);
95 DrawRectYellow(target, 40, 90, 600, 900);
96 infoBox.SetMaxWidth(850);
97 infoBox.Draw(target, 50, 100);
98 bExit.Draw(globalData.screen, SDL_GetTicks(), xsize-buttonOffset, ysize-buttonOffset);
99 #if DEBUG
100 static sago::SagoTextField mousePos;
101 mousePos.SetHolder(&globalData.spriteHolder->GetDataHolder());
102 mousePos.SetFontSize(16);
103 mousePos.SetOutline(1, {128,128,128,255});
104 mousePos.SetText(std::string("Mouse position: ")+std::to_string(globalData.mousex)+std::string(", ")+std::to_string(globalData.mousey));
105 mousePos.Draw(target, 0,0);
106 #endif
107 }
108
109 void HelpAboutState::Update() {
110 // If the mouse button is released, make bMouseUp equal true
111 if ( !(SDL_GetMouseState(nullptr, nullptr)&SDL_BUTTON(1)) ) {
112 bMouseUp=true;
113 }
114
115 if (SDL_GetMouseState(nullptr,nullptr)&SDL_BUTTON(1) && bMouseUp) {
116 bMouseUp = false;
117
118 //The Score button:
119 if ((globalData.mousex>xsize-buttonOffset) && (globalData.mousex<xsize-buttonOffset+bExit.GetWidth())
120 && (globalData.mousey>ysize-buttonOffset) && (globalData.mousey<ysize-buttonOffset+bExit.GetHeight())) {
121 isActive = false;
122 }
123
124 }
125 }
0 /*
1 ===========================================================================
2 blockattack - Block Attack - Rise of the Blocks
3 Copyright (C) 2005-2018 Poul Sander
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see http://www.gnu.org/licenses/
17
18 Source information and contacts persons can be found at
19 https://blockattack.net
20 ===========================================================================
21 */
22
23 #ifndef HELPABOUT_HPP
24 #define HELPABOUT_HPP
25
26 #include "sago/GameStateInterface.hpp"
27 #include "sago/SagoTextBox.hpp"
28 #include "sago/SagoTextField.hpp"
29
30 class HelpAboutState : public sago::GameStateInterface {
31 public:
32 HelpAboutState();
33 HelpAboutState(const HelpAboutState& orig) = delete;
34 virtual ~HelpAboutState();
35
36 bool IsActive() override;
37 void Draw(SDL_Renderer* target) override;
38 void ProcessInput(const SDL_Event& event, bool &processed) override;
39 void Update() override;
40
41 private:
42 bool isActive = true;
43 bool bMouseUp = true;
44 sago::SagoTextField titleField;
45 sago::SagoTextBox infoBox;
46 };
47
48 #endif /* HELPABOUT_HPP */
49
0 /*
1 ===========================================================================
2 blockattack - Block Attack - Rise of the Blocks
3 Copyright (C) 2005-2018 Poul Sander
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see http://www.gnu.org/licenses/
17
18 Source information and contacts persons can be found at
19 https://blockattack.net
20 ===========================================================================
21 */
22
23 #include "HelpGamepadState.hpp"
24 #include "global.hpp"
25 #include "common.h"
26 #include "MenuSystem.h"
27 #include "gamecontroller.h"
28
29 const int xsize = 1024;
30 const int ysize = 768;
31 const int buttonOffset = 160;
32
33 static void setHelpGamepadFont(const sago::SagoDataHolder* holder, sago::SagoTextField& field, const char* text) {
34 field.SetHolder(holder);
35 field.SetFont("freeserif");
36 field.SetColor({255,255,255,255});
37 field.SetFontSize(30);
38 field.SetOutline(2, {0,0,0,255});
39 field.SetText(text);
40 }
41
42 static void setHelpGamepadFont(const sago::SagoDataHolder* holder, sago::SagoTextBox& field, const char* text) {
43 field.SetHolder(holder);
44 field.SetFont("freeserif");
45 field.SetColor({255,255,255,255});
46 field.SetFontSize(30);
47 field.SetOutline(2, {0,0,0,255});
48 field.SetText(text);
49 }
50
51
52 HelpGamepadState::HelpGamepadState() {
53 setHelpGamepadFont(&globalData.spriteHolder->GetDataHolder(), moveLabel, _("Move cursor"));
54 setHelpGamepadFont(&globalData.spriteHolder->GetDataHolder(), pushLabel, _("Push line"));
55 setHelpGamepadFont(&globalData.spriteHolder->GetDataHolder(), backLabel, _("Back (Menu)"));
56 setHelpGamepadFont(&globalData.spriteHolder->GetDataHolder(), switchLabel, _("Switch"));
57 setHelpGamepadFont(&globalData.spriteHolder->GetDataHolder(), confirmLabel, _("Confirm"));
58 std::string s = _("Only SDL2 compatible controllers are supported!\nSupported controllers: ");
59 for (size_t i = 0 ; i<GetSupportedControllerNames().size(); ++i ) {
60 if (i != 0) {
61 s+= ", ";
62 }
63 s+= GetSupportedControllerNames().at(i);
64 }
65 setHelpGamepadFont(&globalData.spriteHolder->GetDataHolder(), supportedControllers, s.c_str());
66 supportedControllers.SetMaxWidth(740);
67 }
68
69 HelpGamepadState::~HelpGamepadState() {
70 }
71
72 bool HelpGamepadState::IsActive() {
73 return isActive;
74 }
75
76 void HelpGamepadState::ProcessInput(const SDL_Event& event, bool& processed) {
77 UpdateMouseCoordinates(event, globalData.mousex, globalData.mousey);
78
79 if (isConfirmEvent(event) || isEscapeEvent(event)) {
80 isActive = false;
81 processed = true;
82 }
83 }
84
85 extern sago::SagoSprite bExit;
86
87 void HelpGamepadState::Draw(SDL_Renderer* target) {
88 DrawBackground(target);
89 const sago::SagoSprite& gamepad = globalData.spriteHolder->GetSprite("help_controller");
90 gamepad.Draw(target, SDL_GetTicks(), globalData.xsize/2-480/2, 100);
91 SDL_RenderDrawLine(target, 100, 210, globalData.xsize/2-480/2+130, 210);
92 SDL_RenderDrawLine(target, 100, 298, globalData.xsize/2-480/2+158, 298);
93 SDL_RenderDrawLine(target, 100, 210, 100, 400);
94 moveLabel.Draw(target, 100, 404, sago::SagoTextField::Alignment::center);
95 SDL_RenderDrawLine(target, globalData.xsize/2-480/2+140, 90, globalData.xsize/2-480/2+140, 105);
96 SDL_RenderDrawLine(target, globalData.xsize/2+480/2-140, 90, globalData.xsize/2+480/2-140, 105);
97 SDL_RenderDrawLine(target, globalData.xsize/2-480/2+140, 90, globalData.xsize/2+480/2-140, 90);
98 SDL_RenderDrawLine(target, globalData.xsize/2, 80, globalData.xsize/2, 90);
99 pushLabel.Draw(target, globalData.xsize/2, 80, sago::SagoTextField::Alignment::center, sago::SagoTextField::VerticalAlignment::bottom);
100 SDL_RenderDrawLine(target, 625, 168, 800, 168);
101 SDL_RenderDrawLine(target, 800, 158, 800, 168);
102 backLabel.Draw(target, 800, 156, sago::SagoTextField::Alignment::center, sago::SagoTextField::VerticalAlignment::bottom);
103 SDL_RenderDrawLine(target, 625, 241, 900, 241);
104 SDL_RenderDrawLine(target, 663, 207, 900, 207);
105 SDL_RenderDrawLine(target, 900, 207, 900, 400);
106 switchLabel.Draw(target, 900, 404, sago::SagoTextField::Alignment::center);
107 confirmLabel.Draw(target, 900, 404+30, sago::SagoTextField::Alignment::center);
108 bExit.Draw(globalData.screen, SDL_GetTicks(), xsize-buttonOffset, ysize-buttonOffset);
109 supportedControllers.Draw(target, 10, 600);
110
111 #if DEBUG
112 static sago::SagoTextField mousePos;
113 mousePos.SetHolder(&globalData.spriteHolder->GetDataHolder());
114 mousePos.SetFontSize(16);
115 mousePos.SetOutline(1, {128,128,128,255});
116 mousePos.SetText(std::string("Mouse position: ")+std::to_string(globalData.mousex)+std::string(", ")+std::to_string(globalData.mousey));
117 mousePos.Draw(target, 0,0);
118 #endif
119 }
120
121 void HelpGamepadState::Update() {
122 // If the mouse button is released, make bMouseUp equal true
123 if ( !(SDL_GetMouseState(nullptr, nullptr)&SDL_BUTTON(1)) ) {
124 bMouseUp=true;
125 }
126
127 if (SDL_GetMouseState(nullptr,nullptr)&SDL_BUTTON(1) && bMouseUp) {
128 bMouseUp = false;
129
130 //The Score button:
131 if ((globalData.mousex>xsize-buttonOffset) && (globalData.mousex<xsize-buttonOffset+bExit.GetWidth())
132 && (globalData.mousey>ysize-buttonOffset) && (globalData.mousey<ysize-buttonOffset+bExit.GetHeight())) {
133 isActive = false;
134 }
135
136 }
137 }
0 /*
1 ===========================================================================
2 blockattack - Block Attack - Rise of the Blocks
3 Copyright (C) 2005-2018 Poul Sander
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see http://www.gnu.org/licenses/
17
18 Source information and contacts persons can be found at
19 https://blockattack.net
20 ===========================================================================
21 */
22
23 #ifndef HELPGAMEPADSTATE_HPP
24 #define HELPGAMEPADSTATE_HPP
25
26 #include "sago/GameStateInterface.hpp"
27 #include "sago/SagoTextField.hpp"
28 #include "sago/SagoTextBox.hpp"
29
30 class HelpGamepadState : public sago::GameStateInterface {
31 public:
32 HelpGamepadState();
33 HelpGamepadState(const HelpGamepadState& orig) = delete;
34 virtual ~HelpGamepadState();
35
36 bool IsActive() override;
37 void Draw(SDL_Renderer* target) override;
38 void ProcessInput(const SDL_Event& event, bool &processed) override;
39 void Update() override;
40
41 private:
42 bool isActive = true;
43 bool bMouseUp = true;
44 sago::SagoTextField moveLabel;
45 sago::SagoTextField pushLabel;
46 sago::SagoTextField backLabel;
47 sago::SagoTextField switchLabel;
48 sago::SagoTextField confirmLabel;
49 sago::SagoTextBox supportedControllers;
50 };
51
52 #endif /* HELPGAMEPADSTATE_HPP */
53
0 /*
1 ===========================================================================
2 blockattack - Block Attack - Rise of the Blocks
3 Copyright (C) 2005-2018 Poul Sander
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see http://www.gnu.org/licenses/
17
18 Source information and contacts persons can be found at
19 https://blockattack.net
20 ===========================================================================
21 */
22
23 #include "HelpHowtoState.hpp"
24 #include "global.hpp"
25 #include "common.h"
26 #include "MenuSystem.h"
27 #include <cmath>
28
29 const int xsize = 1024;
30 const int ysize = 768;
31 const int buttonOffset = 160;
32 extern sago::SagoSprite bExit;
33 extern sago::SagoSprite bricks[7];
34
35 /**
36 * Draws bricks with a string like:
37 * "aab" for two identical one and another
38 * "aaB" the third one will have a bomb
39 * The any char not in 'a' to 'g' or 'A' to 'G' the behavior is undefined.
40 * @param target Target to draw to
41 * @param bricks description on what to draw as a string
42 * @param x
43 * @param y
44 */
45 static void RenderRowOfBricks(SDL_Renderer* target, const std::string& brickStr, int x, int y) {
46 Uint32 tick = SDL_GetTicks();
47 for (size_t i = 0; i < brickStr.size(); ++i) {
48 bool bomb = false;
49 char brickChar = brickStr[i];
50 if (brickChar >= 'A' && brickChar <= 'G') {
51 bomb = true;
52 brickChar = brickChar + 'a' - 'A';
53 }
54 if (brickChar >= 'a' && brickChar <= 'g') {
55 bricks[brickChar - 'a'].Draw(target, tick, x+i*50, y);
56 if (bomb) {
57 globalData.spriteHolder->GetSprite("block_bomb").Draw(target, tick, x+i*50, y);
58 }
59 }
60 }
61 }
62
63 class HorizontalSwitchAnimation {
64 public:
65 std::string brickStr = "abc";
66 int cursorPos = 0;
67 int state = 0; //0=move left, 1 = switch, 2 = move right, 3 = switch
68 Uint32 lastTick = 0;
69 Uint32 animationSpeed = 2000;
70
71 void Update (Uint32 tick) {
72 if (tick > lastTick + animationSpeed) {
73 lastTick = tick;
74 switch (state) {
75 case 0:
76 cursorPos = 1;
77 break;
78 case 1: //fallthough
79 case 3:
80 std::swap(brickStr[cursorPos], brickStr[cursorPos + 1]);
81 break;
82 case 2:
83 cursorPos = 0;
84 break;
85 }
86 ++state;
87 if (state > 3) {
88 state = 0;
89 }
90 }
91 }
92 };
93
94 class MultiLineBlocks {
95 private:
96 std::vector<std::string> lines;
97 public:
98 MultiLineBlocks& addLine(const std::string& line) {
99 lines.push_back(line);
100 return *this;
101 }
102
103 void Render(SDL_Renderer* target, int x, int y) {
104 for (size_t i = 0; i < lines.size(); ++i) {
105 RenderRowOfBricks(target, lines[i], x, y+i*50);
106 }
107 }
108
109 };
110
111 HorizontalSwitchAnimation switchAnimation;
112 sago::SagoTextField switchAnimationField;
113 sago::SagoTextField clearRowfield;
114 sago::SagoTextField comboField;
115 sago::SagoTextField dropField;
116 sago::SagoTextField chainField;
117
118 static void InitTextField(sago::SagoTextField& field, const char* text) {
119 field.SetHolder(&globalData.spriteHolder->GetDataHolder());
120 field.SetFontSize(30);
121 field.SetOutline(2, {0,0,0,255});
122 field.SetText(text);
123 }
124
125 HelpHowtoState::HelpHowtoState() {
126 InitTextField(switchAnimationField, _("Switch block horizontally"));
127 InitTextField(clearRowfield, _("Match 3 to clear"));
128 InitTextField(comboField, _("Create combos!"));
129 InitTextField(dropField, _("Drop blocks!"));
130 InitTextField(chainField, _("Create a chain effect"));
131 }
132
133 HelpHowtoState::~HelpHowtoState() {
134 }
135
136 bool HelpHowtoState::IsActive() {
137 return isActive;
138 }
139
140 void HelpHowtoState::ProcessInput(const SDL_Event& event, bool& processed) {
141
142 UpdateMouseCoordinates(event, globalData.mousex, globalData.mousey);
143
144 if (isConfirmEvent(event) || isEscapeEvent(event)) {
145 isActive = false;
146 processed = true;
147 }
148 }
149
150 const double PI =3.141592653589793238463;
151
152 static void DrawArrow(SDL_Renderer* target, int x1, int y1, int x2, int y2) {
153 double dx = x1-x2;
154 double dy = y1-y2;
155 double distance = std::sqrt((dx*dx)+(dy*dy));
156 dx = dx * 10.0 / distance;
157 dy = dy * 10.0 / distance;
158 double angle= PI/4.0;
159 double nx1 = dx * std::cos(angle) - dy * std::sin(angle) + x2;
160 double ny1 = dx * std::sin(angle) + dy * std::cos(angle) + y2;
161 SDL_RenderDrawLine(target, x1, y1, x2, y2);
162 SDL_RenderDrawLine(target, nx1, ny1, x2, y2);
163 nx1 = dx * std::cos(-angle) - dy * std::sin(-angle) + x2;
164 ny1 = dx * std::sin(-angle) + dy * std::cos(-angle) + y2;
165 SDL_RenderDrawLine(target, nx1, ny1, x2, y2);
166 }
167
168 void HelpHowtoState::Draw(SDL_Renderer* target) {
169 DrawBackground(target);
170 RenderRowOfBricks(target, switchAnimation.brickStr, 50, 50);
171 globalData.spriteHolder->GetSprite("cursor").Draw(target, SDL_GetTicks(), 50+switchAnimation.cursorPos*50, 50);
172 switchAnimationField.Draw(target, 50 +150+30, 50+25, sago::SagoTextField::Alignment::left, sago::SagoTextField::VerticalAlignment::center);
173 RenderRowOfBricks(target, "adaa", 50, 150);
174 globalData.spriteHolder->GetSprite("cursor").Draw(target, SDL_GetTicks(), 50, 150);
175 RenderRowOfBricks(target, "dAAA", 50+300, 150);
176 DrawArrow(target, 50+200+25, 150+25, 50+300-25, 150+25);
177 clearRowfield.Draw(target, 600, 150+25, sago::SagoTextField::Alignment::left, sago::SagoTextField::VerticalAlignment::center);
178 comboField.Draw(target, 50+175, 410, sago::SagoTextField::Alignment::center);
179 MultiLineBlocks().addLine("ab").addLine("ba").addLine("ab").Render(target, 50, 250);
180 globalData.spriteHolder->GetSprite("cursor").Draw(target, SDL_GetTicks(), 50, 250+50);
181 MultiLineBlocks().addLine("AB").addLine("AB").addLine("AB").Render(target, 50+200, 250);
182 DrawArrow(target, 175, 325, 225, 325);
183 MultiLineBlocks().addLine("a").addLine("b").addLine("e").Render(target, 50+400, 250);
184 globalData.spriteHolder->GetSprite("cursor").Draw(target, SDL_GetTicks(), 50+400, 250);
185 MultiLineBlocks().addLine(" ").addLine("b").addLine("ea").Render(target, 50+400+200, 250);
186 dropField.Draw(target, 50+400+150, 410, sago::SagoTextField::Alignment::center);
187 DrawArrow(target, 575, 325, 625, 325);
188 DrawArrow(target, 475, 275, 525, 275);
189 DrawArrow(target, 525, 275, 525, 375);
190 DrawArrow(target, 675, 275, 725, 275);
191 DrawArrow(target, 725, 275, 725, 375);
192 MultiLineBlocks().addLine(" d").addLine(" f").addLine(" f").addLine("fdd").Render(target, 50, 500);
193 MultiLineBlocks().addLine(" d").addLine(" F").addLine(" F").addLine("dFd").Render(target, 50+200, 500);
194 MultiLineBlocks().addLine(" d").addLine(" ").addLine(" ").addLine("d d").Render(target, 50+200*2, 500);
195 MultiLineBlocks().addLine(" ").addLine(" ").addLine(" ").addLine("DDD").Render(target, 50+200*3, 500);
196 globalData.spriteHolder->GetSprite("cursor").Draw(target, SDL_GetTicks(), 50, 650);
197 DrawArrow(target, 200, 600, 250, 600);
198 DrawArrow(target, 400, 600, 450, 600);
199 DrawArrow(target, 600, 600, 650, 600);
200 DrawArrow(target, 525, 525, 525, 675);
201 chainField.Draw(target, 400, 710, sago::SagoTextField::Alignment::center);
202 bExit.Draw(globalData.screen, SDL_GetTicks(), xsize-buttonOffset, ysize-buttonOffset);
203 #if DEBUG
204 static sago::SagoTextField mousePos;
205 mousePos.SetHolder(&globalData.spriteHolder->GetDataHolder());
206 mousePos.SetFontSize(16);
207 mousePos.SetOutline(1, {128,128,128,255});
208 mousePos.SetText(std::string("Mouse position: ")+std::to_string(globalData.mousex)+std::string(", ")+std::to_string(globalData.mousey));
209 mousePos.Draw(target, 0,0);
210 #endif
211 }
212
213 void HelpHowtoState::Update() {
214 // If the mouse button is released, make bMouseUp equal true
215 if ( !(SDL_GetMouseState(nullptr, nullptr)&SDL_BUTTON(1)) ) {
216 bMouseUp=true;
217 }
218
219 if (SDL_GetMouseState(nullptr,nullptr)&SDL_BUTTON(1) && bMouseUp) {
220 bMouseUp = false;
221
222 //The Score button:
223 if ((globalData.mousex>xsize-buttonOffset) && (globalData.mousex<xsize-buttonOffset+bExit.GetWidth())
224 && (globalData.mousey>ysize-buttonOffset) && (globalData.mousey<ysize-buttonOffset+bExit.GetHeight())) {
225 isActive = false;
226 }
227
228 }
229 switchAnimation.Update(SDL_GetTicks());
230 }
0 /*
1 ===========================================================================
2 blockattack - Block Attack - Rise of the Blocks
3 Copyright (C) 2005-2018 Poul Sander
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see http://www.gnu.org/licenses/
17
18 Source information and contacts persons can be found at
19 https://blockattack.net
20 ===========================================================================
21 */
22
23 #ifndef HELPHOWTOSTATE_HPP
24 #define HELPHOWTOSTATE_HPP
25
26 #include "sago/GameStateInterface.hpp"
27 #include "sago/SagoTextField.hpp"
28 #include "sago/SagoTextBox.hpp"
29
30 class HelpHowtoState : public sago::GameStateInterface {
31 public:
32 HelpHowtoState();
33 HelpHowtoState(const HelpHowtoState& orig) = delete;
34 virtual ~HelpHowtoState();
35
36 bool IsActive() override;
37 void Draw(SDL_Renderer* target) override;
38 void ProcessInput(const SDL_Event& event, bool &processed) override;
39 void Update() override;
40
41 private:
42 bool isActive = true;
43 bool bMouseUp = true;
44 };
45
46 #endif /* HELPHOWTOSTATE_HPP */
47
+0
-1076
source/code/Libs/NFont.cpp less more
0 /*
1 NFont: A font class for SDL and SDL_Renderer
2 by Jonathan Dearborn
3
4 See NFont.h for license info.
5 */
6
7 #include "NFont.h"
8 #include "SDL_FontCache.h"
9
10 #include <cmath>
11 #include <cstdio>
12 #ifndef M_PI
13 #define M_PI 3.14159265358979323846
14 #endif
15
16 #include <string>
17 #include <cstring>
18 #include <list>
19 using std::string;
20 using std::list;
21
22 #ifdef NFONT_USE_SDL_GPU
23 #define NFont_Target GPU_Target
24 #define NFont_Image GPU_Image
25 #define NFont_Log GPU_LogError
26 #else
27 #define NFont_Target SDL_Renderer
28 #define NFont_Image SDL_Texture
29 #define NFont_Log SDL_Log
30 #endif
31
32 #define MIN(a,b) ((a) < (b)? (a) : (b))
33 #define MAX(a,b) ((a) > (b)? (a) : (b))
34
35 #define NFONT_BUFFER_SIZE 1024
36
37 // vsnprintf replacement adapted from Valentin Milea:
38 // http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010
39 #if defined(_MSC_VER) && _MSC_VER < 1900
40
41 #define vsnprintf c99_vsnprintf
42
43 static int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap)
44 {
45 int count = -1;
46
47 if (size != 0)
48 count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
49 if (count == -1)
50 count = _vscprintf(format, ap);
51
52 return count;
53 }
54
55 #endif
56
57
58
59 static inline SDL_Surface* createSurface24(Uint32 width, Uint32 height)
60 {
61 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
62 return SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 24, 0xFF0000, 0x00FF00, 0x0000FF, 0);
63 #else
64 return SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 24, 0x0000FF, 0x00FF00, 0xFF0000, 0);
65 #endif
66 }
67
68 static inline SDL_Surface* createSurface32(Uint32 width, Uint32 height)
69 {
70 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
71 return SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
72 #else
73 return SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
74 #endif
75 }
76
77 static inline char* copyString(const char* c)
78 {
79 if(c == NULL)
80 return NULL;
81
82 char* result = new char[strlen(c)+1];
83 strcpy(result, c);
84
85 return result;
86 }
87
88 static inline Uint32 getPixel(SDL_Surface *Surface, int x, int y)
89 {
90 Uint8* bits;
91 Uint32 bpp;
92
93 if(x < 0 || x >= Surface->w)
94 return 0; // Best I could do for errors
95
96 bpp = Surface->format->BytesPerPixel;
97 bits = ((Uint8*)Surface->pixels) + y*Surface->pitch + x*bpp;
98
99 switch (bpp)
100 {
101 case 1:
102 return *((Uint8*)Surface->pixels + y * Surface->pitch + x);
103 break;
104 case 2:
105 return *((Uint16*)Surface->pixels + y * Surface->pitch/2 + x);
106 break;
107 case 3:
108 // Endian-correct, but slower
109 Uint8 r, g, b;
110 r = *((bits)+Surface->format->Rshift/8);
111 g = *((bits)+Surface->format->Gshift/8);
112 b = *((bits)+Surface->format->Bshift/8);
113 return SDL_MapRGB(Surface->format, r, g, b);
114 break;
115 case 4:
116 return *((Uint32*)Surface->pixels + y * Surface->pitch/4 + x);
117 break;
118 }
119
120 return 0; // FIXME: Handle errors better
121 }
122
123 static inline void setPixel(SDL_Surface* surface, int x, int y, Uint32 color)
124 {
125 int bpp = surface->format->BytesPerPixel;
126 Uint8* bits = ((Uint8 *)surface->pixels) + y*surface->pitch + x*bpp;
127
128 /* Set the pixel */
129 switch(bpp)
130 {
131 case 1:
132 *((Uint8 *)(bits)) = (Uint8)color;
133 break;
134 case 2:
135 *((Uint16 *)(bits)) = (Uint16)color;
136 break;
137 case 3: { /* Format/endian independent */
138 Uint8 r,g,b;
139 r = (color >> surface->format->Rshift) & 0xFF;
140 g = (color >> surface->format->Gshift) & 0xFF;
141 b = (color >> surface->format->Bshift) & 0xFF;
142 *((bits)+surface->format->Rshift/8) = r;
143 *((bits)+surface->format->Gshift/8) = g;
144 *((bits)+surface->format->Bshift/8) = b;
145 }
146 break;
147 case 4:
148 *((Uint32 *)(bits)) = (Uint32)color;
149 break;
150 }
151 }
152
153 static inline void drawPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha)
154 {
155 if(x > surface->clip_rect.x + surface->clip_rect.w || x < surface->clip_rect.x || y > surface->clip_rect.y + surface->clip_rect.h || y < surface->clip_rect.y)
156 return;
157
158 switch (surface->format->BytesPerPixel)
159 {
160 case 1: { /* Assuming 8-bpp */
161
162 Uint8 *pixel = (Uint8 *)surface->pixels + y*surface->pitch + x;
163
164 Uint8 dR = surface->format->palette->colors[*pixel].r;
165 Uint8 dG = surface->format->palette->colors[*pixel].g;
166 Uint8 dB = surface->format->palette->colors[*pixel].b;
167 Uint8 sR = surface->format->palette->colors[color].r;
168 Uint8 sG = surface->format->palette->colors[color].g;
169 Uint8 sB = surface->format->palette->colors[color].b;
170
171 dR = dR + ((sR-dR)*alpha >> 8);
172 dG = dG + ((sG-dG)*alpha >> 8);
173 dB = dB + ((sB-dB)*alpha >> 8);
174
175 *pixel = SDL_MapRGB(surface->format, dR, dG, dB);
176
177 }
178 break;
179
180 case 2: { /* Probably 15-bpp or 16-bpp */
181
182 Uint32 Rmask = surface->format->Rmask, Gmask = surface->format->Gmask, Bmask = surface->format->Bmask, Amask = surface->format->Amask;
183 Uint16 *pixel = (Uint16 *)surface->pixels + y*surface->pitch/2 + x;
184 Uint32 dc = *pixel;
185 Uint32 R,G,B,A=0;
186
187 R = ((dc & Rmask) + (( (color & Rmask) - (dc & Rmask) ) * alpha >> 8)) & Rmask;
188 G = ((dc & Gmask) + (( (color & Gmask) - (dc & Gmask) ) * alpha >> 8)) & Gmask;
189 B = ((dc & Bmask) + (( (color & Bmask) - (dc & Bmask) ) * alpha >> 8)) & Bmask;
190 if( Amask )
191 A = ((dc & Amask) + (( (color & Amask) - (dc & Amask) ) * alpha >> 8)) & Amask;
192
193 *pixel= R | G | B | A;
194
195 }
196 break;
197
198 case 3: { /* Slow 24-bpp mode, usually not used */
199 Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
200 Uint8 rshift8=surface->format->Rshift/8;
201 Uint8 gshift8=surface->format->Gshift/8;
202 Uint8 bshift8=surface->format->Bshift/8;
203 Uint8 ashift8=surface->format->Ashift/8;
204
205
206
207 Uint8 dR, dG, dB, dA;
208 Uint8 sR, sG, sB, sA;
209
210 pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
211
212 dR = *((pix)+rshift8);
213 dG = *((pix)+gshift8);
214 dB = *((pix)+bshift8);
215 dA = *((pix)+ashift8);
216
217 sR = (color>>surface->format->Rshift)&0xff;
218 sG = (color>>surface->format->Gshift)&0xff;
219 sB = (color>>surface->format->Bshift)&0xff;
220 sA = (color>>surface->format->Ashift)&0xff;
221
222 dR = dR + ((sR-dR)*alpha >> 8);
223 dG = dG + ((sG-dG)*alpha >> 8);
224 dB = dB + ((sB-dB)*alpha >> 8);
225 dA = dA + ((sA-dA)*alpha >> 8);
226
227 *((pix)+rshift8) = dR;
228 *((pix)+gshift8) = dG;
229 *((pix)+bshift8) = dB;
230 *((pix)+ashift8) = dA;
231
232 }
233 break;
234
235 case 4: { /* Probably 32-bpp */
236 Uint32 Rmask = surface->format->Rmask, Gmask = surface->format->Gmask, Bmask = surface->format->Bmask, Amask = surface->format->Amask;
237 Uint32* pixel = (Uint32*)surface->pixels + y*surface->pitch/4 + x;
238 Uint32 source = *pixel;
239 Uint32 R,G,B,A;
240 R = color & Rmask;
241 G = color & Gmask;
242 B = color & Bmask;
243 A = 0; // keep this as 0 to avoid corruption of non-alpha surfaces
244
245 // Blend and keep dest alpha
246 if( alpha != SDL_ALPHA_OPAQUE ){
247 R = ((source & Rmask) + (( R - (source & Rmask) ) * alpha >> 8)) & Rmask;
248 G = ((source & Gmask) + (( G - (source & Gmask) ) * alpha >> 8)) & Gmask;
249 B = ((source & Bmask) + (( B - (source & Bmask) ) * alpha >> 8)) & Bmask;
250 }
251 if(Amask)
252 A = (source & Amask);
253
254 *pixel = R | G | B | A;
255 }
256 break;
257 }
258 }
259
260 static inline NFont::Rectf rectUnion(const NFont::Rectf& A, const NFont::Rectf& B)
261 {
262 float x,x2,y,y2;
263 x = MIN(A.x, B.x);
264 y = MIN(A.y, B.y);
265 x2 = MAX(A.x+A.w, B.x+B.w);
266 y2 = MAX(A.y+A.h, B.y+B.h);
267 NFont::Rectf result(x, y, MAX(0, x2 - x), MAX(0, y2 - y));
268 return result;
269 }
270
271 // Adapted from SDL_IntersectRect
272 static inline NFont::Rectf rectIntersect(const NFont::Rectf& A, const NFont::Rectf& B)
273 {
274 NFont::Rectf result;
275 float Amin, Amax, Bmin, Bmax;
276
277 // Horizontal intersection
278 Amin = A.x;
279 Amax = Amin + A.w;
280 Bmin = B.x;
281 Bmax = Bmin + B.w;
282 if(Bmin > Amin)
283 Amin = Bmin;
284 result.x = Amin;
285 if(Bmax < Amax)
286 Amax = Bmax;
287 result.w = Amax - Amin > 0 ? Amax - Amin : 0;
288
289 // Vertical intersection
290 Amin = A.y;
291 Amax = Amin + A.h;
292 Bmin = B.y;
293 Bmax = Bmin + B.h;
294 if(Bmin > Amin)
295 Amin = Bmin;
296 result.y = Amin;
297 if(Bmax < Amax)
298 Amax = Bmax;
299 result.h = Amax - Amin > 0 ? Amax - Amin : 0;
300
301 return result;
302 }
303
304 static inline SDL_Surface* copySurface(SDL_Surface *Surface)
305 {
306 return SDL_ConvertSurface(Surface, Surface->format, Surface->flags);
307 }
308
309
310
311
312
313
314
315
316
317 NFont::Color::Color()
318 : r(0), g(0), b(0), a(255)
319 {}
320 NFont::Color::Color(Uint8 r, Uint8 g, Uint8 b)
321 : r(r), g(g), b(b), a(255)
322 {}
323 NFont::Color::Color(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
324 : r(r), g(g), b(b), a(a)
325 {}
326 NFont::Color::Color(const SDL_Color& color)
327 : r(color.r), g(color.g), b(color.b), a(color.a)
328 {}
329
330 NFont::Color& NFont::Color::rgb(Uint8 R, Uint8 G, Uint8 B)
331 {
332 r = R;
333 g = G;
334 b = B;
335
336 return *this;
337 }
338
339 NFont::Color& NFont::Color::rgba(Uint8 R, Uint8 G, Uint8 B, Uint8 A)
340 {
341 r = R;
342 g = G;
343 b = B;
344 a = A;
345
346 return *this;
347 }
348
349 NFont::Color& NFont::Color::color(const SDL_Color& color)
350 {
351 r = color.r;
352 g = color.g;
353 b = color.b;
354 a = color.a;
355
356 return *this;
357 }
358
359 SDL_Color NFont::Color::to_SDL_Color() const
360 {
361 SDL_Color c = {r, g, b, a};
362 return c;
363 }
364
365
366
367
368 NFont::Rectf::Rectf()
369 : x(0), y(0), w(0), h(0)
370 {}
371
372 NFont::Rectf::Rectf(float x, float y)
373 : x(x), y(y), w(0), h(0)
374 {}
375
376 NFont::Rectf::Rectf(float x, float y, float w, float h)
377 : x(x), y(y), w(w), h(h)
378 {}
379
380 NFont::Rectf::Rectf(const SDL_Rect& rect)
381 : x(rect.x), y(rect.y), w(rect.w), h(rect.h)
382 {}
383
384 #ifdef NFONT_USE_SDL_GPU
385 NFont::Rectf::Rectf(const GPU_Rect& rect)
386 : x(rect.x), y(rect.y), w(rect.w), h(rect.h)
387 {}
388 #endif
389
390 SDL_Rect NFont::Rectf::to_SDL_Rect() const
391 {
392 SDL_Rect r = {int(x), int(y), int(w), int(h)};
393 return r;
394 }
395
396 #ifdef NFONT_USE_SDL_GPU
397 GPU_Rect NFont::Rectf::to_GPU_Rect() const
398 {
399 return GPU_MakeRect(x, y, w, h);
400 }
401 #endif
402
403
404
405
406
407
408
409 char* NFont::buffer = NULL; // Shared buffer for efficient drawing
410
411
412 // Constructors
413 NFont::NFont()
414 {
415 init();
416 }
417
418
419 #ifdef NFONT_USE_SDL_GPU
420 NFont::NFont(TTF_Font* ttf)
421 {
422 init();
423 load(ttf, FC_GetDefaultColor(font));
424 }
425 NFont::NFont(TTF_Font* ttf, const NFont::Color& color)
426 {
427 init();
428 load(ttf, color);
429 }
430 NFont::NFont(const char* filename_ttf, Uint32 pointSize)
431 {
432 init();
433 load(filename_ttf, pointSize);
434 }
435 NFont::NFont(const char* filename_ttf, Uint32 pointSize, const NFont::Color& color, int style)
436 {
437 init();
438 load(filename_ttf, pointSize, color, style);
439 }
440 NFont::NFont(SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, const NFont::Color& color, int style)
441 {
442 init();
443 load(file_rwops_ttf, own_rwops, pointSize, color, style);
444 }
445
446 #else
447
448 NFont::NFont(NFont_Target* renderer, TTF_Font* ttf)
449 {
450 init();
451 load(renderer, ttf, FC_GetDefaultColor(font));
452 }
453 NFont::NFont(NFont_Target* renderer, TTF_Font* ttf, const NFont::Color& color)
454 {
455 init();
456 load(renderer, ttf, color);
457 }
458 NFont::NFont(NFont_Target* renderer, const char* filename_ttf, Uint32 pointSize)
459 {
460 init();
461 load(renderer, filename_ttf, pointSize);
462 }
463 NFont::NFont(NFont_Target* renderer, const char* filename_ttf, Uint32 pointSize, const NFont::Color& color, int style)
464 {
465 init();
466 load(renderer, filename_ttf, pointSize, color, style);
467 }
468 NFont::NFont(NFont_Target* renderer, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, const NFont::Color& color, int style)
469 {
470 init();
471 load(renderer, file_rwops_ttf, own_rwops, pointSize, color, style);
472 }
473 #endif
474
475
476 NFont::~NFont()
477 {
478 FC_FreeFont(font);
479 }
480
481 void NFont::init()
482 {
483 font = FC_CreateFont();
484
485 if(buffer == NULL)
486 buffer = new char[NFONT_BUFFER_SIZE];
487 }
488
489
490
491
492
493
494 void NFont::setLoadingString(const char* str)
495 {
496 FC_SetLoadingString(font, str);
497 }
498
499 #ifdef NFONT_USE_SDL_GPU
500 bool NFont::load(TTF_Font* ttf)
501 #else
502 bool NFont::load(NFont_Target* renderer, TTF_Font* ttf)
503 #endif
504 {
505 #ifdef NFONT_USE_SDL_GPU
506 return load(ttf, FC_GetDefaultColor(font));
507 #else
508 return load(renderer, ttf, Color(0,0,0,255));
509 #endif
510 }
511
512 #ifdef NFONT_USE_SDL_GPU
513 bool NFont::load(TTF_Font* ttf, const NFont::Color& color)
514 #else
515 bool NFont::load(NFont_Target* renderer, TTF_Font* ttf, const NFont::Color& color)
516 #endif
517 {
518 if(ttf == NULL)
519 return false;
520
521 #ifndef NFONT_USE_SDL_GPU
522 if(renderer == NULL)
523 return false;
524 #endif
525
526 FC_ClearFont(font);
527 #ifdef NFONT_USE_SDL_GPU
528 return FC_LoadFontFromTTF(font, ttf, color.to_SDL_Color());
529 #else
530 return FC_LoadFontFromTTF(font, renderer, ttf, color.to_SDL_Color());
531 #endif
532 }
533
534 #ifdef NFONT_USE_SDL_GPU
535 bool NFont::load(const char* filename_ttf, Uint32 pointSize)
536 #else
537 bool NFont::load(NFont_Target* renderer, const char* filename_ttf, Uint32 pointSize)
538 #endif
539 {
540 #ifdef NFONT_USE_SDL_GPU
541 return load(filename_ttf, pointSize, Color(0,0,0,255));
542 #else
543 return load(renderer, filename_ttf, pointSize, Color(0,0,0,255));
544 #endif
545 }
546
547 #ifdef NFONT_USE_SDL_GPU
548 bool NFont::load(const char* filename_ttf, Uint32 pointSize, const NFont::Color& color, int style)
549 #else
550 bool NFont::load(NFont_Target* renderer, const char* filename_ttf, Uint32 pointSize, const NFont::Color& color, int style)
551 #endif
552 {
553 FC_ClearFont(font);
554 #ifdef NFONT_USE_SDL_GPU
555 return FC_LoadFont(font, filename_ttf, pointSize, color.to_SDL_Color(), style);
556 #else
557 return FC_LoadFont(font, renderer, filename_ttf, pointSize, color.to_SDL_Color(), style);
558 #endif
559 }
560
561 #ifdef NFONT_USE_SDL_GPU
562 bool NFont::load(SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, const NFont::Color& color, int style)
563 #else
564 bool NFont::load(NFont_Target* renderer, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, const NFont::Color& color, int style)
565 #endif
566 {
567 FC_ClearFont(font);
568 #ifdef NFONT_USE_SDL_GPU
569 return FC_LoadFont_RW(font, file_rwops_ttf, own_rwops, pointSize, color.to_SDL_Color(), style);
570 #else
571 return FC_LoadFont_RW(font, renderer, file_rwops_ttf, own_rwops, pointSize, color.to_SDL_Color(), style);
572 #endif
573 }
574
575
576
577 void NFont::free()
578 {
579 FC_ClearFont(font);
580 }
581
582
583
584 NFont::Rectf NFont::draw(NFont_Target* dest, float x, float y, const char* formatted_text, ...)
585 {
586 if(formatted_text == NULL)
587 return Rectf(x, y, 0, 0);
588
589 va_list lst;
590 va_start(lst, formatted_text);
591 vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst);
592 va_end(lst);
593
594 return FC_Draw(font, dest, x, y, "%s", buffer);
595 }
596
597 /*static int getIndexPastWidth(const char* text, int width, const int* charWidth)
598 {
599 int charnum;
600 int len = strlen(text);
601
602 for (int index = 0; index < len; index++)
603 {
604 char c = text[index];
605 charnum = (unsigned char)(c) - 33;
606
607 // spaces and nonprintable characters
608 if (c == ' ' || charnum > 222)
609 {
610 width -= charWidth[0];
611 }
612 else
613 width -= charWidth[charnum];
614
615 if(width <= 0)
616 return index;
617 }
618 return 0;
619 }*/
620
621
622
623 /*static list<string> explode(const string& str, char delimiter)
624 {
625 list<string> result;
626
627 size_t oldPos = 0;
628 size_t pos = str.find_first_of(delimiter);
629 while(pos != string::npos)
630 {
631 result.push_back(str.substr(oldPos, pos - oldPos));
632 oldPos = pos+1;
633 pos = str.find_first_of(delimiter, oldPos);
634 }
635
636 result.push_back(str.substr(oldPos, string::npos));
637
638 return result;
639 }*/
640
641 NFont::Rectf NFont::drawBox(NFont_Target* dest, const Rectf& box, const char* formatted_text, ...)
642 {
643 if(formatted_text == NULL)
644 return Rectf(box.x, box.y, 0, 0);
645
646 va_list lst;
647 va_start(lst, formatted_text);
648 vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst);
649 va_end(lst);
650
651 #ifdef NFONT_USE_SDL_GPU
652 return FC_DrawBox(font, dest, box.to_GPU_Rect(), "%s", buffer);
653 #else
654 return FC_DrawBox(font, dest, box.to_SDL_Rect(), "%s", buffer);
655 #endif
656 }
657
658 static FC_AlignEnum translate_enum_NFont_to_FC(NFont::AlignEnum align)
659 {
660 switch(align)
661 {
662 case NFont::LEFT:
663 return FC_ALIGN_LEFT;
664 case NFont::CENTER:
665 return FC_ALIGN_CENTER;
666 case NFont::RIGHT:
667 return FC_ALIGN_RIGHT;
668 default:
669 return FC_ALIGN_LEFT;
670 }
671 }
672
673 NFont::Rectf NFont::drawBox(NFont_Target* dest, const Rectf& box, AlignEnum align, const char* formatted_text, ...)
674 {
675 if(formatted_text == NULL)
676 return Rectf(box.x, box.y, 0, 0);
677
678 va_list lst;
679 va_start(lst, formatted_text);
680 vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst);
681 va_end(lst);
682
683 #ifdef NFONT_USE_SDL_GPU
684 return FC_DrawBoxAlign(font, dest, box.to_GPU_Rect(), translate_enum_NFont_to_FC(align), "%s", buffer);
685 #else
686 return FC_DrawBoxAlign(font, dest, box.to_SDL_Rect(), translate_enum_NFont_to_FC(align), "%s", buffer);
687 #endif
688 }
689
690 NFont::Rectf NFont::drawBox(NFont_Target* dest, const Rectf& box, const Scale& scale, const char* formatted_text, ...)
691 {
692 if(formatted_text == NULL)
693 return Rectf(box.x, box.y, 0, 0);
694
695 va_list lst;
696 va_start(lst, formatted_text);
697 vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst);
698 va_end(lst);
699
700 #ifdef NFONT_USE_SDL_GPU
701 return FC_DrawBoxScale(font, dest, box.to_GPU_Rect(), FC_MakeScale(scale.x, scale.y), "%s", buffer);
702 #else
703 return FC_DrawBoxScale(font, dest, box.to_SDL_Rect(), FC_MakeScale(scale.x, scale.y), "%s", buffer);
704 #endif
705 }
706
707 NFont::Rectf NFont::drawBox(NFont_Target* dest, const Rectf& box, const Color& color, const char* formatted_text, ...)
708 {
709 if(formatted_text == NULL)
710 return Rectf(box.x, box.y, 0, 0);
711
712 va_list lst;
713 va_start(lst, formatted_text);
714 vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst);
715 va_end(lst);
716
717 #ifdef NFONT_USE_SDL_GPU
718 return FC_DrawBoxColor(font, dest, box.to_GPU_Rect(), color.to_SDL_Color(), "%s", buffer);
719 #else
720 return FC_DrawBoxColor(font, dest, box.to_SDL_Rect(), color.to_SDL_Color(), "%s", buffer);
721 #endif
722 }
723
724 NFont::Rectf NFont::drawBox(NFont_Target* dest, const Rectf& box, const Effect& effect, const char* formatted_text, ...)
725 {
726 if(formatted_text == NULL)
727 return Rectf(box.x, box.y, 0, 0);
728
729 va_list lst;
730 va_start(lst, formatted_text);
731 vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst);
732 va_end(lst);
733
734 #ifdef NFONT_USE_SDL_GPU
735 return FC_DrawBoxEffect(font, dest, box.to_GPU_Rect(), FC_MakeEffect(translate_enum_NFont_to_FC(effect.alignment), FC_MakeScale(effect.scale.x, effect.scale.y), effect.color.to_SDL_Color()), "%s", buffer);
736 #else
737 return FC_DrawBoxEffect(font, dest, box.to_SDL_Rect(), FC_MakeEffect(translate_enum_NFont_to_FC(effect.alignment), FC_MakeScale(effect.scale.x, effect.scale.y), effect.color.to_SDL_Color()), "%s", buffer);
738 #endif
739 }
740
741 NFont::Rectf NFont::drawColumn(NFont_Target* dest, float x, float y, Uint16 width, const char* formatted_text, ...)
742 {
743 if(formatted_text == NULL)
744 return Rectf(x, y, 0, 0);
745
746 va_list lst;
747 va_start(lst, formatted_text);
748 vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst);
749 va_end(lst);
750
751 return FC_DrawColumn(font, dest, x, y, width, "%s", buffer);
752 }
753
754 NFont::Rectf NFont::drawColumn(NFont_Target* dest, float x, float y, Uint16 width, AlignEnum align, const char* formatted_text, ...)
755 {
756 if(formatted_text == NULL)
757 return Rectf(x, y, 0, 0);
758
759 va_list lst;
760 va_start(lst, formatted_text);
761 vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst);
762 va_end(lst);
763
764 return FC_DrawColumnAlign(font, dest, x, y, width, translate_enum_NFont_to_FC(align), "%s", buffer);
765 }
766
767 NFont::Rectf NFont::drawColumn(NFont_Target* dest, float x, float y, Uint16 width, const Scale& scale, const char* formatted_text, ...)
768 {
769 if(formatted_text == NULL)
770 return Rectf(x, y, 0, 0);
771
772 va_list lst;
773 va_start(lst, formatted_text);
774 vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst);
775 va_end(lst);
776
777 return FC_DrawColumnScale(font, dest, x, y, width, FC_MakeScale(scale.x, scale.y), "%s", buffer);
778 }
779
780 NFont::Rectf NFont::drawColumn(NFont_Target* dest, float x, float y, Uint16 width, const Color& color, const char* formatted_text, ...)
781 {
782 if(formatted_text == NULL)
783 return Rectf(x, y, 0, 0);
784
785 va_list lst;
786 va_start(lst, formatted_text);
787 vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst);
788 va_end(lst);
789
790 return FC_DrawColumnColor(font, dest, x, y, width, color.to_SDL_Color(), "%s", buffer);
791 }
792
793 NFont::Rectf NFont::drawColumn(NFont_Target* dest, float x, float y, Uint16 width, const Effect& effect, const char* formatted_text, ...)
794 {
795 if(formatted_text == NULL)
796 return Rectf(x, y, 0, 0);
797
798 va_list lst;
799 va_start(lst, formatted_text);
800 vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst);
801 va_end(lst);
802
803 #ifdef NFONT_USE_SDL_GPU
804 return FC_DrawColumnEffect(font, dest, x, y, width, FC_MakeEffect(translate_enum_NFont_to_FC(effect.alignment), FC_MakeScale(effect.scale.x, effect.scale.y), effect.color.to_SDL_Color()), "%s", buffer);
805 #else
806 return FC_DrawColumnEffect(font, dest, x, y, width, FC_MakeEffect(translate_enum_NFont_to_FC(effect.alignment), FC_MakeScale(effect.scale.x, effect.scale.y), effect.color.to_SDL_Color()), "%s", buffer);
807 #endif
808 }
809
810
811
812 NFont::Rectf NFont::draw(NFont_Target* dest, float x, float y, const Scale& scale, const char* formatted_text, ...)
813 {
814 if(formatted_text == NULL)
815 return Rectf(x, y, 0, 0);
816
817 va_list lst;
818 va_start(lst, formatted_text);
819 vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst);
820 va_end(lst);
821
822 return FC_DrawScale(font, dest, x, y, FC_MakeScale(scale.x, scale.y), "%s", buffer);
823 }
824
825 NFont::Rectf NFont::draw(NFont_Target* dest, float x, float y, AlignEnum align, const char* formatted_text, ...)
826 {
827 if(formatted_text == NULL)
828 return Rectf(x, y, 0, 0);
829
830 va_list lst;
831 va_start(lst, formatted_text);
832 vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst);
833 va_end(lst);
834
835 return FC_DrawAlign(font, dest, x, y, translate_enum_NFont_to_FC(align), "%s", buffer);
836 }
837
838 NFont::Rectf NFont::draw(NFont_Target* dest, float x, float y, const Color& color, const char* formatted_text, ...)
839 {
840 if(formatted_text == NULL)
841 return Rectf(x, y, 0, 0);
842
843 va_list lst;
844 va_start(lst, formatted_text);
845 vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst);
846 va_end(lst);
847
848 return FC_DrawColor(font, dest, x, y, color.to_SDL_Color(), "%s", buffer);
849 }
850
851
852 NFont::Rectf NFont::draw(NFont_Target* dest, float x, float y, const Effect& effect, const char* formatted_text, ...)
853 {
854 if(formatted_text == NULL)
855 return Rectf(x, y, 0, 0);
856
857 va_list lst;
858 va_start(lst, formatted_text);
859 vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst);
860 va_end(lst);
861
862 return FC_DrawEffect(font, dest, x, y, FC_MakeEffect(translate_enum_NFont_to_FC(effect.alignment), FC_MakeScale(effect.scale.x, effect.scale.y), effect.color.to_SDL_Color()), "%s", buffer);
863 }
864
865
866
867
868 // Getters
869
870
871 NFont::FilterEnum NFont::getFilterMode() const
872 {
873 FC_FilterEnum f = FC_GetFilterMode(font);
874 if(f == FC_FILTER_LINEAR)
875 return NFont::LINEAR;
876 return NFont::NEAREST;
877 }
878
879 Uint16 NFont::getHeight() const
880 {
881 return FC_GetLineHeight(font);
882 }
883
884 Uint16 NFont::getHeight(const char* formatted_text, ...) const
885 {
886 if(formatted_text == NULL)
887 return 0;
888
889 va_list lst;
890 va_start(lst, formatted_text);
891 vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst);
892 va_end(lst);
893
894 return FC_GetHeight(font, "%s", buffer);
895 }
896
897 Uint16 NFont::getWidth(const char* formatted_text, ...)
898 {
899 if (formatted_text == NULL)
900 return 0;
901
902 va_list lst;
903 va_start(lst, formatted_text);
904 vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst);
905 va_end(lst);
906
907 return FC_GetWidth(font, "%s", buffer);
908 }
909
910
911 NFont::Rectf NFont::getCharacterOffset(Uint16 position_index, int column_width, const char* formatted_text, ...)
912 {
913 if(formatted_text == NULL)
914 return Rectf(0,0,0,0);
915
916 va_list lst;
917 va_start(lst, formatted_text);
918 vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst);
919 va_end(lst);
920
921 return FC_GetCharacterOffset(font, position_index, column_width, "%s", buffer);
922 }
923
924 // Given an offset (x,y) from the text draw position (the upper-left corner), returns the character position (UTF-8 index)
925 Uint16 NFont::getPositionFromOffset(float x, float y, int column_width, NFont::AlignEnum align, const char* formatted_text, ...)
926 {
927 if(formatted_text == NULL)
928 return 0;
929
930 va_list lst;
931 va_start(lst, formatted_text);
932 vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst);
933 va_end(lst);
934
935 return FC_GetPositionFromOffset(font, x, y, column_width, translate_enum_NFont_to_FC(align), "%s", buffer);
936 }
937
938
939 Uint16 NFont::getColumnHeight(Uint16 width, const char* formatted_text, ...)
940 {
941 if(formatted_text == NULL || width == 0)
942 return 0;
943
944 va_list lst;
945 va_start(lst, formatted_text);
946 vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst);
947 va_end(lst);
948
949 return FC_GetColumnHeight(font, width, "%s", buffer);
950 }
951
952 int NFont::getAscent(const char character)
953 {
954 return FC_GetAscent(font, "%c", character);
955 }
956
957 int NFont::getAscent() const
958 {
959 return FC_GetAscent(font, NULL);
960 }
961
962 int NFont::getAscent(const char* formatted_text, ...)
963 {
964 if(formatted_text == NULL)
965 return FC_GetAscent(font, NULL);
966
967 va_list lst;
968 va_start(lst, formatted_text);
969 vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst);
970 va_end(lst);
971
972 return FC_GetAscent(font, "%s", buffer);
973 }
974
975 int NFont::getDescent(const char character)
976 {
977 return FC_GetDescent(font, "%c", character);
978 }
979
980 int NFont::getDescent() const
981 {
982 return FC_GetDescent(font, NULL);
983 }
984
985 int NFont::getDescent(const char* formatted_text, ...)
986 {
987 if(formatted_text == NULL)
988 return FC_GetDescent(font, NULL);
989
990 va_list lst;
991 va_start(lst, formatted_text);
992 vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst);
993 va_end(lst);
994
995 return FC_GetDescent(font, "%s", buffer);
996 }
997
998 int NFont::getSpacing() const
999 {
1000 return FC_GetSpacing(font);
1001 }
1002
1003 int NFont::getLineSpacing() const
1004 {
1005 return FC_GetLineSpacing(font);
1006 }
1007
1008 Uint16 NFont::getBaseline() const
1009 {
1010 return FC_GetBaseline(font);
1011 }
1012
1013 Uint16 NFont::getMaxWidth() const
1014 {
1015 return FC_GetMaxWidth(font);
1016 }
1017
1018 NFont::Color NFont::getDefaultColor() const
1019 {
1020 return FC_GetDefaultColor(font);
1021 }
1022
1023
1024 int NFont::getNumCacheLevels() const
1025 {
1026 return FC_GetNumCacheLevels(font);
1027 }
1028
1029 NFont_Image* NFont::getCacheLevel(int level) const
1030 {
1031 return FC_GetGlyphCacheLevel(font, level);
1032 }
1033
1034
1035
1036
1037
1038 // Setters
1039
1040 void NFont::setFilterMode(NFont::FilterEnum filter)
1041 {
1042 if(filter == NFont::LINEAR)
1043 FC_SetFilterMode(font, FC_FILTER_LINEAR);
1044 else
1045 FC_SetFilterMode(font, FC_FILTER_NEAREST);
1046 }
1047
1048 void NFont::setSpacing(int LetterSpacing)
1049 {
1050 FC_SetSpacing(font, LetterSpacing);
1051 }
1052
1053 void NFont::setLineSpacing(int LineSpacing)
1054 {
1055 FC_SetLineSpacing(font, LineSpacing);
1056 }
1057
1058 void NFont::setBaseline()
1059 {
1060
1061 }
1062
1063 void NFont::setDefaultColor(const Color& color)
1064 {
1065 FC_SetDefaultColor(font, color.to_SDL_Color());
1066 }
1067
1068 void NFont::enableTTFOwnership()
1069 {
1070
1071 }
1072
1073
1074
1075
+0
-320
source/code/Libs/NFont.h less more
0 /*
1 NFont v5.0.0: A font class for SDL and SDL_Renderer
2 by Jonathan Dearborn
3 Dedicated to the memory of Florian Hufsky
4
5 License:
6 The short:
7 Use it however you'd like, but keep the copyright and license notice
8 whenever these files or parts of them are distributed in uncompiled form.
9
10 The long:
11 Copyright (c) 2016 Jonathan Dearborn
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in
21 all copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 THE SOFTWARE.
30 */
31
32 #ifndef _NFONT_H__
33 #define _NFONT_H__
34
35 #include "SDL.h"
36
37 #if defined(FC_USE_SDL_GPU) && !defined(NFONT_USE_SDL_GPU)
38 #define NFONT_USE_SDL_GPU
39 #endif
40
41 #ifdef NFONT_USE_SDL_GPU
42 #include "SDL_gpu.h"
43 #endif
44
45 #ifndef NFONT_FORMAT
46
47 #if ( (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) )
48 #define NFONT_FORMAT(X) __attribute__ ((format (printf, X, X+1)))
49 #else
50 #define NFONT_FORMAT(X)
51 #endif
52
53 #endif
54
55 #include "stdarg.h"
56
57 // Let's pretend this exists...
58 #ifndef TTF_STYLE_OUTLINE
59 #define TTF_STYLE_OUTLINE 16
60 #endif
61
62 struct FC_Font;
63
64 typedef struct _TTF_Font TTF_Font;
65
66 // Differences between SDL_Renderer and SDL_gpu
67 #ifdef NFONT_USE_SDL_GPU
68 #define NFont_Image GPU_Image
69 #else
70 #define NFont_Image SDL_Texture
71 #endif
72
73 #if defined(NFONT_DLL) || defined(NFONT_DLL_EXPORT)
74 #ifdef NFONT_DLL_EXPORT
75 #define NFONT_EXPORT __declspec(dllexport)
76 #else
77 #define NFONT_EXPORT __declspec(dllimport)
78 #endif
79 #else
80 #define NFONT_EXPORT
81 #endif
82
83 class NFONT_EXPORT NFont
84 {
85 public:
86
87 class NFONT_EXPORT Color
88 {
89 public:
90
91 Uint8 r, g, b, a;
92
93 Color();
94 Color(Uint8 r, Uint8 g, Uint8 b);
95 Color(Uint8 r, Uint8 g, Uint8 b, Uint8 a);
96 Color(const SDL_Color& color);
97
98 Color& rgb(Uint8 R, Uint8 G, Uint8 B);
99 Color& rgba(Uint8 R, Uint8 G, Uint8 B, Uint8 A);
100 Color& color(const SDL_Color& color);
101
102 SDL_Color to_SDL_Color() const;
103 };
104
105 class NFONT_EXPORT Rectf
106 {
107 public:
108 float x, y;
109 float w, h;
110
111 Rectf();
112 Rectf(float x, float y);
113 Rectf(float x, float y, float w, float h);
114 Rectf(const SDL_Rect& rect);
115
116 SDL_Rect to_SDL_Rect() const;
117
118 #ifdef NFONT_USE_SDL_GPU
119 Rectf(const GPU_Rect& rect);
120 GPU_Rect to_GPU_Rect() const;
121 #endif
122 };
123
124
125 enum AlignEnum {LEFT, CENTER, RIGHT};
126 enum FilterEnum {NEAREST, LINEAR};
127
128 class NFONT_EXPORT Scale
129 {
130 public:
131
132 float x;
133 float y;
134
135 enum ScaleTypeEnum {NEAREST};
136 ScaleTypeEnum type;
137
138 Scale()
139 : x(1.0f), y(1.0f), type(NEAREST)
140 {}
141 Scale(float xy)
142 : x(xy), y(xy), type(NEAREST)
143 {}
144 Scale(float xy, ScaleTypeEnum type)
145 : x(xy), y(xy), type(type)
146 {}
147 Scale(float x, float y)
148 : x(x), y(y), type(NEAREST)
149 {}
150 Scale(float x, float y, ScaleTypeEnum type)
151 : x(x), y(y), type(type)
152 {}
153 };
154
155 class NFONT_EXPORT Effect
156 {
157 public:
158 AlignEnum alignment;
159 Scale scale;
160 bool use_color;
161 Color color;
162
163 Effect()
164 : alignment(LEFT), use_color(false), color(255, 255, 255, 255)
165 {}
166
167 Effect(const Scale& scale)
168 : alignment(LEFT), scale(scale), use_color(false), color(255, 255, 255, 255)
169 {}
170 Effect(AlignEnum alignment)
171 : alignment(alignment), use_color(false), color(255, 255, 255, 255)
172 {}
173 Effect(const Color& color)
174 : alignment(LEFT), use_color(true), color(color)
175 {}
176
177 Effect(AlignEnum alignment, const Scale& scale)
178 : alignment(alignment), scale(scale), use_color(false), color(255, 255, 255, 255)
179 {}
180 Effect(AlignEnum alignment, const Color& color)
181 : alignment(alignment), use_color(true), color(color)
182 {}
183 Effect(const Scale& scale, const Color& color)
184 : alignment(LEFT), scale(scale), use_color(true), color(color)
185 {}
186 Effect(AlignEnum alignment, const Scale& scale, const Color& color)
187 : alignment(alignment), scale(scale), use_color(true), color(color)
188 {}
189 };
190
191
192 // Constructors
193 NFont();
194 NFont(const NFont& font);
195 #ifdef NFONT_USE_SDL_GPU
196 NFont(SDL_Surface* src);
197 NFont(TTF_Font* ttf);
198 NFont(TTF_Font* ttf, const NFont::Color& color);
199 NFont(const char* filename_ttf, Uint32 pointSize);
200 NFont(const char* filename_ttf, Uint32 pointSize, const NFont::Color& color, int style = 0);
201 NFont(SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, const NFont::Color& color, int style = 0);
202 #else
203 NFont(SDL_Renderer* renderer, SDL_Surface* src);
204 NFont(SDL_Renderer* renderer, TTF_Font* ttf);
205 NFont(SDL_Renderer* renderer, TTF_Font* ttf, const NFont::Color& color);
206 NFont(SDL_Renderer* renderer, const char* filename_ttf, Uint32 pointSize);
207 NFont(SDL_Renderer* renderer, const char* filename_ttf, Uint32 pointSize, const NFont::Color& color, int style = 0);
208 NFont(SDL_Renderer* renderer, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, const NFont::Color& color, int style = 0);
209 #endif
210
211 ~NFont();
212
213 NFont& operator=(const NFont& font);
214
215 // Loading
216 void setLoadingString(const char* str);
217
218 #ifdef NFONT_USE_SDL_GPU
219 bool load(SDL_Surface* FontSurface);
220 bool load(TTF_Font* ttf);
221 bool load(TTF_Font* ttf, const NFont::Color& color);
222 bool load(const char* filename_ttf, Uint32 pointSize);
223 bool load(const char* filename_ttf, Uint32 pointSize, const NFont::Color& color, int style = 0);
224 bool load(SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, const NFont::Color& color, int style = 0);
225 #else
226 bool load(SDL_Renderer* renderer, SDL_Surface* FontSurface);
227 bool load(SDL_Renderer* renderer, TTF_Font* ttf);
228 bool load(SDL_Renderer* renderer, TTF_Font* ttf, const NFont::Color& color);
229 bool load(SDL_Renderer* renderer, const char* filename_ttf, Uint32 pointSize);
230 bool load(SDL_Renderer* renderer, const char* filename_ttf, Uint32 pointSize, const NFont::Color& color, int style = 0);
231 bool load(SDL_Renderer* renderer, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, const NFont::Color& color, int style = 0);
232 #endif
233
234 void free();
235
236 // Drawing
237 #ifdef NFONT_USE_SDL_GPU
238 Rectf draw(GPU_Target* dest, float x, float y, const char* formatted_text, ...) NFONT_FORMAT(5);
239 Rectf draw(GPU_Target* dest, float x, float y, AlignEnum align, const char* formatted_text, ...) NFONT_FORMAT(6);
240 Rectf draw(GPU_Target* dest, float x, float y, const Scale& scale, const char* formatted_text, ...) NFONT_FORMAT(6);
241 Rectf draw(GPU_Target* dest, float x, float y, const Color& color, const char* formatted_text, ...) NFONT_FORMAT(6);
242 Rectf draw(GPU_Target* dest, float x, float y, const Effect& effect, const char* formatted_text, ...) NFONT_FORMAT(6);
243
244 Rectf drawBox(GPU_Target* dest, const Rectf& box, const char* formatted_text, ...) NFONT_FORMAT(4);
245 Rectf drawBox(GPU_Target* dest, const Rectf& box, AlignEnum align, const char* formatted_text, ...) NFONT_FORMAT(5);
246 Rectf drawBox(GPU_Target* dest, const Rectf& box, const Scale& scale, const char* formatted_text, ...) NFONT_FORMAT(5);
247 Rectf drawBox(GPU_Target* dest, const Rectf& box, const Color& color, const char* formatted_text, ...) NFONT_FORMAT(5);
248 Rectf drawBox(GPU_Target* dest, const Rectf& box, const Effect& effect, const char* formatted_text, ...) NFONT_FORMAT(5);
249
250 Rectf drawColumn(GPU_Target* dest, float x, float y, Uint16 width, const char* formatted_text, ...) NFONT_FORMAT(6);
251 Rectf drawColumn(GPU_Target* dest, float x, float y, Uint16 width, AlignEnum align, const char* formatted_text, ...) NFONT_FORMAT(7);
252 Rectf drawColumn(GPU_Target* dest, float x, float y, Uint16 width, const Scale& scale, const char* formatted_text, ...) NFONT_FORMAT(7);
253 Rectf drawColumn(GPU_Target* dest, float x, float y, Uint16 width, const Color& color, const char* formatted_text, ...) NFONT_FORMAT(7);
254 Rectf drawColumn(GPU_Target* dest, float x, float y, Uint16 width, const Effect& effect, const char* formatted_text, ...) NFONT_FORMAT(7);
255 #else
256 Rectf draw(SDL_Renderer* dest, float x, float y, const char* formatted_text, ...) NFONT_FORMAT(5);
257 Rectf draw(SDL_Renderer* dest, float x, float y, AlignEnum align, const char* formatted_text, ...) NFONT_FORMAT(6);
258 Rectf draw(SDL_Renderer* dest, float x, float y, const Scale& scale, const char* formatted_text, ...) NFONT_FORMAT(6);
259 Rectf draw(SDL_Renderer* dest, float x, float y, const Color& color, const char* formatted_text, ...) NFONT_FORMAT(6);
260 Rectf draw(SDL_Renderer* dest, float x, float y, const Effect& effect, const char* formatted_text, ...) NFONT_FORMAT(6);
261
262 Rectf drawBox(SDL_Renderer* dest, const Rectf& box, const char* formatted_text, ...) NFONT_FORMAT(4);
263 Rectf drawBox(SDL_Renderer* dest, const Rectf& box, AlignEnum align, const char* formatted_text, ...) NFONT_FORMAT(5);
264 Rectf drawBox(SDL_Renderer* dest, const Rectf& box, const Scale& scale, const char* formatted_text, ...) NFONT_FORMAT(5);
265 Rectf drawBox(SDL_Renderer* dest, const Rectf& box, const Color& color, const char* formatted_text, ...) NFONT_FORMAT(5);
266 Rectf drawBox(SDL_Renderer* dest, const Rectf& box, const Effect& effect, const char* formatted_text, ...) NFONT_FORMAT(5);
267
268 Rectf drawColumn(SDL_Renderer* dest, float x, float y, Uint16 width, const char* formatted_text, ...) NFONT_FORMAT(6);
269 Rectf drawColumn(SDL_Renderer* dest, float x, float y, Uint16 width, AlignEnum align, const char* formatted_text, ...) NFONT_FORMAT(7);
270 Rectf drawColumn(SDL_Renderer* dest, float x, float y, Uint16 width, const Scale& scale, const char* formatted_text, ...) NFONT_FORMAT(7);
271 Rectf drawColumn(SDL_Renderer* dest, float x, float y, Uint16 width, const Color& color, const char* formatted_text, ...) NFONT_FORMAT(7);
272 Rectf drawColumn(SDL_Renderer* dest, float x, float y, Uint16 width, const Effect& effect, const char* formatted_text, ...) NFONT_FORMAT(7);
273 #endif
274
275 // Getters
276 FilterEnum getFilterMode() const;
277 Uint16 getHeight() const;
278 Uint16 getHeight(const char* formatted_text, ...) const NFONT_FORMAT(2);
279 Uint16 getWidth(const char* formatted_text, ...) NFONT_FORMAT(2);
280 Rectf getCharacterOffset(Uint16 position_index, int column_width, const char* formatted_text, ...) NFONT_FORMAT(4);
281 Uint16 getPositionFromOffset(float x, float y, int column_width, NFont::AlignEnum align, const char* formatted_text, ...) NFONT_FORMAT(6);
282 Uint16 getColumnHeight(Uint16 width, const char* formatted_text, ...) NFONT_FORMAT(3);
283 int getSpacing() const;
284 int getLineSpacing() const;
285 Uint16 getBaseline() const;
286 int getAscent() const;
287 int getAscent(const char character);
288 int getAscent(const char* formatted_text, ...) NFONT_FORMAT(2);
289 int getDescent() const;
290 int getDescent(const char character);
291 int getDescent(const char* formatted_text, ...) NFONT_FORMAT(2);
292 Uint16 getMaxWidth() const;
293 Color getDefaultColor() const;
294
295 int getNumCacheLevels() const;
296 NFont_Image* getCacheLevel(int level) const;
297
298 // Setters
299 void setFilterMode(FilterEnum filter);
300 void setSpacing(int LetterSpacing);
301 void setLineSpacing(int LineSpacing);
302 void setBaseline();
303 void setBaseline(Uint16 Baseline);
304 void setDefaultColor(const Color& color);
305
306 void enableTTFOwnership();
307
308 private:
309
310 static char* buffer;
311 FC_Font* font;
312
313 void init(); // Common constructor
314
315 };
316
317
318
319 #endif // _NFONT_H__
+0
-2640
source/code/Libs/SDL_FontCache.c less more
0 /*
1 SDL_FontCache: A font cache for SDL and SDL_ttf
2 by Jonathan Dearborn
3
4 See SDL_FontCache.h for license info.
5 */
6
7 #include "SDL_FontCache.h"
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12
13 // Visual C does not support static inline
14 #ifndef static_inline
15 #ifdef _MSC_VER
16 #define static_inline static
17 #else
18 #define static_inline static inline
19 #endif
20 #endif
21
22 #if SDL_VERSION_ATLEAST(2,0,0)
23 #define FC_GET_ALPHA(sdl_color) ((sdl_color).a)
24 #else
25 #define FC_GET_ALPHA(sdl_color) ((sdl_color).unused)
26 #endif
27
28 // Need SDL_RenderIsClipEnabled() for proper clipping support
29 #if SDL_VERSION_ATLEAST(2,0,4)
30 #define ENABLE_SDL_CLIPPING
31 #endif
32
33 #define FC_MIN(a,b) ((a) < (b)? (a) : (b))
34 #define FC_MAX(a,b) ((a) > (b)? (a) : (b))
35
36
37 // vsnprintf replacement from Valentin Milea:
38 // http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010
39 #if defined(_MSC_VER) && _MSC_VER < 1900
40
41 #define snprintf c99_snprintf
42 #define vsnprintf c99_vsnprintf
43
44 __inline int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap)
45 {
46 int count = -1;
47
48 if (size != 0)
49 count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
50 if (count == -1)
51 count = _vscprintf(format, ap);
52
53 return count;
54 }
55
56 __inline int c99_snprintf(char *outBuf, size_t size, const char *format, ...)
57 {
58 int count;
59 va_list ap;
60
61 va_start(ap, format);
62 count = c99_vsnprintf(outBuf, size, format, ap);
63 va_end(ap);
64
65 return count;
66 }
67
68 #endif
69
70
71 #define FC_EXTRACT_VARARGS(buffer, start_args) \
72 { \
73 va_list lst; \
74 va_start(lst, start_args); \
75 vsnprintf(buffer, fc_buffer_size, start_args, lst); \
76 va_end(lst); \
77 }
78
79 // Extra pixels of padding around each glyph to avoid linear filtering artifacts
80 #define FC_CACHE_PADDING 1
81
82
83
84 static Uint8 has_clip(FC_Target* dest)
85 {
86 #ifdef FC_USE_SDL_GPU
87 return dest->use_clip_rect;
88 #elif defined(ENABLE_SDL_CLIPPING)
89 return SDL_RenderIsClipEnabled(dest);
90 #else
91 return 0;
92 #endif
93 }
94
95 static FC_Rect get_clip(FC_Target* dest)
96 {
97 #ifdef FC_USE_SDL_GPU
98 return dest->clip_rect;
99 #elif defined(ENABLE_SDL_CLIPPING)
100 SDL_Rect r;
101 SDL_RenderGetClipRect(dest, &r);
102 return r;
103 #else
104 SDL_Rect r = {0, 0, 0, 0};
105 return r;
106 #endif
107 }
108
109 static void set_clip(FC_Target* dest, FC_Rect* rect)
110 {
111 #ifdef FC_USE_SDL_GPU
112 if(rect != NULL)
113 GPU_SetClipRect(dest, *rect);
114 else
115 GPU_UnsetClip(dest);
116 #elif defined(ENABLE_SDL_CLIPPING)
117 SDL_RenderSetClipRect(dest, rect);
118 #endif
119 }
120
121 static void set_color(FC_Image* src, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
122 {
123 #ifdef FC_USE_SDL_GPU
124 GPU_SetRGBA(src, r, g, b, a);
125 #else
126 SDL_SetTextureColorMod(src, r, g, b);
127 SDL_SetTextureAlphaMod(src, a);
128 #endif
129 }
130
131
132
133 static char* new_concat(const char* a, const char* b)
134 {
135 // Create new buffer
136 unsigned int size = strlen(a) + strlen(b);
137 char* new_string = (char*)malloc(size+1);
138
139 // Concatenate strings in the new buffer
140 strcpy(new_string, a);
141 strcat(new_string, b);
142
143 return new_string;
144 }
145
146 static char* replace_concat(char** a, const char* b)
147 {
148 char* new_string = new_concat(*a, b);
149 free(*a);
150 *a = new_string;
151 return *a;
152 }
153
154
155
156
157
158 // Shared buffer for variadic text
159 static char* fc_buffer = NULL;
160 static unsigned int fc_buffer_size = 1024;
161
162 static Uint8 fc_has_render_target_support = 0;
163
164 const char* FC_GetStringASCII(void)
165 {
166 static char* buffer = NULL;
167 if(buffer == NULL)
168 {
169 int i;
170 char c;
171 buffer = (char*)malloc(512);
172 memset(buffer, 0, 512);
173 i = 0;
174 c = 32;
175 while(1)
176 {
177 buffer[i] = c;
178 if(c == 126)
179 break;
180 ++i;
181 ++c;
182 }
183 }
184 return buffer;
185 }
186
187 const char* FC_GetStringLatin1(void)
188 {
189 static char* buffer = NULL;
190 if(buffer == NULL)
191 {
192 int i;
193 unsigned char c;
194 buffer = (char*)malloc(512);
195 memset(buffer, 0, 512);
196 i = 0;
197 c = 0xA0;
198 while(1)
199 {
200 buffer[i] = 0xC2;
201 buffer[i+1] = c;
202 if(c == 0xBF)
203 break;
204 i += 2;
205 ++c;
206 }
207 i += 2;
208 c = 0x80;
209 while(1)
210 {
211 buffer[i] = 0xC3;
212 buffer[i+1] = c;
213 if(c == 0xBF)
214 break;
215 i += 2;
216 ++c;
217 }
218 }
219 return buffer;
220 }
221
222 const char* FC_GetStringASCII_Latin1(void)
223 {
224 static char* buffer = NULL;
225 if(buffer == NULL)
226 buffer = new_concat(FC_GetStringASCII(), FC_GetStringLatin1());
227
228 return buffer;
229 }
230
231 FC_Rect FC_MakeRect(float x, float y, float w, float h)
232 {
233 FC_Rect r = {x, y, w, h};
234 return r;
235 }
236
237 FC_Scale FC_MakeScale(float x, float y)
238 {
239 FC_Scale s = {x, y};
240
241 return s;
242 }
243
244 SDL_Color FC_MakeColor(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
245 {
246 SDL_Color c = {r, g, b, a};
247
248 return c;
249 }
250
251 FC_Effect FC_MakeEffect(FC_AlignEnum alignment, FC_Scale scale, SDL_Color color)
252 {
253 FC_Effect e;
254
255 e.alignment = alignment;
256 e.scale = scale;
257 e.color = color;
258
259 return e;
260 }
261
262 FC_GlyphData FC_MakeGlyphData(int cache_level, Sint16 x, Sint16 y, Uint16 w, Uint16 h)
263 {
264 FC_GlyphData gd;
265
266 gd.rect.x = x;
267 gd.rect.y = y;
268 gd.rect.w = w;
269 gd.rect.h = h;
270 gd.cache_level = cache_level;
271
272 return gd;
273 }
274
275 // Enough to hold all of the ascii characters and some.
276 #define FC_DEFAULT_NUM_BUCKETS 300
277
278 typedef struct FC_MapNode
279 {
280 Uint32 key;
281 FC_GlyphData value;
282 struct FC_MapNode* next;
283
284 } FC_MapNode;
285
286 typedef struct FC_Map
287 {
288 int num_buckets;
289 FC_MapNode** buckets;
290 } FC_Map;
291
292
293
294 static FC_Map* FC_MapCreate(int num_buckets)
295 {
296 int i;
297 FC_Map* map = (FC_Map*)malloc(sizeof(FC_Map));
298
299 map->num_buckets = num_buckets;
300 map->buckets = (FC_MapNode**)malloc(num_buckets * sizeof(FC_MapNode*));
301
302 for(i = 0; i < num_buckets; ++i)
303 {
304 map->buckets[i] = NULL;
305 }
306
307 return map;
308 }
309
310 /*static void FC_MapClear(FC_Map* map)
311 {
312 int i;
313 if(map == NULL)
314 return;
315
316 // Go through each bucket
317 for(i = 0; i < map->num_buckets; ++i)
318 {
319 // Delete the nodes in order
320 FC_MapNode* node = map->buckets[i];
321 while(node != NULL)
322 {
323 FC_MapNode* last = node;
324 node = node->next;
325 free(last);
326 }
327 // Set the bucket to empty
328 map->buckets[i] = NULL;
329 }
330 }*/
331
332 static void FC_MapFree(FC_Map* map)
333 {
334 int i;
335 if(map == NULL)
336 return;
337
338 // Go through each bucket
339 for(i = 0; i < map->num_buckets; ++i)
340 {
341 // Delete the nodes in order
342 FC_MapNode* node = map->buckets[i];
343 while(node != NULL)
344 {
345 FC_MapNode* last = node;
346 node = node->next;
347 free(last);
348 }
349 }
350
351 free(map->buckets);
352 free(map);
353 }
354
355 // Note: Does not handle duplicates in any special way.
356 static FC_GlyphData* FC_MapInsert(FC_Map* map, Uint32 codepoint, FC_GlyphData glyph)
357 {
358 Uint32 index;
359 FC_MapNode* node;
360 if(map == NULL)
361 return NULL;
362
363 // Get index for bucket
364 index = codepoint % map->num_buckets;
365
366 // If this bucket is empty, create a node and return its value
367 if(map->buckets[index] == NULL)
368 {
369 node = map->buckets[index] = (FC_MapNode*)malloc(sizeof(FC_MapNode));
370 node->key = codepoint;
371 node->value = glyph;
372 node->next = NULL;
373 return &node->value;
374 }
375
376 for(node = map->buckets[index]; node != NULL; node = node->next)
377 {
378 // Find empty node and add a new one on.
379 if(node->next == NULL)
380 {
381 node->next = (FC_MapNode*)malloc(sizeof(FC_MapNode));
382 node = node->next;
383
384 node->key = codepoint;
385 node->value = glyph;
386 node->next = NULL;
387 return &node->value;
388 }
389 }
390
391 return NULL;
392 }
393
394 static FC_GlyphData* FC_MapFind(FC_Map* map, Uint32 codepoint)
395 {
396 Uint32 index;
397 FC_MapNode* node;
398 if(map == NULL)
399 return NULL;
400
401 // Get index for bucket
402 index = codepoint % map->num_buckets;
403
404 // Go through list until we find a match
405 for(node = map->buckets[index]; node != NULL; node = node->next)
406 {
407 if(node->key == codepoint)
408 return &node->value;
409 }
410
411 return NULL;
412 }
413
414
415
416 struct FC_Font
417 {
418 #ifndef FC_USE_SDL_GPU
419 SDL_Renderer* renderer;
420 #endif
421
422 TTF_Font* ttf_source; // TTF_Font source of characters
423 Uint8 owns_ttf_source; // Can we delete the TTF_Font ourselves?
424
425 FC_FilterEnum filter;
426
427 SDL_Color default_color;
428 Uint16 height;
429
430 Uint16 maxWidth;
431 Uint16 baseline;
432 int ascent;
433 int descent;
434
435 int lineSpacing;
436 int letterSpacing;
437
438 // Uses 32-bit (4-byte) Unicode codepoints to refer to each glyph
439 // Codepoints are little endian (reversed from UTF-8) so that something like 0x00000005 is ASCII 5 and the map can be indexed by ASCII values
440 FC_Map* glyphs;
441
442 FC_GlyphData last_glyph; // Texture packing cursor
443 int glyph_cache_size;
444 int glyph_cache_count;
445 FC_Image** glyph_cache;
446
447 char* loading_string;
448
449 };
450
451 // Private
452 static FC_GlyphData* FC_PackGlyphData(FC_Font* font, Uint32 codepoint, Uint16 width, Uint16 maxWidth, Uint16 maxHeight);
453
454
455 static FC_Rect FC_RenderLeft(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* text);
456 static FC_Rect FC_RenderCenter(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* text);
457 static FC_Rect FC_RenderRight(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* text);
458
459
460 static_inline SDL_Surface* FC_CreateSurface32(Uint32 width, Uint32 height)
461 {
462 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
463 return SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
464 #else
465 return SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
466 #endif
467 }
468
469
470 char* U8_alloc(unsigned int size)
471 {
472 char* result;
473 if(size == 0)
474 return NULL;
475
476 result = (char*)malloc(size);
477 result[0] = '\0';
478
479 return result;
480 }
481
482 void U8_free(char* string)
483 {
484 free(string);
485 }
486
487 char* U8_strdup(const char* string)
488 {
489 char* result;
490 if(string == NULL)
491 return NULL;
492
493 result = (char*)malloc(strlen(string)+1);
494 strcpy(result, string);
495
496 return result;
497 }
498
499 int U8_strlen(const char* string)
500 {
501 int length = 0;
502 if(string == NULL)
503 return 0;
504
505 while(*string != '\0')
506 {
507 string = U8_next(string);
508 ++length;
509 }
510
511 return length;
512 }
513
514 int U8_charsize(const char* character)
515 {
516 if(character == NULL)
517 return 0;
518
519 if((unsigned char)*character <= 0x7F)
520 return 1;
521 else if((unsigned char)*character < 0xE0)
522 return 2;
523 else if((unsigned char)*character < 0xF0)
524 return 3;
525 else
526 return 4;
527 return 1;
528 }
529
530 int U8_charcpy(char* buffer, const char* source, int buffer_size)
531 {
532 int charsize;
533 if(buffer == NULL || source == NULL || buffer_size < 1)
534 return 0;
535
536 charsize = U8_charsize(source);
537 if(charsize > buffer_size)
538 return 0;
539
540 memcpy(buffer, source, charsize);
541 return charsize;
542 }
543
544 const char* U8_next(const char* string)
545 {
546 return string + U8_charsize(string);
547 }
548
549 int U8_strinsert(char* string, int position, const char* source, int max_bytes)
550 {
551 int pos_bytes;
552 int len;
553 int add_len;
554 int ulen;
555
556 if(string == NULL || source == NULL)
557 return 0;
558
559 len = strlen(string);
560 add_len = strlen(source);
561 ulen = U8_strlen(string);
562
563 if(position == -1)
564 position = ulen;
565
566 if(position < 0 || position > ulen || len + add_len + 1 > max_bytes)
567 return 0;
568
569 // Move string pointer to the proper position
570 pos_bytes = 0;
571 while(*string != '\0' && pos_bytes < position)
572 {
573 string = (char*)U8_next(string);
574 ++pos_bytes;
575 }
576
577 // Move the rest of the string out of the way
578 memmove(string + add_len, string, len - pos_bytes + 1);
579
580 // Copy in the new characters
581 memcpy(string, source, add_len);
582
583 return 1;
584 }
585
586 void U8_strdel(char* string, int position)
587 {
588 if(string == NULL || position < 0)
589 return;
590
591 while(*string != '\0')
592 {
593 if(position == 0)
594 {
595 int chars_to_erase = U8_charsize(string);
596 int remaining_bytes = strlen(string) + 1;
597 memmove(string, string + chars_to_erase, remaining_bytes);
598 break;
599 }
600
601 string = (char*)U8_next(string);
602 --position;
603 }
604 }
605
606
607
608
609
610 static_inline FC_Rect FC_RectUnion(FC_Rect A, FC_Rect B)
611 {
612 float x,x2,y,y2;
613 x = FC_MIN(A.x, B.x);
614 y = FC_MIN(A.y, B.y);
615 x2 = FC_MAX(A.x+A.w, B.x+B.w);
616 y2 = FC_MAX(A.y+A.h, B.y+B.h);
617 {
618 FC_Rect result = {x, y, FC_MAX(0, x2 - x), FC_MAX(0, y2 - y)};
619 return result;
620 }
621 }
622
623 // Adapted from SDL_IntersectRect
624 static_inline FC_Rect FC_RectIntersect(FC_Rect A, FC_Rect B)
625 {
626 FC_Rect result;
627 float Amin, Amax, Bmin, Bmax;
628
629 // Horizontal intersection
630 Amin = A.x;
631 Amax = Amin + A.w;
632 Bmin = B.x;
633 Bmax = Bmin + B.w;
634 if(Bmin > Amin)
635 Amin = Bmin;
636 result.x = Amin;
637 if(Bmax < Amax)
638 Amax = Bmax;
639 result.w = Amax - Amin > 0 ? Amax - Amin : 0;
640
641 // Vertical intersection
642 Amin = A.y;
643 Amax = Amin + A.h;
644 Bmin = B.y;
645 Bmax = Bmin + B.h;
646 if(Bmin > Amin)
647 Amin = Bmin;
648 result.y = Amin;
649 if(Bmax < Amax)
650 Amax = Bmax;
651 result.h = Amax - Amin > 0 ? Amax - Amin : 0;
652
653 return result;
654 }
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669 FC_Rect FC_DefaultRenderCallback(FC_Image* src, FC_Rect* srcrect, FC_Target* dest, float x, float y, float xscale, float yscale)
670 {
671 float w = srcrect->w * xscale;
672 float h = srcrect->h * yscale;
673 FC_Rect result;
674
675 // FIXME: Why does the scaled offset look so wrong?
676 #ifdef FC_USE_SDL_GPU
677 {
678 GPU_Rect r = *srcrect;
679 GPU_BlitScale(src, &r, dest, x + xscale*r.w/2.0f, y + r.h/2.0f, xscale, yscale);
680 }
681 #else
682 {
683 SDL_RendererFlip flip = SDL_FLIP_NONE;
684 if(xscale < 0)
685 {
686 xscale = -xscale;
687 flip = (SDL_RendererFlip) ((int)flip | (int)SDL_FLIP_HORIZONTAL);
688 }
689 if(yscale < 0)
690 {
691 yscale = -yscale;
692 flip = (SDL_RendererFlip) ((int)flip | (int)SDL_FLIP_VERTICAL);
693 }
694
695 SDL_Rect r = *srcrect;
696 SDL_Rect dr = {(int)x, (int)y, (int)(xscale*r.w), (int)(yscale*r.h)};
697 SDL_RenderCopyEx(dest, src, &r, &dr, 0, NULL, flip);
698 }
699 #endif
700
701 result.x = x;
702 result.y = y;
703 result.w = w;
704 result.h = h;
705 return result;
706 }
707
708 static FC_Rect (*fc_render_callback)(FC_Image* src, FC_Rect* srcrect, FC_Target* dest, float x, float y, float xscale, float yscale) = &FC_DefaultRenderCallback;
709
710 void FC_SetRenderCallback(FC_Rect (*callback)(FC_Image* src, FC_Rect* srcrect, FC_Target* dest, float x, float y, float xscale, float yscale))
711 {
712 if(callback == NULL)
713 fc_render_callback = &FC_DefaultRenderCallback;
714 else
715 fc_render_callback = callback;
716 }
717
718 void FC_GetUTF8FromCodepoint(char* result, Uint32 codepoint)
719 {
720 char a, b, c, d;
721
722 if(result == NULL)
723 return;
724
725 a = (codepoint >> 24) & 0xFF;
726 b = (codepoint >> 16) & 0xFF;
727 c = (codepoint >> 8) & 0xFF;
728 d = codepoint & 0xFF;
729
730 if(a == 0)
731 {
732 if(b == 0)
733 {
734 if(c == 0)
735 {
736 result[0] = d;
737 result[1] = '\0';
738 }
739 else
740 {
741 result[0] = c;
742 result[1] = d;
743 result[2] = '\0';
744 }
745 }
746 else
747 {
748 result[0] = b;
749 result[1] = c;
750 result[2] = d;
751 result[3] = '\0';
752 }
753 }
754 else
755 {
756 result[0] = a;
757 result[1] = b;
758 result[2] = c;
759 result[3] = d;
760 result[4] = '\0';
761 }
762 }
763
764 Uint32 FC_GetCodepointFromUTF8(const char** c, Uint8 advance_pointer)
765 {
766 Uint32 result = 0;
767 const char* str;
768 if(c == NULL || *c == NULL)
769 return 0;
770
771 str = *c;
772 if((unsigned char)*str <= 0x7F)
773 result = *str;
774 else if((unsigned char)*str < 0xE0)
775 {
776 result |= (unsigned char)(*str) << 8;
777 result |= (unsigned char)(*(str+1));
778 if(advance_pointer)
779 *c += 1;
780 }
781 else if((unsigned char)*str < 0xF0)
782 {
783 result |= (unsigned char)(*str) << 16;
784 result |= (unsigned char)(*(str+1)) << 8;
785 result |= (unsigned char)(*(str+2));
786 if(advance_pointer)
787 *c += 2;
788 }
789 else
790 {
791 result |= (unsigned char)(*str) << 24;
792 result |= (unsigned char)(*(str+1)) << 16;
793 result |= (unsigned char)(*(str+2)) << 8;
794 result |= (unsigned char)(*(str+3));
795 if(advance_pointer)
796 *c += 3;
797 }
798 return result;
799 }
800
801
802 void FC_SetLoadingString(FC_Font* font, const char* string)
803 {
804 if(font == NULL)
805 return;
806
807 free(font->loading_string);
808 font->loading_string = U8_strdup(string);
809 }
810
811
812 unsigned int FC_GetBufferSize(void)
813 {
814 return fc_buffer_size;
815 }
816
817 void FC_SetBufferSize(unsigned int size)
818 {
819 free(fc_buffer);
820 if(size > 0)
821 {
822 fc_buffer_size = size;
823 fc_buffer = (char*)malloc(fc_buffer_size);
824 }
825 else
826 fc_buffer = (char*)malloc(fc_buffer_size);
827 }
828
829
830
831
832
833 // Constructors
834
835 static void FC_Init(FC_Font* font)
836 {
837 if(font == NULL)
838 return;
839
840 #ifndef FC_USE_SDL_GPU
841 font->renderer = NULL;
842 #endif
843
844 font->ttf_source = NULL;
845 font->owns_ttf_source = 0;
846
847 font->filter = FC_FILTER_NEAREST;
848
849 font->default_color.r = 0;
850 font->default_color.g = 0;
851 font->default_color.b = 0;
852 FC_GET_ALPHA(font->default_color) = 255;
853
854 font->height = 0; // ascent+descent
855
856 font->maxWidth = 0;
857 font->baseline = 0;
858 font->ascent = 0;
859 font->descent = 0;
860
861 font->lineSpacing = 0;
862 font->letterSpacing = 0;
863
864 // Give a little offset for when filtering/mipmaps are used. Depending on mipmap level, this will still not be enough.
865 font->last_glyph.rect.x = FC_CACHE_PADDING;
866 font->last_glyph.rect.y = FC_CACHE_PADDING;
867 font->last_glyph.rect.w = 0;
868 font->last_glyph.rect.h = 0;
869 font->last_glyph.cache_level = 0;
870
871 if(font->glyphs != NULL)
872 FC_MapFree(font->glyphs);
873
874 font->glyphs = FC_MapCreate(FC_DEFAULT_NUM_BUCKETS);
875
876 font->glyph_cache_size = 3;
877 font->glyph_cache_count = 0;
878
879
880 font->glyph_cache = (FC_Image**)malloc(font->glyph_cache_size * sizeof(FC_Image*));
881
882 if(font->loading_string == NULL)
883 font->loading_string = U8_strdup(FC_GetStringASCII());
884
885 if(fc_buffer == NULL)
886 fc_buffer = (char*)malloc(fc_buffer_size);
887 }
888
889 static Uint8 FC_GrowGlyphCache(FC_Font* font)
890 {
891 if(font == NULL)
892 return 0;
893 #ifdef FC_USE_SDL_GPU
894 GPU_Image* new_level = GPU_CreateImage(font->height * 12, font->height * 12, GPU_FORMAT_RGBA);
895 #else
896 SDL_Texture* new_level = SDL_CreateTexture(font->renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, font->height * 12, font->height * 12);
897 #endif
898 if(new_level == NULL || !FC_SetGlyphCacheLevel(font, font->glyph_cache_count, new_level))
899 {
900 FC_Log("Error: SDL_FontCache ran out of packing space and could not add another cache level.\n");
901 #ifdef FC_USE_SDL_GPU
902 GPU_FreeImage(new_level);
903 #else
904 SDL_DestroyTexture(new_level);
905 #endif
906 return 0;
907 }
908 return 1;
909 }
910
911 Uint8 FC_UploadGlyphCache(FC_Font* font, int cache_level, SDL_Surface* data_surface)
912 {
913 if(font == NULL || data_surface == NULL)
914 return 0;
915 #ifdef FC_USE_SDL_GPU
916 GPU_Image* new_level = GPU_CopyImageFromSurface(data_surface);
917 if(FC_GetFilterMode(font) == FC_FILTER_LINEAR)
918 GPU_SetImageFilter(new_level, GPU_FILTER_LINEAR);
919 else
920 GPU_SetImageFilter(new_level, GPU_FILTER_NEAREST);
921 #else
922 SDL_Texture* new_level;
923 if(!fc_has_render_target_support)
924 new_level = SDL_CreateTextureFromSurface(font->renderer, data_surface);
925 else
926 {
927 // Must upload with render target enabled so we can put more glyphs on later
928 SDL_Renderer* renderer = font->renderer;
929
930 // Set filter mode for new texture
931 char old_filter_mode[16]; // Save it so we can change the hint value in the meantime
932 snprintf(old_filter_mode, 16, "%s", SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY));
933
934 if(FC_GetFilterMode(font) == FC_FILTER_LINEAR)
935 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
936 else
937 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
938
939 new_level = SDL_CreateTexture(renderer, data_surface->format->format, SDL_TEXTUREACCESS_TARGET, data_surface->w, data_surface->h);
940 SDL_SetTextureBlendMode(new_level, SDL_BLENDMODE_BLEND);
941
942 // Reset filter mode for the temp texture
943 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
944
945 {
946 Uint8 r, g, b, a;
947 SDL_Texture* temp = SDL_CreateTextureFromSurface(renderer, data_surface);
948 SDL_SetTextureBlendMode(temp, SDL_BLENDMODE_NONE);
949 SDL_SetRenderTarget(renderer, new_level);
950
951 SDL_GetRenderDrawColor(renderer, &r, &g, &b, &a);
952 SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
953 SDL_RenderClear(renderer);
954 SDL_SetRenderDrawColor(renderer, r, g, b, a);
955
956 SDL_RenderCopy(renderer, temp, NULL, NULL);
957 SDL_SetRenderTarget(renderer, NULL);
958
959 SDL_DestroyTexture(temp);
960 }
961
962 // Reset to the old filter value
963 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, old_filter_mode);
964
965 }
966 #endif
967 if(new_level == NULL || !FC_SetGlyphCacheLevel(font, cache_level, new_level))
968 {
969 FC_Log("Error: SDL_FontCache ran out of packing space and could not add another cache level.\n");
970 #ifdef FC_USE_SDL_GPU
971 GPU_FreeImage(new_level);
972 #else
973 SDL_DestroyTexture(new_level);
974 #endif
975 return 0;
976 }
977 return 1;
978 }
979
980 static FC_GlyphData* FC_PackGlyphData(FC_Font* font, Uint32 codepoint, Uint16 width, Uint16 maxWidth, Uint16 maxHeight)
981 {
982 FC_Map* glyphs = font->glyphs;
983 FC_GlyphData* last_glyph = &font->last_glyph;
984 Uint16 height = font->height + FC_CACHE_PADDING;
985
986 if(last_glyph->rect.x + last_glyph->rect.w + width >= maxWidth - FC_CACHE_PADDING)
987 {
988 if(last_glyph->rect.y + height + height >= maxHeight - FC_CACHE_PADDING)
989 {
990 // Get ready to pack on the next cache level when it is ready
991 last_glyph->cache_level = font->glyph_cache_count;
992 last_glyph->rect.x = FC_CACHE_PADDING;
993 last_glyph->rect.y = FC_CACHE_PADDING;
994 last_glyph->rect.w = 0;
995 return NULL;
996 }
997 else
998 {
999 // Go to next row
1000 last_glyph->rect.x = FC_CACHE_PADDING;
1001 last_glyph->rect.y += height;
1002 last_glyph->rect.w = 0;
1003 }
1004 }
1005
1006 // Move to next space
1007 last_glyph->rect.x += last_glyph->rect.w + 1 + FC_CACHE_PADDING;
1008 last_glyph->rect.w = width;
1009
1010 return FC_MapInsert(glyphs, codepoint, FC_MakeGlyphData(last_glyph->cache_level, last_glyph->rect.x, last_glyph->rect.y, last_glyph->rect.w, last_glyph->rect.h));
1011 }
1012
1013
1014 FC_Image* FC_GetGlyphCacheLevel(FC_Font* font, int cache_level)
1015 {
1016 if(font == NULL || cache_level < 0 || cache_level > font->glyph_cache_count)
1017 return NULL;
1018
1019 return font->glyph_cache[cache_level];
1020 }
1021
1022 Uint8 FC_SetGlyphCacheLevel(FC_Font* font, int cache_level, FC_Image* cache_texture)
1023 {
1024 if(font == NULL || cache_level < 0)
1025 return 0;
1026
1027 // Must be sequentially added
1028 if(cache_level > font->glyph_cache_count + 1)
1029 return 0;
1030
1031 if(cache_level == font->glyph_cache_count)
1032 {
1033 font->glyph_cache_count++;
1034
1035 // Grow cache?
1036 if(font->glyph_cache_count > font->glyph_cache_size)
1037 {
1038 // Copy old cache to new one
1039 int i;
1040 FC_Image** new_cache;
1041 new_cache = (FC_Image**)malloc(font->glyph_cache_count * sizeof(FC_Image*));
1042 for(i = 0; i < font->glyph_cache_size; ++i)
1043 new_cache[i] = font->glyph_cache[i];
1044
1045 // Save new cache
1046 free(font->glyph_cache);
1047 font->glyph_cache_size = font->glyph_cache_count;
1048 font->glyph_cache = new_cache;
1049 }
1050 }
1051
1052 font->glyph_cache[cache_level] = cache_texture;
1053 return 1;
1054 }
1055
1056
1057 FC_Font* FC_CreateFont(void)
1058 {
1059 FC_Font* font;
1060
1061 font = (FC_Font*)malloc(sizeof(FC_Font));
1062 memset(font, 0, sizeof(FC_Font));
1063
1064 FC_Init(font);
1065
1066 return font;
1067 }
1068
1069
1070 // Assume this many will be enough...
1071 #define FC_LOAD_MAX_SURFACES 10
1072
1073 #ifdef FC_USE_SDL_GPU
1074 Uint8 FC_LoadFontFromTTF(FC_Font* font, TTF_Font* ttf, SDL_Color color)
1075 #else
1076 Uint8 FC_LoadFontFromTTF(FC_Font* font, SDL_Renderer* renderer, TTF_Font* ttf, SDL_Color color)
1077 #endif
1078 {
1079 if(font == NULL || ttf == NULL)
1080 return 0;
1081 #ifndef FC_USE_SDL_GPU
1082 if(renderer == NULL)
1083 return 0;
1084 #endif
1085
1086 FC_ClearFont(font);
1087
1088
1089 // Might as well check render target support here
1090 #ifdef FC_USE_SDL_GPU
1091 fc_has_render_target_support = GPU_IsFeatureEnabled(GPU_FEATURE_RENDER_TARGETS);
1092 #else
1093 SDL_RendererInfo info;
1094 SDL_GetRendererInfo(renderer, &info);
1095 fc_has_render_target_support = (info.flags & SDL_RENDERER_TARGETTEXTURE);
1096
1097 font->renderer = renderer;
1098 #endif
1099
1100 font->ttf_source = ttf;
1101
1102 //font->line_height = TTF_FontLineSkip(ttf);
1103 font->height = TTF_FontHeight(ttf);
1104 font->ascent = TTF_FontAscent(ttf);
1105 font->descent = -TTF_FontDescent(ttf);
1106
1107 font->baseline = font->height - font->descent;
1108
1109 font->default_color = color;
1110
1111 {
1112 SDL_Color white = {255, 255, 255, 255};
1113 SDL_Surface* glyph_surf;
1114 char buff[5];
1115 const char* buff_ptr = buff;
1116 const char* source_string;
1117 Uint8 packed = 0;
1118
1119 // Copy glyphs from the surface to the font texture and store the position data
1120 // Pack row by row into a square texture
1121 // Try figuring out dimensions that make sense for the font size.
1122 unsigned int w = font->height*12;
1123 unsigned int h = font->height*12;
1124 SDL_Surface* surfaces[FC_LOAD_MAX_SURFACES];
1125 int num_surfaces = 1;
1126 surfaces[0] = FC_CreateSurface32(w, h);
1127 font->last_glyph.rect.x = FC_CACHE_PADDING;
1128 font->last_glyph.rect.y = FC_CACHE_PADDING;
1129 font->last_glyph.rect.w = 0;
1130 font->last_glyph.rect.h = font->height;
1131
1132 memset(buff, 0, 5);
1133 source_string = font->loading_string;
1134 for(; *source_string != '\0'; source_string = U8_next(source_string))
1135 {
1136 if(!U8_charcpy(buff, source_string, 5))
1137 continue;
1138 glyph_surf = TTF_RenderUTF8_Blended(ttf, buff, white);
1139 if(glyph_surf == NULL)
1140 continue;
1141
1142 // Try packing. If it fails, create a new surface for the next cache level.
1143 packed = (FC_PackGlyphData(font, FC_GetCodepointFromUTF8(&buff_ptr, 0), glyph_surf->w, surfaces[num_surfaces-1]->w, surfaces[num_surfaces-1]->h) != NULL);
1144 if(!packed)
1145 {
1146 int i = num_surfaces-1;
1147 if(num_surfaces >= FC_LOAD_MAX_SURFACES)
1148 {
1149 // Can't do any more!
1150 FC_Log("SDL_FontCache error: Could not create enough cache surfaces to fit all of the loading string!\n");
1151 SDL_FreeSurface(glyph_surf);
1152 break;
1153 }
1154
1155 // Upload the current surface to the glyph cache now so we can keep the cache level packing cursor up to date as we go.
1156 FC_UploadGlyphCache(font, i, surfaces[i]);
1157 SDL_FreeSurface(surfaces[i]);
1158 #ifndef FC_USE_SDL_GPU
1159 SDL_SetTextureBlendMode(font->glyph_cache[i], SDL_BLENDMODE_BLEND);
1160 #endif
1161 // Update the glyph cursor to the new cache level. We need to do this here because the actual cache lags behind our use of the packing above.
1162 font->last_glyph.cache_level = num_surfaces;
1163
1164
1165 surfaces[num_surfaces] = FC_CreateSurface32(w, h);
1166 num_surfaces++;
1167 }
1168
1169 // Try packing for the new surface, then blit onto it.
1170 if(packed || FC_PackGlyphData(font, FC_GetCodepointFromUTF8(&buff_ptr, 0), glyph_surf->w, surfaces[num_surfaces-1]->w, surfaces[num_surfaces-1]->h) != NULL)
1171 {
1172 SDL_SetSurfaceBlendMode(glyph_surf, SDL_BLENDMODE_NONE);
1173 SDL_Rect srcRect = {0, 0, glyph_surf->w, glyph_surf->h};
1174 SDL_Rect destrect = font->last_glyph.rect;
1175 SDL_BlitSurface(glyph_surf, &srcRect, surfaces[num_surfaces-1], &destrect);
1176 }
1177
1178 SDL_FreeSurface(glyph_surf);
1179 }
1180
1181 {
1182 int i = num_surfaces-1;
1183 FC_UploadGlyphCache(font, i, surfaces[i]);
1184 SDL_FreeSurface(surfaces[i]);
1185 #ifndef FC_USE_SDL_GPU
1186 SDL_SetTextureBlendMode(font->glyph_cache[i], SDL_BLENDMODE_BLEND);
1187 #endif
1188 }
1189 }
1190
1191 return 1;
1192 }
1193
1194
1195 #ifdef FC_USE_SDL_GPU
1196 Uint8 FC_LoadFont(FC_Font* font, const char* filename_ttf, Uint32 pointSize, SDL_Color color, int style)
1197 #else
1198 Uint8 FC_LoadFont(FC_Font* font, FC_Target* renderer, const char* filename_ttf, Uint32 pointSize, SDL_Color color, int style)
1199 #endif
1200 {
1201 SDL_RWops* rwops;
1202
1203 if(font == NULL)
1204 return 0;
1205
1206 rwops = SDL_RWFromFile(filename_ttf, "rb");
1207
1208 if(rwops == NULL)
1209 {
1210 FC_Log("Unable to open file for reading: %s \n", SDL_GetError());
1211 return 0;
1212 }
1213
1214 #ifdef FC_USE_SDL_GPU
1215 return FC_LoadFont_RW(font, rwops, 1, pointSize, color, style);
1216 #else
1217 return FC_LoadFont_RW(font, renderer, rwops, 1, pointSize, color, style);
1218 #endif
1219 }
1220
1221 #ifdef FC_USE_SDL_GPU
1222 Uint8 FC_LoadFont_RW(FC_Font* font, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, SDL_Color color, int style)
1223 #else
1224 Uint8 FC_LoadFont_RW(FC_Font* font, FC_Target* renderer, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, SDL_Color color, int style)
1225 #endif
1226 {
1227 Uint8 result;
1228 TTF_Font* ttf;
1229 Uint8 outline;
1230
1231 if(font == NULL)
1232 return 0;
1233
1234 if(!TTF_WasInit() && TTF_Init() < 0)
1235 {
1236 FC_Log("Unable to initialize SDL_ttf: %s \n", TTF_GetError());
1237 if(own_rwops)
1238 SDL_RWclose(file_rwops_ttf);
1239 return 0;
1240 }
1241
1242 ttf = TTF_OpenFontRW(file_rwops_ttf, own_rwops, pointSize);
1243
1244 if(ttf == NULL)
1245 {
1246 FC_Log("Unable to load TrueType font: %s \n", TTF_GetError());
1247 if(own_rwops)
1248 SDL_RWclose(file_rwops_ttf);
1249 return 0;
1250 }
1251
1252 outline = (style & TTF_STYLE_OUTLINE);
1253 if(outline)
1254 {
1255 style &= ~TTF_STYLE_OUTLINE;
1256 TTF_SetFontOutline(ttf, 1);
1257 }
1258 TTF_SetFontStyle(ttf, style);
1259
1260 #ifdef FC_USE_SDL_GPU
1261 result = FC_LoadFontFromTTF(font, ttf, color);
1262 #else
1263 result = FC_LoadFontFromTTF(font, renderer, ttf, color);
1264 #endif
1265
1266 // Can only load new (uncached) glyphs if we can keep the SDL_RWops open.
1267 font->owns_ttf_source = own_rwops;
1268 if(!own_rwops)
1269 {
1270 TTF_CloseFont(font->ttf_source);
1271 font->ttf_source = NULL;
1272 }
1273
1274 return result;
1275 }
1276
1277
1278 void FC_ClearFont(FC_Font* font)
1279 {
1280 int i;
1281 if(font == NULL)
1282 return;
1283
1284 // Release resources
1285 if(font->owns_ttf_source)
1286 TTF_CloseFont(font->ttf_source);
1287
1288 font->owns_ttf_source = 0;
1289 font->ttf_source = NULL;
1290
1291 // Delete glyph map
1292 FC_MapFree(font->glyphs);
1293 font->glyphs = NULL;
1294
1295 // Delete glyph cache
1296 for(i = 0; i < font->glyph_cache_count; ++i)
1297 {
1298 #ifdef FC_USE_SDL_GPU
1299 GPU_FreeImage(font->glyph_cache[i]);
1300 #else
1301 SDL_DestroyTexture(font->glyph_cache[i]);
1302 #endif
1303 }
1304 free(font->glyph_cache);
1305 font->glyph_cache = NULL;
1306
1307 // Reset font
1308 FC_Init(font);
1309 }
1310
1311
1312 void FC_FreeFont(FC_Font* font)
1313 {
1314 int i;
1315 if(font == NULL)
1316 return;
1317
1318 // Release resources
1319 if(font->owns_ttf_source)
1320 TTF_CloseFont(font->ttf_source);
1321
1322 // Delete glyph map
1323 FC_MapFree(font->glyphs);
1324
1325 // Delete glyph cache
1326 for(i = 0; i < font->glyph_cache_count; ++i)
1327 {
1328 #ifdef FC_USE_SDL_GPU
1329 GPU_FreeImage(font->glyph_cache[i]);
1330 #else
1331 SDL_DestroyTexture(font->glyph_cache[i]);
1332 #endif
1333 }
1334 free(font->glyph_cache);
1335
1336 free(font->loading_string);
1337
1338 free(font);
1339 }
1340
1341 int FC_GetNumCacheLevels(FC_Font* font)
1342 {
1343 return font->glyph_cache_count;
1344 }
1345
1346 Uint8 FC_AddGlyphToCache(FC_Font* font, SDL_Surface* glyph_surface)
1347 {
1348 if(font == NULL || glyph_surface == NULL)
1349 return 0;
1350
1351 SDL_SetSurfaceBlendMode(glyph_surface, SDL_BLENDMODE_NONE);
1352 FC_Image* dest = FC_GetGlyphCacheLevel(font, font->last_glyph.cache_level);
1353 if(dest == NULL)
1354 return 0;
1355
1356 #ifdef FC_USE_SDL_GPU
1357 {
1358 GPU_Target* target = GPU_LoadTarget(dest);
1359 if(target == NULL)
1360 return 0;
1361 GPU_Image* img = GPU_CopyImageFromSurface(glyph_surface);
1362 GPU_SetImageFilter(img, GPU_FILTER_NEAREST);
1363 GPU_SetBlendMode(img, GPU_BLEND_SET);
1364
1365 SDL_Rect destrect = font->last_glyph.rect;
1366 GPU_Blit(img, NULL, target, destrect.x + destrect.w/2, destrect.y + destrect.h/2);
1367
1368 GPU_FreeImage(img);
1369 GPU_FreeTarget(target);
1370 }
1371 #else
1372 {
1373 SDL_Renderer* renderer = font->renderer;
1374 Uint8 use_clip;
1375 FC_Rect clip_rect;
1376 SDL_Texture* img;
1377 SDL_Rect destrect;
1378
1379 use_clip = has_clip(renderer);
1380 if(use_clip)
1381 {
1382 clip_rect = get_clip(renderer);
1383 set_clip(renderer, NULL);
1384 }
1385
1386 img = SDL_CreateTextureFromSurface(renderer, glyph_surface);
1387
1388 destrect = font->last_glyph.rect;
1389 SDL_SetRenderTarget(renderer, dest);
1390 SDL_RenderCopy(renderer, img, NULL, &destrect);
1391 SDL_SetRenderTarget(renderer, NULL);
1392 SDL_DestroyTexture(img);
1393
1394 if(use_clip)
1395 set_clip(renderer, &clip_rect);
1396 }
1397 #endif
1398
1399 return 1;
1400 }
1401
1402
1403 unsigned int FC_GetNumCodepoints(FC_Font* font)
1404 {
1405 FC_Map* glyphs;
1406 int i;
1407 unsigned int result = 0;
1408 if(font == NULL || font->glyphs == NULL)
1409 return 0;
1410
1411 glyphs = font->glyphs;
1412
1413 for(i = 0; i < glyphs->num_buckets; ++i)
1414 {
1415 FC_MapNode* node;
1416 for(node = glyphs->buckets[i]; node != NULL; node = node->next)
1417 {
1418 result++;
1419 }
1420 }
1421
1422 return result;
1423 }
1424
1425 void FC_GetCodepoints(FC_Font* font, Uint32* result)
1426 {
1427 FC_Map* glyphs;
1428 int i;
1429 unsigned int count = 0;
1430 if(font == NULL || font->glyphs == NULL)
1431 return;
1432
1433 glyphs = font->glyphs;
1434
1435 for(i = 0; i < glyphs->num_buckets; ++i)
1436 {
1437 FC_MapNode* node;
1438 for(node = glyphs->buckets[i]; node != NULL; node = node->next)
1439 {
1440 result[count] = node->key;
1441 count++;
1442 }
1443 }
1444 }
1445
1446 Uint8 FC_GetGlyphData(FC_Font* font, FC_GlyphData* result, Uint32 codepoint)
1447 {
1448 FC_GlyphData* e = FC_MapFind(font->glyphs, codepoint);
1449 if(e == NULL)
1450 {
1451 char buff[5];
1452 int w, h;
1453 SDL_Color white = {255, 255, 255, 255};
1454 SDL_Surface* surf;
1455 FC_Image* cache_image;
1456
1457 if(font->ttf_source == NULL)
1458 return 0;
1459
1460 FC_GetUTF8FromCodepoint(buff, codepoint);
1461
1462 cache_image = FC_GetGlyphCacheLevel(font, font->last_glyph.cache_level);
1463 if(cache_image == NULL)
1464 {
1465 FC_Log("SDL_FontCache: Failed to load cache image, so cannot add new glyphs!\n");
1466 return 0;
1467 }
1468
1469 #ifdef FC_USE_SDL_GPU
1470 w = cache_image->w;
1471 h = cache_image->h;
1472 #else
1473 SDL_QueryTexture(cache_image, NULL, NULL, &w, &h);
1474 #endif
1475
1476 surf = TTF_RenderUTF8_Blended(font->ttf_source, buff, white);
1477 if(surf == NULL)
1478 {
1479 return 0;
1480 }
1481
1482 e = FC_PackGlyphData(font, codepoint, surf->w, w, h);
1483 if(e == NULL)
1484 {
1485 // Grow the cache
1486 FC_GrowGlyphCache(font);
1487
1488 // Try packing again
1489 e = FC_PackGlyphData(font, codepoint, surf->w, w, h);
1490 if(e == NULL)
1491 {
1492 SDL_FreeSurface(surf);
1493 return 0;
1494 }
1495 }
1496
1497 // Render onto the cache texture
1498 FC_AddGlyphToCache(font, surf);
1499
1500 SDL_FreeSurface(surf);
1501 }
1502
1503 if(result != NULL && e != NULL)
1504 *result = *e;
1505
1506 return 1;
1507 }
1508
1509
1510 FC_GlyphData* FC_SetGlyphData(FC_Font* font, Uint32 codepoint, FC_GlyphData glyph_data)
1511 {
1512 return FC_MapInsert(font->glyphs, codepoint, glyph_data);
1513 }
1514
1515
1516
1517 // Drawing
1518 static FC_Rect FC_RenderLeft(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* text)
1519 {
1520 const char* c = text;
1521 FC_Rect srcRect;
1522 FC_Rect dstRect;
1523 FC_Rect dirtyRect = FC_MakeRect(x, y, 0, 0);
1524
1525 FC_GlyphData glyph;
1526 Uint32 codepoint;
1527
1528 float destX = x;
1529 float destY = y;
1530 float destH;
1531 float destLineSpacing;
1532 float destLetterSpacing;
1533
1534 if(font == NULL)
1535 return dirtyRect;
1536
1537 destH = font->height * scale.y;
1538 destLineSpacing = font->lineSpacing*scale.y;
1539 destLetterSpacing = font->letterSpacing*scale.x;
1540
1541 if(c == NULL || font->glyph_cache_count == 0 || dest == NULL)
1542 return dirtyRect;
1543
1544 int newlineX = x;
1545
1546 for(; *c != '\0'; c++)
1547 {
1548 if(*c == '\n')
1549 {
1550 destX = newlineX;
1551 destY += destH + destLineSpacing;
1552 continue;
1553 }
1554
1555 codepoint = FC_GetCodepointFromUTF8(&c, 1); // Increments 'c' to skip the extra UTF-8 bytes
1556 if(!FC_GetGlyphData(font, &glyph, codepoint))
1557 {
1558 codepoint = ' ';
1559 if(!FC_GetGlyphData(font, &glyph, codepoint))
1560 continue; // Skip bad characters
1561 }
1562
1563 if (codepoint == ' ')
1564 {
1565 destX += glyph.rect.w*scale.x + destLetterSpacing;
1566 continue;
1567 }
1568 /*if(destX >= dest->w)
1569 continue;
1570 if(destY >= dest->h)
1571 continue;*/
1572
1573 #ifdef FC_USE_SDL_GPU
1574 srcRect.x = glyph.rect.x;
1575 srcRect.y = glyph.rect.y;
1576 srcRect.w = glyph.rect.w;
1577 srcRect.h = glyph.rect.h;
1578 #else
1579 srcRect = glyph.rect;
1580 #endif
1581 dstRect = fc_render_callback(FC_GetGlyphCacheLevel(font, glyph.cache_level), &srcRect, dest, destX, destY, scale.x, scale.y);
1582 if(dirtyRect.w == 0 || dirtyRect.h == 0)
1583 dirtyRect = dstRect;
1584 else
1585 dirtyRect = FC_RectUnion(dirtyRect, dstRect);
1586
1587 destX += glyph.rect.w*scale.x + destLetterSpacing;
1588 }
1589
1590 return dirtyRect;
1591 }
1592
1593 static void set_color_for_all_caches(FC_Font* font, SDL_Color color)
1594 {
1595 // TODO: How can I predict which glyph caches are to be used?
1596 FC_Image* img;
1597 int i;
1598 int num_levels = FC_GetNumCacheLevels(font);
1599 for(i = 0; i < num_levels; ++i)
1600 {
1601 img = FC_GetGlyphCacheLevel(font, i);
1602 set_color(img, color.r, color.g, color.b, FC_GET_ALPHA(color));
1603 }
1604 }
1605
1606 FC_Rect FC_Draw(FC_Font* font, FC_Target* dest, float x, float y, const char* formatted_text, ...)
1607 {
1608 if(formatted_text == NULL || font == NULL)
1609 return FC_MakeRect(x, y, 0, 0);
1610
1611 FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
1612
1613 set_color_for_all_caches(font, font->default_color);
1614
1615 return FC_RenderLeft(font, dest, x, y, FC_MakeScale(1,1), fc_buffer);
1616 }
1617
1618
1619
1620 typedef struct FC_StringList
1621 {
1622 char* value;
1623 struct FC_StringList* next;
1624 } FC_StringList;
1625
1626 void FC_StringListFree(FC_StringList* node)
1627 {
1628 // Delete the nodes in order
1629 while(node != NULL)
1630 {
1631 FC_StringList* last = node;
1632 node = node->next;
1633
1634 free(last->value);
1635 free(last);
1636 }
1637 }
1638
1639 FC_StringList** FC_StringListPushBack(FC_StringList** node, char* value, Uint8 copy)
1640 {
1641 // Get to the last node
1642 while(node != NULL && *node != NULL)
1643 {
1644 node = &(*node)->next;
1645 }
1646
1647 *node = (FC_StringList*)malloc(sizeof(FC_StringList));
1648
1649 (*node)->value = (copy? U8_strdup(value) : value);
1650 (*node)->next = NULL;
1651
1652 return node;
1653 }
1654
1655 static FC_StringList* FC_Explode(const char* text, char delimiter)
1656 {
1657 FC_StringList* head;
1658 FC_StringList* new_node;
1659 FC_StringList** node;
1660 const char* start;
1661 const char* end;
1662 unsigned int size;
1663 if(text == NULL)
1664 return NULL;
1665
1666 head = NULL;
1667 node = &head;
1668
1669 // Doesn't technically support UTF-8, but it's probably fine, right?
1670 size = 0;
1671 start = end = text;
1672 while(1)
1673 {
1674 if(*end == delimiter || *end == '\0')
1675 {
1676 *node = (FC_StringList*)malloc(sizeof(FC_StringList));
1677 new_node = *node;
1678
1679 new_node->value = (char*)malloc(size + 1);
1680 memcpy(new_node->value, start, size);
1681 new_node->value[size] = '\0';
1682
1683 new_node->next = NULL;
1684
1685 if(*end == '\0')
1686 break;
1687
1688 node = &((*node)->next);
1689 start = end+1;
1690 size = 0;
1691 }
1692 else
1693 ++size;
1694
1695 ++end;
1696 }
1697
1698 return head;
1699 }
1700
1701 static FC_StringList* FC_ExplodeAndKeep(const char* text, char delimiter)
1702 {
1703 FC_StringList* head;
1704 FC_StringList* new_node;
1705 FC_StringList** node;
1706 const char* start;
1707 const char* end;
1708 unsigned int size;
1709 if(text == NULL)
1710 return NULL;
1711
1712 head = NULL;
1713 node = &head;
1714
1715 // Doesn't technically support UTF-8, but it's probably fine, right?
1716 size = 0;
1717 start = end = text;
1718 while(1)
1719 {
1720 if(*end == delimiter || *end == '\0')
1721 {
1722 *node = (FC_StringList*)malloc(sizeof(FC_StringList));
1723 new_node = *node;
1724
1725 new_node->value = (char*)malloc(size + 1);
1726 memcpy(new_node->value, start, size);
1727 new_node->value[size] = '\0';
1728
1729 new_node->next = NULL;
1730
1731 if(*end == '\0')
1732 break;
1733
1734 node = &((*node)->next);
1735 start = end;
1736 size = 1;
1737 }
1738 else
1739 ++size;
1740
1741 ++end;
1742 }
1743
1744 return head;
1745 }
1746
1747 static void FC_RenderAlign(FC_Font* font, FC_Target* dest, float x, float y, int width, FC_Scale scale, FC_AlignEnum align, const char* text)
1748 {
1749 switch(align)
1750 {
1751 case FC_ALIGN_LEFT:
1752 FC_RenderLeft(font, dest, x, y, scale, text);
1753 break;
1754 case FC_ALIGN_CENTER:
1755 FC_RenderCenter(font, dest, x + width/2, y, scale, text);
1756 break;
1757 case FC_ALIGN_RIGHT:
1758 FC_RenderRight(font, dest, x + width, y, scale, text);
1759 break;
1760 }
1761 }
1762
1763 static FC_StringList* FC_GetBufferFitToColumn(FC_Font* font, int width, FC_Scale scale, Uint8 keep_newlines)
1764 {
1765 FC_StringList* result = NULL;
1766 FC_StringList** current = &result;
1767
1768 FC_StringList *ls, *iter;
1769
1770 ls = (keep_newlines? FC_ExplodeAndKeep(fc_buffer, '\n') : FC_Explode(fc_buffer, '\n'));
1771 for(iter = ls; iter != NULL; iter = iter->next)
1772 {
1773 char* line = iter->value;
1774
1775 // If line is too long, then add words one at a time until we go over.
1776 if(width > 0 && FC_GetWidth(font, "%s", line) > width)
1777 {
1778 FC_StringList *words, *word_iter;
1779
1780 words = FC_Explode(line, ' ');
1781 // Skip the first word for the iterator, so there will always be at least one word per line
1782 line = new_concat(words->value, " ");
1783 for(word_iter = words->next; word_iter != NULL; word_iter = word_iter->next)
1784 {
1785 char* line_plus_word = new_concat(line, word_iter->value);
1786 char* word_plus_space = new_concat(word_iter->value, " ");
1787 if(FC_GetWidth(font, "%s", line_plus_word) > width)
1788 {
1789 current = FC_StringListPushBack(current, line, 0);
1790
1791 line = word_plus_space;
1792 }
1793 else
1794 {
1795 replace_concat(&line, word_plus_space);
1796 free(word_plus_space);
1797 }
1798 free(line_plus_word);
1799 }
1800 current = FC_StringListPushBack(current, line, 0);
1801 FC_StringListFree(words);
1802 }
1803 else
1804 {
1805 current = FC_StringListPushBack(current, line, 0);
1806 iter->value = NULL;
1807 }
1808 }
1809 FC_StringListFree(ls);
1810
1811 return result;
1812 }
1813
1814 static void FC_DrawColumnFromBuffer(FC_Font* font, FC_Target* dest, FC_Rect box, int* total_height, FC_Scale scale, FC_AlignEnum align)
1815 {
1816 int y = box.y;
1817 FC_StringList *ls, *iter;
1818
1819 ls = FC_GetBufferFitToColumn(font, box.w, scale, 0);
1820 for(iter = ls; iter != NULL; iter = iter->next)
1821 {
1822 FC_RenderAlign(font, dest, box.x, y, box.w, scale, align, iter->value);
1823 y += FC_GetLineHeight(font);
1824 }
1825 FC_StringListFree(ls);
1826
1827 if(total_height != NULL)
1828 *total_height = y - box.y;
1829 }
1830
1831 FC_Rect FC_DrawBox(FC_Font* font, FC_Target* dest, FC_Rect box, const char* formatted_text, ...)
1832 {
1833 Uint8 useClip;
1834 if(formatted_text == NULL || font == NULL)
1835 return FC_MakeRect(box.x, box.y, 0, 0);
1836
1837 FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
1838
1839 useClip = has_clip(dest);
1840 FC_Rect oldclip, newclip;
1841 if(useClip)
1842 {
1843 oldclip = get_clip(dest);
1844 newclip = FC_RectIntersect(oldclip, box);
1845 }
1846 else
1847 newclip = box;
1848
1849 set_clip(dest, &newclip);
1850
1851 set_color_for_all_caches(font, font->default_color);
1852
1853 FC_DrawColumnFromBuffer(font, dest, box, NULL, FC_MakeScale(1,1), FC_ALIGN_LEFT);
1854
1855 if(useClip)
1856 set_clip(dest, &oldclip);
1857 else
1858 set_clip(dest, NULL);
1859
1860 return box;
1861 }
1862
1863 FC_Rect FC_DrawBoxAlign(FC_Font* font, FC_Target* dest, FC_Rect box, FC_AlignEnum align, const char* formatted_text, ...)
1864 {
1865 Uint8 useClip;
1866 if(formatted_text == NULL || font == NULL)
1867 return FC_MakeRect(box.x, box.y, 0, 0);
1868
1869 FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
1870
1871 useClip = has_clip(dest);
1872 FC_Rect oldclip, newclip;
1873 if(useClip)
1874 {
1875 oldclip = get_clip(dest);
1876 newclip = FC_RectIntersect(oldclip, box);
1877 }
1878 else
1879 newclip = box;
1880 set_clip(dest, &newclip);
1881
1882 set_color_for_all_caches(font, font->default_color);
1883
1884 FC_DrawColumnFromBuffer(font, dest, box, NULL, FC_MakeScale(1,1), align);
1885
1886 if(useClip)
1887 set_clip(dest, &oldclip);
1888 else
1889 set_clip(dest, NULL);
1890
1891 return box;
1892 }
1893
1894 FC_Rect FC_DrawBoxScale(FC_Font* font, FC_Target* dest, FC_Rect box, FC_Scale scale, const char* formatted_text, ...)
1895 {
1896 Uint8 useClip;
1897 if(formatted_text == NULL || font == NULL)
1898 return FC_MakeRect(box.x, box.y, 0, 0);
1899
1900 FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
1901
1902 useClip = has_clip(dest);
1903 FC_Rect oldclip, newclip;
1904 if(useClip)
1905 {
1906 oldclip = get_clip(dest);
1907 newclip = FC_RectIntersect(oldclip, box);
1908 }
1909 else
1910 newclip = box;
1911 set_clip(dest, &newclip);
1912
1913 set_color_for_all_caches(font, font->default_color);
1914
1915 FC_DrawColumnFromBuffer(font, dest, box, NULL, scale, FC_ALIGN_LEFT);
1916
1917 if(useClip)
1918 set_clip(dest, &oldclip);
1919 else
1920 set_clip(dest, NULL);
1921
1922 return box;
1923 }
1924
1925 FC_Rect FC_DrawBoxColor(FC_Font* font, FC_Target* dest, FC_Rect box, SDL_Color color, const char* formatted_text, ...)
1926 {
1927 Uint8 useClip;
1928 if(formatted_text == NULL || font == NULL)
1929 return FC_MakeRect(box.x, box.y, 0, 0);
1930
1931 FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
1932
1933 useClip = has_clip(dest);
1934 FC_Rect oldclip, newclip;
1935 if(useClip)
1936 {
1937 oldclip = get_clip(dest);
1938 newclip = FC_RectIntersect(oldclip, box);
1939 }
1940 else
1941 newclip = box;
1942 set_clip(dest, &newclip);
1943
1944 set_color_for_all_caches(font, color);
1945
1946 FC_DrawColumnFromBuffer(font, dest, box, NULL, FC_MakeScale(1,1), FC_ALIGN_LEFT);
1947
1948 if(useClip)
1949 set_clip(dest, &oldclip);
1950 else
1951 set_clip(dest, NULL);
1952
1953 return box;
1954 }
1955
1956 FC_Rect FC_DrawBoxEffect(FC_Font* font, FC_Target* dest, FC_Rect box, FC_Effect effect, const char* formatted_text, ...)
1957 {
1958 Uint8 useClip;
1959 if(formatted_text == NULL || font == NULL)
1960 return FC_MakeRect(box.x, box.y, 0, 0);
1961
1962 FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
1963
1964 useClip = has_clip(dest);
1965 FC_Rect oldclip, newclip;
1966 if(useClip)
1967 {
1968 oldclip = get_clip(dest);
1969 newclip = FC_RectIntersect(oldclip, box);
1970 }
1971 else
1972 newclip = box;
1973 set_clip(dest, &newclip);
1974
1975 set_color_for_all_caches(font, effect.color);
1976
1977 FC_DrawColumnFromBuffer(font, dest, box, NULL, effect.scale, effect.alignment);
1978
1979 if(useClip)
1980 set_clip(dest, &oldclip);
1981 else
1982 set_clip(dest, NULL);
1983
1984 return box;
1985 }
1986
1987 FC_Rect FC_DrawColumn(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, const char* formatted_text, ...)
1988 {
1989 FC_Rect box = {x, y, width, 0};
1990 int total_height;
1991
1992 if(formatted_text == NULL || font == NULL)
1993 return FC_MakeRect(x, y, 0, 0);
1994
1995 FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
1996
1997 set_color_for_all_caches(font, font->default_color);
1998
1999 FC_DrawColumnFromBuffer(font, dest, box, &total_height, FC_MakeScale(1,1), FC_ALIGN_LEFT);
2000
2001 return FC_MakeRect(box.x, box.y, width, total_height);
2002 }
2003
2004 FC_Rect FC_DrawColumnAlign(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_AlignEnum align, const char* formatted_text, ...)
2005 {
2006 FC_Rect box = {x, y, width, 0};
2007 int total_height;
2008
2009 if(formatted_text == NULL || font == NULL)
2010 return FC_MakeRect(x, y, 0, 0);
2011
2012 FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
2013
2014 set_color_for_all_caches(font, font->default_color);
2015
2016 switch(align)
2017 {
2018 case FC_ALIGN_CENTER:
2019 box.x -= width/2;
2020 break;
2021 case FC_ALIGN_RIGHT:
2022 box.x -= width;
2023 break;
2024 default:
2025 break;
2026 }
2027
2028 FC_DrawColumnFromBuffer(font, dest, box, &total_height, FC_MakeScale(1,1), align);
2029
2030 return FC_MakeRect(box.x, box.y, width, total_height);
2031 }
2032
2033 FC_Rect FC_DrawColumnScale(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_Scale scale, const char* formatted_text, ...)
2034 {
2035 FC_Rect box = {x, y, width, 0};
2036 int total_height;
2037
2038 if(formatted_text == NULL || font == NULL)
2039 return FC_MakeRect(x, y, 0, 0);
2040
2041 FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
2042
2043 set_color_for_all_caches(font, font->default_color);
2044
2045 FC_DrawColumnFromBuffer(font, dest, box, &total_height, scale, FC_ALIGN_LEFT);
2046
2047 return FC_MakeRect(box.x, box.y, width, total_height);
2048 }
2049
2050 FC_Rect FC_DrawColumnColor(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, SDL_Color color, const char* formatted_text, ...)
2051 {
2052 FC_Rect box = {x, y, width, 0};
2053 int total_height;
2054
2055 if(formatted_text == NULL || font == NULL)
2056 return FC_MakeRect(x, y, 0, 0);
2057
2058 FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
2059
2060 set_color_for_all_caches(font, color);
2061
2062 FC_DrawColumnFromBuffer(font, dest, box, &total_height, FC_MakeScale(1,1), FC_ALIGN_LEFT);
2063
2064 return FC_MakeRect(box.x, box.y, width, total_height);
2065 }
2066
2067 FC_Rect FC_DrawColumnEffect(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_Effect effect, const char* formatted_text, ...)
2068 {
2069 FC_Rect box = {x, y, width, 0};
2070 int total_height;
2071
2072 if(formatted_text == NULL || font == NULL)
2073 return FC_MakeRect(x, y, 0, 0);
2074
2075 FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
2076
2077 set_color_for_all_caches(font, effect.color);
2078
2079 switch(effect.alignment)
2080 {
2081 case FC_ALIGN_CENTER:
2082 box.x -= width/2;
2083 break;
2084 case FC_ALIGN_RIGHT:
2085 box.x -= width;
2086 break;
2087 default:
2088 break;
2089 }
2090
2091 FC_DrawColumnFromBuffer(font, dest, box, &total_height, effect.scale, effect.alignment);
2092
2093 return FC_MakeRect(box.x, box.y, width, total_height);
2094 }
2095
2096 static FC_Rect FC_RenderCenter(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* text)
2097 {
2098 FC_Rect result = {x, y, 0, 0};
2099 if(text == NULL || font == NULL)
2100 return result;
2101
2102 char* str = U8_strdup(text);
2103 char* del = str;
2104 char* c;
2105
2106 // Go through str, when you find a \n, replace it with \0 and print it
2107 // then move down, back, and continue.
2108 for(c = str; *c != '\0';)
2109 {
2110 if(*c == '\n')
2111 {
2112 *c = '\0';
2113 result = FC_RectUnion(FC_RenderLeft(font, dest, x - scale.x*FC_GetWidth(font, "%s", str)/2.0f, y, scale, str), result);
2114 *c = '\n';
2115 c++;
2116 str = c;
2117 y += scale.y*font->height;
2118 }
2119 else
2120 c++;
2121 }
2122
2123 result = FC_RectUnion(FC_RenderLeft(font, dest, x - scale.x*FC_GetWidth(font, "%s", str)/2.0f, y, scale, str), result);
2124
2125 free(del);
2126 return result;
2127 }
2128
2129 static FC_Rect FC_RenderRight(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* text)
2130 {
2131 FC_Rect result = {x, y, 0, 0};
2132 if(text == NULL || font == NULL)
2133 return result;
2134
2135 char* str = U8_strdup(text);
2136 char* del = str;
2137 char* c;
2138
2139 for(c = str; *c != '\0';)
2140 {
2141 if(*c == '\n')
2142 {
2143 *c = '\0';
2144 result = FC_RectUnion(FC_RenderLeft(font, dest, x - scale.x*FC_GetWidth(font, "%s", str), y, scale, str), result);
2145 *c = '\n';
2146 c++;
2147 str = c;
2148 y += scale.y*font->height;
2149 }
2150 else
2151 c++;
2152 }
2153
2154 result = FC_RectUnion(FC_RenderLeft(font, dest, x - scale.x*FC_GetWidth(font, "%s", str), y, scale, str), result);
2155
2156 free(del);
2157 return result;
2158 }
2159
2160
2161
2162 FC_Rect FC_DrawScale(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* formatted_text, ...)
2163 {
2164 if(formatted_text == NULL || font == NULL)
2165 return FC_MakeRect(x, y, 0, 0);
2166
2167 FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
2168
2169 set_color_for_all_caches(font, font->default_color);
2170
2171 return FC_RenderLeft(font, dest, x, y, scale, fc_buffer);
2172 }
2173
2174 FC_Rect FC_DrawAlign(FC_Font* font, FC_Target* dest, float x, float y, FC_AlignEnum align, const char* formatted_text, ...)
2175 {
2176 if(formatted_text == NULL || font == NULL)
2177 return FC_MakeRect(x, y, 0, 0);
2178
2179 FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
2180
2181 set_color_for_all_caches(font, font->default_color);
2182
2183 FC_Rect result;
2184 switch(align)
2185 {
2186 case FC_ALIGN_LEFT:
2187 result = FC_RenderLeft(font, dest, x, y, FC_MakeScale(1,1), fc_buffer);
2188 break;
2189 case FC_ALIGN_CENTER:
2190 result = FC_RenderCenter(font, dest, x, y, FC_MakeScale(1,1), fc_buffer);
2191 break;
2192 case FC_ALIGN_RIGHT:
2193 result = FC_RenderRight(font, dest, x, y, FC_MakeScale(1,1), fc_buffer);
2194 break;
2195 default:
2196 result = FC_MakeRect(x, y, 0, 0);
2197 break;
2198 }
2199
2200 return result;
2201 }
2202
2203 FC_Rect FC_DrawColor(FC_Font* font, FC_Target* dest, float x, float y, SDL_Color color, const char* formatted_text, ...)
2204 {
2205 if(formatted_text == NULL || font == NULL)
2206 return FC_MakeRect(x, y, 0, 0);
2207
2208 FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
2209
2210 set_color_for_all_caches(font, color);
2211
2212 return FC_RenderLeft(font, dest, x, y, FC_MakeScale(1,1), fc_buffer);
2213 }
2214
2215
2216 FC_Rect FC_DrawEffect(FC_Font* font, FC_Target* dest, float x, float y, FC_Effect effect, const char* formatted_text, ...)
2217 {
2218 if(formatted_text == NULL || font == NULL)
2219 return FC_MakeRect(x, y, 0, 0);
2220
2221 FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
2222
2223 set_color_for_all_caches(font, effect.color);
2224
2225 FC_Rect result;
2226 switch(effect.alignment)
2227 {
2228 case FC_ALIGN_LEFT:
2229 result = FC_RenderLeft(font, dest, x, y, effect.scale, fc_buffer);
2230 break;
2231 case FC_ALIGN_CENTER:
2232 result = FC_RenderCenter(font, dest, x, y, effect.scale, fc_buffer);
2233 break;
2234 case FC_ALIGN_RIGHT:
2235 result = FC_RenderRight(font, dest, x, y, effect.scale, fc_buffer);
2236 break;
2237 default:
2238 result = FC_MakeRect(x, y, 0, 0);
2239 break;
2240 }
2241
2242 return result;
2243 }
2244
2245
2246
2247
2248 // Getters
2249
2250
2251 FC_FilterEnum FC_GetFilterMode(FC_Font* font)
2252 {
2253 if(font == NULL)
2254 return FC_FILTER_NEAREST;
2255
2256 return font->filter;
2257 }
2258
2259 Uint16 FC_GetLineHeight(FC_Font* font)
2260 {
2261 if(font == NULL)
2262 return 0;
2263
2264 return font->height;
2265 }
2266
2267 Uint16 FC_GetHeight(FC_Font* font, const char* formatted_text, ...)
2268 {
2269 if(formatted_text == NULL || font == NULL)
2270 return 0;
2271
2272 FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
2273
2274 Uint16 numLines = 1;
2275 const char* c;
2276
2277 for (c = fc_buffer; *c != '\0'; c++)
2278 {
2279 if(*c == '\n')
2280 numLines++;
2281 }
2282
2283 // Actual height of letter region + line spacing
2284 return font->height*numLines + font->lineSpacing*(numLines - 1); //height*numLines;
2285 }
2286
2287 Uint16 FC_GetWidth(FC_Font* font, const char* formatted_text, ...)
2288 {
2289 if(formatted_text == NULL || font == NULL)
2290 return 0;
2291
2292 FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
2293
2294 const char* c;
2295 Uint16 width = 0;
2296 Uint16 bigWidth = 0; // Allows for multi-line strings
2297
2298 for (c = fc_buffer; *c != '\0'; c++)
2299 {
2300 if(*c == '\n')
2301 {
2302 bigWidth = bigWidth >= width? bigWidth : width;
2303 width = 0;
2304 continue;
2305 }
2306
2307 FC_GlyphData glyph;
2308 Uint32 codepoint = FC_GetCodepointFromUTF8(&c, 1);
2309 if(FC_GetGlyphData(font, &glyph, codepoint) || FC_GetGlyphData(font, &glyph, ' '))
2310 width += glyph.rect.w;
2311 }
2312 bigWidth = bigWidth >= width? bigWidth : width;
2313
2314 return bigWidth;
2315 }
2316
2317 // If width == -1, use no width limit
2318 FC_Rect FC_GetCharacterOffset(FC_Font* font, Uint16 position_index, int column_width, const char* formatted_text, ...)
2319 {
2320 FC_Rect result = {0, 0, 1, FC_GetLineHeight(font)};
2321 FC_StringList *ls, *iter;
2322 int num_lines = 0;
2323 Uint8 done = 0;
2324
2325 if(formatted_text == NULL || column_width == 0 || position_index == 0 || font == NULL)
2326 return result;
2327
2328 FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
2329
2330 ls = FC_GetBufferFitToColumn(font, column_width, FC_MakeScale(1,1), 1);
2331 for(iter = ls; iter != NULL;)
2332 {
2333 char* line;
2334 int i = 0;
2335 FC_StringList* next_iter = iter->next;
2336
2337 ++num_lines;
2338 for(line = iter->value; line != NULL && *line != '\0'; line = (char*)U8_next(line))
2339 {
2340 ++i;
2341 --position_index;
2342 if(position_index == 0)
2343 {
2344 // FIXME: Doesn't handle box-wrapped newlines correctly
2345 line = (char*)U8_next(line);
2346 line[0] = '\0';
2347 result.x = FC_GetWidth(font, "%s", iter->value);
2348 done = 1;
2349 break;
2350 }
2351 }
2352 if(done)
2353 break;
2354
2355 // Prevent line wrapping if there are no more lines
2356 if(next_iter == NULL && !done)
2357 result.x = FC_GetWidth(font, "%s", iter->value);
2358 iter = next_iter;
2359 }
2360 FC_StringListFree(ls);
2361
2362 if(num_lines > 1)
2363 {
2364 result.y = (num_lines - 1) * FC_GetLineHeight(font);
2365 }
2366
2367 return result;
2368 }
2369
2370
2371 Uint16 FC_GetColumnHeight(FC_Font* font, Uint16 width, const char* formatted_text, ...)
2372 {
2373 int y = 0;
2374
2375 FC_StringList *ls, *iter;
2376
2377 if(font == NULL)
2378 return 0;
2379
2380 if(formatted_text == NULL || width == 0)
2381 return font->height;
2382
2383 FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
2384
2385 ls = FC_GetBufferFitToColumn(font, width, FC_MakeScale(1,1), 0);
2386 for(iter = ls; iter != NULL; iter = iter->next)
2387 {
2388 y += FC_GetLineHeight(font);
2389 }
2390 FC_StringListFree(ls);
2391
2392 return y;
2393 }
2394
2395 static int FC_GetAscentFromCodepoint(FC_Font* font, Uint32 codepoint)
2396 {
2397 FC_GlyphData glyph;
2398
2399 if(font == NULL)
2400 return 0;
2401
2402 // FIXME: Store ascent so we can return it here
2403 FC_GetGlyphData(font, &glyph, codepoint);
2404 return glyph.rect.h;
2405 }
2406
2407 static int FC_GetDescentFromCodepoint(FC_Font* font, Uint32 codepoint)
2408 {
2409 FC_GlyphData glyph;
2410
2411 if(font == NULL)
2412 return 0;
2413
2414 // FIXME: Store descent so we can return it here
2415 FC_GetGlyphData(font, &glyph, codepoint);
2416 return glyph.rect.h;
2417 }
2418
2419 int FC_GetAscent(FC_Font* font, const char* formatted_text, ...)
2420 {
2421 Uint32 codepoint;
2422 int max, ascent;
2423 const char* c;
2424
2425 if(font == NULL)
2426 return 0;
2427
2428 if(formatted_text == NULL)
2429 return font->ascent;
2430
2431 FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
2432
2433 max = 0;
2434 c = fc_buffer;
2435
2436 while(*c != '\0')
2437 {
2438 codepoint = FC_GetCodepointFromUTF8(&c, 1);
2439 if(codepoint != 0)
2440 {
2441 ascent = FC_GetAscentFromCodepoint(font, codepoint);
2442 if(ascent > max)
2443 max = ascent;
2444 }
2445 ++c;
2446 }
2447 return max;
2448 }
2449
2450 int FC_GetDescent(FC_Font* font, const char* formatted_text, ...)
2451 {
2452 Uint32 codepoint;
2453 int max, descent;
2454 const char* c;
2455
2456 if(font == NULL)
2457 return 0;
2458
2459 if(formatted_text == NULL)
2460 return font->descent;
2461
2462 FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
2463
2464 max = 0;
2465 c = fc_buffer;
2466
2467 while(*c != '\0')
2468 {
2469 codepoint = FC_GetCodepointFromUTF8(&c, 1);
2470 if(codepoint != 0)
2471 {
2472 descent = FC_GetDescentFromCodepoint(font, codepoint);
2473 if(descent > max)
2474 max = descent;
2475 }
2476 ++c;
2477 }
2478 return max;
2479 }
2480
2481 int FC_GetBaseline(FC_Font* font)
2482 {
2483 if(font == NULL)
2484 return 0;
2485
2486 return font->baseline;
2487 }
2488
2489 int FC_GetSpacing(FC_Font* font)
2490 {
2491 if(font == NULL)
2492 return 0;
2493
2494 return font->letterSpacing;
2495 }
2496
2497 int FC_GetLineSpacing(FC_Font* font)
2498 {
2499 if(font == NULL)
2500 return 0;
2501
2502 return font->lineSpacing;
2503 }
2504
2505 Uint16 FC_GetMaxWidth(FC_Font* font)
2506 {
2507 if(font == NULL)
2508 return 0;
2509
2510 return font->maxWidth;
2511 }
2512
2513 SDL_Color FC_GetDefaultColor(FC_Font* font)
2514 {
2515 if(font == NULL)
2516 {
2517 SDL_Color c = {0,0,0,255};
2518 return c;
2519 }
2520
2521 return font->default_color;
2522 }
2523
2524
2525 Uint8 FC_InRect(float x, float y, FC_Rect input_rect)
2526 {
2527 return (input_rect.x <= x && x <= input_rect.x + input_rect.w && input_rect.y <= y && y <= input_rect.y + input_rect.h);
2528 }
2529
2530 // TODO: Make it work with alignment
2531 Uint16 FC_GetPositionFromOffset(FC_Font* font, float x, float y, int column_width, FC_AlignEnum align, const char* formatted_text, ...)
2532 {
2533 FC_StringList *ls, *iter;
2534 Uint8 done = 0;
2535 int height = FC_GetLineHeight(font);
2536 Uint16 position = 0;
2537 int current_x = 0;
2538 int current_y = 0;
2539 FC_GlyphData glyph_data;
2540
2541 if(formatted_text == NULL || column_width == 0 || font == NULL)
2542 return 0;
2543
2544 FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
2545
2546 ls = FC_GetBufferFitToColumn(font, column_width, FC_MakeScale(1,1), 1);
2547 for(iter = ls; iter != NULL; iter = iter->next)
2548 {
2549 char* line;
2550
2551 for(line = iter->value; line != NULL && *line != '\0'; line = (char*)U8_next(line))
2552 {
2553 if(FC_GetGlyphData(font, &glyph_data, FC_GetCodepointFromUTF8((const char**)&line, 0)))
2554 {
2555 if(FC_InRect(x, y, FC_MakeRect(current_x, current_y, glyph_data.rect.w, glyph_data.rect.h)))
2556 {
2557 done = 1;
2558 break;
2559 }
2560
2561 current_x += glyph_data.rect.w;
2562 }
2563 position++;
2564 }
2565 if(done)
2566 break;
2567
2568 current_x = 0;
2569 current_y += height;
2570 if(y < current_y)
2571 break;
2572 }
2573 FC_StringListFree(ls);
2574
2575 return position;
2576 }
2577
2578
2579
2580
2581 // Setters
2582
2583
2584 void FC_SetFilterMode(FC_Font* font, FC_FilterEnum filter)
2585 {
2586 if(font == NULL)
2587 return;
2588
2589 if(font->filter != filter)
2590 {
2591 font->filter = filter;
2592
2593 #ifdef FC_USE_SDL_GPU
2594 // Update each texture to use this filter mode
2595 {
2596 int i;
2597 GPU_FilterEnum gpu_filter = GPU_FILTER_NEAREST;
2598 if(FC_GetFilterMode(font) == FC_FILTER_LINEAR)
2599 gpu_filter = GPU_FILTER_LINEAR;
2600
2601 for(i = 0; i < font->glyph_cache_count; ++i)
2602 {
2603 GPU_SetImageFilter(font->glyph_cache[i], gpu_filter);
2604 }
2605 }
2606 #endif
2607 }
2608 }
2609
2610
2611 void FC_SetSpacing(FC_Font* font, int LetterSpacing)
2612 {
2613 if(font == NULL)
2614 return;
2615
2616 font->letterSpacing = LetterSpacing;
2617 }
2618
2619 void FC_SetLineSpacing(FC_Font* font, int LineSpacing)
2620 {
2621 if(font == NULL)
2622 return;
2623
2624 font->lineSpacing = LineSpacing;
2625 }
2626
2627 void FC_SetDefaultColor(FC_Font* font, SDL_Color color)
2628 {
2629 if(font == NULL)
2630 return;
2631
2632 font->default_color = color;
2633 }
2634
2635
2636
2637
2638
2639
+0
-311
source/code/Libs/SDL_FontCache.h less more
0 /*
1 SDL_FontCache v0.9.0: A font cache for SDL and SDL_ttf
2 by Jonathan Dearborn
3 Dedicated to the memory of Florian Hufsky
4
5 License:
6 The short:
7 Use it however you'd like, but keep the copyright and license notice
8 whenever these files or parts of them are distributed in uncompiled form.
9
10 The long:
11 Copyright (c) 2016 Jonathan Dearborn
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in
21 all copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 THE SOFTWARE.
30 */
31
32 #ifndef _SDL_FONTCACHE_H__
33 #define _SDL_FONTCACHE_H__
34
35 #include "SDL.h"
36 #include "SDL_ttf.h"
37
38 #ifdef FC_USE_SDL_GPU
39 #include "SDL_gpu.h"
40 #endif
41
42
43 #include <stdarg.h>
44
45 #ifdef __cplusplus
46 extern "C" {
47 #endif
48
49
50 // Let's pretend this exists...
51 #define TTF_STYLE_OUTLINE 16
52
53
54
55 // Differences between SDL_Renderer and SDL_gpu
56 #ifdef FC_USE_SDL_GPU
57 #define FC_Rect GPU_Rect
58 #define FC_Target GPU_Target
59 #define FC_Image GPU_Image
60 #define FC_Log GPU_LogError
61 #else
62 #define FC_Rect SDL_Rect
63 #define FC_Target SDL_Renderer
64 #define FC_Image SDL_Texture
65 #define FC_Log SDL_Log
66 #endif
67
68
69 // SDL_FontCache types
70
71 typedef enum
72 {
73 FC_ALIGN_LEFT,
74 FC_ALIGN_CENTER,
75 FC_ALIGN_RIGHT
76 } FC_AlignEnum;
77
78 typedef enum
79 {
80 FC_FILTER_NEAREST,
81 FC_FILTER_LINEAR
82 } FC_FilterEnum;
83
84 typedef struct FC_Scale
85 {
86 float x;
87 float y;
88
89 } FC_Scale;
90
91 typedef struct FC_Effect
92 {
93 FC_AlignEnum alignment;
94 FC_Scale scale;
95 SDL_Color color;
96
97 } FC_Effect;
98
99 // Opaque type
100 typedef struct FC_Font FC_Font;
101
102
103 typedef struct FC_GlyphData
104 {
105 SDL_Rect rect;
106 int cache_level;
107
108 } FC_GlyphData;
109
110
111
112
113 // Object creation
114
115 FC_Rect FC_MakeRect(float x, float y, float w, float h);
116
117 FC_Scale FC_MakeScale(float x, float y);
118
119 SDL_Color FC_MakeColor(Uint8 r, Uint8 g, Uint8 b, Uint8 a);
120
121 FC_Effect FC_MakeEffect(FC_AlignEnum alignment, FC_Scale scale, SDL_Color color);
122
123 FC_GlyphData FC_MakeGlyphData(int cache_level, Sint16 x, Sint16 y, Uint16 w, Uint16 h);
124
125
126
127 // Font object
128
129 FC_Font* FC_CreateFont(void);
130
131 #ifdef FC_USE_SDL_GPU
132 Uint8 FC_LoadFont(FC_Font* font, const char* filename_ttf, Uint32 pointSize, SDL_Color color, int style);
133
134 Uint8 FC_LoadFontFromTTF(FC_Font* font, TTF_Font* ttf, SDL_Color color);
135
136 Uint8 FC_LoadFont_RW(FC_Font* font, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, SDL_Color color, int style);
137 #else
138 Uint8 FC_LoadFont(FC_Font* font, SDL_Renderer* renderer, const char* filename_ttf, Uint32 pointSize, SDL_Color color, int style);
139
140 Uint8 FC_LoadFontFromTTF(FC_Font* font, SDL_Renderer* renderer, TTF_Font* ttf, SDL_Color color);
141
142 Uint8 FC_LoadFont_RW(FC_Font* font, SDL_Renderer* renderer, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, SDL_Color color, int style);
143 #endif
144
145 void FC_ClearFont(FC_Font* font);
146
147 void FC_FreeFont(FC_Font* font);
148
149
150
151 // Built-in loading strings
152
153 const char* FC_GetStringASCII(void);
154
155 const char* FC_GetStringLatin1(void);
156
157 const char* FC_GetStringASCII_Latin1(void);
158
159
160 // UTF-8 to SDL_FontCache codepoint conversion
161
162 /*!
163 Returns the Uint32 codepoint (not UTF-32) parsed from the given UTF-8 string.
164 \param c A pointer to a string of proper UTF-8 character values.
165 \param advance_pointer If true, the source pointer will be incremented to skip the extra bytes from multibyte codepoints.
166 */
167 Uint32 FC_GetCodepointFromUTF8(const char** c, Uint8 advance_pointer);
168
169 /*!
170 Parses the given codepoint and stores the UTF-8 bytes in 'result'. The result is NULL terminated.
171 \param result A memory buffer for the UTF-8 values. Must be at least 5 bytes long.
172 \param codepoint The Uint32 codepoint to parse (not UTF-32).
173 */
174 void FC_GetUTF8FromCodepoint(char* result, Uint32 codepoint);
175
176
177 // UTF-8 string operations
178
179 /*! Allocates a new string of 'size' bytes that is already NULL-terminated. The NULL byte counts toward the size limit, as usual. Returns NULL if size is 0. */
180 char* U8_alloc(unsigned int size);
181
182 /*! Deallocates the given string. */
183 void U8_free(char* string);
184
185 /*! Allocates a copy of the given string. */
186 char* U8_strdup(const char* string);
187
188 /*! Returns the number of UTF-8 characters in the given string. */
189 int U8_strlen(const char* string);
190
191 /*! Returns the number of bytes in the UTF-8 multibyte character pointed at by 'character'. */
192 int U8_charsize(const char* character);
193
194 /*! Copies the source multibyte character into the given buffer without overrunning it. Returns 0 on failure. */
195 int U8_charcpy(char* buffer, const char* source, int buffer_size);
196
197 /*! Returns a pointer to the next UTF-8 character. */
198 const char* U8_next(const char* string);
199
200 /*! Inserts a UTF-8 string into 'string' at the given position. Use a position of -1 to append. Returns 0 when unable to insert the string. */
201 int U8_strinsert(char* string, int position, const char* source, int max_bytes);
202
203 /*! Erases the UTF-8 character at the given position, moving the subsequent characters down. */
204 void U8_strdel(char* string, int position);
205
206
207 // Internal settings
208
209 /*! Sets the string from which to load the initial glyphs. Use this if you need upfront loading for any reason (such as lack of render-target support). */
210 void FC_SetLoadingString(FC_Font* font, const char* string);
211
212 /*! Returns the size of the internal buffer which is used for unpacking variadic text data. This buffer is shared by all FC_Fonts. */
213 unsigned int FC_GetBufferSize(void);
214
215 /*! Changes the size of the internal buffer which is used for unpacking variadic text data. This buffer is shared by all FC_Fonts. */
216 void FC_SetBufferSize(unsigned int size);
217
218 void FC_SetRenderCallback(FC_Rect (*callback)(FC_Image* src, FC_Rect* srcrect, FC_Target* dest, float x, float y, float xscale, float yscale));
219
220 FC_Rect FC_DefaultRenderCallback(FC_Image* src, FC_Rect* srcrect, FC_Target* dest, float x, float y, float xscale, float yscale);
221
222
223 // Custom caching
224
225 /*! Returns the number of cache levels that are active. */
226 int FC_GetNumCacheLevels(FC_Font* font);
227
228 /*! Returns the cache source texture at the given cache level. */
229 FC_Image* FC_GetGlyphCacheLevel(FC_Font* font, int cache_level);
230
231 // TODO: Specify ownership of the texture (should be shareable)
232 /*! Sets a cache source texture for rendering. New cache levels must be sequential. */
233 Uint8 FC_SetGlyphCacheLevel(FC_Font* font, int cache_level, FC_Image* cache_texture);
234
235 /*! Copies the given surface to the given cache level as a texture. New cache levels must be sequential. */
236 Uint8 FC_UploadGlyphCache(FC_Font* font, int cache_level, SDL_Surface* data_surface);
237
238
239 /*! Returns the number of codepoints that are stored in the font's glyph data map. */
240 unsigned int FC_GetNumCodepoints(FC_Font* font);
241
242 /*! Copies the stored codepoints into the given array. */
243 void FC_GetCodepoints(FC_Font* font, Uint32* result);
244
245 /*! Stores the glyph data for the given codepoint in 'result'. Returns 0 if the codepoint was not found in the cache. */
246 Uint8 FC_GetGlyphData(FC_Font* font, FC_GlyphData* result, Uint32 codepoint);
247
248 /*! Sets the glyph data for the given codepoint. Duplicates are not checked. Returns a pointer to the stored data. */
249 FC_GlyphData* FC_SetGlyphData(FC_Font* font, Uint32 codepoint, FC_GlyphData glyph_data);
250
251
252 // Rendering
253
254 FC_Rect FC_Draw(FC_Font* font, FC_Target* dest, float x, float y, const char* formatted_text, ...);
255 FC_Rect FC_DrawAlign(FC_Font* font, FC_Target* dest, float x, float y, FC_AlignEnum align, const char* formatted_text, ...);
256 FC_Rect FC_DrawScale(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* formatted_text, ...);
257 FC_Rect FC_DrawColor(FC_Font* font, FC_Target* dest, float x, float y, SDL_Color color, const char* formatted_text, ...);
258 FC_Rect FC_DrawEffect(FC_Font* font, FC_Target* dest, float x, float y, FC_Effect effect, const char* formatted_text, ...);
259
260 FC_Rect FC_DrawBox(FC_Font* font, FC_Target* dest, FC_Rect box, const char* formatted_text, ...);
261 FC_Rect FC_DrawBoxAlign(FC_Font* font, FC_Target* dest, FC_Rect box, FC_AlignEnum align, const char* formatted_text, ...);
262 FC_Rect FC_DrawBoxScale(FC_Font* font, FC_Target* dest, FC_Rect box, FC_Scale scale, const char* formatted_text, ...);
263 FC_Rect FC_DrawBoxColor(FC_Font* font, FC_Target* dest, FC_Rect box, SDL_Color color, const char* formatted_text, ...);
264 FC_Rect FC_DrawBoxEffect(FC_Font* font, FC_Target* dest, FC_Rect box, FC_Effect effect, const char* formatted_text, ...);
265
266 FC_Rect FC_DrawColumn(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, const char* formatted_text, ...);
267 FC_Rect FC_DrawColumnAlign(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_AlignEnum align, const char* formatted_text, ...);
268 FC_Rect FC_DrawColumnScale(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_Scale scale, const char* formatted_text, ...);
269 FC_Rect FC_DrawColumnColor(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, SDL_Color color, const char* formatted_text, ...);
270 FC_Rect FC_DrawColumnEffect(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_Effect effect, const char* formatted_text, ...);
271
272
273 // Getters
274
275 FC_FilterEnum FC_GetFilterMode(FC_Font* font);
276 Uint16 FC_GetLineHeight(FC_Font* font);
277 Uint16 FC_GetHeight(FC_Font* font, const char* formatted_text, ...);
278 Uint16 FC_GetWidth(FC_Font* font, const char* formatted_text, ...);
279
280 // Returns a 1-pixel wide box in front of the character in the given position (index)
281 FC_Rect FC_GetCharacterOffset(FC_Font* font, Uint16 position_index, int column_width, const char* formatted_text, ...);
282 Uint16 FC_GetColumnHeight(FC_Font* font, Uint16 width, const char* formatted_text, ...);
283
284 int FC_GetAscent(FC_Font* font, const char* formatted_text, ...);
285 int FC_GetDescent(FC_Font* font, const char* formatted_text, ...);
286 int FC_GetBaseline(FC_Font* font);
287 int FC_GetSpacing(FC_Font* font);
288 int FC_GetLineSpacing(FC_Font* font);
289 Uint16 FC_GetMaxWidth(FC_Font* font);
290 SDL_Color FC_GetDefaultColor(FC_Font* font);
291
292 Uint8 FC_InRect(float x, float y, FC_Rect input_rect);
293 // Given an offset (x,y) from the text draw position (the upper-left corner), returns the character position (UTF-8 index)
294 Uint16 FC_GetPositionFromOffset(FC_Font* font, float x, float y, int column_width, FC_AlignEnum align, const char* formatted_text, ...);
295
296 // Setters
297
298 void FC_SetFilterMode(FC_Font* font, FC_FilterEnum filter);
299 void FC_SetSpacing(FC_Font* font, int LetterSpacing);
300 void FC_SetLineSpacing(FC_Font* font, int LineSpacing);
301 void FC_SetDefaultColor(FC_Font* font, SDL_Color color);
302
303
304 #ifdef __cplusplus
305 }
306 #endif
307
308
309
310 #endif
4848 }
4949 }
5050
51 sago::SagoTextField* ButtonGfx::getLabel(const std::string& text) {
52 const auto& theLabel = labels.find(text);
53 if (theLabel != labels.end()) {
54 return labels[text].get();
55 }
56 std::shared_ptr<sago::SagoTextField> newField = std::make_shared<sago::SagoTextField>();
57 newField->SetHolder(&globalData.spriteHolder->GetDataHolder());
58 newField->SetFont("freeserif");
59 newField->SetFontSize(30);
60 newField->SetOutline(1, {64,64,64,255});
61 newField->SetText(text);
62 labels[text] = newField;
63 return labels[text].get();
64 }
65
5166 Button::Button() {
5267 label = "";
5368 marked = false;
97112 globalData.spriteHolder->GetSprite(menu_unmarked).Draw(globalData.screen, SDL_GetTicks(), b.x, b.y);
98113 }
99114
100 standardButton.thefont->draw(globalData.screen, b.x+standardButton.xsize/2,b.y+standardButton.ysize/2-standardButton.thefont->getHeight("%s", b.label.c_str())/2, NFont::CENTER, "%s", b.label.c_str());
115 standardButton.getLabel(b.label)->Draw(globalData.screen, b.x+standardButton.xsize/2,b.y+standardButton.ysize/2,
116 sago::SagoTextField::Alignment::center, sago::SagoTextField::VerticalAlignment::center);
117 //standardButton.thefont->drawCenterAlsoHeight(globalData.screen, b.x+standardButton.xsize/2,b.y+standardButton.ysize/2, b.label);
101118 }
102119
103120
114131 drawToScreen(*b);
115132 }
116133 drawToScreen(exit);
117 standardButton.thefont->draw(target, 50, 50, "%s", title.c_str());
134 standardButton.getLabel(title)->Draw(target, 50, 50);
118135 }
119136
120137
300317 void Menu::Draw(SDL_Renderer* target) {
301318 placeButtons();
302319 drawSelf(target);
320 #if DEBUG
321 static unsigned long int Frames;
322 static unsigned long int Ticks;
323 static char FPS[10];
324 static sago::SagoTextField fpsField;
325 sagoTextSetBlueFont(fpsField);
326 Frames++;
327 if (SDL_GetTicks() >= Ticks + 1000) {
328 if (Frames > 999) {
329 Frames=999;
330 }
331 snprintf(FPS, sizeof(FPS), "%lu fps", Frames);
332 Frames = 0;
333 Ticks = SDL_GetTicks();
334 }
335 fpsField.SetText(FPS);
336 fpsField.Draw(globalData.screen, 800, 4);
337 #endif
303338 }
304339 void Menu::ProcessInput(const SDL_Event& event, bool& processed) {
305340 if (isUpEvent(event)) {
370405 if (buttons.at(i)->isPopOnRun()) {
371406 running = false;
372407 }
373 globalData.mousex = 0;
408 //Quit here to ensure that we do not continue checking buttons after we have done the action.
409 return;
374410 }
375411 }
376412 if (isClicked(exit, globalData.mousex, globalData.mousey)) {
2626
2727 #include <string>
2828 #include "SDL.h"
29 #include <map>
2930 #include <vector>
30 #include "Libs/NFont.h"
3131 #include "sago/SagoSprite.hpp"
3232 #include "sago/GameStateInterface.hpp"
3333 #include <memory>
34 #include "sago/SagoTextField.hpp"
3435
3536 //The ButtonGfx object hold common media for all buttons, so we can reskin them by only changeing one pointer
3637 struct ButtonGfx
3839 //The size of the buttons, so we don't have to ask w and h from the SDL Surfaces each time
3940 int xsize = 0;
4041 int ysize = 0;
41 //A TTFont used for writing the label on the buttons
42 NFont* thefont = nullptr;
42 sago::SagoTextField* getLabel(const std::string& text);
4343 void setSurfaces();
44 private:
45 std::map<std::string, std::shared_ptr<sago::SagoTextField> > labels;
4446 };
4547
4648 extern ButtonGfx standardButton;
2929
3030
3131 /*static void MoveBlockGameSdls( BlockGameSdl& game1, BlockGameSdl& game2 ) {
32 game1.SetTopXY(50, globalData.ysize/2-284);
33 game2.SetTopXY(globalData.xsize-500, globalData.ysize/2-284);
32 game1.SetTopXY(50, globalData.ysize/2-284);
33 game2.SetTopXY(globalData.xsize-500, globalData.ysize/2-284);
3434 }*/
3535
3636
3030 using std::cerr;
3131 using std::vector;
3232
33 static void NFont_Write(SDL_Renderer* target, int x, int y, const char* text) {
34 globalData.nf_standard_blue_font.draw(target, x, y, "%s", text);
33 static void setButtonFont(const sago::SagoDataHolder* holder, sago::SagoTextField& field, const char* text) {
34 field.SetHolder(holder);
35 field.SetFont("freeserif");
36 field.SetColor({255,255,255,255});
37 field.SetFontSize(24);
38 field.SetOutline(1, {128,128,128,255});
39 field.SetText(text);
40 }
41
42 sago::SagoTextField* ScoresDisplay::getCachedText(const std::string& text) {
43 std::shared_ptr<sago::SagoTextField> ptr = fieldCache[text];
44 if (!ptr) {
45 std::shared_ptr<sago::SagoTextField> newText = std::make_shared<sago::SagoTextField>();
46 sagoTextSetBlueFont(*newText.get());
47 newText->SetText(text);
48 fieldCache[text] = newText;
49 }
50 return fieldCache[text].get();
51 }
52
53 void ScoresDisplay::Write(SDL_Renderer* target, int x, int y, const char* text) {
54 getCachedText(text)->Draw(target, x, y);
3555 }
3656
3757 const int numberOfPages = 3;
4767 void ScoresDisplay::DrawHighscores(int x, int y, bool endless) {
4868 DrawBackgroundAndCalcPlacements();
4969 if (endless) {
50 globalData.nf_standard_blue_font.draw(globalData.screen, x+100,y+100, "%s",_("Endless:") );
70 Write(globalData.screen, x+100,y+100, _("Endless:") );
5171 }
5272 else {
53 globalData.nf_standard_blue_font.draw(globalData.screen, x+100,y+100, "%s",_("Time Trial:") );
73 Write(globalData.screen, x+100,y+100, _("Time Trial:") );
5474 }
5575 for (int i =0; i<10; i++) {
5676 record r;
6484 char playerName[32];
6585 snprintf(playerScore, sizeof(playerScore), "%i", r.score);
6686 snprintf(playerName, sizeof(playerName), "%s", r.name.c_str());
67 globalData.nf_standard_blue_font.draw(globalData.screen, x+420,y+150+i*35, "%s",playerScore);
68 globalData.nf_standard_blue_font.draw(globalData.screen, x+60,y+150+i*35, "%s",playerName);
87 Write(globalData.screen, x+420,y+150+i*35, playerScore);
88 Write(globalData.screen, x+60,y+150+i*35, playerName);
6989 }
7090 }
7191
7393 DrawBackgroundAndCalcPlacements();
7494 int y = 5;
7595 const int y_spacing = 30;
76 NFont_Write(globalData.screen, 10,y,_("Stats") );
96 Write(globalData.screen, 10,y,_("Stats") );
7797 y+=y_spacing*2;
78 NFont_Write(globalData.screen, 10,y,_("Chains") );
98 Write(globalData.screen, 10,y,_("Chains") );
7999 for (int i=2; i<13; i++) {
80100 y+=y_spacing;
81 NFont_Write(globalData.screen, 10,y,(std::to_string(i)+"X").c_str());
101 Write(globalData.screen, 10,y,(std::to_string(i)+"X").c_str());
82102 string numberAsString = std::to_string(Stats::getInstance()->getNumberOf("chainX"+std::to_string(i)));
83 NFont_Write(globalData.screen, 300,y,numberAsString.c_str());
103 Write(globalData.screen, 300,y,numberAsString.c_str());
84104 }
85105 y+=y_spacing*2;
86 NFont_Write(globalData.screen, 10,y,_("Lines Pushed: ") );
106 Write(globalData.screen, 10,y,_("Lines Pushed: ") );
87107 string numberAsString = std::to_string(Stats::getInstance()->getNumberOf("linesPushed"));
88 NFont_Write(globalData.screen, 300,y,numberAsString.c_str());
89
90 y+=y_spacing;
91 NFont_Write(globalData.screen, 10,y, _("Puzzles solved: ") );
108 Write(globalData.screen, 300,y,numberAsString.c_str());
109
110 y+=y_spacing;
111 Write(globalData.screen, 10,y, _("Puzzles solved: ") );
92112 numberAsString = std::to_string(Stats::getInstance()->getNumberOf("puzzlesSolved"));
93 NFont_Write(globalData.screen, 300,y,numberAsString.c_str());
113 Write(globalData.screen, 300,y,numberAsString.c_str());
94114
95115 y+=y_spacing*2;
96 NFont_Write(globalData.screen, 10,y, _("Run time: ") );
116 Write(globalData.screen, 10,y, _("Run time: ") );
97117 commonTime ct = TimeHandler::peekTime("totalTime",TimeHandler::ms2ct(SDL_GetTicks()));
98118 y+=y_spacing;
99 NFont_Write(globalData.screen, 10, y, SPrintCF( _("Days: %i"), ct.days) );
100 y+=y_spacing;
101 NFont_Write(globalData.screen, 10, y, SPrintCF( _("Hours: %i"), ct.hours) );
102 y+=y_spacing;
103 NFont_Write(globalData.screen, 10, y, SPrintCF( _("Minutes: %i"), ct.minutes) );
104 y+=y_spacing;
105 NFont_Write(globalData.screen, 10, y, SPrintCF( _("Seconds: %i"), ct.seconds) );
119 Write(globalData.screen, 10, y, SPrintCF( _("Days: %i"), ct.days) );
120 y+=y_spacing;
121 Write(globalData.screen, 10, y, SPrintCF( _("Hours: %i"), ct.hours) );
122 y+=y_spacing;
123 Write(globalData.screen, 10, y, SPrintCF( _("Minutes: %i"), ct.minutes) );
124 y+=y_spacing;
125 Write(globalData.screen, 10, y, SPrintCF( _("Seconds: %i"), ct.seconds) );
106126
107127 y-=y_spacing*4; //Four rows back
108128 const int x_offset3 = globalData.xsize/3+10; //Ofset for three rows
109 NFont_Write(globalData.screen, x_offset3,y, _("Play time: ") );
129 Write(globalData.screen, x_offset3,y, _("Play time: ") );
110130 ct = TimeHandler::getTime("playTime");
111131 y+=y_spacing;
112 NFont_Write(globalData.screen, x_offset3, y, SPrintCF( _("Days: %i"), ct.days) );
113 y+=y_spacing;
114 NFont_Write(globalData.screen, x_offset3, y, SPrintCF( _("Hours: %i"), ct.hours) );
115 y+=y_spacing;
116 NFont_Write(globalData.screen, x_offset3, y, SPrintCF( _("Minutes: %i"), ct.minutes) );
117 y+=y_spacing;
118 NFont_Write(globalData.screen, x_offset3, y, SPrintCF( _("Seconds: %i"), ct.seconds) );
132 Write(globalData.screen, x_offset3, y, SPrintCF( _("Days: %i"), ct.days) );
133 y+=y_spacing;
134 Write(globalData.screen, x_offset3, y, SPrintCF( _("Hours: %i"), ct.hours) );
135 y+=y_spacing;
136 Write(globalData.screen, x_offset3, y, SPrintCF( _("Minutes: %i"), ct.minutes) );
137 y+=y_spacing;
138 Write(globalData.screen, x_offset3, y, SPrintCF( _("Seconds: %i"), ct.seconds) );
119139
120140 const int x_offset = globalData.xsize/2+10;
121141 y = 5+y_spacing*2;
122 NFont_Write(globalData.screen, x_offset,y, _("VS CPU (win/loss)") );
142 Write(globalData.screen, x_offset,y, _("VS CPU (win/loss)") );
123143 for (int i=0; i<7; i++) {
124144 y += y_spacing;
125 NFont_Write(globalData.screen, x_offset,y,string("AI "+std::to_string(i+1)).c_str());
145 Write(globalData.screen, x_offset,y,string("AI "+std::to_string(i+1)).c_str());
126146 numberAsString = std::to_string(Stats::getInstance()->getNumberOf("defeatedAI"+std::to_string(i)));
127147 string numberAsString2 = std::to_string(Stats::getInstance()->getNumberOf("defeatedByAI"+std::to_string(i)));
128148 string toPrint = numberAsString + "/" + numberAsString2;
129 NFont_Write(globalData.screen, x_offset+230,y,toPrint.c_str());
149 Write(globalData.screen, x_offset+230,y,toPrint.c_str());
130150 }
131151 }
132152
155175 DrawStats();
156176 };
157177
178 const sago::SagoDataHolder* holder = &globalData.spriteHolder->GetDataHolder();
158179 //Draw buttons:
159180 globalData.bHighScore.Draw(globalData.screen, 0, scoreX,scoreY);
160181 globalData.bBack.Draw(globalData.screen, 0, backX, backY);
161 globalData.nf_button_font.draw(globalData.screen, backX+60,backY+10, NFont::CENTER ,_("Back"));
182 static sago::SagoTextField backLabel;
183 setButtonFont(holder, backLabel, _("Back"));
184 backLabel.Draw(globalData.screen, backX+60,backY+10, sago::SagoTextField::Alignment::center);
162185 globalData.bNext.Draw(globalData.screen, 0, nextX, nextY);
163 globalData.nf_button_font.draw(globalData.screen, nextX+60,nextY+10, NFont::CENTER,_("Next"));
186 static sago::SagoTextField nextLabel;
187 setButtonFont(holder, nextLabel, _("Next"));
188 nextLabel.Draw(globalData.screen, nextX+60, nextY+10, sago::SagoTextField::Alignment::center);
164189
165190 //Draw page number
166191 string pageXofY = SPrintStringF(_("Page %i of %i"), page+1, numberOfPages);
167 NFont_Write(globalData.screen, globalData.xsize/2-globalData.nf_standard_blue_font.getWidth( "%s", pageXofY.c_str())/2, globalData.ysize-60, pageXofY.c_str());
192 getCachedText(pageXofY)->Draw(globalData.screen, globalData.xsize/2, globalData.ysize-60, sago::SagoTextField::Alignment::center);
168193 }
169194
170195 void ScoresDisplay::ProcessInput(const SDL_Event& event, bool& processed) {
2424 #define SCORESDISPLAY_HPP
2525
2626 #include "sago/GameStateInterface.hpp"
27 #include "sago/SagoTextField.hpp"
28 #include <map>
29 #include <memory>
2730
2831 class ScoresDisplay : public sago::GameStateInterface {
2932 public:
4649 void DrawHighscores(int x, int y, bool endless);
4750 void DrawStats();
4851 void DrawBackgroundAndCalcPlacements();
52 void Write(SDL_Renderer* target, int x, int y, const char* text);
53 sago::SagoTextField* getCachedText(const std::string& text);
54 std::map<std::string, std::shared_ptr<sago::SagoTextField> > fieldCache;
4955 bool isActive = true;
5056 bool bMouseUp = false;
5157 int backX = 20;
0 /*
1 ===========================================================================
2 blockattack - Block Attack - Rise of the Blocks
3 Copyright (C) 2005-2018 Poul Sander
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 You should have received a copy of the GNU General Public License
13 along with this program. If not, see http://www.gnu.org/licenses/
14 Source information and contacts persons can be found at
15 https://blockattack.net
16 ===========================================================================
17 */
18
19 #include "ShowFileState.hpp"
20 #include "global.hpp"
21 #include "common.h"
22 #include "MenuSystem.h"
23
24 const int xsize = 1024;
25 const int ysize = 768;
26 const int buttonOffset = 160;
27 extern sago::SagoSprite bExit;
28
29 static void setHelpGamepadFont(const sago::SagoDataHolder* holder, sago::SagoTextField& field, const char* text) {
30 field.SetHolder(holder);
31 field.SetFont("freeserif");
32 field.SetColor({255,255,255,255});
33 field.SetFontSize(30);
34 field.SetOutline(1, {128,128,128,255});
35 field.SetText(text);
36 }
37
38 static void setHelpGamepadFont(const sago::SagoDataHolder* holder, sago::SagoTextBox& field, const char* text) {
39 field.SetHolder(holder);
40 field.SetFont("freeserif");
41 field.SetColor({255,255,255,255});
42 field.SetColor({0,0,0,255});
43 field.SetFontSize(20);
44 field.SetOutline(0, {0,0,0,255});
45 field.SetText(text);
46 }
47
48 ShowFileState::ShowFileState() {
49 setHelpGamepadFont(&globalData.spriteHolder->GetDataHolder(), titleField, "");
50 setHelpGamepadFont(&globalData.spriteHolder->GetDataHolder(), infoBox, "");
51 setHelpGamepadFont(&globalData.spriteHolder->GetDataHolder(), filenameField, "");
52 }
53
54 ShowFileState::~ShowFileState() {
55 }
56
57 bool ShowFileState::IsActive() {
58 return isActive;
59 }
60
61 void ShowFileState::ProcessInput(const SDL_Event& event, bool& processed) {
62
63 UpdateMouseCoordinates(event, globalData.mousex, globalData.mousey);
64
65 if (isConfirmEvent(event) || isEscapeEvent(event)) {
66 isActive = false;
67 processed = true;
68 }
69 }
70
71 extern void DrawRectYellow(SDL_Renderer* target, int topx, int topy, int height, int width);
72
73 void ShowFileState::Draw(SDL_Renderer* target) {
74 DrawBackground(target);
75 titleField.Draw(target, 50, 50);
76 DrawRectYellow(target, 40, 90, 600, 900);
77 infoBox.SetMaxWidth(850);
78 infoBox.Draw(target, 50, 100);
79 DrawRectYellow(target, 40, 700, 50, 900);
80 filenameField.Draw(target, 50, 715);
81 bExit.Draw(globalData.screen, SDL_GetTicks(), xsize-buttonOffset, ysize-buttonOffset);
82 #if DEBUG
83 static sago::SagoTextField mousePos;
84 mousePos.SetHolder(&globalData.spriteHolder->GetDataHolder());
85 mousePos.SetFontSize(16);
86 mousePos.SetOutline(1, {128,128,128,255});
87 mousePos.SetText(std::string("Mouse position: ")+std::to_string(globalData.mousex)+std::string(", ")+std::to_string(globalData.mousey));
88 mousePos.Draw(target, 0,0);
89 #endif
90 }
91
92 void ShowFileState::Update() {
93 // If the mouse button is released, make bMouseUp equal true
94 if ( !(SDL_GetMouseState(nullptr, nullptr)&SDL_BUTTON(1)) ) {
95 bMouseUp=true;
96 }
97
98 if (SDL_GetMouseState(nullptr,nullptr)&SDL_BUTTON(1) && bMouseUp) {
99 bMouseUp = false;
100
101 //The Score button:
102 if ((globalData.mousex>xsize-buttonOffset) && (globalData.mousex<xsize-buttonOffset+bExit.GetWidth())
103 && (globalData.mousey>ysize-buttonOffset) && (globalData.mousey<ysize-buttonOffset+bExit.GetHeight())) {
104 isActive = false;
105 }
106
107 }
108 }
0 /*
1 ===========================================================================
2 blockattack - Block Attack - Rise of the Blocks
3 Copyright (C) 2005-2018 Poul Sander
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 You should have received a copy of the GNU General Public License
13 along with this program. If not, see http://www.gnu.org/licenses/
14 Source information and contacts persons can be found at
15 https://blockattack.net
16 ===========================================================================
17 */
18
19 #ifndef SHOWFILESTATE_HPP
20 #define SHOWFILESTATE_HPP
21
22
23 #include "sago/GameStateInterface.hpp"
24 #include "sago/SagoTextField.hpp"
25 #include "sago/SagoTextBox.hpp"
26 #include "sago/SagoMisc.hpp"
27 #include <string>
28 #include "common.h"
29
30 class ShowFileState : public sago::GameStateInterface {
31 public:
32 ShowFileState();
33 ShowFileState(const ShowFileState& orig) = delete;
34 virtual ~ShowFileState();
35
36 bool IsActive() override;
37 void Draw(SDL_Renderer* target) override;
38 void ProcessInput(const SDL_Event& event, bool &processed) override;
39 void Update() override;
40
41 void SetData(const std::string& filename, const std::string& header) {
42 titleField.SetText(header);
43 infoBox.SetText(sago::GetFileContent(filename));
44 filenameField.SetText(SPrintStringF(_("Showing content of: %s"), filename.c_str()));
45 }
46
47 private:
48 bool isActive = true;
49 bool bMouseUp = true;
50 sago::SagoTextField titleField;
51 sago::SagoTextBox filenameField;
52 sago::SagoTextBox infoBox;
53 };
54
55 #endif /* SHOWFILESTATE_HPP */
56
1616 along with this program. If not, see http://www.gnu.org/licenses/
1717
1818 Source information and contacts persons can be found at
19 http://www.blockattack.net
19 https://blockattack.net
2020 ===========================================================================
2121 */
2222
3030 private:
3131 int x = 0;
3232 int y = 0;
33 std::string textt;
33 unsigned int textt = 0;
3434 unsigned long int time = 0;
3535 unsigned long int placeTime = 0; //Then the text was placed
3636 public:
4040 }
4141
4242 //constructor:
43 TextMessage(int X, int Y,const char* Text,unsigned int Time) {
43 TextMessage(int X, int Y,unsigned int Text,unsigned int Time) {
4444 placeTime = SDL_GetTicks();
4545 x = X;
4646 y = Y;
6161 return y;
6262 }
6363
64 const char* getText() {
65 return textt.c_str();
64 unsigned int getText() {
65 return textt;
6666 }
6767 }; //text popup
6868
7474 TextManager() {
7575 }
7676
77 int addText(int x, int y, const std::string& Text,unsigned int Time) {
77 int addText(int x, int y, unsigned int Text, unsigned int Time) {
7878 size_t textNumber = 0;
7979 while (textNumber<textArray.size() && textArray[textNumber].inUse) {
8080 textNumber++;
8282 if (textNumber==textArray.size()) {
8383 return -1;
8484 }
85 textArray[textNumber] = TextMessage(x,y,Text.c_str(),Time);
85 textArray[textNumber] = TextMessage(x,y,Text,Time);
8686 textArray[textNumber].inUse = true;
8787 return 1;
8888 } //addText
156156 stringstream inFile(filecontent);
157157 string key;
158158 string previuskey;
159 char value[MAX_VAR_LENGTH];
160159 if (inFile) {
161160 while (!inFile.eof()) {
162161 inFile >> key;
165164 }
166165 previuskey = key;
167166 inFile.get(); //Read the space between the key and the content
168 inFile.getline(value,MAX_VAR_LENGTH);
167 std::string value;
168 std::getline(inFile, value);
169169 #if DEBUG
170170 cerr << "Config read: " << key << " with:\"" << value << "\"" << "\n";
171171 #endif
172 configMap[key] = (string)value;
172 configMap[key] = value;
173173 }
174174 }
175175 }
185185 void Config::save() {
186186 std::stringstream outFile;
187187 map<string,string>::iterator iter;
188 for (iter = configMap.begin(); iter != configMap.end(); iter++) {
188 for (iter = configMap.begin(); iter != configMap.end(); ++iter) {
189189 outFile << iter->first << " " << iter->second << "\n";
190190 }
191191 outFile << "\n"; //The last entry in the file will be read double if a linebreak is missing
4747 unsigned int seconds = 0;
4848 };
4949
50 //std::string itoa(int num) __attribute__((const));
51
5250 bool strequals(const char* a, const char* b);
5351
5452 /**
3636 };
3737
3838 static std::map<SDL_JoystickID, ControllerStatus> controllerStatusMap;
39 static std::map<std::string, int> gamecontrollers_assigned;
40 static std::vector<std::string> supportedControllers;
3941
4042
4143 void GameControllerSetVerbose(bool value) {
6062 return ret;
6163 }
6264
63 static std::map<std::string, int> gamecontrollers_assigned;
6465
6566 static int GetNextPlayerByGui(const SDL_JoystickGUID& guid) {
6667 Config::getInstance()->setDefault("gc_AllToOnePlayer", "0");
99100 SDL_JoystickGUID guid = SDL_JoystickGetGUID(j);
100101 int assingToPlayer = GetNextPlayerByGui(guid);
101102 controllerStatusMap[instanceId].player = assingToPlayer;
103 supportedControllers.push_back(GameControllerGetName(controller));
102104 if (verbose) {
103105 std::cout << "Supported game controller detected: " << GameControllerGetName(controller) << ", mapping: " << SDL_GameControllerMapping(controller) << "\n";
104106 std::cout << "Assigned to player: " << controllerStatusMap[instanceId].player << "\n";
105107 }
106108 }
107109 }
110 }
111
112 const std::vector<std::string>& GetSupportedControllerNames() {
113 return supportedControllers;
108114 }
109115
110116 void checkDeadZone(const SDL_Event& event) {
2121 */
2222
2323 #include "SDL.h"
24
24 #include <vector>
25 #include <string>
2526
2627 const int deadZoneLimit = 20000;
2728
3435 bool isPlayerSwitchEvent(int playerNumber, const SDL_Event& event);
3536 bool isPlayerPushEvent(int playerNumber, const SDL_Event& event);
3637 void GameControllerSetVerbose(bool value);
38 const std::vector<std::string>& GetSupportedControllerNames();
3739
3840 /**
3941 * Checks that the given event is in the dead zone.
2323 #ifndef _GLOBAL_HPP
2424 #define _GLOBAL_HPP
2525
26 #include "Libs/NFont.h"
2726 #include <memory>
2827 #include "sago/SagoSpriteHolder.hpp"
2928 #include "highscore.h"
3029 #include "sago/GameStateInterface.hpp"
3130 #include "TextManager.hpp"
3231 #include "ExplosionManager.hpp"
32 #include "sago/SagoTextField.hpp"
3333
3434 void MainMenu();
3535 void ResetFullscreen();
4444 void DrawIMG(const sago::SagoSprite& sprite, SDL_Renderer* target, int x, int y);
4545 void DrawIMG_Bounded(const sago::SagoSprite& sprite, SDL_Renderer* target, int x, int y, int minx, int miny, int maxx, int maxy);
4646
47 void sagoTextSetHelpFont(sago::SagoTextField& field);
48 void sagoTextSetBlueFont(sago::SagoTextField& field);
49
4750 struct GlobalData {
4851 sago::SagoSprite bHighScore;
4952 sago::SagoSprite bBack;
5255 sago::SagoSprite iLevelCheckBox;
5356 sago::SagoSprite iLevelCheckBoxMarked;
5457 sago::SagoSprite iCheckBoxArea;
55 NFont nf_scoreboard_font;
56 NFont nf_standard_blue_font;
57 NFont nf_button_font;
5858 bool MusicEnabled; //true if background music is enabled
5959 bool SoundEnabled; //true if sound effects is enabled
6060 bool bFullscreen; //true if game is running fullscreen
6262 std::string player1name;
6363 std::string player2name;
6464 SDL_Renderer *screen = nullptr; //The whole screen;
65 Mix_Chunk *typingChunk;
65 sago::SoundHandler typingChunk;
6666 sago::SagoSprite mouse;
6767 bool highPriority = false;
6868 bool NoSound = false;
1616 along with this program. If not, see http://www.gnu.org/licenses/
1717
1818 Source information and contacts persons can be found at
19 http://www.blockattack.net
19 https://blockattack.net
2020 ===========================================================================
2121 */
2222
1616 along with this program. If not, see http://www.gnu.org/licenses/
1717
1818 Source information and contacts persons can be found at
19 http://www.blockattack.net
19 https://blockattack.net
2020 ===========================================================================
2121 */
2222
3737
3838 static bool bMouseUp; //true if the mouse(1) is unpressed
3939
40 static void NFont_Write(SDL_Renderer* target, int x, int y, const std::string& text) {
41 globalData.nf_standard_blue_font.draw(target, x, y, "%s", text.c_str());
40 static std::map<std::string, std::shared_ptr<sago::SagoTextField> > fieldCache;
41
42 static sago::SagoTextField* getCachedText(const std::string& text) {
43 std::shared_ptr<sago::SagoTextField> ptr = fieldCache[text];
44 if (!ptr) {
45 std::shared_ptr<sago::SagoTextField> newText = std::make_shared<sago::SagoTextField>();
46 sagoTextSetBlueFont(*newText.get());
47 newText->SetText(text);
48 fieldCache[text] = newText;
49 }
50 return fieldCache[text].get();
51 }
52
53 static void Write(SDL_Renderer* target, int x, int y, const char* text) {
54 getCachedText(text)->Draw(target, x, y);
4255 }
4356
4457 //The function that allows the player to choose PuzzleLevel
5366 Uint32 totalScore = 0;
5467 Uint32 totalTime = 0;
5568 int selected = 0;
69 fieldCache.clear();
5670
5771 //Loads the levels, if they havn't been loaded:
5872 if (Type == 0) {
7488 DrawBackground(globalData.screen);
7589 globalData.iCheckBoxArea.Draw(globalData.screen,ticks,xplace,yplace);
7690 if (Type == 0) {
77 NFont_Write(globalData.screen, xplace+12,yplace+2,_("Select Puzzle") );
91 Write(globalData.screen, xplace+12,yplace+2,_("Select Puzzle") );
7892 }
7993 if (Type == 1) {
80 NFont_Write(globalData.screen, xplace+12,yplace+2, _("Stage Clear Level Select") );
94 Write(globalData.screen, xplace+12,yplace+2, _("Stage Clear Level Select") );
8195 }
8296 //Now drow the fields you click in (and a V if clicked):
8397 for (int i = 0; i < nrOfLevels; i++) {
190204 timeString = SPrintStringF(_("Time used: %d : %02d"), GetStageTime(selected)/1000/60, (GetStageTime(selected)/1000)%60);
191205 }
192206
193 NFont_Write(globalData.screen, 200,200,scoreString.c_str());
194 NFont_Write(globalData.screen, 200,250,timeString.c_str());
207 Write(globalData.screen, 200,200,scoreString.c_str());
208 Write(globalData.screen, 200,250,timeString.c_str());
195209 string totalString = SPrintStringF(_("Total score: %i in %i:%02i"), totalScore, totalTime/1000/60, ((totalTime/1000)%60) );
196 NFont_Write(globalData.screen, 200,600,totalString.c_str());
210 Write(globalData.screen, 200,600,totalString.c_str());
197211 }
198212
199213 globalData.mouse.Draw(globalData.screen, SDL_GetTicks(), globalData.mousex, globalData.mousey);
3333 #define WITH_SDL 1
3434
3535 #include "sago/SagoSpriteHolder.hpp"
36 #include "sago/SagoTextBox.hpp"
3637 #include <iostream>
3738 #include <stdlib.h>
3839 #include <time.h> //Used for srand()
4243 #include <SDL_mixer.h> //Used for sound & music
4344 #include <SDL_image.h> //To load PNG images!
4445 #include <physfs.h> //Abstract file system. To use containers
45 #include "Libs/NFont.h"
4646 #include <vector>
4747 #include "MenuSystem.h"
4848 #include "puzzlehandler.hpp"
180180 globalData.mouse = holder.GetSprite("mouse");
181181 backBoard = holder.GetSprite("back_board");
182182
183 SDL_Color nf_button_color, nf_standard_blue_color, nf_standard_small_color;
184 memset(&nf_button_color,0,sizeof(SDL_Color));
185 nf_button_color.b = 255;
186 nf_button_color.g = 255;
187 nf_button_color.r = 255;
188 nf_button_color.a = 255;
189 nf_standard_blue_color.b = 255;
190 nf_standard_blue_color.g = 0;
191 nf_standard_blue_color.r = 0;
192 nf_standard_blue_color.a = 255;
193 nf_standard_small_color.b = 0;
194 nf_standard_small_color.g = 0;
195 nf_standard_small_color.r = 200;
196 nf_standard_small_color.a = 255;
197 globalData.nf_button_font.load(globalData.screen, holder.GetDataHolder().getFontPtr("freeserif", 24), nf_button_color);
198 globalData.nf_standard_blue_font.load(globalData.screen, holder.GetDataHolder().getFontPtr("freeserif", 30), nf_standard_blue_color);
199 nf_standard_small_font.load(globalData.screen, holder.GetDataHolder().getFontPtr("freeserif", 16), nf_standard_small_color);
200 globalData.nf_scoreboard_font.load(globalData.screen, holder.GetDataHolder().getFontPtr("penguinattack", 20), nf_button_color);
183 sagoTextSetBlueFont(player1name);
184 sagoTextSetBlueFont(player2name);
185 sagoTextSetBlueFont(player1time);
186 sagoTextSetBlueFont(player2time);
187 sagoTextSetBlueFont(player1score);
188 sagoTextSetBlueFont(player2score);
189 sagoTextSetBlueFont(player1chain);
190 sagoTextSetBlueFont(player2chain);
191 sagoTextSetBlueFont(player1speed);
192 sagoTextSetBlueFont(player2speed);
193
201194
202195 //Loads the sound if sound present
203196 if (!globalData.NoSound) {
204197 //And here the music:
205 bgMusic = holder.GetDataHolder().getMusicPtr("bgmusic");
206 highbeatMusic = holder.GetDataHolder().getMusicPtr("highbeat");
198 bgMusic = holder.GetDataHolder().getMusicHandler("bgmusic");
199 highbeatMusic = holder.GetDataHolder().getMusicHandler("highbeat");
207200 //the music... we just hope it exists, else the user won't hear anything
208201 //Same goes for the sounds
209 boing = holder.GetDataHolder().getSoundPtr("pop");
210 applause = holder.GetDataHolder().getSoundPtr("applause");
211 photoClick = holder.GetDataHolder().getSoundPtr("cameraclick");
212 globalData.typingChunk = holder.GetDataHolder().getSoundPtr("typing");
213 counterChunk = holder.GetDataHolder().getSoundPtr("counter");
214 counterFinalChunk = holder.GetDataHolder().getSoundPtr("counter_final");
202 boing = holder.GetDataHolder().getSoundHandler("pop");
203 applause = holder.GetDataHolder().getSoundHandler("applause");
204 photoClick = holder.GetDataHolder().getSoundHandler("cameraclick");
205 globalData.typingChunk = holder.GetDataHolder().getSoundHandler("typing");
206 counterChunk = holder.GetDataHolder().getSoundHandler("counter");
207 counterFinalChunk = holder.GetDataHolder().getSoundHandler("counter_final");
215208 const int soundVolume = 84; //0-128
216 Mix_VolumeChunk(boing, soundVolume);
217 Mix_VolumeChunk(applause, soundVolume);
218 Mix_VolumeChunk(photoClick, soundVolume);
219 Mix_VolumeChunk(globalData.typingChunk, soundVolume);
220 Mix_VolumeChunk(counterChunk, soundVolume);
221 Mix_VolumeChunk(counterFinalChunk, soundVolume);
209 Mix_VolumeChunk(boing.get(), soundVolume);
210 Mix_VolumeChunk(applause.get(), soundVolume);
211 Mix_VolumeChunk(photoClick.get(), soundVolume);
212 Mix_VolumeChunk(globalData.typingChunk.get(), soundVolume);
213 Mix_VolumeChunk(counterChunk.get(), soundVolume);
214 Mix_VolumeChunk(counterFinalChunk.get(), soundVolume);
222215 } //All sound has been loaded or not
223216 return 0;
224217 } //InitImages()
225218
226219 /*Draws a image from on a given Surface. Takes source image, destination surface and coordinates*/
227220 void DrawIMG(const sago::SagoSprite& sprite, SDL_Renderer* target, int x, int y) {
228 sprite.Draw(target, SDL_GetTicks() ,x,y);
221 sprite.Draw(target, SDL_GetTicks(),x,y);
229222 }
230223
231224 void DrawIMG_Bounded(const sago::SagoSprite& sprite, SDL_Renderer* target, int x, int y, int minx, int miny, int maxx, int maxy) {
237230 sprite.DrawBounded(target, SDL_GetTicks(),x,y,bounds);
238231 }
239232
240
241 static void NFont_Write(SDL_Renderer* target, int x, int y, const string& text) {
242 globalData.nf_standard_blue_font.draw(target, x, y, "%s", text.c_str());
243 }
244
245 static void NFont_Write(SDL_Renderer* target, int x, int y, const char* text) {
246 globalData.nf_standard_blue_font.draw(target, x, y, "%s", text);
247 }
248
249233 SDL_Window* sdlWindow;
250234
251 std::unique_ptr<sago::SagoDataHolder> dataHolder;
235 sago::SagoDataHolder dataHolder;
252236
253237 void ResetFullscreen() {
254238 Mix_HaltMusic(); //We need to reload all data in case the screen type changes. Music must be stopped before unload.
258242 else {
259243 SDL_SetWindowFullscreen(sdlWindow, 0);
260244 }
261 dataHolder.reset(new sago::SagoDataHolder(globalData.screen));
262 globalData.spriteHolder.reset(new sago::SagoSpriteHolder( *(dataHolder.get()) ) );
245 dataHolder.invalidateAll(globalData.screen);
246 globalData.spriteHolder.reset(new sago::SagoSpriteHolder( dataHolder ) );
263247 InitImages(*(globalData.spriteHolder.get()) );
264248 SDL_ShowCursor(SDL_DISABLE);
265249 }
331315 SDL_FreeSurface(sreenshotSurface);
332316 if (!globalData.NoSound) {
333317 if (globalData.SoundEnabled) {
334 Mix_PlayChannel(1, photoClick, 0);
318 Mix_PlayChannel(1, photoClick.get(), 0);
335319 }
336320 }
337321 }
393377 }
394378
395379
380 static sago::SagoTextField* getSmallInt(size_t number) {
381 static std::vector<std::shared_ptr<sago::SagoTextField> > smallFontCache;
382 if (smallFontCache.size() < number+1) {
383 smallFontCache.resize(number+1);
384 }
385 if (!smallFontCache[number]) {
386 std::shared_ptr<sago::SagoTextField> newNumber = std::make_shared<sago::SagoTextField>();
387 newNumber->SetHolder(&globalData.spriteHolder->GetDataHolder());
388 newNumber->SetFont("freeserif");
389 newNumber->SetFontSize(16);
390 newNumber->SetColor({255,0,0,255});
391 newNumber->SetText(std::to_string(number));
392 smallFontCache[number] = newNumber;
393 }
394 return smallFontCache[number].get();
395 }
396
396397 //Draws the balls and explosions
397398 static void DrawBalls() {
398399 for (size_t i = 0; i< theBallManager.ballArray.size(); i++) {
411412 int y = globalData.theTextManager.textArray[i].getY()-12;
412413 DrawIMG(iChainFrame,globalData.screen,x,y);
413414
414 nf_standard_small_font.draw(globalData.screen, x+12,y+7, NFont::CENTER, "%s", globalData.theTextManager.textArray[i].getText());
415 getSmallInt(globalData.theTextManager.textArray[i].getText())->Draw(globalData.screen, x+12, y+7,
416 sago::SagoTextField::Alignment::center);
415417 }
416418 }
417419 } //DrawBalls
418420
421 template <class T> void sagoTextSetHelpFont(T& field) {
422 field.SetHolder(&globalData.spriteHolder->GetDataHolder());
423 field.SetFont("freeserif");
424 field.SetFontSize(30);
425 field.SetOutline(1, {128,128,128,255});
426 }
427
428 void sagoTextSetHelpFont(sago::SagoTextField& gametypeNameField) {
429 sagoTextSetHelpFont<sago::SagoTextField>(gametypeNameField);
430 }
431
432 void sagoTextSetBlueFont(sago::SagoTextField& field) {
433 field.SetHolder(&globalData.spriteHolder->GetDataHolder());
434 field.SetFont("freeserif");
435 field.SetFontSize(30);
436 field.SetColor({0,0,255,255});
437 field.SetOutline(1, {128,128,255,255});
438 }
419439
420440 //draws everything
421441 void DrawEverything(int xsize, int ysize,BlockGameSdl* theGame, BlockGameSdl* theGame2) {
425445 theGame2->DoPaintJob();
426446 string strHolder;
427447 strHolder = std::to_string(theGame->GetScore()+theGame->GetHandicap());
428 NFont_Write(globalData.screen, theGame->GetTopX()+310,theGame->GetTopY()+100,strHolder.c_str());
448 player1score.SetText(strHolder);
449 player1score.Draw(globalData.screen, theGame->GetTopX()+310,theGame->GetTopY()+100);
429450 if (theGame->GetAIenabled()) {
430 NFont_Write(globalData.screen, theGame->GetTopX()+10,theGame->GetTopY()-34,_("AI") );
431 }
432 else if (editorMode || singlePuzzle) {
433 NFont_Write(globalData.screen, theGame->GetTopX()+10,theGame->GetTopY()-34,_("Playing field") );
451 player1name.SetText(_("AI"));
452 }
453 else if (singlePuzzle) {
454 player1name.SetText(_("Playing field"));
434455 }
435456 else {
436 NFont_Write(globalData.screen, theGame->GetTopX()+10,theGame->GetTopY()-34, globalData.player1name);
437 }
457 player1name.SetText(globalData.player1name);
458 }
459 player1name.Draw(globalData.screen, theGame->GetTopX()+10,theGame->GetTopY()-34);
438460 if (theGame->isTimeTrial()) {
439461 int tid = (int)SDL_GetTicks()-theGame->GetGameStartedAt();
440462 int minutes;
459481 else {
460482 strHolder = std::to_string(minutes)+":0"+std::to_string(seconds);
461483 }
462 //if ((SoundEnabled)&&(!NoSound)&&(tid>0)&&(seconds<5)&&(minutes == 0)&&(seconds>1)&&(!(Mix_Playing(6)))) Mix_PlayChannel(6,heartBeat,0);
463 NFont_Write(globalData.screen, theGame->GetTopX()+310,theGame->GetTopY()+150,strHolder.c_str());
484 player1time.SetText(strHolder);
464485 }
465486 else {
466487 int minutes = ((abs((int)SDL_GetTicks()-(int)theGame->GetGameStartedAt())))/60/1000;
477498 else {
478499 strHolder = std::to_string(minutes)+":0"+std::to_string(seconds);
479500 }
480 NFont_Write(globalData.screen, theGame->GetTopX()+310,theGame->GetTopY()+150,strHolder.c_str());
481 }
501 player1time.SetText(strHolder);
502 }
503 player1time.Draw(globalData.screen, theGame->GetTopX()+310,theGame->GetTopY()+150);
482504 strHolder = std::to_string(theGame->GetChains());
483 NFont_Write(globalData.screen, theGame->GetTopX()+310,theGame->GetTopY()+200,strHolder.c_str());
505 player1chain.SetText(strHolder);
506 player1chain.Draw(globalData.screen, theGame->GetTopX()+310,theGame->GetTopY()+200);
484507 //drawspeedLevel:
485508 strHolder = std::to_string(theGame->GetSpeedLevel());
486 NFont_Write(globalData.screen, theGame->GetTopX()+310,theGame->GetTopY()+250,strHolder.c_str());
509 player1speed.SetText(strHolder);
510 player1speed.Draw(globalData.screen, theGame->GetTopX()+310,theGame->GetTopY()+250);
487511 if ((theGame->isStageClear()) &&(theGame->GetTopY()+700+50*(theGame->GetStageClearLimit()-theGame->GetLinesCleared())-theGame->GetPixels()-1<600+theGame->GetTopY())) {
488512 oldBubleX = theGame->GetTopX()+280;
489513 oldBubleY = theGame->GetTopY()+650+50*(theGame->GetStageClearLimit()-theGame->GetLinesCleared())-theGame->GetPixels()-1;
490514 DrawIMG(stageBobble,globalData.screen,theGame->GetTopX()+280,theGame->GetTopY()+650+50*(theGame->GetStageClearLimit()-theGame->GetLinesCleared())-theGame->GetPixels()-1);
491515 }
492516 //player1 finnish, player2 start
493 if (!editorMode /*&& !singlePuzzle*/ ) {
517 if (true ) {
494518 /*
495519 *If single player mode (and not VS)
496520 */
518542 infostring = _("Score as much as possible. No time limit.");
519543 }
520544 if (infostring.length() > 0) {
521 NFont_Write(globalData.screen, theGame2->GetTopX()+7,theGame2->GetTopY()+10, gametypeName);
522 NFont_Write(globalData.screen, theGame2->GetTopX()+7,theGame2->GetTopY()+160, _("Objective:"));
523 globalData.nf_standard_blue_font.drawBox(globalData.screen, { static_cast<float>(theGame2->GetTopX()+7),static_cast<float>(theGame2->GetTopY()+160+32), 280, 200}, "%s", infostring.c_str());
545 static sago::SagoTextBox infoBox;
546 static sago::SagoTextField objectiveField;
547 static sago::SagoTextField gametypeNameField;
548 sagoTextSetHelpFont(infoBox);
549 infoBox.SetMaxWidth(290);
550 infoBox.SetText(infostring);
551 sagoTextSetHelpFont(objectiveField);
552 objectiveField.SetText(_("Objective:"));
553 sagoTextSetHelpFont(gametypeNameField);
554 gametypeNameField.SetText(gametypeName);
555 gametypeNameField.Draw(globalData.screen, theGame2->GetTopX()+7,theGame2->GetTopY()+10);
556 objectiveField.Draw(globalData.screen, theGame2->GetTopX()+7, theGame2->GetTopY()+160);
557 infoBox.Draw(globalData.screen, theGame2->GetTopX()+7, theGame2->GetTopY()+160+32);
524558 }
525559
526560 //Write the keys that are in use
527561 int y = theGame2->GetTopY()+400;
528 NFont_Write(globalData.screen, theGame2->GetTopX()+7,y,_("Movement keys:") );
529 NFont_Write(globalData.screen, theGame2->GetTopX()+7,y+40,(getKeyName(keySettings[0].left)+", "+getKeyName(keySettings[0].right)+"," ).c_str() );
530 NFont_Write(globalData.screen, theGame2->GetTopX()+7,y+76,(getKeyName(keySettings[0].up)+", "+getKeyName(keySettings[0].down)).c_str() );
531 NFont_Write(globalData.screen, theGame2->GetTopX()+7,y+120,( _("Switch: ")+getKeyName(keySettings[0].change) ).c_str() );
562 std::string controldBoxText = std::string(_("Movement keys:"))+"\n"+getKeyName(keySettings[0].left)+", "+getKeyName(keySettings[0].right)+",\n"
563 + getKeyName(keySettings[0].up)+", "+getKeyName(keySettings[0].down)+"\n"
564 + _("Switch: ") + getKeyName(keySettings[0].change);
532565 if (theGame->isPuzzleMode()) {
533 NFont_Write(globalData.screen, theGame2->GetTopX()+7,y+160,( _("Restart: ")+getKeyName(keySettings[0].push) ).c_str() );
566 controldBoxText += std::string("\n") + _("Restart: ")+getKeyName(keySettings[0].push);
534567 }
535568 else {
536 NFont_Write(globalData.screen, theGame2->GetTopX()+7,y+160,( _("Push line: ")+getKeyName(keySettings[0].push) ).c_str() );
537 }
538
569 controldBoxText += std::string("\n") + _("Push line: ")+getKeyName(keySettings[0].push);
570 }
571 static sago::SagoTextBox controldBox;
572 controldBox.SetHolder(&globalData.spriteHolder->GetDataHolder());
573 sagoTextSetHelpFont(controldBox);
574 controldBox.SetMaxWidth(290);
575 controldBox.SetText(controldBoxText);
576 controldBox.Draw(globalData.screen, theGame2->GetTopX()+7,y);
539577 }
540578 strHolder = std::to_string(theGame2->GetScore()+theGame2->GetHandicap());
541 NFont_Write(globalData.screen, theGame2->GetTopX()+310,theGame2->GetTopY()+100,strHolder.c_str());
579 player2score.SetText(strHolder);
580 player2score.Draw(globalData.screen, theGame2->GetTopX()+310, theGame2->GetTopY()+100);
542581 if (theGame2->GetAIenabled()) {
543 NFont_Write(globalData.screen, theGame2->GetTopX()+10,theGame2->GetTopY()-34,_("AI") );
582 player2name.SetText(_("AI"));
544583 }
545584 else {
546 NFont_Write(globalData.screen, theGame2->GetTopX()+10,theGame2->GetTopY()-34,theGame2->name);
547 }
585 player2name.SetText(theGame2->name);
586 }
587 player2name.Draw(globalData.screen, theGame2->GetTopX()+10,theGame2->GetTopY()-34);
548588 if (theGame2->isTimeTrial()) {
549589 int tid = (int)SDL_GetTicks()-theGame2->GetGameStartedAt();
550590 int minutes;
569609 else {
570610 strHolder = std::to_string(minutes)+":0"+std::to_string(seconds);
571611 }
572 //if ((SoundEnabled)&&(!NoSound)&&(tid>0)&&(seconds<5)&&(minutes == 0)&&(seconds>1)&&(!(Mix_Playing(6)))) Mix_PlayChannel(6,heartBeat,0);
573 NFont_Write(globalData.screen, theGame2->GetTopX()+310,theGame2->GetTopY()+150,strHolder.c_str());
574612 }
575613 else {
576614 int minutes = (abs((int)SDL_GetTicks()-(int)theGame2->GetGameStartedAt()))/60/1000;
587625 else {
588626 strHolder = std::to_string(minutes)+":0"+std::to_string(seconds);
589627 }
590 NFont_Write(globalData.screen, theGame2->GetTopX()+310,theGame2->GetTopY()+150,strHolder.c_str());
591 }
628 }
629 player2time.SetText(strHolder);
630 player2time.Draw(globalData.screen, theGame2->GetTopX()+310,theGame2->GetTopY()+150);
592631 strHolder = std::to_string(theGame2->GetChains());
593 NFont_Write(globalData.screen, theGame2->GetTopX()+310,theGame2->GetTopY()+200,strHolder.c_str());
632 player2chain.SetText(strHolder);
633 player2chain.Draw(globalData.screen, theGame2->GetTopX()+310,theGame2->GetTopY()+200);
594634 strHolder = std::to_string(theGame2->GetSpeedLevel());
595 NFont_Write(globalData.screen, theGame2->GetTopX()+310,theGame2->GetTopY()+250,strHolder.c_str());
635 player2speed.SetText(strHolder);
636 player2speed.Draw(globalData.screen, theGame2->GetTopX()+310,theGame2->GetTopY()+250);
596637 }
597638 //player2 finnish
598639
602643 DrawBalls();
603644
604645 #if DEBUG
646 static sago::SagoTextField fpsField;
647 sagoTextSetBlueFont(fpsField);
605648 Frames++;
606649 if (SDL_GetTicks() >= Ticks + 1000) {
607650 if (Frames > 999) {
611654 Frames = 0;
612655 Ticks = SDL_GetTicks();
613656 }
614
615 globalData.nf_standard_blue_font.draw(globalData.screen, 800, 4, "%s", FPS);
657 fpsField.SetText(FPS);
658 fpsField.Draw(globalData.screen, 800, 4);
616659 #endif
617660 }
618661
745788 string puzzleName;
746789 bool allowResize = true;
747790 bool autoScale = true;
791 bool softwareRenderer = false;
748792 };
749793
750794 static void ParseArguments(int argc, char* argv[], globalConfig& conf) {
765809 ("config,c", boost::program_options::value<vector<string> >(), "Read a config file with the values. Can be given multiple times")
766810 ("nosound", "Disables the sound. Can be used if sound errors prevents you from starting")
767811 ("priority", "Causes the game to not sleep between frames.")
812 ("software-renderer", "Asks SDL2 to use software renderer")
768813 ("verbose-basic", "Enables basic verbose messages")
769814 ("verbose-game-controller", "Enables verbose messages regarding controllers")
770815 ("print-search-path", "Prints the search path and quits")
816861 cout << "Examples:" << "\n";
817862 cout << "\tblockattack \tStart the game normally" << "\n";
818863 cout << "\tblockattack --nosound\tStart the game without sound. Can be used if sound problems prevents the game from starting" << "\n";
864 cout << "\tblockattack --puzzle-level-file puzzle.levels --puzzle-single-level 3\tStart the game with the default puzzles in level 3" << "\n";
865 cout << "\tblockattack --bind-text-domain /dev/null\t Disables translations" << "\n";
819866 cout << "\n";
820867 cout << "Report bugs to the issue tracker here: <https://github.com/blockattack/blockattack-game/issues>" << "\n";
821868 exit(0);
834881 }
835882 if (vm.count("priority")) {
836883 globalData.highPriority = true;
884 }
885 if (vm.count("software-renderer")) {
886 conf.softwareRenderer = true;
837887 }
838888 if (vm.count("verbose-basic")) {
839889 globalData.verboseLevel++;
10241074 globalData.xsize, globalData.ysize,
10251075 createWindowParams );
10261076 dieOnNullptr(sdlWindow, "Unable to create window");
1027 SDL_Renderer* renderer = SDL_CreateRenderer(sdlWindow, -1, 0);
1077 int rendererFlags = 0;
1078 if (config.softwareRenderer) {
1079 rendererFlags |= SDL_RENDERER_SOFTWARE;
1080 }
1081 SDL_Renderer* renderer = SDL_CreateRenderer(sdlWindow, -1, rendererFlags);
10281082 dieOnNullptr(renderer, "Unable to create render");
10291083 if (config.autoScale) {
10301084 SDL_RenderSetLogicalSize(renderer, 1024, 768);
10311085 logicalRenderer = true;
10321086 }
1087 if (globalData.verboseLevel) {
1088 SDL_RendererInfo info;
1089 SDL_GetRendererInfo(renderer, &info);
1090 cout << "Renderer: " << info.name << "\n";
1091 }
10331092 globalData.screen = renderer;
10341093 ResetFullscreen();
10351094 SetSDLIcon(sdlWindow);
10381097 cout << "Images loaded" << "\n";
10391098 }
10401099
1041 BlockGameSdl theGame = BlockGameSdl(50, 100); //creates game objects
1042 BlockGameSdl theGame2 = BlockGameSdl(globalData.xsize-500, 100);
1100 BlockGameSdl theGame = BlockGameSdl(50, 100, &globalData.spriteHolder->GetDataHolder()); //creates game objects
1101 BlockGameSdl theGame2 = BlockGameSdl(globalData.xsize-500, 100, &globalData.spriteHolder->GetDataHolder());
10431102 player1 = &theGame;
10441103 player2 = &theGame2;
10451104
10801139
10811140
10821141 //Saves options
1083 if (!editorMode) {
1142 if (true) {
10841143 configSettings->setInt("fullscreen",(int)globalData.bFullscreen);
10851144 configSettings->setInt("musicenabled",(int)globalData.MusicEnabled);
10861145 configSettings->setInt("soundenabled",(int)globalData.SoundEnabled);
11381197 globalData.theTopScoresTimeTrial = Highscore("timetrial");
11391198 drawBalls = true;
11401199 puzzleLoaded = false;
1141 bool bNearDeath = false; //Play music faster or louder while tru
1200 bool bNearDeath = false; //Play music faster or louder while tru
11421201
11431202 theBallManager = BallManager();
11441203 theExplosionManager = ExplosionManager();
1145 BlockGameSdl theGame = BlockGameSdl(50,100); //creates game objects
1146 BlockGameSdl theGame2 = BlockGameSdl(globalData.xsize-500,100);
1204 BlockGameSdl theGame = BlockGameSdl(50, 100, &globalData.spriteHolder->GetDataHolder()); //creates game objects
1205 BlockGameSdl theGame2 = BlockGameSdl(globalData.xsize-500, 100, &globalData.spriteHolder->GetDataHolder());
11471206 player1 = &theGame;
11481207 player2 = &theGame2;
1149 theGame.DoPaintJob(); //Makes sure what there is something to paint
1208 theGame.DoPaintJob(); //Makes sure what there is something to paint
11501209 theGame2.DoPaintJob();
11511210 BlockGameAction a;
11521211 a.action = BlockGameAction::Action::SET_GAME_OVER;
12761335 done=1;
12771336 DrawBackground(globalData.screen);
12781337 }
1279 if ((!editorMode)&&(!editorModeTest)&&(!theGame.GetAIenabled())) {
1338 if (!theGame.GetAIenabled()) {
12801339 //player1:
12811340 if ( event.key.keysym.sym == keySettings[player1keys].up ) {
12821341 a.action = BlockGameAction::Action::MOVE;
13071366 theGame.DoAction(a);
13081367 }
13091368 }
1310 if (!editorMode && !theGame2.GetAIenabled()) {
1369 if (!theGame2.GetAIenabled()) {
13111370 //player2:
13121371 if ( event.key.keysym.sym == keySettings[player2keys].up ) {
13131372 a.action = BlockGameAction::Action::MOVE;
13391398 }
13401399 }
13411400 //common:
1342 if ((!singlePuzzle)&&(!editorMode)) {
1401 if (!singlePuzzle) {
13431402 if ( event.key.keysym.sym == SDLK_F2 ) {
13441403 /*#if NETWORK
13451404 if ((!showOptions)&&(!networkActive)){
15251584 bMouseUp2=true;
15261585 }
15271586
1528 if (!editorMode ) {
1587 if (true ) {
15291588 //read mouse events
15301589 if (SDL_GetMouseState(nullptr,nullptr)&SDL_BUTTON(1) && bMouseUp) {
15311590 //This is the mouse events
15651624 //Sees if music is stopped and if music is enabled
15661625 if ((!globalData.NoSound)&&(!Mix_PlayingMusic())&&(globalData.MusicEnabled)&&(!bNearDeath)) {
15671626 // then starts playing it.
1568 Mix_PlayMusic(bgMusic, -1); //music loop
1627 Mix_PlayMusic(bgMusic.get(), -1); //music loop
15691628 Mix_VolumeMusic((MIX_MAX_VOLUME*3)/10);
15701629 }
15711630
15721631 if (bNearDeath!=bNearDeathPrev) {
15731632 if (bNearDeath) {
15741633 if (!globalData.NoSound &&(globalData.MusicEnabled)) {
1575 Mix_PlayMusic(highbeatMusic, 1);
1634 Mix_PlayMusic(highbeatMusic.get(), 1);
15761635 Mix_VolumeMusic((MIX_MAX_VOLUME*5)/10);
15771636 }
15781637 }
15791638 else {
15801639 if (!globalData.NoSound &&(globalData.MusicEnabled)) {
1581 Mix_PlayMusic(bgMusic, -1);
1640 Mix_PlayMusic(bgMusic.get(), -1);
15821641 Mix_VolumeMusic((MIX_MAX_VOLUME*3)/10);
15831642 }
15841643 }
2626
2727 #include "sago/SagoSprite.hpp"
2828 #include "BlockGame.hpp"
29 #include "sago/SagoTextField.hpp"
2930
3031
3132 //main variables and constants
4243
4344 const char sharedir[] = SHAREDIR;
4445
45 //All graphic in the game (as pointers):
46 //All graphic in the game:
4647 sago::SagoSprite backgroundImage; //Stores the background image
48 sago::SagoSprite bExit;
4749 static sago::SagoSprite backBoard; //Stores the background to the board
4850 static sago::SagoSprite bForward; //The "forward" button
4951 #if NETWORK
6668 static sago::SagoSprite explosion[4]; //Then a block explodes
6769 //Animations end
6870 static sago::SagoSprite counter[3]; //Counts down from 3
69 static sago::SagoSprite bricks[7]; //The bricks, saved in an array of pointers
71 sago::SagoSprite bricks[7]; //The bricks, saved in an array of pointers
7072 static sago::SagoSprite crossover; //Cross the bricks that will be cleared soon
7173 static sago::SagoSprite balls[7]; //The balls (the small ones that jump around)
7274
9092 static sago::SagoSprite transCover; //The transperant block, covers the upcomming
9193 static sago::SagoSprite bSkip;
9294 static sago::SagoSprite bRetry;
93 static sago::SagoSprite bExit;
9495 const int bExitSize = 100; //height and width of the exit button
9596 const int bExitOffset = 140; //pixels from the buttom right corner to the top left of the exit button
9697
97 static NFont nf_standard_small_font;
98
99 static Mix_Music *bgMusic; //backgroundMusic
100 static Mix_Music *highbeatMusic; //Background music with higher beat
101 static Mix_Chunk *boing; //boing sound when clearing
102 static Mix_Chunk *applause; //Applause, then the player is good
103 static Mix_Chunk *photoClick; //clickSound
104 static Mix_Chunk *counterChunk; //When counting down
105 static Mix_Chunk *counterFinalChunk;
98 static sago::MusicHandler bgMusic; //backgroundMusic
99 static sago::MusicHandler highbeatMusic; //Background music with higher beat
100 static sago::SoundHandler boing; //boing sound when clearing
101 static sago::SoundHandler applause; //Applause, then the player is good
102 static sago::SoundHandler photoClick; //clickSound
103 static sago::SoundHandler counterChunk; //When counting down
104 static sago::SoundHandler counterFinalChunk;
106105
107106 static bool bMouseUp; //true if the mouse(1) is unpressed
108107 static bool bMouseUp2; //true if the mouse(2) is unpressed
112111 static bool bNearDeathPrev; //Near death status last time checked.
113112 static bool puzzleLoaded; //true if the puzzle levels have been loaded
114113 static bool drawBalls; //if true balls are drawed to the screen, this might lower framerate too much
115
116 static bool editorMode = false;
117 static bool editorModeTest = false;
118114
119115
120116
196192 cordRetryButton.ysize = buttonYsize
197193 };
198194
199 #endif
195 static sago::SagoTextField player1name;
196 static sago::SagoTextField player2name;
197 static sago::SagoTextField player1time;
198 static sago::SagoTextField player2time;
199 static sago::SagoTextField player1score;
200 static sago::SagoTextField player2score;
201 static sago::SagoTextField player1chain;
202 static sago::SagoTextField player2chain;
203 static sago::SagoTextField player1speed;
204 static sago::SagoTextField player2speed;
205
206
207 #endif
2424 #include <stdlib.h>
2525 #include "MenuSystem.h"
2626 #include "common.h"
27 #include "HelpHowtoState.hpp"
28 #include "HelpGamepadState.hpp"
29 #include "HelpAboutState.hpp"
30 #include "ShowFileState.hpp"
2731
2832 using std::string;
2933 using std::cerr;
9599
96100 void InitMenues() {
97101 standardButton.setSurfaces();
98 standardButton.thefont = &globalData.nf_button_font;
99102 }
100103
101104 static void runSinglePlayerEndless() {
266269 RunGameState(mm);
267270 }
268271
269 void MainMenu() {
270 InitMenues();
271 Menu m(globalData.screen,_("Block Attack - Rise of the blocks"),false);
272 Button bHi,bTimetrial1, bStageClear, bPuzzle, bVs1, bMulti, bConfigure,bHighscore;
272 static void runHowto() {
273 HelpHowtoState howto;
274 RunGameState(howto);
275 }
276
277 static void runHelpGamepad() {
278 HelpGamepadState helpGamepad;
279 RunGameState(helpGamepad);
280 }
281
282 static void runHelpAbout() {
283 HelpAboutState helpAbout;
284 RunGameState(helpAbout);
285 }
286
287 static void runCredits() {
288 ShowFileState creditsFile;
289 creditsFile.SetData("misc/AUTHORS", _("Credits"));
290 RunGameState(creditsFile);
291 }
292
293 static void HelpMenu() {
294 Menu m(globalData.screen, _("Help"), true);
295 Button bHowto;
296 bHowto.setLabel(_("How to"));
297 bHowto.setAction(runHowto);
298 m.addButton(&bHowto);
299 Button bGamepad;
300 bGamepad.setLabel(_("Gamepad"));
301 bGamepad.setAction(runHelpGamepad);
302 m.addButton(&bGamepad);
303 Button bCredits;
304 bCredits.setLabel(_("Credits"));
305 bCredits.setAction(runCredits);
306 m.addButton(&bCredits);
307 Button bAbout;
308 bAbout.setLabel(_("About"));
309 bAbout.setAction(runHelpAbout);
310 m.addButton(&bAbout);
311 RunGameState(m);
312 }
313
314 static void SinglePlayerMenu() {
315 Menu m(globalData.screen, _("Single player"), true);
316 Button bHi,bTimetrial1, bStageClear, bPuzzle, bVs1;
273317 bHi.setLabel(_("Single player - endless") );
274318 bHi.setAction(runSinglePlayerEndless);
275319 bTimetrial1.setLabel(_("Single player - time trial") );
280324 bPuzzle.setAction(runSinglePlayerPuzzle);
281325 bVs1.setLabel(_("Single player - vs") );
282326 bVs1.setAction(SinglePlayerVsMenu);
327 m.addButton(&bHi);
328 m.addButton(&bTimetrial1);
329 m.addButton(&bStageClear);
330 m.addButton(&bPuzzle);
331 m.addButton(&bVs1);
332 RunGameState(m);
333 }
334
335 void MainMenu() {
336 InitMenues();
337 Menu m(globalData.screen,_("Block Attack - Rise of the blocks"),false);
338 Button bHi, bMulti, bConfigure, bHighscore, bHelp;
339 bHi.setLabel(_("Single player") );
340 bHi.setAction(SinglePlayerMenu);
283341 bMulti.setLabel(_("Multi player") );
284342 bMulti.setAction(MultiplayerMenu);
285343 bConfigure.setLabel(_("Configure") );
286344 bConfigure.setAction(ConfigureMenu);
287345 bHighscore.setLabel(_("Highscores") );
288346 bHighscore.setAction(buttonActionHighscores);
347 bHelp.setLabel(_("Help"));
348 bHelp.setAction(HelpMenu);
289349 m.addButton(&bHi);
290 m.addButton(&bTimetrial1);
291 m.addButton(&bStageClear);
292 m.addButton(&bPuzzle);
293 m.addButton(&bVs1);
294350 m.addButton(&bMulti);
295351 m.addButton(&bConfigure);
296352 m.addButton(&bHighscore);
353 m.addButton(&bHelp);
297354 RunGameState(m);
298355 }
3232 }
3333
3434 static std::string CreateFileName(const std::tm& t ) {
35 std::string ret = "replays/blockattack_game_";
3635 char buffer[200];
3736 snprintf(buffer, sizeof(buffer), "replays/blockattack_game_%i-%02i-%02iT%02i_%02i_%02i_AUTO.replay", t.tm_year+1900, t.tm_mon+1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
38 ret = buffer;
37 std::string ret = buffer;
3938 return ret;
4039 }
4140
4545 virtual void ProcessInput(const SDL_Event& event, bool &processed) = 0;
4646
4747 virtual void Update() {}
48
49 virtual ~GameStateInterface() {}
4850 };
4951
5052 } //sago
4141 std::vector<SDL_RWops*> rwOpsToFree;
4242 std::vector<std::unique_ptr<char[]>> dataToFree;
4343 bool verbose = false;
44 Uint64 version = 0;
4445 SDL_Renderer* renderer = nullptr;
4546 };
4647
4748 static void printFileWeLoad(const std::string& value) {
4849 std::cout << "Loading " << value << "\n";
50 }
51
52 SagoDataHolder::SagoDataHolder() {
53 data = new SagoDataHolderData();
4954 }
5055
5156 SagoDataHolder::SagoDataHolder(SDL_Renderer* renderer) {
5358 data->renderer = renderer;
5459 }
5560
56 SagoDataHolder::~SagoDataHolder() {
61 void SagoDataHolder::invalidateAll(SDL_Renderer* renderer) {
62 invalidateAll();
63 data->renderer = renderer;
64 }
65
66 void SagoDataHolder::invalidateAll() {
67 data->version++;
5768 for (auto& item : data->textures) {
5869 SDL_DestroyTexture(item.second);
5970 }
71 data->textures.clear();
6072 for (auto& item : data->music) {
6173 Mix_FreeMusic(item.second);
6274 }
75 data->music.clear();
6376 for (auto& item : data->sounds) {
6477 Mix_FreeChunk(item.second);
6578 }
79 data->sounds.clear();
6680 for (auto& item : data->fonts) {
6781 for (auto& item2 : item.second) {
6882 TTF_CloseFont(item2.second);
6983 }
7084 }
85 data->fonts.clear();
7186 for (auto& item : data->rwOpsToFree) {
7287 SDL_FreeRW(item);
7388 }
89 data->rwOpsToFree.clear();
90 }
91
92 SagoDataHolder::~SagoDataHolder() {
93 invalidateAll();
7494 delete data;
7595 }
7696
7797 SDL_Texture* SagoDataHolder::getTexturePtr(const std::string& textureName) const {
98 if (!data->renderer) {
99 throw std::runtime_error("SagoDataHolder used before setting the renderer");
100 }
78101 SDL_Texture* ret = data->textures[textureName];
79102 if (ret) {
80103 return ret;
243266 data->verbose = value;
244267 }
245268
269 Uint64 SagoDataHolder::getVersion() const {
270 return data->version;
271 }
272
273 TextureHandler::TextureHandler(const SagoDataHolder* holder, const std::string &textureName) {
274 this->holder = holder;
275 this->version = this->holder->getVersion();
276 this->textureName = textureName;
277 this->data = this->holder->getTexturePtr(this->textureName);
278 }
279
280 SDL_Texture* TextureHandler::get() {
281 if (version != holder->getVersion()) {
282 //The holder has been invalidated
283 this->data = this->holder->getTexturePtr(textureName);
284 }
285 return data;
286 }
287
288
289 MusicHandler::MusicHandler(const SagoDataHolder* holder, const std::string& musicName) {
290 this->holder = holder;
291 this->version = this->holder->getVersion();
292 this->musicName = musicName;
293 this->data = this->holder->getMusicPtr(this->musicName);
294 }
295
296 Mix_Music* MusicHandler::get() {
297 if (version != holder->getVersion()) {
298 //The holder has been invalidated
299 this->data = this->holder->getMusicPtr(musicName);
300 }
301 return data;
302 }
303
304 SoundHandler::SoundHandler(const SagoDataHolder* holder, const std::string& soundName) {
305 this->holder = holder;
306 this->version = this->holder->getVersion();
307 this->soundName = soundName;
308 this->data = this->holder->getSoundPtr(this->soundName);
309 }
310
311 Mix_Chunk* SoundHandler::get() {
312 if (version != holder->getVersion()) {
313 //The holder has been invalidated
314 this->data = this->holder->getSoundPtr(soundName);
315 }
316 return data;
317 }
318
319
320 TextureHandler SagoDataHolder::getTextureHandler(const std::string &textureName) const {
321 return TextureHandler(this, textureName);
322 }
323
324 MusicHandler SagoDataHolder::getMusicHandler(const std::string &musicName) const {
325 return MusicHandler(this, musicName);
326 }
327
328 SoundHandler SagoDataHolder::getSoundHandler(const std::string &soundName) const {
329 return SoundHandler(this, soundName);
330 }
331
246332 } //name space sago
3333
3434 namespace sago {
3535
36 class SagoDataHolder {
36 class SagoDataHolder;
37
38 class TextureHandler {
3739 public:
38 SagoDataHolder(SDL_Renderer* renderer);
40 TextureHandler() {};
41 TextureHandler(const SagoDataHolder* holder, const std::string &textureName);
42 SDL_Texture* get();
43 private:
44 std::string textureName;
45 const SagoDataHolder* holder = nullptr;
46 SDL_Texture* data = nullptr;
47 Uint64 version = 0;
48 };
49
50
51 class MusicHandler final {
52 public:
53 MusicHandler() {};
54 MusicHandler(const SagoDataHolder* holder, const std::string &musicName);
55 Mix_Music* get();
56 private:
57 std::string musicName;
58 const SagoDataHolder* holder = nullptr;
59 Mix_Music* data = nullptr;
60 Uint64 version = 0;
61 };
62
63
64 class SoundHandler final {
65 public:
66 SoundHandler() {};
67 SoundHandler(const SagoDataHolder* holder, const std::string &soundName);
68 Mix_Chunk* get();
69 private:
70 std::string soundName;
71 const SagoDataHolder* holder = nullptr;
72 Mix_Chunk* data = nullptr;
73 Uint64 version = 0;
74 };
75
76 class SagoDataHolder final {
77 public:
3978 /**
40 * Return a pointer to the given texture. The pointer is valid for the lifetime of SagoDataHolder object it was taken from.
79 * The renderer must be set before requesting a texture.
80 * If the constructor without elements is used then invalidateAll(SDL_Renderer*) must be called before getTexturePtr
81 */
82 SagoDataHolder();
83 explicit SagoDataHolder(SDL_Renderer* renderer);
84 /**
85 * Return a pointer to the given texture. The pointer is valid for the lifetime of SagoDataHolder object it was taken from or until invalidateAll is called.
4186 * @param textureName Name of the texture
4287 * @return Pointer to the loaded texture
4388 */
4489 SDL_Texture* getTexturePtr(const std::string &textureName) const;
90 TextureHandler getTextureHandler(const std::string &textureName) const;
4591 TTF_Font* getFontPtr(const std::string &fontName, int ptsize) const;
4692 Mix_Music* getMusicPtr(const std::string &musicName) const;
93 MusicHandler getMusicHandler(const std::string &musicName) const;
4794 Mix_Chunk* getSoundPtr(const std::string &soundName) const;
95 SoundHandler getSoundHandler(const std::string &soundName) const;
4896 void setVerbose(bool value);
49 virtual ~SagoDataHolder();
97 /**
98 * Invalidates all pointers returned by any of the get variables
99 */
100 void invalidateAll();
101 /**
102 * Invalidates all pointers returned by any of the get variables.
103 * Also sets a new renderer.
104 *
105 * Setting a new renderer might cause all old textures to no longer match the renderer format.
106 */
107 void invalidateAll(SDL_Renderer* renderer);
108 /**
109 * The version number. Changes everytime the pointers are invalidated.
110 * Can be used to determen if it is neccecary to get a new pointer.
111 * @return A globally unique number.
112 */
113 Uint64 getVersion() const;
114 ~SagoDataHolder();
50115 private:
51116 SagoDataHolder(const SagoDataHolder& base) = delete;
52117 SagoDataHolder& operator=(const SagoDataHolder& base) = delete;
7070 return ret;
7171 }
7272
73 static void CreatePathToFile(const std::string& path) {
74 size_t end_of_path = path.find_last_of("/");
75 if (end_of_path == std::string::npos) {
76 //No path
77 return;
78 }
79 std::string path2dir = path.substr(0, end_of_path);
80 PHYSFS_mkdir(path2dir.c_str());
81 }
82
7383 void WriteFileContent(const char* filename, const std::string& content) {
84 CreatePathToFile(filename);
7485 PHYSFS_file* myfile = PHYSFS_openWrite(filename);
7586 if (!myfile) {
7687 cerr << "Failed to open file for writing, " << PHYSFS_getLastError() << "\n";
2727 namespace sago {
2828
2929 struct SagoSprite::SagoSpriteData {
30 SDL_Texture* tex = nullptr;
31 SDL_Rect imgCord{};
32 SDL_Rect origin{};
30 TextureHandler tex;
31 SDL_Rect imgCord = {};
32 SDL_Rect origin = {};
3333 int aniFrames = 0;
3434 int aniFrameTime = 0;
3535 };
4040
4141 SagoSprite::SagoSprite(const SagoDataHolder& texHolder, const std::string& texture,const SDL_Rect& initImage,const int animationFrames, const int animationFrameLength) {
4242 data = new SagoSpriteData();
43 data->tex = texHolder.getTexturePtr(texture);
43 data->tex = texHolder.getTextureHandler(texture);
4444 data->imgCord = initImage;
4545 data->aniFrames = animationFrames;
4646 data->aniFrameTime = animationFrameLength;
6464 }
6565
6666 void SagoSprite::DrawScaled(SDL_Renderer* target, Sint32 frameTime, int x, int y, int w, int h) const {
67 if (!data->tex) {
67 if (!data->tex.get()) {
6868 std::cerr << "Texture is null!\n";
6969 }
7070 SDL_Rect rect = data->imgCord;
7171 rect.x+=rect.w*((frameTime/data->aniFrameTime)%data->aniFrames);
7272 SDL_Rect pos = rect;
73 pos.x = x;
74 pos.y = y;
73 pos.x = x - this->data->origin.x;
74 pos.y = y - this->data->origin.y;
7575 if (w > 0) {
7676 pos.w = w;
7777 }
7878 if (h > 0) {
7979 pos.h = h;
8080 }
81 SDL_RenderCopy(target, data->tex, &rect, &pos);
81 SDL_RenderCopy(target, data->tex.get(), &rect, &pos);
8282 }
8383
8484 void SagoSprite::Draw(SDL_Renderer* target, Sint32 frameTime, int x, int y, const SDL_Rect& part) const {
8989 rect.w = part.w;
9090 rect.h = part.h;
9191 SDL_Rect pos = rect;
92 pos.x = x;
93 pos.y = y;
94 SDL_RenderCopy(target, data->tex, &rect, &pos);
92 pos.x = x - this->data->origin.x;
93 pos.y = y - this->data->origin.y;
94 SDL_RenderCopy(target, data->tex.get(), &rect, &pos);
95 }
96
97 void SagoSprite::DrawProgressive(SDL_Renderer* target, float progress, int x, int y) const {
98 Sint32 frameNumber = progress*data->aniFrames;
99 Sint32 frameTime = frameNumber*data->aniFrameTime;
100 Draw(target, frameTime, x, y);
95101 }
96102
97103 void SagoSprite::DrawBounded(SDL_Renderer* target, Sint32 frameTime, int x, int y, const SDL_Rect& bounds) const {
137143 rect.h -= absDiff;
138144 }
139145
140 SDL_RenderCopy(target, data->tex, &rect, &pos);
146 SDL_RenderCopy(target, data->tex.get(), &rect, &pos);
141147 }
142148
143149 void SagoSprite::SetOrigin(const SDL_Rect& newOrigin) {
2828
2929 namespace sago {
3030
31 class SagoSprite {
31 class SagoSprite final {
3232 public:
3333 SagoSprite();
3434 SagoSprite(const SagoDataHolder &texHolder, const std::string &texture,const SDL_Rect& initImage,const int animationFrames, const int animationFrameLength);
5757 * @param y Place to draw the sprite
5858 * @param bounds A recagular area that we must not draw outside.
5959 */
60 void DrawBounded(SDL_Renderer* target, Sint32 frameTime, int x, int y, const SDL_Rect& bounds) const;
60 void DrawBounded(SDL_Renderer* target, Sint32 frameTime, int x, int y, const SDL_Rect& bounds) const;/**
61 * Draws the sprite to a given render window
62 * @param target The render window to draw on
63 * @param progress A float with value from 0.0f to 1.0f. Tells how far in the animation that we got
64 * @param x Place to draw the sprite
65 * @param y Place to draw the sprite
66 */
67 void DrawProgressive(SDL_Renderer* target, float progress, int x, int y) const;
6168 void DrawScaled(SDL_Renderer* target, Sint32 frameTime, int x, int y, int w, int h) const;
6269 /**
6370 * Set a different origin. Normally it is the top left cornor. But in some cases you might want to center the origin or tranform it for other reasons
6875 SagoSprite& operator=(const SagoSprite& base);
6976 int GetWidth() const;
7077 int GetHeight() const;
71 virtual ~SagoSprite();
78 ~SagoSprite();
7279 private:
7380 struct SagoSpriteData;
7481 SagoSpriteData *data;
6363 static int getDefaultValue(const rapidjson::Value& value, const char* name, int defaultValue) {
6464 assert(value.IsObject());
6565 const auto& t = value.GetObject().FindMember(name);
66 if (t->value.IsInt()) {
66 if (t != value.MemberEnd() && t->value.IsInt()) {
6767 return t->value.GetInt();
6868 }
6969 return defaultValue;
7272 static std::string getDefaultValue(const rapidjson::Value& value, const char* name, std::string defaultValue) {
7373 assert(value.IsObject());
7474 const auto& t = value.GetObject().FindMember(name);
75 if (t->value.IsString()) {
75 if (t != value.MemberEnd() && t->value.IsString()) {
7676 defaultValue = t->value.GetString();
7777 }
7878 return defaultValue;
102102 int width = getDefaultValue(m.value, "width",0);
103103 int number_of_frames = getDefaultValue(m.value, "number_of_frames",1);
104104 int frame_time = getDefaultValue(m.value, "frame_time",1);
105 int originx = getDefaultValue(m.value, "originx",0);
106 int originy = getDefaultValue(m.value, "originy",0);
105 SDL_Rect origin = {};
106 origin.x = getDefaultValue(m.value, "originx",0);
107 origin.y = getDefaultValue(m.value, "originy",0);
107108 if (number_of_frames < 1) {
108109 number_of_frames = 1;
109110 }
111112 frame_time = 1;
112113 }
113114 std::shared_ptr<sago::SagoSprite> ptr(new SagoSprite(*(data->tex),textureName, {topx,topy,width,height},number_of_frames,frame_time));
114 ptr->SetOrigin({originx,originy, 0, 0});
115 ptr->SetOrigin(origin);
115116 this->data->sprites[std::string(spriteName)] = ptr;
116117 }
117118 }
2929
3030 namespace sago {
3131
32 class SagoSpriteHolder {
32 class SagoSpriteHolder final {
3333 public:
34 SagoSpriteHolder(const SagoDataHolder &texHolder);
35 virtual ~SagoSpriteHolder();
34 explicit SagoSpriteHolder(const SagoDataHolder &texHolder);
35 ~SagoSpriteHolder();
3636 void ReadSprites();
3737 const sago::SagoSprite& GetSprite(const std::string &spritename) const;
3838 const SagoDataHolder& GetDataHolder() const;
0 /*
1 Copyright (c) 2018 Poul Sander
2
3 Permission is hereby granted, free of charge, to any person
4 obtaining a copy of this software and associated documentation files
5 (the "Software"), to deal in the Software without restriction,
6 including without limitation the rights to use, copy, modify, merge,
7 publish, distribute, sublicense, and/or sell copies of the Software,
8 and to permit persons to whom the Software is furnished to do so,
9 subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be
12 included in all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
18 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 SOFTWARE.
22 */
23
24 #include "SagoTextBox.hpp"
25 #include "SagoTextField.hpp"
26 #include <vector>
27 #include <iostream>
28 #include "utf8.h"
29 #include <algorithm>
30
31 namespace sago {
32
33 struct SagoTextBox::SagoTextBoxData {
34 const sago::SagoDataHolder* tex = nullptr;
35 std::string fontName = "freeserif";
36 SDL_Color color = { 255, 255, 255, 0 };
37 SDL_Color outlineColor = { 255, 255, 0, 0 };
38 int fontSize = 16;
39 int outline = 0;
40 std::string text = "";
41 std::string renderedText = "";
42 std::vector<SagoTextField> lines;
43 int maxWidth = 0;
44 };
45
46 SagoTextBox::SagoTextBox() {
47 data = new SagoTextBoxData();
48 }
49
50 SagoTextBox::~SagoTextBox() {
51 delete data;
52 }
53
54 void SagoTextBox::SetHolder(const SagoDataHolder* holder) {
55 data->tex = holder;
56 }
57
58 void SagoTextBox::SetText(const char* text) {
59 data->text = text;
60 }
61
62 void SagoTextBox::SetText(const std::string& text) {
63 data->text = text;
64 }
65
66 void SagoTextBox::SetColor(const SDL_Color& color) {
67 data->color = color;
68 }
69
70 void SagoTextBox::SetFont(const char* fontName) {
71 data->fontName = fontName;
72 }
73
74 void SagoTextBox::SetFontSize(int fontSize) {
75 data->fontSize = fontSize;
76 }
77
78 void SagoTextBox::SetOutline(int outlineSize, const SDL_Color& color) {
79 data->outline = outlineSize;
80 data->outlineColor = color;
81 }
82
83 void SagoTextBox::SetMaxWidth(int width) {
84 data->maxWidth = width;
85 }
86
87 const std::string& SagoTextBox::GetText() const {
88 return data->text;
89 }
90
91 void SagoTextBox::AppendLineToCache(const std::string& text) {
92 data->lines.resize(data->lines.size()+1);
93 SagoTextField& tf = data->lines.back();
94 tf.SetHolder(data->tex);
95 tf.SetFont(data->fontName.c_str());
96 tf.SetFontSize(data->fontSize);
97 tf.SetColor(data->color);
98 tf.SetOutline(data->outline, data->outlineColor);
99 tf.SetText(text);
100 }
101
102
103 void SagoTextBox::SplitAndAppendLineToCache(TTF_Font* font, const std::string& text) {
104 int width = data->maxWidth;
105 TTF_SizeUTF8(font, text.c_str(),&width, nullptr);
106 if (data->maxWidth <= 0 || width <= data->maxWidth || text.length() == 1) {
107 AppendLineToCache(text);
108 return;
109 }
110 std::string::const_iterator splitLocation = text.begin()+1;
111 bool splitDone = false;
112 while (!splitDone) {
113 std::string::const_iterator nextSearchStart = splitLocation+1;
114 if (nextSearchStart == text.end()) {
115 splitDone = true;
116 continue;
117 }
118 std::string::const_iterator nextSpace = std::find(nextSearchStart, text.end(), ' ');
119 std::string attemptSubString(text.begin(), nextSpace);
120 TTF_SizeUTF8(font, attemptSubString.c_str(),&width, nullptr);
121 if (width <= data->maxWidth && nextSpace != text.end()) {
122 splitLocation = nextSpace;
123 }
124 else {
125 splitDone = true;
126 }
127 }
128 if (splitLocation == text.begin()+1) {
129 splitLocation = text.begin();
130 utf8::advance(splitLocation, 1, text.end());
131 splitDone = false;
132 while (!splitDone && splitLocation != text.end()) {
133 std::string::const_iterator nextSplit = splitLocation;
134 utf8::advance(nextSplit, 1, text.end());
135 std::string attemptSubString(text.begin(), nextSplit);
136 TTF_SizeUTF8(font, attemptSubString.c_str(), &width, nullptr);
137 if (width <= data->maxWidth) {
138 splitLocation = nextSplit;
139 }
140 else {
141 splitDone = true;
142 }
143 }
144 }
145 std::string firstPart(text.begin(), splitLocation);
146 AppendLineToCache(firstPart);
147 while (splitLocation != text.end() && *splitLocation == ' ') {
148 //Trim spaces after an automatic line break.
149 ++splitLocation;
150 }
151 if (splitLocation == text.end()) {
152 return;
153 }
154 std::string secondPart(splitLocation, text.end());
155 SplitAndAppendLineToCache(font, secondPart);
156 }
157
158 void SagoTextBox::UpdateCache() {
159 if (!data->tex) {
160 std::cerr << "FATAL: SagoTextBox::UpdateCache - DataHolder not set!\n";
161 abort();
162 }
163 TTF_Font *font = data->tex->getFontPtr(data->fontName, data->fontSize);
164 const char delim = '\n';
165 const std::string& s = data->text;
166 auto start = 0U;
167 auto end = s.find(delim);
168 data->lines.clear();
169 while (end != std::string::npos)
170 {
171 const std::string& theSubString = s.substr(start, end - start);
172 SplitAndAppendLineToCache(font, theSubString);
173 start = end + 1;
174 end = s.find(delim, start);
175 }
176 SplitAndAppendLineToCache(font, s.substr(start, end));
177 data->renderedText = data->text;
178 }
179
180 void SagoTextBox::Draw(SDL_Renderer* target, int x, int y) {
181 if (data->text != data->renderedText) {
182 UpdateCache();
183 }
184 TTF_Font *font = data->tex->getFontPtr(data->fontName, data->fontSize);
185 int lineSkip = TTF_FontLineSkip(font);
186 for (size_t i = 0; i < data->lines.size(); ++i) {
187 data->lines[i].Draw(target, x, y+i*lineSkip);
188 }
189 }
190
191 } //namespace sago
0 /*
1 Copyright (c) 2018 Poul Sander
2
3 Permission is hereby granted, free of charge, to any person
4 obtaining a copy of this software and associated documentation files
5 (the "Software"), to deal in the Software without restriction,
6 including without limitation the rights to use, copy, modify, merge,
7 publish, distribute, sublicense, and/or sell copies of the Software,
8 and to permit persons to whom the Software is furnished to do so,
9 subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be
12 included in all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
18 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 SOFTWARE.
22 */
23
24 #ifndef SAGOTEXTBOX_HPP
25 #define SAGOTEXTBOX_HPP
26
27 #include "SagoDataHolder.hpp"
28 #include "SagoTextField.hpp"
29
30 namespace sago {
31
32 class SagoTextBox final {
33 public:
34 SagoTextBox();
35 ~SagoTextBox();
36 void SetHolder(const SagoDataHolder* holder);
37 void SetText(const char* text);
38 void SetText(const std::string& text);
39 void SetColor(const SDL_Color& color);
40
41 /**
42 * Set the name of the font. Must be known to the data holder.
43 * The name could for instance be "freeserif".
44 * @param fontName Name of the font as required by SagoDataHolder
45 */
46 void SetFont(const char* fontName);
47 void SetFontSize(int fontSize);
48 void SetOutline(int outlineSize, const SDL_Color& color);
49 /**
50 * Sets the max width to generate. SagoTextBox will insert line breaks to keep the width below this number.
51 * Outline is not included in the width: If you have a 2 pixels outline the rendere may go 2 pixels beyond.
52 * You will always need to generate at least one char per line. If max width is too low one char will be drawn per line even if it goes above max width.
53 * Setting this to 0 will disable the feature.
54 * @param width The maximum width before forcing a line break
55 */
56 void SetMaxWidth(int width);
57 const std::string& GetText() const;
58 void Draw(SDL_Renderer* target, int x, int y);
59 void UpdateCache();
60 private:
61 void AppendLineToCache(const std::string& text);
62 void SplitAndAppendLineToCache(TTF_Font* font, const std::string& text);
63 SagoTextBox(const SagoTextBox& orig) = delete;
64 SagoTextBox& operator=(const SagoTextBox& base) = delete;
65 struct SagoTextBoxData;
66 SagoTextBoxData *data;
67 };
68
69 } //namespace sago
70
71 #endif /* SAGOTEXTBOX_HPP */
72
0 /*
1 Copyright (c) 2018 Poul Sander
2
3 Permission is hereby granted, free of charge, to any person
4 obtaining a copy of this software and associated documentation files
5 (the "Software"), to deal in the Software without restriction,
6 including without limitation the rights to use, copy, modify, merge,
7 publish, distribute, sublicense, and/or sell copies of the Software,
8 and to permit persons to whom the Software is furnished to do so,
9 subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be
12 included in all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
18 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 SOFTWARE.
22 */
23
24 #include "SagoTextField.hpp"
25 #include <iostream>
26 #include <SDL_ttf.h>
27
28 namespace sago {
29
30 class OutlineHandler {
31 TTF_Font* font;
32 int originalOutline = 0;
33 int targetOutline;
34 bool doChange = false;
35 public:
36 OutlineHandler(TTF_Font* font, int outline) : font{font}, targetOutline{outline} {
37 originalOutline = TTF_GetFontOutline(font);
38 if (originalOutline == targetOutline) {
39 return;
40 }
41 doChange = true;
42 TTF_SetFontOutline(font, targetOutline);
43 };
44
45 void reset() {
46 if (doChange) {
47 TTF_SetFontOutline(font,originalOutline);
48 doChange = false;
49 }
50 }
51
52 ~OutlineHandler() {
53 reset();
54 }
55 private:
56 OutlineHandler(const OutlineHandler& orig) = delete;
57 OutlineHandler& operator=(const OutlineHandler& base) = delete;
58 };
59
60 struct SagoTextField::SagoTextFieldData {
61 const sago::SagoDataHolder* tex = nullptr;
62 SDL_Surface* textSurface = nullptr;
63 SDL_Texture* texture = nullptr;
64 SDL_Surface* outlineTextSurface = nullptr;
65 SDL_Texture* outlineTexture = nullptr;
66 std::string fontName = "freeserif";
67 SDL_Color color = { 255, 255, 255, 0 };
68 SDL_Color outlineColor = { 255, 255, 0, 0 };
69 int fontSize = 16;
70 int outline = 0;
71 std::string text = "";
72 std::string renderedText = "";
73 Uint64 renderedVersion = 0;
74 };
75
76 SagoTextField::SagoTextField() {
77 data = new SagoTextFieldData();
78 }
79
80 SagoTextField::SagoTextField(SagoTextField&& o) noexcept {
81 data = o.data;
82 o.data = nullptr;
83 }
84
85 SagoTextField& SagoTextField::CopyFrom(const SagoTextField& base) {
86 ClearCache();
87 try {
88 *data = *(base.data);
89 //Copy all data but do not reuse the cache as it would result in a double free
90 data->outlineTextSurface = nullptr;
91 data->outlineTexture = nullptr;
92 data->textSurface = nullptr;
93 data->texture = nullptr;
94 return *this;
95 } catch (...) {
96 delete data;
97 throw;
98 }
99 }
100
101 SagoTextField::~SagoTextField() {
102 if(!data) {
103 return;
104 }
105 ClearCache();
106 delete data;
107 }
108
109 void SagoTextField::SetHolder(const SagoDataHolder* holder) {
110 data->tex = holder;
111 }
112
113 void SagoTextField::SetText(const char* text) {
114 data->text = text;
115 }
116
117 void SagoTextField::SetText(const std::string& text) {
118 data->text = text;
119 }
120
121 void SagoTextField::SetColor(const SDL_Color& color) {
122 data->color = color;
123 }
124
125 void SagoTextField::SetFont(const char* fontName) {
126 data->fontName = fontName;
127 }
128
129 void SagoTextField::SetFontSize(int fontSize) {
130 data->fontSize = fontSize;
131 }
132
133 void SagoTextField::SetOutline(int outlineSize, const SDL_Color& color) {
134 data->outline = outlineSize;
135 data->outlineColor = color;
136 }
137
138 const std::string& SagoTextField::GetText() const {
139 return data->text;
140 }
141
142 void SagoTextField::ClearCache() {
143 if (data->texture) {
144 SDL_DestroyTexture(data->texture);
145 data->texture = nullptr;
146 }
147 if (data->textSurface) {
148 SDL_FreeSurface(data->textSurface);
149 data->textSurface = nullptr;
150 }
151 if (data->outlineTexture) {
152 SDL_DestroyTexture(data->outlineTexture);
153 data->outlineTexture = nullptr;
154 }
155 if (data->outlineTextSurface) {
156 SDL_FreeSurface(data->outlineTextSurface);
157 data->outlineTextSurface = nullptr;
158 }
159 }
160
161 void SagoTextField::UpdateCache(SDL_Renderer* target) {
162 if (!data->tex) {
163 std::cerr << "FATAL: DataHolder not set!\n";
164 abort();
165 }
166 ClearCache();
167 TTF_Font *font = data->tex->getFontPtr(data->fontName, data->fontSize);
168 data->textSurface = TTF_RenderUTF8_Blended (font, data->text.c_str(), data->color);
169 data->texture = SDL_CreateTextureFromSurface(target, data->textSurface);
170 if (data->outline > 0) {
171 OutlineHandler oh(font, data->outline);
172 data->outlineTextSurface = TTF_RenderUTF8_Blended (font, data->text.c_str(), data->outlineColor);
173 data->outlineTexture = SDL_CreateTextureFromSurface(target, data->outlineTextSurface);
174 oh.reset();
175 }
176 data->renderedText = data->text;
177 data->renderedVersion = data->tex->getVersion();
178 }
179
180 void SagoTextField::GetRenderedSize(const char* text, int* w, int* h) {
181 TTF_Font *font = data->tex->getFontPtr(data->fontName, data->fontSize);
182 int ret = TTF_SizeUTF8(font, text, w, h);
183 if (ret) {
184 if (w) {
185 *w = 0;
186 }
187 if (h) {
188 *h = 0;
189 }
190 std::cerr << "GetRenderedSize failed to find size of " << text << ". Error code: " << ret << "\n";
191 }
192 }
193
194 void SagoTextField::Draw(SDL_Renderer* target, int x, int y, Alignment alignment, VerticalAlignment verticalAlignment) {
195 if (data->text.empty()) {
196 return;
197 }
198 if (data->text != data->renderedText || data->renderedVersion != data->tex->getVersion()) {
199 UpdateCache(target);
200 }
201 if (!data->texture) {
202 return;
203 }
204 int texW = 0;
205 int texH = 0;
206 SDL_QueryTexture(data->texture, NULL, NULL, &texW, &texH);
207 if (alignment == Alignment::center) {
208 x -= texW/2;
209 }
210 if (alignment == Alignment::right) {
211 y -= texW;
212 }
213 if (verticalAlignment == VerticalAlignment::center) {
214 y -= texH/2;
215 }
216 if (verticalAlignment == VerticalAlignment::bottom) {
217 y -= texH;
218 }
219 SDL_Rect dstrect = { x, y, texW, texH };
220 if (data->outlineTexture) {
221 int outlineTexW = 0;
222 int outlineTexH = 0;
223 SDL_QueryTexture(data->outlineTexture, NULL, NULL, &outlineTexW, &outlineTexH);
224 SDL_Rect dstrectOutline = { x-(data->outline), y-(data->outline), outlineTexW, outlineTexH };
225 SDL_RenderCopy(target, data->outlineTexture, NULL, &dstrectOutline);
226 }
227 SDL_RenderCopy(target, data->texture, NULL, &dstrect);
228 }
229
230 } //namespace sago
0 /*
1 Copyright (c) 2018 Poul Sander
2
3 Permission is hereby granted, free of charge, to any person
4 obtaining a copy of this software and associated documentation files
5 (the "Software"), to deal in the Software without restriction,
6 including without limitation the rights to use, copy, modify, merge,
7 publish, distribute, sublicense, and/or sell copies of the Software,
8 and to permit persons to whom the Software is furnished to do so,
9 subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be
12 included in all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
18 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 SOFTWARE.
22 */
23
24 #ifndef SAGOTEXTFIELD_HPP
25 #define SAGOTEXTFIELD_HPP
26
27 #include "SagoDataHolder.hpp"
28
29 namespace sago {
30
31 /**
32 * This is a text field.
33 * It represents a line of text to be drawn on screen. It is not possible to have line breaks.
34 * If line breaks are needed use SagoTextBox instead.
35 *
36 * This object renderes to a texture and cahces the texture. The texture will be automatically refreshed if the text changes, the SagoDataHolder is invalidated or ClearCache is called.
37 * Normally all values will be set at the beginning before text is drawn.
38 * SetHolder MUST be called before the field is drawn!
39 */
40 class SagoTextField final {
41 public:
42 SagoTextField();
43 SagoTextField(SagoTextField&& o) noexcept;
44 SagoTextField& operator=(const SagoTextField&& base) = delete;
45 SagoTextField& operator=(const SagoTextField& base) = delete;
46 ~SagoTextField();
47 /**
48 * This method creates a copy of a given font.
49 * The cache will not be copied.
50 * This is ALMOST like the "= operator" but given its own name to prevent implicit calling.
51 * @param base The object to copy from
52 * @return A reference to this object.
53 */
54 SagoTextField& CopyFrom(const SagoTextField& base);
55 /**
56 * Sets the data holder. This is MANDATORY
57 * @param holder The data holder to fetch the fonts from
58 */
59 void SetHolder(const SagoDataHolder* holder);
60 /**
61 * Set the text to display.
62 * @param text The actual UTF-8 encoded text
63 */
64 void SetText(const char* text);
65 /**
66 * Set the text to display.
67 * @param text The actual UTF-8 encoded text
68 */
69 void SetText(const std::string& text);
70 void SetColor(const SDL_Color& color);
71 /**
72 * Set the name of the font. Must be known to the data holder.
73 * The name could for instance be "freeserif".
74 * @param fontName Name of the font as required by SagoDataHolder
75 */
76 void SetFont(const char* fontName);
77 void SetFontSize(int fontSize);
78 /**
79 * Enable outline against the font.
80 * @param outlineSize Number of pixels of outline.
81 * @param color The color of the outline.
82 */
83 void SetOutline(int outlineSize, const SDL_Color& color);
84 /**
85 * Get the text we are currently drawing
86 * @return The text
87 */
88 const std::string& GetText() const;
89 /**
90 * A Shorthand for calling TTF_SizeUTF8 on the right font
91 * The size is measuered WITHOUT the outline!
92 * Will fail silently on error (except writing to stderr) and set w and h to 0 if they are not null.
93 * @param text The text to check the rendered size for
94 * @param w Pointer to an int where the width of the text will be stored. Maybe null.
95 * @param h Pointer to an int where the hight of the text will be stored. Maybe null.
96 */
97 void GetRenderedSize(const char* text, int* w = nullptr, int* h = nullptr);
98 enum class Alignment { left = 0, right=1, center = 2 };
99 enum class VerticalAlignment { top = 0, center = 1, bottom = 2};
100 void Draw(SDL_Renderer* target, int x, int y, Alignment alignment = Alignment::left, VerticalAlignment verticalAlignment = VerticalAlignment::top);
101 /**
102 * Updates the cache.
103 * You normally do not want to call this from the outside as it is done just in time.
104 * Unless you want to precache of course....
105 * @param target Target the the text will eventually be rendered to
106 */
107 void UpdateCache(SDL_Renderer* target);
108 /**
109 * Clears the cache and forces the SagoTextField to render it again the next time it is drawn.
110 * Can be used if you have changed font, color or sizes.
111 * Changing the text implices a cache clear.
112 */
113 void ClearCache();
114 private:
115 SagoTextField(const SagoTextField& orig) = delete;
116 struct SagoTextFieldData;
117 SagoTextFieldData *data;
118 };
119
120 } //namespace sago
121
122 #endif /* SAGOTEXTFIELD_HPP */
123
111111 }
112112
113113 /**
114 * Retrives the effective user's home dir.
115 * If the user is running as root we ignore the HOME environment. It works badly with sudo.
114 * Retrives the effective user's home dir.
115 * If the user is running as root we ignore the HOME environment. It works badly with sudo.
116116 * Writing to $HOME as root implies security concerns that a multiplatform program cannot be assumed to handle.
117 * @return The home directory. HOME environment is respected for non-root users if it exists.
117 * @return The home directory. HOME environment is respected for non-root users if it exists.
118118 */
119119 static std::string getHome() {
120120 std::string res;
259259 folders["XDG_TEMPLATES_DIR"] = "$HOME/.Templates";
260260 folders["XDG_VIDEOS_DIR"] = "$HOME/Videos";
261261 PlatformFoldersAddFromFile( getConfigHome()+"/user-dirs.dirs", folders);
262 for (std::map<std::string, std::string>::iterator itr = folders.begin() ; itr != folders.end() ; itr ++ ) {
262 for (std::map<std::string, std::string>::iterator itr = folders.begin() ; itr != folders.end() ; ++itr ) {
263263 std::string& value = itr->second;
264264 if (value.compare(0, 5, "$HOME") == 0) {
265265 value = getHome() + value.substr(5, std::string::npos);
2626 */
2727
2828 #ifndef SAGO_PLATFORM_FOLDERS_H
29 #define SAGO_PLATFORM_FOLDERS_H
29 #define SAGO_PLATFORM_FOLDERS_H
3030
3131 #include <vector>
3232 #include <string>
161161 private:
162162 PlatformFolders(const PlatformFolders&);
163163 PlatformFolders& operator=(const PlatformFolders&);
164 #if defined(_WIN32)
165 #elif defined(__APPLE__)
166 #else
164167 struct PlatformFoldersData;
165168 PlatformFoldersData *data;
169 #endif
166170 };
167171
168172 } //namespace sago
169173
170 #endif /* PLATFORM_FOLDERS_H */
171
174 #endif /* PLATFORM_FOLDERS_H */
2929 class SDL_RendererHolder {
3030 SDL_Renderer* ptr;
3131 public:
32 SDL_RendererHolder(SDL_Renderer* input) {
32 explicit SDL_RendererHolder(SDL_Renderer* input) {
3333 dieOnNullptr(input, "Failed to get render");
3434 ptr = input;
3535 }
2929 #include "cereal/types/vector.hpp"
3030 #include "cereal/archives/json.hpp"
3131 #include "sago/SagoMisc.hpp"
32 #include "Libs/include/cereal/details/helpers.hpp"
3332
3433 //paths
3534 const char* const stageClearSaveName = "stageClear.json.SCsave";
6767 void Stats::save() {
6868 std::stringstream outFile;
6969 map<string,unsigned int>::iterator iter;
70 for (iter = statMap.begin(); iter != statMap.end(); iter++) {
70 for (iter = statMap.begin(); iter != statMap.end(); ++iter) {
7171 outFile << iter->first << " " << iter->second << "\n";
7272 }
7373 sago::WriteFileContent(statsFileName, outFile.str());
2121 */
2222
2323 #ifndef VERSION_NUMBER
24 #define VERSION_NUMBER "2.1.2"
24 #define VERSION_NUMBER "2.2.0"
2525 #endif
0 #! /bin/bash
01 astyle -t -j -y -c -k1 -z2 -A2 --pad-header ../../code/*.cpp
0 FROM fedora:25
1
2 RUN dnf -y install cmake \
3 make \
4 gcc-c++ \
5 SDL2-devel \
6 boost-devel \
7 physfs-devel \
8 SDL2_image-devel SDL2_ttf-devel SDL2_mixer-devel \
9 utf8cpp-devel \
10 findutils \
11 gettext \
12 zip \
13 && dnf -y clean all
14
15 COPY . /staging/blockattack-game
16
17 ENV BLOCKATTACK_VERSION 2.2.0
18
19 RUN cd /staging/blockattack-game && \
20 ./packdata.sh && \
21 cmake . && \
22 make
0 FROM ubuntu:12.04
1
2 RUN apt-get update && apt-get install -y build-essential cmake pkg-config libfreetype6-dev libvorbis-dev libgl1-mesa-dev libpulse-dev libpng12-dev zip gettext
3
4 RUN apt-get update && apt-get install -y python-software-properties && \
5 add-apt-repository ppa:ubuntu-toolchain-r/test && \
6 apt-get update && \
7 apt-get install -y gcc-4.8 g++-4.8 && \
8 update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 50 && \
9 update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 50
10
11 COPY source/misc/standalone/compile_requirements.sh /
12 RUN /compile_requirements.sh
13
14
15
16 COPY . /staging/blockattack-game
17
18 ENV BLOCKATTACK_VERSION 2.2.0
19
20 RUN cd /staging/blockattack-game && \
21 ./packdata.sh && \
22 cp source/misc/travis_help/utf8_v2_3_4/source/utf8.h source/code/ && \
23 cp source/misc/travis_help/utf8_v2_3_4/source/utf8.h source/code/sago/ && \
24 cp -r source/misc/travis_help/utf8_v2_3_4/source/utf8 source/code/ && \
25 cp -r source/misc/travis_help/utf8_v2_3_4/source/utf8 source/code/sago/ && \
26 cmake -D Boost_USE_STATIC_LIBS=ON -D INSTALL_DATA_DIR=. -D CMAKE_INSTALL_PREFIX=. -D STANDALONE=1 . && make
00 FROM ubuntu:14.04
11
2 RUN apt-get update && apt-get install -y build-essential libphysfs-dev libboost-dev cmake libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev libboost-program-options-dev libutfcpp-dev zip gettext
2 RUN apt-get update && apt-get install -yy build-essential libphysfs-dev libboost-dev cmake libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev libboost-program-options-dev libutfcpp-dev zip gettext
33
44 RUN mkdir -p /staging/blockattack-game
55
66 COPY . /staging/blockattack-game
77
8 ENV BLOCKATTACK_VERSION 2.1.0
8 ENV BLOCKATTACK_VERSION 2.2.0
99
1010 RUN cd /staging/blockattack-game && \
1111 ./packdata.sh && \
0 FROM ubuntu:14.04
1
2 RUN apt-get update && apt-get install -y build-essential libboost-dev cmake pkg-config libboost-program-options-dev libfreetype6-dev libvorbis-dev libgl1-mesa-dev libpulse-dev libutfcpp-dev zip gettext
3
4 COPY source/misc/standalone/compile_requirements.sh /
5 RUN /compile_requirements.sh
6
7 COPY . /staging/blockattack-game
8
9 ENV BLOCKATTACK_VERSION 2.2.0
10
11 RUN cd /staging/blockattack-game && \
12 ./packdata.sh && \
13 cmake -D Boost_USE_STATIC_LIBS=ON -D INSTALL_DATA_DIR=. -D CMAKE_INSTALL_PREFIX=. -D STANDALONE=1 . && make
0 FROM ioft/i386-ubuntu:14.04
1
2 RUN apt-get update && apt-get install -y build-essential libboost-dev cmake pkg-config libboost-program-options-dev libfreetype6-dev libvorbis-dev libgl1-mesa-dev libpulse-dev libutfcpp-dev zip gettext
3
4 COPY source/misc/standalone/compile_requirements.sh /
5 RUN /compile_requirements.sh
6
7 COPY . /staging/blockattack-game
8
9 ENV BLOCKATTACK_VERSION 2.2.0
10
11 RUN cd /staging/blockattack-game && \
12 ./packdata.sh && \
13 cmake -D Boost_USE_STATIC_LIBS=ON -D INSTALL_DATA_DIR=. -D CMAKE_INSTALL_PREFIX=. -D STANDALONE=1 . && make
77
88 COPY . /staging/blockattack-game
99
10 ENV BLOCKATTACK_VERSION 2.1.2
10 ENV BLOCKATTACK_VERSION 2.2.0
1111
1212 RUN cd /staging/blockattack-game && \
1313 ./packdata.sh && \
14 cp source/misc/travis_help/utf8_v2_3_4/source/utf8.h source/code/ && \
15 cp -r source/misc/travis_help/utf8_v2_3_4/source/utf8 source/code/ && \
14 cp source/misc/travis_help/utf8_v2_3_4/source/utf8.h source/code/Libs/include/ && \
15 cp -r source/misc/travis_help/utf8_v2_3_4/source/utf8 source/code/Libs/include/ && \
1616 i686-w64-mingw32.static-cmake . && \
1717 make && \
1818 cd windows\ installer/ && \
0 #! /bin/bash
1 set -e
2 set +H
3 if [ "$#" -lt 3 ]; then
4 echo "Must be called with $0 <MAJOR> <MINOR> <PATCH> [>TAG>]"
5 echo "Like: $0 2 2 10 SNAPSHOT"
6 exit 1
7 fi
8 MAJOR=$1
9 MINOR=$2
10 PATCH=$3
11 TAG=$4
12
13 FULLVERSION=$MAJOR.$MINOR.$PATCH
14
15 if [ "$#" -gt 3 ]; then
16 FULLVERSION="$FULLVERSION-$TAG"
17 fi
18
19 sed -i "/SET(CPACK_PACKAGE_VERSION /c\\SET(CPACK_PACKAGE_VERSION \"$FULLVERSION\")" CMakeLists.txt
20 sed -i "/SET(CPACK_PACKAGE_VERSION_MAJOR /c\\SET(CPACK_PACKAGE_VERSION_MAJOR \"$MAJOR\")" CMakeLists.txt
21 sed -i "/SET(CPACK_PACKAGE_VERSION_MINOR /c\\SET(CPACK_PACKAGE_VERSION_MINOR \"$MINOR\")" CMakeLists.txt
22 sed -i "/SET(CPACK_PACKAGE_VERSION_PATCH /c\\SET(CPACK_PACKAGE_VERSION_PATCH \"$PATCH\")" CMakeLists.txt
23
24
25 sed -i -E "s/#define VERSION_NUMBER.*$/#define VERSION_NUMBER \"$FULLVERSION\"/" source/code/version.h
26 sed -i -E "s/!define PRODUCT_VERSION .*$/!define PRODUCT_VERSION \"$FULLVERSION\"/" "windows installer/install_script.nsi"
27 sed -i -E "s/#ENV BLOCKATTACK_VERSION .*$/#ENV BLOCKATTACK_VERSION $FULLVERSION/" source/misc/docker/Dockerfile.WindoesBuild
28
29 make
30 pushd man
31 COLUMNS=300 help2man --no-info --section=6 --name="a puzzle game inspired by Tetris Attack" ../Game/blockattack | sed 's@'"$HOME"'@$HOME@g' > blockattack.man
32 popd
0 Block Attack - Rise of the Blocks - Linux build
1
2 This is the standalone version. It is precompiled and includes the necessary libraries to run.
3
4 Both a 32 bit and 64 bit version is provided.
5 It has been tested on Ubuntu 14.04 and Fedora 22
6 Some systems might require the game to be launched from the command line.
7 PulseAudio is required for sound.
8
9 Check www.blockattack.net for more info.
0 #!/bin/bash
1
2 # This file is based on the guide from https://itch.io/docs/itch/integrating/platforms/linux.html
3
4 # Move to script's directory
5 cd "`dirname "$0"`"
6
7 # Get the kernel/architecture information
8 ARCH=`uname -m`
9
10 # Set the libpath and pick the proper binary
11 if [ "$ARCH" == "x86_64" ]; then
12 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./x86_64/
13 ./x86_64/blockattack "$@"
14 else
15 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./x86/
16 ./x86/blockattack "$@"
17 fi
0 #! /bin/bash
1 set -e
2
3 if [ "$#" -ne 1 ]; then
4 echo "Must be called with $0 <archivename>"
5 exit 1
6 fi
7
8 ARCHIVENAME=$1
9
10 rm -rf staging
11 mkdir -p staging/$ARCHIVENAME/x86_64
12 mkdir -p staging/$ARCHIVENAME/x86
13 mkdir -p staging/$ARCHIVENAME/docs
14 cp blockattack_standalone_launcher staging/$ARCHIVENAME/blockattack
15 cp README.txt staging/$ARCHIVENAME/README
16 chmod +x staging/$ARCHIVENAME/blockattack
17
18 cd ../../..
19
20 docker build -f source/misc/docker/Dockerfile.Ubuntu12.04build_Standalone . -t blockattack_test
21
22 echo Copying to: $(pwd)/source/misc/standalone/staging/$ARCHIVENAME
23
24 docker run -it --rm -v $(pwd)/source/misc/standalone/staging/$ARCHIVENAME/:/output blockattack_test /bin/bash -c "cp /staging/blockattack-game/Game/blockattack /output/x86_64/ && \
25 cp /usr/local/lib/libSDL2-2.0.so.0 /output/x86_64/ && \
26 cp /usr/local/lib/libphysfs.so.1 /output/x86_64/ && \
27 cp /usr/local/lib/libSDL2_mixer-2.0.so.0 /output/x86_64/ && \
28 cp /usr/local/lib/libSDL2_ttf-2.0.so.0 /output/x86_64/ && \
29 cp /usr/lib/x86_64-linux-gnu/libfreetype.so.6 /output/x86_64/ && \
30 cp /lib/x86_64-linux-gnu/libpng12.so.0 /output/x86_64/ && \
31 cp /usr/local/lib/libSDL2_image-2.0.so.0 /output/x86_64/"
32
33 docker run -it --rm -v $(pwd)/source/misc/standalone/staging/$ARCHIVENAME/:/output blockattack_test /bin/bash -c "cp -r /staging/blockattack-game/source/misc/translation/locale /output/ && \
34 cp /staging/blockattack-game/Game/blockattack.data /output/ && \
35 cp -r /staging/blockattack-game/source/misc/icons /output/ && \
36 cp /staging/blockattack-game/COPYING /output/ && \
37 cp /staging/blockattack-game/man/blockattack.man /output/docs/ && \
38 cp /staging/blockattack-game/README.md /output/docs/README_ORG.md && \
39 chown -R 1000 /output"
40
41 scp source/misc/standalone/compile_requirements.sh blockattack_build:/
42 scp source/misc/standalone/install_requirements.sh blockattack_build:/
43 ssh blockattack_build /install_requirements.sh
44 ssh blockattack_build /compile_requirements.sh
45 ssh blockattack_build rm -rf /staging/blockattack-game
46 scp -r . blockattack_build:/staging/blockattack-game
47 ssh blockattack_build rm -f /staging/blockattack-game/CMakeCache.txt
48
49 ssh blockattack_build "BLOCKATTACK_VERSION=2.2.0 && cd /staging/blockattack-game && \
50 ./packdata.sh && \
51 cp source/misc/travis_help/utf8_v2_3_4/source/utf8.h source/code/ && \
52 cp source/misc/travis_help/utf8_v2_3_4/source/utf8.h source/code/sago/ && \
53 cp -r source/misc/travis_help/utf8_v2_3_4/source/utf8 source/code/ && \
54 cp -r source/misc/travis_help/utf8_v2_3_4/source/utf8 source/code/sago/ && \
55 cmake -D Boost_USE_STATIC_LIBS=ON -D INSTALL_DATA_DIR=. -D CMAKE_INSTALL_PREFIX=. -D STANDALONE=1 . && make clean && make"
56
57 OUTPUT=$(pwd)/source/misc/standalone/staging/$ARCHIVENAME/
58
59 scp blockattack_build:/staging/blockattack-game/Game/blockattack $OUTPUT/x86/ && \
60 scp blockattack_build:/usr/local/lib/libSDL2-2.0.so.0 $OUTPUT/x86/ && \
61 scp blockattack_build:/usr/local/lib/libphysfs.so.1 $OUTPUT/x86/ && \
62 scp blockattack_build:/usr/local/lib/libSDL2_mixer-2.0.so.0 $OUTPUT/x86/ && \
63 scp blockattack_build:/usr/local/lib/libSDL2_ttf-2.0.so.0 $OUTPUT/x86/ && \
64 scp blockattack_build:/usr/lib/i386-linux-gnu/libfreetype.so.6 $OUTPUT/x86/ && \
65 scp blockattack_build:/lib/i386-linux-gnu/libpng12.so.0 $OUTPUT/x86/ && \
66 scp blockattack_build:/usr/local/lib/libSDL2_image-2.0.so.0 $OUTPUT/x86/
67
68 exit 0
69
70 docker build -f source/misc/docker/Dockerfile.Ubuntu12.04build_Standalone32 . -t blockattack_test
71
72 docker run -it --rm -v $(pwd)/source/misc/standalone/staging/$ARCHIVENAME/:/output blockattack_test /bin/bash -c "cp /staging/blockattack-game/Game/blockattack /output/x86/ && \
73 cp /usr/local/lib/libSDL2-2.0.so.0 /output/x86/ && \
74 cp /usr/local/lib/libphysfs.so.1 /output/x86/ && \
75 cp /usr/local/lib/libSDL2_mixer-2.0.so.0 /output/x86/ && \
76 cp /usr/local/lib/libSDL2_ttf-2.0.so.0 /output/x86/ && \
77 cp /usr/lib/i386-linux-gnu/libfreetype.so.6 /output/x86/ && \
78 cp /lib/i386-linux-gnu/libpng12.so.0 /output/x86/ && \
79 cp /usr/local/lib/libSDL2_image-2.0.so.0 /output/x86/"
80
81 cd source/misc/standalone/staging/
82 tar -cvjSf "$ARCHIVENAME.tar.bz2" "$ARCHIVENAME"
0 #! /bin/bash
1 set -e
2 set -x
3
4 mkdir -p /staging/deps && cd /staging/deps && curl https://libsdl.org/release/SDL2-2.0.6.tar.gz | tar -zx && cd SDL2-2.0.6 && ls -lrt
5 cd /staging/deps/SDL2-2.0.6 && ./configure --enable-shared --enable-static && make && make install
6
7 #https://www.libsdl.org/projects/SDL_image/release/SDL2_image-2.0.1.tar.gz
8 mkdir -p /staging/deps && cd /staging/deps && curl https://www.libsdl.org/projects/SDL_image/release/SDL2_image-2.0.1.tar.gz | tar -zx && cd SDL2_image-2.0.1 && ls -lrt
9 cd /staging/deps/SDL2_image-2.0.1 && ./configure --enable-shared --enable-static && make && make install
10
11 #https://www.libsdl.org/projects/SDL_mixer/release/SDL2_mixer-2.0.1.tar.gz
12 mkdir -p /staging/deps && cd /staging/deps && curl https://www.libsdl.org/projects/SDL_mixer/release/SDL2_mixer-2.0.1.tar.gz | tar -zx && cd SDL2_mixer-2.0.1 && ls -lrt
13 cd /staging/deps/SDL2_mixer-2.0.1 && ./configure --enable-shared --enable-static && make && make install
14
15 #https://www.libsdl.org/projects/SDL_ttf/release/SDL2_ttf-2.0.14.tar.gz
16 mkdir -p /staging/deps && cd /staging/deps && curl https://www.libsdl.org/projects/SDL_ttf/release/SDL2_ttf-2.0.14.tar.gz | tar -zx && cd SDL2_ttf-2.0.14 && ls -lrt
17 cd /staging/deps/SDL2_ttf-2.0.14 && ./configure --enable-shared --enable-static && make && make install
18 mkdir -p /staging/blockattack-game
19
20 mkdir -p /staging/deps && cd /staging/deps && curl http://icculus.org/physfs/downloads/physfs-2.0.3.tar.bz2 | tar -jx && cd physfs-2.0.3 && ls -lrt
21 cd /staging/deps/physfs-2.0.3 && cmake . && make && make install
22
23 # boost
24 cd ~
25 mkdir -p Downloads
26 cd Downloads
27 curl https://files.poulsander.com/~poul19/public_files/boost_1_65_1.tar.bz2 -O
28 tar xvfj boost_1_65_1.tar.bz2
29 pushd boost_1_65_1
30 ./bootstrap.sh --with-libraries=program_options
31 ./b2 install -j 2 --prefix=/usr link=static
32 popd
0 #! /bin/bash
1 set -e
2 apt-get update && apt-get install -y build-essential cmake pkg-config libfreetype6-dev libvorbis-dev libgl1-mesa-dev libpulse-dev libpng12-dev zip gettext
3
4 apt-get update && apt-get install -y python-software-properties
5 add-apt-repository ppa:ubuntu-toolchain-r/test
6 apt-get update
7 apt-get install -y gcc-4.8 g++-4.8
8 update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 50
9 update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 50
44
55 POFILE=$1
66
7 LANGUAGE=${1##*/}
7 LANGUAGE=${POFILE##*/}
88 LANGUAGE=${LANGUAGE%%.*}
99 mkdir -p locale/$LANGUAGE/LC_MESSAGES
10 echo "Building $LANGUAGE from $1"
11 msgfmt -o locale/$LANGUAGE/LC_MESSAGES/blockattack_roftb.mo $1
10 echo "Building $LANGUAGE from $POFILE"
11 msgfmt -o locale/$LANGUAGE/LC_MESSAGES/blockattack_roftb.mo $POFILE
0 #! /bin/bash
01 mkdir -p template
1 xgettext -k_ ../../code/*.cpp ../../code/*.inc --output=template/blockattack_roftb.pot
2 xgettext -k_ ../../code/*.cpp ../../code/*.inc ../../code/*.hpp --output=template/blockattack_roftb.pot
66 msgstr ""
77 "Project-Id-Version: \n"
88 "Report-Msgid-Bugs-To: \n"
9 "POT-Creation-Date: 2017-03-29 19:57+0200\n"
10 "PO-Revision-Date: 2017-03-29 19:57+0200\n"
9 "POT-Creation-Date: 2018-05-19 18:29+0200\n"
10 "PO-Revision-Date: 2018-05-19 18:30+0200\n"
1111 "Last-Translator: \n"
1212 "Language-Team: \n"
1313 "Language: da\n"
1414 "MIME-Version: 1.0\n"
1515 "Content-Type: text/plain; charset=UTF-8\n"
1616 "Content-Transfer-Encoding: 8bit\n"
17 "X-Generator: Poedit 1.8.7.1\n"
17 "X-Generator: Poedit 2.0.6\n"
1818 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1919
20 #: ../../code/DialogBox.cpp:103
20 #: ../../code/DialogBox.cpp:92
2121 msgid "Enter to accept"
2222 msgstr "Bekræft med Enter"
2323
24 #: ../../code/DialogBox.cpp:104
24 #: ../../code/DialogBox.cpp:93
2525 msgid "Esc to cancel"
2626 msgstr "Annuller med Esc"
2727
28 #: ../../code/levelselect.cpp:78
28 #: ../../code/HelpAboutState.cpp:62
29 msgid "Name:"
30 msgstr "Navn:"
31
32 #: ../../code/HelpAboutState.cpp:62
33 msgid "Block Attack - Rise of the Blocks"
34 msgstr "Block Attack - Blokkenes opstand"
35
36 #: ../../code/HelpAboutState.cpp:63
37 msgid "Original name:"
38 msgstr "Originalt navn:"
39
40 #: ../../code/HelpAboutState.cpp:64
41 msgid "Version:"
42 msgstr "Version:"
43
44 #: ../../code/HelpAboutState.cpp:65
45 msgid "Homepage:"
46 msgstr "Hjemmeside:"
47
48 #: ../../code/HelpAboutState.cpp:66
49 msgid "Github page:"
50 msgstr "Github side:"
51
52 #: ../../code/HelpAboutState.cpp:67
53 msgid "SDL render:"
54 msgstr "SDL render:"
55
56 #: ../../code/HelpAboutState.cpp:68
57 msgid "Save folder:"
58 msgstr "Mappe til gemte spil:"
59
60 #: ../../code/HelpAboutState.cpp:69
61 msgid "Locale:"
62 msgstr "Lokalitet:"
63
64 #: ../../code/HelpAboutState.cpp:70 ../../code/menudef.cpp:309
65 msgid "About"
66 msgstr "Om"
67
68 #: ../../code/HelpGamepadState.cpp:54
69 msgid "Move cursor"
70 msgstr "Flyt markøren"
71
72 #: ../../code/HelpGamepadState.cpp:55
73 msgid "Push line"
74 msgstr "Skub linje"
75
76 #: ../../code/HelpGamepadState.cpp:56
77 msgid "Back (Menu)"
78 msgstr "Tilbage (Menu)"
79
80 #: ../../code/HelpGamepadState.cpp:57
81 msgid "Switch"
82 msgstr "Skift"
83
84 #: ../../code/HelpGamepadState.cpp:58
85 msgid "Confirm"
86 msgstr "Bekræft"
87
88 #: ../../code/HelpGamepadState.cpp:59
89 msgid ""
90 "Only SDL2 compatible controllers are supported!\n"
91 "Supported controllers: "
92 msgstr ""
93 "Kun SDL2 kompatible kontrollere er understøttet!\n"
94 "Understøttede kontrollere: "
95
96 #: ../../code/HelpHowtoState.cpp:127
97 msgid "Switch block horizontally"
98 msgstr "Skift blokke horisontalt"
99
100 #: ../../code/HelpHowtoState.cpp:128
101 msgid "Match 3 to clear"
102 msgstr "Sammensæt 3 for at fjerne"
103
104 #: ../../code/HelpHowtoState.cpp:129
105 msgid "Create combos!"
106 msgstr "Sammensæt mange!"
107
108 #: ../../code/HelpHowtoState.cpp:130
109 msgid "Drop blocks!"
110 msgstr "Lad blokke falde!"
111
112 #: ../../code/HelpHowtoState.cpp:131
113 msgid "Create a chain effect"
114 msgstr "Lav en kæde effekt"
115
116 #: ../../code/levelselect.cpp:92
29117 msgid "Select Puzzle"
30118 msgstr "Vælg gåde"
31119
32 #: ../../code/levelselect.cpp:81
120 #: ../../code/levelselect.cpp:95
33121 msgid "Stage Clear Level Select"
34122 msgstr "Vælg Stage Clear-bane"
35123
36 #: ../../code/levelselect.cpp:187
124 #: ../../code/levelselect.cpp:201
37125 #, c-format
38126 msgid "Best score: %i"
39127 msgstr "Bedste resultat: %i"
40128
41 #: ../../code/levelselect.cpp:188
129 #: ../../code/levelselect.cpp:202
42130 #, c-format
43131 msgid "Time used: %s"
44132 msgstr "Tid brugt: %s"
45133
46 #: ../../code/levelselect.cpp:191
134 #: ../../code/levelselect.cpp:205
47135 #, c-format
48136 msgid "Time used: %d : %02d"
49137 msgstr "Tid brugt: %d : %02d"
50138
51 #: ../../code/levelselect.cpp:196
139 #: ../../code/levelselect.cpp:210
52140 #, c-format
53141 msgid "Total score: %i in %i:%02i"
54142 msgstr "Sammenlagt: %i på %i:%02i"
55143
56 #: ../../code/main.cpp:431 ../../code/main.cpp:544
144 #: ../../code/main.cpp:452 ../../code/main.cpp:583
57145 msgid "AI"
58146 msgstr "Computer"
59147
60 #: ../../code/main.cpp:434
148 #: ../../code/main.cpp:455
61149 msgid "Playing field"
62150 msgstr "Spilleflade"
63151
64 #: ../../code/main.cpp:505
152 #: ../../code/main.cpp:529
65153 msgid "Time Trial"
66154 msgstr "På tid"
67155
68 #: ../../code/main.cpp:506
156 #: ../../code/main.cpp:530
69157 msgid "Score as much as possible in 2 minutes"
70158 msgstr "Se hvor mange point du kan opnå på 2 minutter"
71159
72 #: ../../code/main.cpp:510
160 #: ../../code/main.cpp:534
73161 msgid "Stage Clear"
74162 msgstr "Stage Clear"
75163
76 #: ../../code/main.cpp:511
164 #: ../../code/main.cpp:535
77165 msgid "You must clear a number of lines. Speed is rapidly increased."
78166 msgstr "Fjern et specifik antal linjer. Hastigheden stiger hurtigt."
79167
80 #: ../../code/main.cpp:514
168 #: ../../code/main.cpp:538
81169 msgid "Puzzle"
82170 msgstr "Gåde"
83171
84 #: ../../code/main.cpp:515
172 #: ../../code/main.cpp:539
85173 msgid "Clear the entire board with a limited number of moves."
86174 msgstr "Fjern alle blokke med et begrænset antal flyt."
87175
88 #: ../../code/main.cpp:518
176 #: ../../code/main.cpp:542
89177 msgid "Endless"
90178 msgstr "Evighed"
91179
92 #: ../../code/main.cpp:519
180 #: ../../code/main.cpp:543
93181 msgid "Score as much as possible. No time limit."
94182 msgstr "Opnå så mange point som muligt. Ingen tidsbegrænsning."
95183
96 #: ../../code/main.cpp:523
184 #: ../../code/main.cpp:553
97185 msgid "Objective:"
98186 msgstr "Formål:"
99187
100 #: ../../code/main.cpp:529
188 #: ../../code/main.cpp:563
101189 msgid "Movement keys:"
102190 msgstr "Bevægelsestaster:"
103191
104 #: ../../code/main.cpp:532
192 #: ../../code/main.cpp:565
105193 msgid "Switch: "
106194 msgstr "Skift: "
107195
108 #: ../../code/main.cpp:534
196 #: ../../code/main.cpp:567
109197 msgid "Restart: "
110198 msgstr "Genstart: "
111199
112 #: ../../code/main.cpp:537
200 #: ../../code/main.cpp:570
113201 msgid "Push line: "
114202 msgstr "Skub linje: "
115203
116 #: ../../code/main.cpp:945
204 #: ../../code/main.cpp:995
117205 msgid "Player 1"
118206 msgstr "Spiller 1"
119207
120 #: ../../code/main.cpp:946
208 #: ../../code/main.cpp:996
121209 msgid "Player 2"
122210 msgstr "Spiller 2"
123211
124 #: ../../code/menudef.cpp:135 ../../code/menudef.cpp:203
212 #: ../../code/menudef.cpp:138 ../../code/menudef.cpp:206
125213 msgid "Music: On"
126214 msgstr "Musik: Til"
127215
128 #: ../../code/menudef.cpp:135 ../../code/menudef.cpp:203
216 #: ../../code/menudef.cpp:138 ../../code/menudef.cpp:206
129217 msgid "Music: Off"
130218 msgstr "Musik: Fra"
131219
132 #: ../../code/menudef.cpp:143 ../../code/menudef.cpp:204
220 #: ../../code/menudef.cpp:146 ../../code/menudef.cpp:207
133221 msgid "Sound: On"
134222 msgstr "Lyd: Til"
135223
136 #: ../../code/menudef.cpp:143 ../../code/menudef.cpp:204
224 #: ../../code/menudef.cpp:146 ../../code/menudef.cpp:207
137225 msgid "Sound: Off"
138226 msgstr "Lyd: Fra"
139227
140 #: ../../code/menudef.cpp:150 ../../code/menudef.cpp:205
228 #: ../../code/menudef.cpp:153 ../../code/menudef.cpp:208
141229 msgid "Fullscreen: On"
142230 msgstr "Fuldskærm: Til"
143231
144 #: ../../code/menudef.cpp:150 ../../code/menudef.cpp:205
232 #: ../../code/menudef.cpp:153 ../../code/menudef.cpp:208
145233 msgid "Fullscreen: Off"
146234 msgstr "Fuldskærm: Fra"
147235
148 #: ../../code/menudef.cpp:156
236 #: ../../code/menudef.cpp:159
149237 msgid "Enter player 1 name:"
150238 msgstr "Indtast navnet på spiller 1:"
151239
152 #: ../../code/menudef.cpp:162
240 #: ../../code/menudef.cpp:165
153241 msgid "Enter player 2 name:"
154242 msgstr "Indtast navnet på spiller 2:"
155243
156 #: ../../code/menudef.cpp:172
244 #: ../../code/menudef.cpp:175
157245 msgid "Change key bindings"
158246 msgstr "Skift taster"
159247
160 #: ../../code/menudef.cpp:173
248 #: ../../code/menudef.cpp:176
161249 msgid "Left"
162250 msgstr "Venstre"
163251
164 #: ../../code/menudef.cpp:174
252 #: ../../code/menudef.cpp:177
165253 msgid "Right"
166254 msgstr "Højre"
167255
168 #: ../../code/menudef.cpp:175
256 #: ../../code/menudef.cpp:178
169257 msgid "Up"
170258 msgstr "Op"
171259
172 #: ../../code/menudef.cpp:176
260 #: ../../code/menudef.cpp:179
173261 msgid "Down"
174262 msgstr "Ned"
175263
176 #: ../../code/menudef.cpp:177
264 #: ../../code/menudef.cpp:180
177265 msgid "Push"
178266 msgstr "Skub"
179267
180 #: ../../code/menudef.cpp:178
268 #: ../../code/menudef.cpp:181
181269 msgid "Change"
182270 msgstr "Skift"
183271
184 #: ../../code/menudef.cpp:197
272 #: ../../code/menudef.cpp:200
185273 msgid "Configuration"
186274 msgstr "Konfiguration"
187275
188 #: ../../code/menudef.cpp:207
276 #: ../../code/menudef.cpp:210
189277 msgid "Change player 1's name"
190278 msgstr "Skift navn på spiller 1"
191279
192 #: ../../code/menudef.cpp:209
280 #: ../../code/menudef.cpp:212
193281 msgid "Change player 2's name"
194282 msgstr "Skift navn på spiller 2"
195283
196 #: ../../code/menudef.cpp:211
284 #: ../../code/menudef.cpp:214
197285 msgid "Change player 1's keys"
198286 msgstr "Tildel taster til spiller 1"
199287
200 #: ../../code/menudef.cpp:213
288 #: ../../code/menudef.cpp:216
201289 msgid "Change player 2's keys"
202290 msgstr "Tildel taster til spiller 2"
203291
204 #: ../../code/menudef.cpp:225
292 #: ../../code/menudef.cpp:228
205293 msgid "Single player VS"
206294 msgstr "En spiller - VS"
207295
208 #: ../../code/menudef.cpp:241
296 #: ../../code/menudef.cpp:244
209297 msgid "Very easy"
210298 msgstr "Meget let"
211299
212 #: ../../code/menudef.cpp:242
300 #: ../../code/menudef.cpp:245
213301 msgid "Easy"
214302 msgstr "Let"
215303
216 #: ../../code/menudef.cpp:243
304 #: ../../code/menudef.cpp:246
217305 msgid "Below normal"
218306 msgstr "Under normal"
219307
220 #: ../../code/menudef.cpp:244
308 #: ../../code/menudef.cpp:247
221309 msgid "Normal"
222310 msgstr "Normal"
223311
224 #: ../../code/menudef.cpp:245
312 #: ../../code/menudef.cpp:248
225313 msgid "Above normal"
226314 msgstr "Over normal"
227315
228 #: ../../code/menudef.cpp:246
316 #: ../../code/menudef.cpp:249
229317 msgid "Hard"
230318 msgstr "Svær"
231319
232 #: ../../code/menudef.cpp:247
320 #: ../../code/menudef.cpp:250
233321 msgid "Hardest"
234322 msgstr "Meget svær"
235323
236 #: ../../code/menudef.cpp:259
324 #: ../../code/menudef.cpp:262
237325 msgid "Multiplayer"
238326 msgstr "Flerspiller"
239327
240 #: ../../code/menudef.cpp:261
328 #: ../../code/menudef.cpp:264
241329 msgid "Two player - time trial"
242330 msgstr "To spillere - På tid"
243331
244 #: ../../code/menudef.cpp:263
332 #: ../../code/menudef.cpp:266
245333 msgid "Two player - vs"
246334 msgstr "To spillere - VS"
247335
248 #: ../../code/menudef.cpp:272
249 msgid "Block Attack - Rise of the blocks"
250 msgstr "Block Attack - Rise of the blocks"
251
252 #: ../../code/menudef.cpp:274
336 #: ../../code/menudef.cpp:290 ../../code/menudef.cpp:305
337 msgid "Credits"
338 msgstr "Bidragydere"
339
340 #: ../../code/menudef.cpp:295 ../../code/menudef.cpp:348
341 msgid "Help"
342 msgstr "Hjælp"
343
344 #: ../../code/menudef.cpp:297
345 msgid "How to"
346 msgstr "Guide"
347
348 #: ../../code/menudef.cpp:301
349 msgid "Gamepad"
350 msgstr "Spilkontroller"
351
352 #: ../../code/menudef.cpp:316 ../../code/menudef.cpp:340
353 msgid "Single player"
354 msgstr "Enkeltspiller"
355
356 #: ../../code/menudef.cpp:318
253357 msgid "Single player - endless"
254358 msgstr "En spiller - Evighed"
255359
256 #: ../../code/menudef.cpp:276
360 #: ../../code/menudef.cpp:320
257361 msgid "Single player - time trial"
258 msgstr "En spiller - Time Trial"
259
260 #: ../../code/menudef.cpp:278
362 msgstr "En spiller - På tid"
363
364 #: ../../code/menudef.cpp:322
261365 msgid "Single player - stage clear"
262366 msgstr "En spiller - Stage Clear"
263367
264 #: ../../code/menudef.cpp:280
368 #: ../../code/menudef.cpp:324
265369 msgid "Single player - puzzle mode"
266370 msgstr "En spiller - Gåde"
267371
268 #: ../../code/menudef.cpp:282
372 #: ../../code/menudef.cpp:326
269373 msgid "Single player - vs"
270374 msgstr "En spiller - VS"
271375
272 #: ../../code/menudef.cpp:284
376 #: ../../code/menudef.cpp:338
377 msgid "Block Attack - Rise of the blocks"
378 msgstr "Block Attack - Blokkenes opstand"
379
380 #: ../../code/menudef.cpp:342
273381 msgid "Multi player"
274382 msgstr "Flere spillere"
275383
276 #: ../../code/menudef.cpp:286
384 #: ../../code/menudef.cpp:344
277385 msgid "Configure"
278386 msgstr "Instillinger"
279387
280 #: ../../code/menudef.cpp:288
388 #: ../../code/menudef.cpp:346
281389 msgid "Highscores"
282390 msgstr "Bedste resultater"
283391
284 #: ../../code/MenuSystem.cpp:145 ../../code/MenuSystem.cpp:153
285 #: ../../code/MenuSystem.cpp:166 ../../code/ScoresDisplay.cpp:162
392 #: ../../code/MenuSystem.cpp:162 ../../code/MenuSystem.cpp:170
393 #: ../../code/MenuSystem.cpp:183 ../../code/ScoresDisplay.cpp:184
286394 msgid "Back"
287395 msgstr "Tilbage"
288396
289 #: ../../code/MenuSystem.cpp:156 ../../code/MenuSystem.cpp:169
397 #: ../../code/MenuSystem.cpp:173 ../../code/MenuSystem.cpp:186
290398 msgid "Exit"
291399 msgstr "Afslut"
292400
293 #: ../../code/ScoresDisplay.cpp:51
401 #: ../../code/ScoresDisplay.cpp:71
294402 msgid "Endless:"
295403 msgstr "Evighed:"
296404
297 #: ../../code/ScoresDisplay.cpp:54
405 #: ../../code/ScoresDisplay.cpp:74
298406 msgid "Time Trial:"
299407 msgstr "På tid:"
300408
301 #: ../../code/ScoresDisplay.cpp:77
409 #: ../../code/ScoresDisplay.cpp:97
302410 msgid "Stats"
303411 msgstr "Statistik"
304412
305 #: ../../code/ScoresDisplay.cpp:79
413 #: ../../code/ScoresDisplay.cpp:99
306414 msgid "Chains"
307415 msgstr "Kæder"
308416
309 #: ../../code/ScoresDisplay.cpp:87
417 #: ../../code/ScoresDisplay.cpp:107
310418 msgid "Lines Pushed: "
311419 msgstr "Linjer skubbet: "
312420
313 #: ../../code/ScoresDisplay.cpp:92
421 #: ../../code/ScoresDisplay.cpp:112
314422 msgid "Puzzles solved: "
315423 msgstr "Gåder løst: "
316424
317 #: ../../code/ScoresDisplay.cpp:97
425 #: ../../code/ScoresDisplay.cpp:117
318426 msgid "Run time: "
319427 msgstr "Kørselstid: "
320428
321 #: ../../code/ScoresDisplay.cpp:100 ../../code/ScoresDisplay.cpp:113
429 #: ../../code/ScoresDisplay.cpp:120 ../../code/ScoresDisplay.cpp:133
322430 #, c-format
323431 msgid "Days: %i"
324432 msgstr "Dage: %i"
325433
326 #: ../../code/ScoresDisplay.cpp:102 ../../code/ScoresDisplay.cpp:115
434 #: ../../code/ScoresDisplay.cpp:122 ../../code/ScoresDisplay.cpp:135
327435 #, c-format
328436 msgid "Hours: %i"
329437 msgstr "Timer: %i"
330438
331 #: ../../code/ScoresDisplay.cpp:104 ../../code/ScoresDisplay.cpp:117
439 #: ../../code/ScoresDisplay.cpp:124 ../../code/ScoresDisplay.cpp:137
332440 #, c-format
333441 msgid "Minutes: %i"
334442 msgstr "Minutter: %i"
335443
336 #: ../../code/ScoresDisplay.cpp:106 ../../code/ScoresDisplay.cpp:119
444 #: ../../code/ScoresDisplay.cpp:126 ../../code/ScoresDisplay.cpp:139
337445 #, c-format
338446 msgid "Seconds: %i"
339447 msgstr "Sekunder: %i"
340448
341 #: ../../code/ScoresDisplay.cpp:110
449 #: ../../code/ScoresDisplay.cpp:130
342450 msgid "Play time: "
343 msgstr "Spilletid:"
344
345 #: ../../code/ScoresDisplay.cpp:123
451 msgstr "Spilletid: "
452
453 #: ../../code/ScoresDisplay.cpp:143
346454 msgid "VS CPU (win/loss)"
347 msgstr "mod computeren (vundet/tabt)"
348
349 #: ../../code/ScoresDisplay.cpp:164 ../../code/BlockGameSdl.inc:315
350 #: ../../code/BlockGameSdl.inc:333
455 msgstr "Mod computeren (vundet/tabt)"
456
457 #: ../../code/ScoresDisplay.cpp:188 ../../code/BlockGameSdl.inc:54
351458 msgid "Next"
352459 msgstr "Næste"
353460
354 #: ../../code/ScoresDisplay.cpp:167
461 #: ../../code/ScoresDisplay.cpp:192
355462 #, c-format
356463 msgid "Page %i of %i"
357464 msgstr "Side %i af %i"
358465
359 #: ../../code/BlockGameSdl.inc:293
466 #: ../../code/BlockGameSdl.inc:50
360467 msgid "Score:"
361468 msgstr "Resultat:"
362469
363 #: ../../code/BlockGameSdl.inc:294
470 #: ../../code/BlockGameSdl.inc:51
364471 msgid "Time:"
365472 msgstr "Tid:"
366473
367 #: ../../code/BlockGameSdl.inc:295
474 #: ../../code/BlockGameSdl.inc:52
368475 msgid "Chain:"
369476 msgstr "Kæde:"
370477
371 #: ../../code/BlockGameSdl.inc:296
478 #: ../../code/BlockGameSdl.inc:53
372479 msgid "Speed:"
373480 msgstr "Hastighed:"
374481
375 #: ../../code/BlockGameSdl.inc:305
482 #: ../../code/BlockGameSdl.inc:55
483 msgid "Retry"
484 msgstr "Prøv igen"
485
486 #: ../../code/BlockGameSdl.inc:56
487 msgid "Skip"
488 msgstr "Spring over"
489
490 #: ../../code/BlockGameSdl.inc:327
376491 msgid "Moves left: "
377492 msgstr "Træk tilbage: "
378493
379 #: ../../code/BlockGameSdl.inc:311 ../../code/BlockGameSdl.inc:329
380 msgid "Retry"
381 msgstr "Prøv igen"
382
383 #: ../../code/BlockGameSdl.inc:319 ../../code/BlockGameSdl.inc:337
384 msgid "Skip"
385 msgstr "Spring over"
494 #: ../../code/BlockGameSdl.inc:350
495 msgid "Last puzzle"
496 msgstr "Sidste gåde"
497
498 #: ../../code/BlockGameSdl.inc:370
499 msgid "Last stage"
500 msgstr "Sidste bane"
501
502 #: ../../code/ShowFileState.hpp:45
503 #, c-format
504 msgid "Showing content of: %s"
505 msgstr "Viser indhold af: %s"
506
507 #~ msgid "Author:"
508 #~ msgstr "Forfatter:"
509
510 #~ msgid "Contributers:"
511 #~ msgstr "Bidragydere:"
512
513 #~ msgid "Other credits:"
514 #~ msgstr "Andre bidrag:"
386515
387516 #~ msgid "Total score: %1% in %2%:%3%"
388517 #~ msgstr "Sammenlagt resultat: %1% på %2%:%3%"
77 msgstr ""
88 "Project-Id-Version: PACKAGE VERSION\n"
99 "Report-Msgid-Bugs-To: \n"
10 "POT-Creation-Date: 2017-03-29 19:48+0200\n"
10 "POT-Creation-Date: 2018-05-19 18:29+0200\n"
1111 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1212 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313 "Language-Team: LANGUAGE <LL@li.org>\n"
1616 "Content-Type: text/plain; charset=CHARSET\n"
1717 "Content-Transfer-Encoding: 8bit\n"
1818
19 #: ../../code/DialogBox.cpp:103
19 #: ../../code/DialogBox.cpp:92
2020 msgid "Enter to accept"
2121 msgstr ""
2222
23 #: ../../code/DialogBox.cpp:104
23 #: ../../code/DialogBox.cpp:93
2424 msgid "Esc to cancel"
2525 msgstr ""
2626
27 #: ../../code/levelselect.cpp:78
27 #: ../../code/HelpAboutState.cpp:62
28 msgid "Name:"
29 msgstr ""
30
31 #: ../../code/HelpAboutState.cpp:62
32 msgid "Block Attack - Rise of the Blocks"
33 msgstr ""
34
35 #: ../../code/HelpAboutState.cpp:63
36 msgid "Original name:"
37 msgstr ""
38
39 #: ../../code/HelpAboutState.cpp:64
40 msgid "Version:"
41 msgstr ""
42
43 #: ../../code/HelpAboutState.cpp:65
44 msgid "Homepage:"
45 msgstr ""
46
47 #: ../../code/HelpAboutState.cpp:66
48 msgid "Github page:"
49 msgstr ""
50
51 #: ../../code/HelpAboutState.cpp:67
52 msgid "SDL render:"
53 msgstr ""
54
55 #: ../../code/HelpAboutState.cpp:68
56 msgid "Save folder:"
57 msgstr ""
58
59 #: ../../code/HelpAboutState.cpp:69
60 msgid "Locale:"
61 msgstr ""
62
63 #: ../../code/HelpAboutState.cpp:70 ../../code/menudef.cpp:309
64 msgid "About"
65 msgstr ""
66
67 #: ../../code/HelpGamepadState.cpp:54
68 msgid "Move cursor"
69 msgstr ""
70
71 #: ../../code/HelpGamepadState.cpp:55
72 msgid "Push line"
73 msgstr ""
74
75 #: ../../code/HelpGamepadState.cpp:56
76 msgid "Back (Menu)"
77 msgstr ""
78
79 #: ../../code/HelpGamepadState.cpp:57
80 msgid "Switch"
81 msgstr ""
82
83 #: ../../code/HelpGamepadState.cpp:58
84 msgid "Confirm"
85 msgstr ""
86
87 #: ../../code/HelpGamepadState.cpp:59
88 msgid ""
89 "Only SDL2 compatible controllers are supported!\n"
90 "Supported controllers: "
91 msgstr ""
92
93 #: ../../code/HelpHowtoState.cpp:127
94 msgid "Switch block horizontally"
95 msgstr ""
96
97 #: ../../code/HelpHowtoState.cpp:128
98 msgid "Match 3 to clear"
99 msgstr ""
100
101 #: ../../code/HelpHowtoState.cpp:129
102 msgid "Create combos!"
103 msgstr ""
104
105 #: ../../code/HelpHowtoState.cpp:130
106 msgid "Drop blocks!"
107 msgstr ""
108
109 #: ../../code/HelpHowtoState.cpp:131
110 msgid "Create a chain effect"
111 msgstr ""
112
113 #: ../../code/levelselect.cpp:92
28114 msgid "Select Puzzle"
29115 msgstr ""
30116
31 #: ../../code/levelselect.cpp:81
117 #: ../../code/levelselect.cpp:95
32118 msgid "Stage Clear Level Select"
33119 msgstr ""
34120
35 #: ../../code/levelselect.cpp:187
121 #: ../../code/levelselect.cpp:201
36122 #, c-format
37123 msgid "Best score: %i"
38124 msgstr ""
39125
40 #: ../../code/levelselect.cpp:188
126 #: ../../code/levelselect.cpp:202
41127 #, c-format
42128 msgid "Time used: %s"
43129 msgstr ""
44130
45 #: ../../code/levelselect.cpp:191
131 #: ../../code/levelselect.cpp:205
46132 #, c-format
47133 msgid "Time used: %d : %02d"
48134 msgstr ""
49135
50 #: ../../code/levelselect.cpp:196
136 #: ../../code/levelselect.cpp:210
51137 #, c-format
52138 msgid "Total score: %i in %i:%02i"
53139 msgstr ""
54140
55 #: ../../code/main.cpp:431 ../../code/main.cpp:544
141 #: ../../code/main.cpp:452 ../../code/main.cpp:583
56142 msgid "AI"
57143 msgstr ""
58144
59 #: ../../code/main.cpp:434
145 #: ../../code/main.cpp:455
60146 msgid "Playing field"
61147 msgstr ""
62148
63 #: ../../code/main.cpp:505
149 #: ../../code/main.cpp:529
64150 msgid "Time Trial"
65151 msgstr ""
66152
67 #: ../../code/main.cpp:506
153 #: ../../code/main.cpp:530
68154 msgid "Score as much as possible in 2 minutes"
69155 msgstr ""
70156
71 #: ../../code/main.cpp:510
157 #: ../../code/main.cpp:534
72158 msgid "Stage Clear"
73159 msgstr ""
74160
75 #: ../../code/main.cpp:511
161 #: ../../code/main.cpp:535
76162 msgid "You must clear a number of lines. Speed is rapidly increased."
77163 msgstr ""
78164
79 #: ../../code/main.cpp:514
165 #: ../../code/main.cpp:538
80166 msgid "Puzzle"
81167 msgstr ""
82168
83 #: ../../code/main.cpp:515
169 #: ../../code/main.cpp:539
84170 msgid "Clear the entire board with a limited number of moves."
85171 msgstr ""
86172
87 #: ../../code/main.cpp:518
173 #: ../../code/main.cpp:542
88174 msgid "Endless"
89175 msgstr ""
90176
91 #: ../../code/main.cpp:519
177 #: ../../code/main.cpp:543
92178 msgid "Score as much as possible. No time limit."
93179 msgstr ""
94180
95 #: ../../code/main.cpp:523
181 #: ../../code/main.cpp:553
96182 msgid "Objective:"
97183 msgstr ""
98184
99 #: ../../code/main.cpp:529
185 #: ../../code/main.cpp:563
100186 msgid "Movement keys:"
101187 msgstr ""
102188
103 #: ../../code/main.cpp:532
189 #: ../../code/main.cpp:565
104190 msgid "Switch: "
105191 msgstr ""
106192
107 #: ../../code/main.cpp:534
193 #: ../../code/main.cpp:567
108194 msgid "Restart: "
109195 msgstr ""
110196
111 #: ../../code/main.cpp:537
197 #: ../../code/main.cpp:570
112198 msgid "Push line: "
113199 msgstr ""
114200
115 #: ../../code/main.cpp:945
201 #: ../../code/main.cpp:995
116202 msgid "Player 1"
117203 msgstr ""
118204
119 #: ../../code/main.cpp:946
205 #: ../../code/main.cpp:996
120206 msgid "Player 2"
121207 msgstr ""
122208
123 #: ../../code/menudef.cpp:135 ../../code/menudef.cpp:203
209 #: ../../code/menudef.cpp:138 ../../code/menudef.cpp:206
124210 msgid "Music: On"
125211 msgstr ""
126212
127 #: ../../code/menudef.cpp:135 ../../code/menudef.cpp:203
213 #: ../../code/menudef.cpp:138 ../../code/menudef.cpp:206
128214 msgid "Music: Off"
129215 msgstr ""
130216
131 #: ../../code/menudef.cpp:143 ../../code/menudef.cpp:204
217 #: ../../code/menudef.cpp:146 ../../code/menudef.cpp:207
132218 msgid "Sound: On"
133219 msgstr ""
134220
135 #: ../../code/menudef.cpp:143 ../../code/menudef.cpp:204
221 #: ../../code/menudef.cpp:146 ../../code/menudef.cpp:207
136222 msgid "Sound: Off"
137223 msgstr ""
138224
139 #: ../../code/menudef.cpp:150 ../../code/menudef.cpp:205
225 #: ../../code/menudef.cpp:153 ../../code/menudef.cpp:208
140226 msgid "Fullscreen: On"
141227 msgstr ""
142228
143 #: ../../code/menudef.cpp:150 ../../code/menudef.cpp:205
229 #: ../../code/menudef.cpp:153 ../../code/menudef.cpp:208
144230 msgid "Fullscreen: Off"
145231 msgstr ""
146232
147 #: ../../code/menudef.cpp:156
233 #: ../../code/menudef.cpp:159
148234 msgid "Enter player 1 name:"
149235 msgstr ""
150236
151 #: ../../code/menudef.cpp:162
237 #: ../../code/menudef.cpp:165
152238 msgid "Enter player 2 name:"
153239 msgstr ""
154240
155 #: ../../code/menudef.cpp:172
241 #: ../../code/menudef.cpp:175
156242 msgid "Change key bindings"
157243 msgstr ""
158244
159 #: ../../code/menudef.cpp:173
245 #: ../../code/menudef.cpp:176
160246 msgid "Left"
161247 msgstr ""
162248
163 #: ../../code/menudef.cpp:174
249 #: ../../code/menudef.cpp:177
164250 msgid "Right"
165251 msgstr ""
166252
167 #: ../../code/menudef.cpp:175
253 #: ../../code/menudef.cpp:178
168254 msgid "Up"
169255 msgstr ""
170256
171 #: ../../code/menudef.cpp:176
257 #: ../../code/menudef.cpp:179
172258 msgid "Down"
173259 msgstr ""
174260
175 #: ../../code/menudef.cpp:177
261 #: ../../code/menudef.cpp:180
176262 msgid "Push"
177263 msgstr ""
178264
179 #: ../../code/menudef.cpp:178
265 #: ../../code/menudef.cpp:181
180266 msgid "Change"
181267 msgstr ""
182268
183 #: ../../code/menudef.cpp:197
269 #: ../../code/menudef.cpp:200
184270 msgid "Configuration"
185271 msgstr ""
186272
187 #: ../../code/menudef.cpp:207
273 #: ../../code/menudef.cpp:210
188274 msgid "Change player 1's name"
189275 msgstr ""
190276
191 #: ../../code/menudef.cpp:209
277 #: ../../code/menudef.cpp:212
192278 msgid "Change player 2's name"
193279 msgstr ""
194280
195 #: ../../code/menudef.cpp:211
281 #: ../../code/menudef.cpp:214
196282 msgid "Change player 1's keys"
197283 msgstr ""
198284
199 #: ../../code/menudef.cpp:213
285 #: ../../code/menudef.cpp:216
200286 msgid "Change player 2's keys"
201287 msgstr ""
202288
203 #: ../../code/menudef.cpp:225
289 #: ../../code/menudef.cpp:228
204290 msgid "Single player VS"
205291 msgstr ""
206292
207 #: ../../code/menudef.cpp:241
293 #: ../../code/menudef.cpp:244
208294 msgid "Very easy"
209295 msgstr ""
210296
211 #: ../../code/menudef.cpp:242
297 #: ../../code/menudef.cpp:245
212298 msgid "Easy"
213299 msgstr ""
214300
215 #: ../../code/menudef.cpp:243
301 #: ../../code/menudef.cpp:246
216302 msgid "Below normal"
217303 msgstr ""
218304
219 #: ../../code/menudef.cpp:244
305 #: ../../code/menudef.cpp:247
220306 msgid "Normal"
221307 msgstr ""
222308
223 #: ../../code/menudef.cpp:245
309 #: ../../code/menudef.cpp:248
224310 msgid "Above normal"
225311 msgstr ""
226312
227 #: ../../code/menudef.cpp:246
313 #: ../../code/menudef.cpp:249
228314 msgid "Hard"
229315 msgstr ""
230316
231 #: ../../code/menudef.cpp:247
317 #: ../../code/menudef.cpp:250
232318 msgid "Hardest"
233319 msgstr ""
234320
235 #: ../../code/menudef.cpp:259
321 #: ../../code/menudef.cpp:262
236322 msgid "Multiplayer"
237323 msgstr ""
238324
239 #: ../../code/menudef.cpp:261
325 #: ../../code/menudef.cpp:264
240326 msgid "Two player - time trial"
241327 msgstr ""
242328
243 #: ../../code/menudef.cpp:263
329 #: ../../code/menudef.cpp:266
244330 msgid "Two player - vs"
245331 msgstr ""
246332
247 #: ../../code/menudef.cpp:272
333 #: ../../code/menudef.cpp:290 ../../code/menudef.cpp:305
334 msgid "Credits"
335 msgstr ""
336
337 #: ../../code/menudef.cpp:295 ../../code/menudef.cpp:348
338 msgid "Help"
339 msgstr ""
340
341 #: ../../code/menudef.cpp:297
342 msgid "How to"
343 msgstr ""
344
345 #: ../../code/menudef.cpp:301
346 msgid "Gamepad"
347 msgstr ""
348
349 #: ../../code/menudef.cpp:316 ../../code/menudef.cpp:340
350 msgid "Single player"
351 msgstr ""
352
353 #: ../../code/menudef.cpp:318
354 msgid "Single player - endless"
355 msgstr ""
356
357 #: ../../code/menudef.cpp:320
358 msgid "Single player - time trial"
359 msgstr ""
360
361 #: ../../code/menudef.cpp:322
362 msgid "Single player - stage clear"
363 msgstr ""
364
365 #: ../../code/menudef.cpp:324
366 msgid "Single player - puzzle mode"
367 msgstr ""
368
369 #: ../../code/menudef.cpp:326
370 msgid "Single player - vs"
371 msgstr ""
372
373 #: ../../code/menudef.cpp:338
248374 msgid "Block Attack - Rise of the blocks"
249375 msgstr ""
250376
251 #: ../../code/menudef.cpp:274
252 msgid "Single player - endless"
253 msgstr ""
254
255 #: ../../code/menudef.cpp:276
256 msgid "Single player - time trial"
257 msgstr ""
258
259 #: ../../code/menudef.cpp:278
260 msgid "Single player - stage clear"
261 msgstr ""
262
263 #: ../../code/menudef.cpp:280
264 msgid "Single player - puzzle mode"
265 msgstr ""
266
267 #: ../../code/menudef.cpp:282
268 msgid "Single player - vs"
269 msgstr ""
270
271 #: ../../code/menudef.cpp:284
377 #: ../../code/menudef.cpp:342
272378 msgid "Multi player"
273379 msgstr ""
274380
275 #: ../../code/menudef.cpp:286
381 #: ../../code/menudef.cpp:344
276382 msgid "Configure"
277383 msgstr ""
278384
279 #: ../../code/menudef.cpp:288
385 #: ../../code/menudef.cpp:346
280386 msgid "Highscores"
281387 msgstr ""
282388
283 #: ../../code/MenuSystem.cpp:145 ../../code/MenuSystem.cpp:153
284 #: ../../code/MenuSystem.cpp:166 ../../code/ScoresDisplay.cpp:162
389 #: ../../code/MenuSystem.cpp:162 ../../code/MenuSystem.cpp:170
390 #: ../../code/MenuSystem.cpp:183 ../../code/ScoresDisplay.cpp:184
285391 msgid "Back"
286392 msgstr ""
287393
288 #: ../../code/MenuSystem.cpp:156 ../../code/MenuSystem.cpp:169
394 #: ../../code/MenuSystem.cpp:173 ../../code/MenuSystem.cpp:186
289395 msgid "Exit"
290396 msgstr ""
291397
292 #: ../../code/ScoresDisplay.cpp:51
398 #: ../../code/ScoresDisplay.cpp:71
293399 msgid "Endless:"
294400 msgstr ""
295401
296 #: ../../code/ScoresDisplay.cpp:54
402 #: ../../code/ScoresDisplay.cpp:74
297403 msgid "Time Trial:"
298404 msgstr ""
299405
300 #: ../../code/ScoresDisplay.cpp:77
406 #: ../../code/ScoresDisplay.cpp:97
301407 msgid "Stats"
302408 msgstr ""
303409
304 #: ../../code/ScoresDisplay.cpp:79
410 #: ../../code/ScoresDisplay.cpp:99
305411 msgid "Chains"
306412 msgstr ""
307413
308 #: ../../code/ScoresDisplay.cpp:87
414 #: ../../code/ScoresDisplay.cpp:107
309415 msgid "Lines Pushed: "
310416 msgstr ""
311417
312 #: ../../code/ScoresDisplay.cpp:92
418 #: ../../code/ScoresDisplay.cpp:112
313419 msgid "Puzzles solved: "
314420 msgstr ""
315421
316 #: ../../code/ScoresDisplay.cpp:97
422 #: ../../code/ScoresDisplay.cpp:117
317423 msgid "Run time: "
318424 msgstr ""
319425
320 #: ../../code/ScoresDisplay.cpp:100 ../../code/ScoresDisplay.cpp:113
426 #: ../../code/ScoresDisplay.cpp:120 ../../code/ScoresDisplay.cpp:133
321427 #, c-format
322428 msgid "Days: %i"
323429 msgstr ""
324430
325 #: ../../code/ScoresDisplay.cpp:102 ../../code/ScoresDisplay.cpp:115
431 #: ../../code/ScoresDisplay.cpp:122 ../../code/ScoresDisplay.cpp:135
326432 #, c-format
327433 msgid "Hours: %i"
328434 msgstr ""
329435
330 #: ../../code/ScoresDisplay.cpp:104 ../../code/ScoresDisplay.cpp:117
436 #: ../../code/ScoresDisplay.cpp:124 ../../code/ScoresDisplay.cpp:137
331437 #, c-format
332438 msgid "Minutes: %i"
333439 msgstr ""
334440
335 #: ../../code/ScoresDisplay.cpp:106 ../../code/ScoresDisplay.cpp:119
441 #: ../../code/ScoresDisplay.cpp:126 ../../code/ScoresDisplay.cpp:139
336442 #, c-format
337443 msgid "Seconds: %i"
338444 msgstr ""
339445
340 #: ../../code/ScoresDisplay.cpp:110
446 #: ../../code/ScoresDisplay.cpp:130
341447 msgid "Play time: "
342448 msgstr ""
343449
344 #: ../../code/ScoresDisplay.cpp:123
450 #: ../../code/ScoresDisplay.cpp:143
345451 msgid "VS CPU (win/loss)"
346452 msgstr ""
347453
348 #: ../../code/ScoresDisplay.cpp:164 ../../code/BlockGameSdl.inc:315
349 #: ../../code/BlockGameSdl.inc:333
454 #: ../../code/ScoresDisplay.cpp:188 ../../code/BlockGameSdl.inc:54
350455 msgid "Next"
351456 msgstr ""
352457
353 #: ../../code/ScoresDisplay.cpp:167
458 #: ../../code/ScoresDisplay.cpp:192
354459 #, c-format
355460 msgid "Page %i of %i"
356461 msgstr ""
357462
358 #: ../../code/BlockGameSdl.inc:293
463 #: ../../code/BlockGameSdl.inc:50
359464 msgid "Score:"
360465 msgstr ""
361466
362 #: ../../code/BlockGameSdl.inc:294
467 #: ../../code/BlockGameSdl.inc:51
363468 msgid "Time:"
364469 msgstr ""
365470
366 #: ../../code/BlockGameSdl.inc:295
471 #: ../../code/BlockGameSdl.inc:52
367472 msgid "Chain:"
368473 msgstr ""
369474
370 #: ../../code/BlockGameSdl.inc:296
475 #: ../../code/BlockGameSdl.inc:53
371476 msgid "Speed:"
372477 msgstr ""
373478
374 #: ../../code/BlockGameSdl.inc:305
479 #: ../../code/BlockGameSdl.inc:55
480 msgid "Retry"
481 msgstr ""
482
483 #: ../../code/BlockGameSdl.inc:56
484 msgid "Skip"
485 msgstr ""
486
487 #: ../../code/BlockGameSdl.inc:327
375488 msgid "Moves left: "
376489 msgstr ""
377490
378 #: ../../code/BlockGameSdl.inc:311 ../../code/BlockGameSdl.inc:329
379 msgid "Retry"
380 msgstr ""
381
382 #: ../../code/BlockGameSdl.inc:319 ../../code/BlockGameSdl.inc:337
383 msgid "Skip"
384 msgstr ""
491 #: ../../code/BlockGameSdl.inc:350
492 msgid "Last puzzle"
493 msgstr ""
494
495 #: ../../code/BlockGameSdl.inc:370
496 msgid "Last stage"
497 msgstr ""
498
499 #: ../../code/ShowFileState.hpp:45
500 #, c-format
501 msgid "Showing content of: %s"
502 msgstr ""
33 # First check for formatting errors
44 bash source/misc/lint/runLint.sh
55
6 docker build -f source/misc/docker/Dockerfile.Ubuntu14.04build . -t blockattack_test
6 docker build -f source/misc/docker/Dockerfile.Fedora25build . -t blockattack_test
7 #docker build -f source/misc/docker/Dockerfile.Ubuntu14.04build . -t blockattack_test
78 docker build -f source/misc/docker/Dockerfile.WindoesBuild . -t blockattack_test
11
22 ; HM NIS Edit Wizard helper defines
33 !define PRODUCT_NAME "Block Attack - Rise Of the Blocks"
4 !define PRODUCT_VERSION "2.1.2"
4 !define PRODUCT_VERSION "2.2.0"
55 !define PRODUCT_PUBLISHER "Poul Sander"
66 !define PRODUCT_WEB_SITE "http://www.blockattack.net"
77 !define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\blockattack.exe"