gosu 0.7.10.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ }