gosu 0.7.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (249) hide show
  1. data/COPYING.txt +29 -0
  2. data/Gosu/Async.hpp +48 -0
  3. data/Gosu/Audio.hpp +145 -0
  4. data/Gosu/AutoLink.hpp +16 -0
  5. data/Gosu/Bitmap.hpp +85 -0
  6. data/Gosu/ButtonsMac.hpp +114 -0
  7. data/Gosu/ButtonsWin.hpp +111 -0
  8. data/Gosu/ButtonsX.hpp +115 -0
  9. data/Gosu/Color.hpp +172 -0
  10. data/Gosu/Directories.hpp +36 -0
  11. data/Gosu/Font.hpp +59 -0
  12. data/Gosu/Fwd.hpp +31 -0
  13. data/Gosu/Gosu.hpp +26 -0
  14. data/Gosu/Graphics.hpp +86 -0
  15. data/Gosu/GraphicsBase.hpp +45 -0
  16. data/Gosu/IO.hpp +255 -0
  17. data/Gosu/Image.hpp +148 -0
  18. data/Gosu/ImageData.hpp +45 -0
  19. data/Gosu/Input.hpp +116 -0
  20. data/Gosu/Math.hpp +95 -0
  21. data/Gosu/Platform.hpp +61 -0
  22. data/Gosu/RotFlip.hpp +116 -0
  23. data/Gosu/Sockets.hpp +129 -0
  24. data/Gosu/Text.hpp +47 -0
  25. data/Gosu/TextInput.hpp +57 -0
  26. data/Gosu/Timing.hpp +16 -0
  27. data/Gosu/Utility.hpp +24 -0
  28. data/Gosu/WinUtility.hpp +76 -0
  29. data/Gosu/Window.hpp +84 -0
  30. data/GosuImpl/Async.cpp +37 -0
  31. data/GosuImpl/AudioFmod.cpp +417 -0
  32. data/GosuImpl/AudioSDL.cpp +255 -0
  33. data/GosuImpl/DirectoriesMac.mm +38 -0
  34. data/GosuImpl/DirectoriesUnix.cpp +48 -0
  35. data/GosuImpl/DirectoriesWin.cpp +42 -0
  36. data/GosuImpl/FileUnix.cpp +100 -0
  37. data/GosuImpl/FileWin.cpp +83 -0
  38. data/GosuImpl/Graphics/Bitmap.cpp +116 -0
  39. data/GosuImpl/Graphics/BitmapBMP.cpp +232 -0
  40. data/GosuImpl/Graphics/BitmapColorKey.cpp +39 -0
  41. data/GosuImpl/Graphics/BitmapPNG.cpp +276 -0
  42. data/GosuImpl/Graphics/BitmapUtils.cpp +67 -0
  43. data/GosuImpl/Graphics/BlockAllocator.cpp +127 -0
  44. data/GosuImpl/Graphics/BlockAllocator.hpp +34 -0
  45. data/GosuImpl/Graphics/Color.cpp +126 -0
  46. data/GosuImpl/Graphics/Common.hpp +21 -0
  47. data/GosuImpl/Graphics/DrawOp.hpp +154 -0
  48. data/GosuImpl/Graphics/Font.cpp +110 -0
  49. data/GosuImpl/Graphics/Graphics.cpp +295 -0
  50. data/GosuImpl/Graphics/Image.cpp +159 -0
  51. data/GosuImpl/Graphics/LargeImageData.cpp +115 -0
  52. data/GosuImpl/Graphics/LargeImageData.hpp +37 -0
  53. data/GosuImpl/Graphics/RotFlip.cpp +184 -0
  54. data/GosuImpl/Graphics/TexChunk.cpp +77 -0
  55. data/GosuImpl/Graphics/TexChunk.hpp +40 -0
  56. data/GosuImpl/Graphics/Text.cpp +223 -0
  57. data/GosuImpl/Graphics/TextMac.cpp +242 -0
  58. data/GosuImpl/Graphics/TextPangoFT.cpp +186 -0
  59. data/GosuImpl/Graphics/TextWin.cpp +172 -0
  60. data/GosuImpl/Graphics/Texture.cpp +104 -0
  61. data/GosuImpl/Graphics/Texture.hpp +34 -0
  62. data/GosuImpl/IO.cpp +48 -0
  63. data/GosuImpl/InputMac.mm +677 -0
  64. data/GosuImpl/InputWin.cpp +444 -0
  65. data/GosuImpl/InputX.cpp +158 -0
  66. data/GosuImpl/MacUtility.hpp +48 -0
  67. data/GosuImpl/Math.cpp +49 -0
  68. data/GosuImpl/RubyGosu.swg +474 -0
  69. data/GosuImpl/RubyGosuStub.mm +17 -0
  70. data/GosuImpl/RubyGosu_DllMain.cxx +30 -0
  71. data/GosuImpl/RubyGosu_wrap.cxx +8521 -0
  72. data/GosuImpl/RubyGosu_wrap.h +31 -0
  73. data/GosuImpl/Sockets/CommSocket.cpp +304 -0
  74. data/GosuImpl/Sockets/ListenerSocket.cpp +60 -0
  75. data/GosuImpl/Sockets/MessageSocket.cpp +136 -0
  76. data/GosuImpl/Sockets/Socket.cpp +145 -0
  77. data/GosuImpl/Sockets/Sockets.hpp +66 -0
  78. data/GosuImpl/TextInputMac.mm +207 -0
  79. data/GosuImpl/TextInputWin.cpp +197 -0
  80. data/GosuImpl/TextInputX.cpp +201 -0
  81. data/GosuImpl/TextTTFWin.cpp +247 -0
  82. data/GosuImpl/TimingUnix.cpp +17 -0
  83. data/GosuImpl/TimingWin.cpp +28 -0
  84. data/GosuImpl/Utility.cpp +140 -0
  85. data/GosuImpl/WinMain.cpp +69 -0
  86. data/GosuImpl/WinUtility.cpp +137 -0
  87. data/GosuImpl/WindowMac.mm +466 -0
  88. data/GosuImpl/WindowWin.cpp +447 -0
  89. data/GosuImpl/WindowX.cpp +392 -0
  90. data/GosuImpl/X11vroot.h +118 -0
  91. data/README.txt +13 -0
  92. data/Rakefile +178 -0
  93. data/examples/ChipmunkIntegration.rb +275 -0
  94. data/examples/CptnRuby.rb +231 -0
  95. data/examples/MoreChipmunkAndRMagick.rb +155 -0
  96. data/examples/OpenGLIntegration.rb +232 -0
  97. data/examples/RMagickIntegration.rb +449 -0
  98. data/examples/TextInput.cpp +170 -0
  99. data/examples/TextInput.rb +139 -0
  100. data/examples/Tutorial.cpp +215 -0
  101. data/examples/Tutorial.rb +137 -0
  102. data/examples/media/Beep.wav +0 -0
  103. data/examples/media/CptnRuby Gem.png +0 -0
  104. data/examples/media/CptnRuby Map.txt +25 -0
  105. data/examples/media/CptnRuby Tileset.png +0 -0
  106. data/examples/media/CptnRuby.png +0 -0
  107. data/examples/media/Cursor.png +0 -0
  108. data/examples/media/Earth.png +0 -0
  109. data/examples/media/Explosion.wav +0 -0
  110. data/examples/media/LargeStar.png +0 -0
  111. data/examples/media/Sky.jpg +0 -0
  112. data/examples/media/Smoke.png +0 -0
  113. data/examples/media/Soldier.png +0 -0
  114. data/examples/media/Space.png +0 -0
  115. data/examples/media/Star.png +0 -0
  116. data/examples/media/Starfighter.bmp +0 -0
  117. data/linux/Makefile.in +98 -0
  118. data/linux/configure +5658 -0
  119. data/linux/configure.ac +126 -0
  120. data/linux/extconf.rb +11 -0
  121. data/mac/English.lproj/InfoPlist.strings +0 -0
  122. data/mac/Gosu-Info.plist +26 -0
  123. data/mac/Gosu.xcodeproj/project.pbxproj +1194 -0
  124. data/mac/RubyGosu Template-Info.plist +26 -0
  125. data/mac/libboost_thread_1_34_1_universal.a +0 -0
  126. data/mac/libboost_thread_d_1_34_1_universal.a +0 -0
  127. data/mac/libfmod_universal.a +0 -0
  128. data/mac/libpng_universal.a +0 -0
  129. data/mac/libz_universal.a +0 -0
  130. data/reference/Async_8hpp-source.html +70 -0
  131. data/reference/Audio_8hpp-source.html +114 -0
  132. data/reference/Audio_8hpp.html +50 -0
  133. data/reference/AutoLink_8hpp-source.html +38 -0
  134. data/reference/AutoLink_8hpp.html +34 -0
  135. data/reference/Bitmap_8hpp-source.html +85 -0
  136. data/reference/Bitmap_8hpp.html +58 -0
  137. data/reference/ButtonsMac_8hpp-source.html +133 -0
  138. data/reference/ButtonsWin_8hpp-source.html +133 -0
  139. data/reference/ButtonsX_8hpp-source.html +134 -0
  140. data/reference/Color_8hpp-source.html +169 -0
  141. data/reference/Color_8hpp.html +85 -0
  142. data/reference/Directories_8hpp-source.html +42 -0
  143. data/reference/Directories_8hpp.html +46 -0
  144. data/reference/Font_8hpp-source.html +65 -0
  145. data/reference/Font_8hpp.html +41 -0
  146. data/reference/Fwd_8hpp-source.html +52 -0
  147. data/reference/Fwd_8hpp.html +37 -0
  148. data/reference/Gosu_8hpp-source.html +48 -0
  149. data/reference/Gosu_8hpp.html +34 -0
  150. data/reference/GraphicsBase_8hpp-source.html +57 -0
  151. data/reference/GraphicsBase_8hpp.html +56 -0
  152. data/reference/Graphics_8hpp-source.html +96 -0
  153. data/reference/Graphics_8hpp.html +53 -0
  154. data/reference/IO_8hpp-source.html +255 -0
  155. data/reference/IO_8hpp.html +74 -0
  156. data/reference/ImageData_8hpp-source.html +62 -0
  157. data/reference/ImageData_8hpp.html +43 -0
  158. data/reference/Image_8hpp-source.html +126 -0
  159. data/reference/Image_8hpp.html +48 -0
  160. data/reference/Input_8hpp-source.html +118 -0
  161. data/reference/Input_8hpp.html +50 -0
  162. data/reference/Math_8hpp-source.html +92 -0
  163. data/reference/Math_8hpp.html +74 -0
  164. data/reference/Platform_8hpp-source.html +83 -0
  165. data/reference/Platform_8hpp.html +73 -0
  166. data/reference/RotFlip_8hpp-source.html +138 -0
  167. data/reference/RotFlip_8hpp.html +77 -0
  168. data/reference/Sockets_8hpp-source.html +130 -0
  169. data/reference/Sockets_8hpp.html +66 -0
  170. data/reference/TextInput_8hpp-source.html +64 -0
  171. data/reference/TextInput_8hpp.html +41 -0
  172. data/reference/Text_8hpp-source.html +51 -0
  173. data/reference/Text_8hpp.html +46 -0
  174. data/reference/Timing_8hpp-source.html +36 -0
  175. data/reference/Timing_8hpp.html +42 -0
  176. data/reference/Utility_8hpp-source.html +44 -0
  177. data/reference/Utility_8hpp.html +48 -0
  178. data/reference/WinUtility_8hpp-source.html +79 -0
  179. data/reference/WinUtility_8hpp.html +64 -0
  180. data/reference/Window_8hpp-source.html +91 -0
  181. data/reference/Window_8hpp.html +41 -0
  182. data/reference/annotated.html +51 -0
  183. data/reference/classGosu_1_1Audio-members.html +34 -0
  184. data/reference/classGosu_1_1Audio.html +46 -0
  185. data/reference/classGosu_1_1Bitmap-members.html +44 -0
  186. data/reference/classGosu_1_1Bitmap.html +263 -0
  187. data/reference/classGosu_1_1Buffer-members.html +44 -0
  188. data/reference/classGosu_1_1Buffer.html +78 -0
  189. data/reference/classGosu_1_1Buffer.png +0 -0
  190. data/reference/classGosu_1_1Button-members.html +36 -0
  191. data/reference/classGosu_1_1Button.html +143 -0
  192. data/reference/classGosu_1_1Color-members.html +56 -0
  193. data/reference/classGosu_1_1Color.html +387 -0
  194. data/reference/classGosu_1_1File-members.html +41 -0
  195. data/reference/classGosu_1_1File.html +69 -0
  196. data/reference/classGosu_1_1File.png +0 -0
  197. data/reference/classGosu_1_1Font-members.html +39 -0
  198. data/reference/classGosu_1_1Font.html +309 -0
  199. data/reference/classGosu_1_1Graphics-members.html +50 -0
  200. data/reference/classGosu_1_1Graphics.html +234 -0
  201. data/reference/classGosu_1_1Image-members.html +45 -0
  202. data/reference/classGosu_1_1Image.html +518 -0
  203. data/reference/classGosu_1_1ImageData-members.html +37 -0
  204. data/reference/classGosu_1_1ImageData.html +60 -0
  205. data/reference/classGosu_1_1Input-members.html +44 -0
  206. data/reference/classGosu_1_1Input.html +223 -0
  207. data/reference/classGosu_1_1MessageSocket-members.html +40 -0
  208. data/reference/classGosu_1_1MessageSocket.html +233 -0
  209. data/reference/classGosu_1_1Resource-members.html +39 -0
  210. data/reference/classGosu_1_1Resource.html +116 -0
  211. data/reference/classGosu_1_1Resource.png +0 -0
  212. data/reference/classGosu_1_1Sample-members.html +37 -0
  213. data/reference/classGosu_1_1Sample.html +200 -0
  214. data/reference/classGosu_1_1SampleInstance-members.html +38 -0
  215. data/reference/classGosu_1_1SampleInstance.html +169 -0
  216. data/reference/classGosu_1_1Song-members.html +43 -0
  217. data/reference/classGosu_1_1Song.html +260 -0
  218. data/reference/classGosu_1_1TextInput-members.html +38 -0
  219. data/reference/classGosu_1_1TextInput.html +121 -0
  220. data/reference/classGosu_1_1Window-members.html +50 -0
  221. data/reference/classGosu_1_1Window.html +271 -0
  222. data/reference/doxyfile +233 -0
  223. data/reference/doxygen.css +433 -0
  224. data/reference/doxygen.png +0 -0
  225. data/reference/files.html +54 -0
  226. data/reference/functions.html +236 -0
  227. data/reference/functions_enum.html +45 -0
  228. data/reference/functions_func.html +227 -0
  229. data/reference/functions_vars.html +47 -0
  230. data/reference/hierarchy.html +53 -0
  231. data/reference/index.html +26 -0
  232. data/reference/namespaceGosu.html +2890 -0
  233. data/reference/namespaceGosu_1_1Colors.html +70 -0
  234. data/reference/namespaceGosu_1_1Win.html +275 -0
  235. data/reference/namespacemembers.html +216 -0
  236. data/reference/namespacemembers_enum.html +52 -0
  237. data/reference/namespacemembers_eval.html +54 -0
  238. data/reference/namespacemembers_func.html +185 -0
  239. data/reference/namespacemembers_type.html +46 -0
  240. data/reference/namespacemembers_vars.html +46 -0
  241. data/reference/namespaces.html +35 -0
  242. data/reference/tab_b.gif +0 -0
  243. data/reference/tab_l.gif +0 -0
  244. data/reference/tab_r.gif +0 -0
  245. data/reference/tabs.css +102 -0
  246. data/windows/Gosu.sln +29 -0
  247. data/windows/Gosu.vcproj +553 -0
  248. data/windows/RubyGosu.vcproj +138 -0
  249. metadata +305 -0
@@ -0,0 +1,223 @@
1
+ #include <Gosu/Text.hpp>
2
+ #include <Gosu/Bitmap.hpp>
3
+ #include <Gosu/Graphics.hpp>
4
+ #include <Gosu/Image.hpp>
5
+ #include <Gosu/Math.hpp>
6
+ #include <boost/bind.hpp>
7
+ #include <boost/algorithm/string.hpp>
8
+ #include <boost/tokenizer.hpp>
9
+ #include <cassert>
10
+ #include <cmath>
11
+ #include <algorithm>
12
+ #include <vector>
13
+ using namespace std;
14
+
15
+ namespace Gosu
16
+ {
17
+ namespace
18
+ {
19
+ struct WordInfo
20
+ {
21
+ wstring text;
22
+ unsigned width;
23
+ };
24
+ typedef vector<WordInfo> Words;
25
+
26
+ // Local helper class which manages building the bitmap from the
27
+ // collected words.
28
+ class TextBlockBuilder
29
+ {
30
+ Bitmap bmp;
31
+ unsigned usedLines, allocatedLines;
32
+
33
+ wstring fontName;
34
+ unsigned fontHeight, fontFlags, lineSpacing;
35
+ TextAlign align;
36
+
37
+ unsigned spaceWidth;
38
+
39
+ void allocNextLine()
40
+ {
41
+ ++usedLines;
42
+ if (usedLines == allocatedLines)
43
+ {
44
+ allocatedLines += 10;
45
+ bmp.resize(bmp.width(),
46
+ (lineSpacing + fontHeight) * allocatedLines,
47
+ Colors::none);
48
+ }
49
+ }
50
+
51
+ public:
52
+ TextBlockBuilder(const wstring& fontName, unsigned fontHeight,
53
+ unsigned fontFlags, unsigned lineSpacing, unsigned width,
54
+ TextAlign align)
55
+ {
56
+ usedLines = 0;
57
+ allocatedLines = 10;
58
+
59
+ bmp.resize(width, (lineSpacing + fontHeight) * allocatedLines, 0x00ffffff);
60
+
61
+ this->fontName = fontName;
62
+ this->fontHeight = fontHeight;
63
+ this->fontFlags = fontFlags;
64
+ this->lineSpacing = lineSpacing;
65
+ this->align = align;
66
+
67
+ spaceWidth = textWidth(L" ");
68
+ }
69
+
70
+ unsigned width() const
71
+ {
72
+ return bmp.width();
73
+ }
74
+
75
+ unsigned textWidth(const std::wstring& text) const
76
+ {
77
+ return Gosu::textWidth(text, fontName, fontHeight, fontFlags);
78
+ }
79
+
80
+ void addLine(Words::const_iterator begin, Words::const_iterator end,
81
+ unsigned wordsWidth, bool overrideAlign)
82
+ {
83
+ allocNextLine();
84
+
85
+ unsigned words = end - begin;
86
+
87
+ // Where does the line start? (y)
88
+ unsigned top = (usedLines - 1) * (fontHeight + lineSpacing);
89
+
90
+ // Where does the line start? (x)
91
+ double pos;
92
+ switch (align)
93
+ {
94
+ // Start so that the text touches the right border.
95
+ case taRight:
96
+ pos = bmp.width() - wordsWidth - (words - 1) * spaceWidth;
97
+ break;
98
+
99
+ // Start so that the text is centered.
100
+ case taCenter:
101
+ pos = bmp.width() - wordsWidth - (words - 1) * spaceWidth;
102
+ pos /= 2;
103
+ break;
104
+
105
+ // Just start at the left border.
106
+ default:
107
+ pos = 0;
108
+ }
109
+
110
+ // How much space is between each word?
111
+ double spacing;
112
+ if (align == taJustify && !overrideAlign)
113
+ spacing = (bmp.width() - wordsWidth) / (words - 1.0);
114
+ else
115
+ spacing = spaceWidth;
116
+
117
+ for (Words::const_iterator cur = begin; cur != end; ++cur)
118
+ {
119
+ drawText(bmp, cur->text, trunc(pos), trunc(top),
120
+ Colors::white, fontName, fontHeight, fontFlags);
121
+ pos += cur->width + spacing;
122
+ }
123
+ }
124
+
125
+ Bitmap result() const
126
+ {
127
+ Bitmap result = bmp;
128
+ result.resize(result.width(),
129
+ usedLines * (lineSpacing + fontHeight));
130
+ return result;
131
+ }
132
+ };
133
+
134
+ void processWords(TextBlockBuilder& builder, const Words& words)
135
+ {
136
+ // Index into words to the first word in the current line.
137
+ Words::const_iterator lineBegin = words.begin();
138
+
139
+ const unsigned spaceWidth = builder.textWidth(L" "); // IMPR.
140
+
141
+ // Used width, in pixels, of the words [lineBegin..w[.
142
+ unsigned wordsWidth = 0;
143
+
144
+ // Used width of the spaces between (w-lineBegin) words.
145
+ unsigned spacesWidth = 0;
146
+
147
+ for (Words::const_iterator w = words.begin(); w != words.end(); ++w)
148
+ {
149
+ unsigned newWordsWidth = wordsWidth + w->width;
150
+
151
+ if (newWordsWidth + spacesWidth <= builder.width())
152
+ {
153
+ // There's enough space for the words [lineBegin..w] plus
154
+ // the spaces between them: Proceed with the next word.
155
+ wordsWidth = newWordsWidth;
156
+ spacesWidth += spaceWidth;
157
+ }
158
+ else
159
+ {
160
+ // No, this word wouldn't fit into the current line: Draw
161
+ // the current line, then start a new line with the current
162
+ // word.
163
+ builder.addLine(lineBegin, w, wordsWidth, false);
164
+
165
+ lineBegin = w;
166
+ wordsWidth = w->width;
167
+ spacesWidth = spaceWidth;
168
+ }
169
+ }
170
+
171
+ // Draw the last line as well.
172
+ if (words.empty() || lineBegin != words.end())
173
+ builder.addLine(lineBegin, words.end(), wordsWidth, true);
174
+ }
175
+
176
+ typedef boost::tokenizer<boost::char_separator<wchar_t>,
177
+ wstring::const_iterator, wstring> Tokenizer;
178
+
179
+ void processParagraph(TextBlockBuilder& builder,
180
+ const wstring& paragraph)
181
+ {
182
+ Words collectedWords;
183
+
184
+ boost::char_separator<wchar_t> sep(L" ");
185
+ Tokenizer words(paragraph, sep);
186
+ for (Tokenizer::iterator i = words.begin(); i != words.end(); ++i)
187
+ {
188
+ WordInfo newWord;
189
+ newWord.text = *i;
190
+ newWord.width = builder.textWidth(newWord.text);
191
+ collectedWords.push_back(newWord);
192
+ }
193
+
194
+ processWords(builder, collectedWords);
195
+ }
196
+
197
+ void processText(TextBlockBuilder& builder, const wstring& text)
198
+ {
199
+ vector<wstring> paragraphs;
200
+ wstring processedText = boost::replace_all_copy(text, L"\r\n", L"\n");
201
+ boost::split(paragraphs, processedText,
202
+ boost::is_any_of(L"\r\n"));
203
+ for_each(paragraphs.begin(), paragraphs.end(),
204
+ boost::bind(processParagraph, boost::ref(builder), _1));
205
+ }
206
+ }
207
+ }
208
+
209
+ Gosu::Bitmap Gosu::createText(const std::wstring& text,
210
+ const std::wstring& fontName, unsigned fontHeight, unsigned lineSpacing,
211
+ unsigned maxWidth, TextAlign align, unsigned fontFlags)
212
+ {
213
+ // Set up the builder object which will manage all the drawing and
214
+ // conversions for us.
215
+ TextBlockBuilder builder(fontName, fontHeight, fontFlags,
216
+ lineSpacing, maxWidth, align);
217
+
218
+ // Let the process* functions draw everything.
219
+ processText(builder, text);
220
+
221
+ // Done!
222
+ return builder.result();
223
+ }
@@ -0,0 +1,242 @@
1
+ #include <Gosu/Bitmap.hpp>
2
+ #include <Gosu/Text.hpp>
3
+ #include <Gosu/Utility.hpp>
4
+ #include <Gosu/IO.hpp>
5
+ #include <boost/utility.hpp>
6
+ #include <boost/cstdint.hpp>
7
+ #include <cmath>
8
+ #include <stdexcept>
9
+ #include <map>
10
+ #include <vector>
11
+ #include <ApplicationServices/ApplicationServices.h>
12
+
13
+ std::wstring Gosu::defaultFontName()
14
+ {
15
+ // OF COURSE Helvetica is better - but the dots above my capital umlauts get
16
+ // eaten when I use it with Gosu. Until this is fixed, keep Arial. (TODO)
17
+ return L"Arial";
18
+ }
19
+
20
+ namespace Gosu
21
+ {
22
+ std::vector<unsigned short> wstringToUniChars(const std::wstring& ws);
23
+ }
24
+
25
+ #include <iostream>
26
+ #include <ostream>
27
+ #include <sstream>
28
+ void throwError(OSStatus status, unsigned line)
29
+ {
30
+ std::ostringstream str;
31
+ str << "Error on line " << line << " (Code " << status << "): "
32
+ << GetMacOSStatusErrorString(status)
33
+ << " (" << GetMacOSStatusCommentString(status) << ")";
34
+ throw std::runtime_error(str.str());
35
+ }
36
+
37
+ #define checkErr(status) if (!(status)) {} else throwError(status, __LINE__)
38
+
39
+ namespace
40
+ {
41
+ class MacBitmap : boost::noncopyable
42
+ {
43
+ boost::uint32_t* buf;
44
+ unsigned width, height;
45
+ CGContextRef ctx;
46
+
47
+ public:
48
+ MacBitmap(boost::uint32_t* buf, unsigned width, unsigned height)
49
+ : buf(buf), width(width), height(height)
50
+ {
51
+ CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceUserRGB);
52
+ ctx = CGBitmapContextCreate (buf, width, height, 8, width * 4, colorSpace,
53
+ kCGImageAlphaPremultipliedLast);
54
+
55
+ CGColorSpaceRelease( colorSpace );
56
+ }
57
+
58
+ ~MacBitmap()
59
+ {
60
+ CGContextRelease(ctx);
61
+ }
62
+
63
+ CGContextRef context() const
64
+ {
65
+ return ctx;
66
+ }
67
+ };
68
+
69
+ struct CachedFontInfo
70
+ {
71
+ ATSUFontID fontId;
72
+ double heightAt1Pt;
73
+ double descentAt1Pt;
74
+ };
75
+ CachedFontInfo& getFont(const std::wstring& fontName)
76
+ {
77
+ static std::map<std::wstring, CachedFontInfo> fonts;
78
+
79
+ if (fonts.count(fontName))
80
+ return fonts[fontName];
81
+
82
+ // Get reference to font, loaded from the system or a file.
83
+ ATSFontRef atsRef;
84
+ if (fontName.find(L"/") == std::wstring::npos)
85
+ {
86
+ // System font
87
+ CFStringRef cfName = CFStringCreateWithCString(NULL, Gosu::narrow(fontName).c_str(), kCFStringEncodingASCII);
88
+ atsRef = ATSFontFindFromName(cfName, kATSOptionFlagsDefault);
89
+ if (!atsRef)
90
+ throw std::runtime_error("Cannot find font " + Gosu::narrow(fontName));
91
+ CFRelease(cfName);
92
+ }
93
+ else
94
+ {
95
+ // Filename to font
96
+ Gosu::Buffer buf;
97
+ Gosu::loadFile(buf, fontName);
98
+
99
+ ATSFontContainerRef container;
100
+ checkErr( ATSFontActivateFromMemory(buf.data(), buf.size(),
101
+ kATSFontContextLocal, kATSFontFormatUnspecified,
102
+ NULL, kATSOptionFlagsDefault, &container) );
103
+
104
+ ATSFontRef fontRefs[1024];
105
+ ItemCount fontCount;
106
+ checkErr( ATSFontFindFromContainer(container, kATSOptionFlagsDefault,
107
+ 1024, fontRefs, &fontCount) );
108
+ if (fontCount == 0)
109
+ throw std::runtime_error("No font found in " + Gosu::narrow(fontName));
110
+
111
+ atsRef = fontRefs[0];
112
+ }
113
+
114
+ // Calculate metrics (for space allocations) and create CachedFontInfo entry.
115
+ CachedFontInfo newFont;
116
+ newFont.fontId = FMGetFontFromATSFontRef(atsRef);
117
+
118
+ ATSFontMetrics metrics;
119
+ checkErr(ATSFontGetHorizontalMetrics(newFont.fontId, kATSOptionFlagsDefault, &metrics));
120
+ newFont.heightAt1Pt = metrics.ascent - metrics.descent;
121
+ newFont.descentAt1Pt = -metrics.descent;
122
+ fonts[fontName] = newFont;
123
+ return fonts[fontName];
124
+ }
125
+
126
+ class ATSULayoutAndStyle
127
+ {
128
+ ATSUStyle style;
129
+ ATSUTextLayout layout;
130
+ std::vector<UniChar> utf16; // More like UCS-2-INTERNAL.
131
+
132
+ template<typename T>
133
+ void setAttribute(ATSUAttributeTag tag, T value)
134
+ {
135
+ ByteCount size = sizeof value;
136
+ ATSUAttributeValuePtr ptr = &value;
137
+ checkErr( ATSUSetAttributes(style, 1, &tag, &size, &ptr) );
138
+ }
139
+
140
+ template<typename T>
141
+ void setLayoutControl(ATSUAttributeTag tag, T value)
142
+ {
143
+ ByteCount size = sizeof value;
144
+ ATSUAttributeValuePtr ptr = &value;
145
+ checkErr( ATSUSetLayoutControls(layout, 1, &tag, &size, &ptr) );
146
+ }
147
+
148
+ public:
149
+ ATSULayoutAndStyle(const std::wstring& text, const std::wstring& fontName, unsigned fontHeightPx, unsigned fontFlags)
150
+ {
151
+ utf16 = Gosu::wstringToUniChars(text);
152
+
153
+ checkErr( ATSUCreateStyle(&style) );
154
+
155
+ CachedFontInfo& font = getFont(fontName);
156
+
157
+ setAttribute<ATSUFontID>(kATSUFontTag, font.fontId);
158
+
159
+ setAttribute<Fixed>(kATSUSizeTag, X2Fix(fontHeightPx / font.heightAt1Pt));
160
+ if (fontFlags & Gosu::ffBold)
161
+ setAttribute<Boolean>(kATSUQDBoldfaceTag, TRUE);
162
+ if (fontFlags & Gosu::ffItalic)
163
+ setAttribute<Boolean>(kATSUQDItalicTag, TRUE);
164
+ if (fontFlags & Gosu::ffUnderline)
165
+ setAttribute<Boolean>(kATSUQDUnderlineTag, TRUE);
166
+
167
+ UniCharCount runLength = utf16.size();
168
+ checkErr( ATSUCreateTextLayoutWithTextPtr(&utf16[0], kATSUFromTextBeginning,
169
+ kATSUToTextEnd, utf16.size(), 1, &runLength, &style, &layout) );
170
+ }
171
+
172
+ ~ATSULayoutAndStyle()
173
+ {
174
+ checkErr( ATSUDisposeStyle(style) );
175
+ checkErr( ATSUDisposeTextLayout(layout) );
176
+ }
177
+
178
+ Rect textExtents() const
179
+ {
180
+ Rect rect;
181
+ checkErr( ATSUSetTransientFontMatching(layout, TRUE) );
182
+ checkErr( ATSUMeasureTextImage(layout, kATSUFromTextBeginning,
183
+ kATSUToTextEnd, X2Fix(0), X2Fix(0), &rect) );
184
+ return rect;
185
+ }
186
+
187
+ void drawToContext(Fixed x, Fixed y, CGContextRef context)
188
+ {
189
+ // Always draw in black - recoloring to white happens in drawText itself.
190
+ // Reason: Text drawn using fallback fonts seems to always be black anyway :(
191
+
192
+ RGBColor color = { 0, 0, 0 };
193
+ setAttribute<RGBColor>(kATSUColorTag, color);
194
+ setLayoutControl<CGContextRef>(kATSUCGContextTag, context);
195
+ checkErr( ATSUSetTransientFontMatching(layout, TRUE) );
196
+ checkErr( ATSUDrawText(layout, kATSUFromTextBeginning, kATSUToTextEnd, x, y) );
197
+ }
198
+ };
199
+ }
200
+
201
+ unsigned Gosu::textWidth(const std::wstring& text,
202
+ const std::wstring& fontName, unsigned fontHeight, unsigned fontFlags)
203
+ {
204
+ // TODO: special case :///7
205
+ if (text == L" ")
206
+ return fontHeight / 3;
207
+
208
+ ATSULayoutAndStyle atlas(text, fontName, fontHeight, fontFlags);
209
+ Rect rect = atlas.textExtents();
210
+ return rect.right + 1 - rect.left;
211
+ }
212
+
213
+ void Gosu::drawText(Bitmap& bitmap, const std::wstring& text, int x, int y,
214
+ Color c, const std::wstring& fontName, unsigned fontHeight,
215
+ unsigned fontFlags)
216
+ {
217
+ CachedFontInfo& font = getFont(fontName);
218
+
219
+ ATSULayoutAndStyle atlas(text, fontName, fontHeight, fontFlags);
220
+ Rect rect = atlas.textExtents();
221
+ unsigned width = rect.right + 1 - rect.left;
222
+ std::vector<boost::uint32_t> buf(width * fontHeight);
223
+ {
224
+ MacBitmap helper(&buf[0], width, fontHeight);
225
+ atlas.drawToContext(X2Fix(-rect.left), X2Fix(fontHeight / font.heightAt1Pt * font.descentAt1Pt),
226
+ helper.context());
227
+ }
228
+
229
+ Bitmap wholeText;
230
+ wholeText.resize(width, fontHeight);
231
+ for (unsigned relY = 0; relY < fontHeight; ++relY)
232
+ for (unsigned relX = 0; relX < width; ++relX)
233
+ {
234
+ #ifdef __BIG_ENDIAN__
235
+ Color::Channel alpha = buf[relY * width + relX];
236
+ #else
237
+ Color::Channel alpha = Color(buf[relY * width + relX]).alpha();
238
+ #endif
239
+ wholeText.setPixel(relX, relY, Color(alpha, 0xff, 0xff, 0xff));
240
+ }
241
+ bitmap.insert(wholeText, x, y);
242
+ }