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.
- data/COPYING.txt +29 -0
- data/Gosu/Async.hpp +48 -0
- data/Gosu/Audio.hpp +145 -0
- data/Gosu/AutoLink.hpp +16 -0
- data/Gosu/Bitmap.hpp +85 -0
- data/Gosu/ButtonsMac.hpp +114 -0
- data/Gosu/ButtonsWin.hpp +111 -0
- data/Gosu/ButtonsX.hpp +115 -0
- data/Gosu/Color.hpp +172 -0
- data/Gosu/Directories.hpp +36 -0
- data/Gosu/Font.hpp +59 -0
- data/Gosu/Fwd.hpp +31 -0
- data/Gosu/Gosu.hpp +26 -0
- data/Gosu/Graphics.hpp +86 -0
- data/Gosu/GraphicsBase.hpp +45 -0
- data/Gosu/IO.hpp +255 -0
- data/Gosu/Image.hpp +148 -0
- data/Gosu/ImageData.hpp +45 -0
- data/Gosu/Input.hpp +116 -0
- data/Gosu/Math.hpp +95 -0
- data/Gosu/Platform.hpp +61 -0
- data/Gosu/RotFlip.hpp +116 -0
- data/Gosu/Sockets.hpp +129 -0
- data/Gosu/Text.hpp +47 -0
- data/Gosu/TextInput.hpp +57 -0
- data/Gosu/Timing.hpp +16 -0
- data/Gosu/Utility.hpp +24 -0
- data/Gosu/WinUtility.hpp +76 -0
- data/Gosu/Window.hpp +84 -0
- data/GosuImpl/Async.cpp +37 -0
- data/GosuImpl/AudioFmod.cpp +417 -0
- data/GosuImpl/AudioSDL.cpp +255 -0
- data/GosuImpl/DirectoriesMac.mm +38 -0
- data/GosuImpl/DirectoriesUnix.cpp +48 -0
- data/GosuImpl/DirectoriesWin.cpp +42 -0
- data/GosuImpl/FileUnix.cpp +100 -0
- data/GosuImpl/FileWin.cpp +83 -0
- data/GosuImpl/Graphics/Bitmap.cpp +116 -0
- data/GosuImpl/Graphics/BitmapBMP.cpp +232 -0
- data/GosuImpl/Graphics/BitmapColorKey.cpp +39 -0
- data/GosuImpl/Graphics/BitmapPNG.cpp +276 -0
- data/GosuImpl/Graphics/BitmapUtils.cpp +67 -0
- data/GosuImpl/Graphics/BlockAllocator.cpp +127 -0
- data/GosuImpl/Graphics/BlockAllocator.hpp +34 -0
- data/GosuImpl/Graphics/Color.cpp +126 -0
- data/GosuImpl/Graphics/Common.hpp +21 -0
- data/GosuImpl/Graphics/DrawOp.hpp +154 -0
- data/GosuImpl/Graphics/Font.cpp +110 -0
- data/GosuImpl/Graphics/Graphics.cpp +295 -0
- data/GosuImpl/Graphics/Image.cpp +159 -0
- data/GosuImpl/Graphics/LargeImageData.cpp +115 -0
- data/GosuImpl/Graphics/LargeImageData.hpp +37 -0
- data/GosuImpl/Graphics/RotFlip.cpp +184 -0
- data/GosuImpl/Graphics/TexChunk.cpp +77 -0
- data/GosuImpl/Graphics/TexChunk.hpp +40 -0
- data/GosuImpl/Graphics/Text.cpp +223 -0
- data/GosuImpl/Graphics/TextMac.cpp +242 -0
- data/GosuImpl/Graphics/TextPangoFT.cpp +186 -0
- data/GosuImpl/Graphics/TextWin.cpp +172 -0
- data/GosuImpl/Graphics/Texture.cpp +104 -0
- data/GosuImpl/Graphics/Texture.hpp +34 -0
- data/GosuImpl/IO.cpp +48 -0
- data/GosuImpl/InputMac.mm +677 -0
- data/GosuImpl/InputWin.cpp +444 -0
- data/GosuImpl/InputX.cpp +158 -0
- data/GosuImpl/MacUtility.hpp +48 -0
- data/GosuImpl/Math.cpp +49 -0
- data/GosuImpl/RubyGosu.swg +474 -0
- data/GosuImpl/RubyGosuStub.mm +17 -0
- data/GosuImpl/RubyGosu_DllMain.cxx +30 -0
- data/GosuImpl/RubyGosu_wrap.cxx +8521 -0
- data/GosuImpl/RubyGosu_wrap.h +31 -0
- data/GosuImpl/Sockets/CommSocket.cpp +304 -0
- data/GosuImpl/Sockets/ListenerSocket.cpp +60 -0
- data/GosuImpl/Sockets/MessageSocket.cpp +136 -0
- data/GosuImpl/Sockets/Socket.cpp +145 -0
- data/GosuImpl/Sockets/Sockets.hpp +66 -0
- data/GosuImpl/TextInputMac.mm +207 -0
- data/GosuImpl/TextInputWin.cpp +197 -0
- data/GosuImpl/TextInputX.cpp +201 -0
- data/GosuImpl/TextTTFWin.cpp +247 -0
- data/GosuImpl/TimingUnix.cpp +17 -0
- data/GosuImpl/TimingWin.cpp +28 -0
- data/GosuImpl/Utility.cpp +140 -0
- data/GosuImpl/WinMain.cpp +69 -0
- data/GosuImpl/WinUtility.cpp +137 -0
- data/GosuImpl/WindowMac.mm +466 -0
- data/GosuImpl/WindowWin.cpp +447 -0
- data/GosuImpl/WindowX.cpp +392 -0
- data/GosuImpl/X11vroot.h +118 -0
- data/README.txt +13 -0
- data/Rakefile +178 -0
- data/examples/ChipmunkIntegration.rb +275 -0
- data/examples/CptnRuby.rb +231 -0
- data/examples/MoreChipmunkAndRMagick.rb +155 -0
- data/examples/OpenGLIntegration.rb +232 -0
- data/examples/RMagickIntegration.rb +449 -0
- data/examples/TextInput.cpp +170 -0
- data/examples/TextInput.rb +139 -0
- data/examples/Tutorial.cpp +215 -0
- data/examples/Tutorial.rb +137 -0
- data/examples/media/Beep.wav +0 -0
- data/examples/media/CptnRuby Gem.png +0 -0
- data/examples/media/CptnRuby Map.txt +25 -0
- data/examples/media/CptnRuby Tileset.png +0 -0
- data/examples/media/CptnRuby.png +0 -0
- data/examples/media/Cursor.png +0 -0
- data/examples/media/Earth.png +0 -0
- data/examples/media/Explosion.wav +0 -0
- data/examples/media/LargeStar.png +0 -0
- data/examples/media/Sky.jpg +0 -0
- data/examples/media/Smoke.png +0 -0
- data/examples/media/Soldier.png +0 -0
- data/examples/media/Space.png +0 -0
- data/examples/media/Star.png +0 -0
- data/examples/media/Starfighter.bmp +0 -0
- data/linux/Makefile.in +98 -0
- data/linux/configure +5658 -0
- data/linux/configure.ac +126 -0
- data/linux/extconf.rb +11 -0
- data/mac/English.lproj/InfoPlist.strings +0 -0
- data/mac/Gosu-Info.plist +26 -0
- data/mac/Gosu.xcodeproj/project.pbxproj +1194 -0
- data/mac/RubyGosu Template-Info.plist +26 -0
- data/mac/libboost_thread_1_34_1_universal.a +0 -0
- data/mac/libboost_thread_d_1_34_1_universal.a +0 -0
- data/mac/libfmod_universal.a +0 -0
- data/mac/libpng_universal.a +0 -0
- data/mac/libz_universal.a +0 -0
- data/reference/Async_8hpp-source.html +70 -0
- data/reference/Audio_8hpp-source.html +114 -0
- data/reference/Audio_8hpp.html +50 -0
- data/reference/AutoLink_8hpp-source.html +38 -0
- data/reference/AutoLink_8hpp.html +34 -0
- data/reference/Bitmap_8hpp-source.html +85 -0
- data/reference/Bitmap_8hpp.html +58 -0
- data/reference/ButtonsMac_8hpp-source.html +133 -0
- data/reference/ButtonsWin_8hpp-source.html +133 -0
- data/reference/ButtonsX_8hpp-source.html +134 -0
- data/reference/Color_8hpp-source.html +169 -0
- data/reference/Color_8hpp.html +85 -0
- data/reference/Directories_8hpp-source.html +42 -0
- data/reference/Directories_8hpp.html +46 -0
- data/reference/Font_8hpp-source.html +65 -0
- data/reference/Font_8hpp.html +41 -0
- data/reference/Fwd_8hpp-source.html +52 -0
- data/reference/Fwd_8hpp.html +37 -0
- data/reference/Gosu_8hpp-source.html +48 -0
- data/reference/Gosu_8hpp.html +34 -0
- data/reference/GraphicsBase_8hpp-source.html +57 -0
- data/reference/GraphicsBase_8hpp.html +56 -0
- data/reference/Graphics_8hpp-source.html +96 -0
- data/reference/Graphics_8hpp.html +53 -0
- data/reference/IO_8hpp-source.html +255 -0
- data/reference/IO_8hpp.html +74 -0
- data/reference/ImageData_8hpp-source.html +62 -0
- data/reference/ImageData_8hpp.html +43 -0
- data/reference/Image_8hpp-source.html +126 -0
- data/reference/Image_8hpp.html +48 -0
- data/reference/Input_8hpp-source.html +118 -0
- data/reference/Input_8hpp.html +50 -0
- data/reference/Math_8hpp-source.html +92 -0
- data/reference/Math_8hpp.html +74 -0
- data/reference/Platform_8hpp-source.html +83 -0
- data/reference/Platform_8hpp.html +73 -0
- data/reference/RotFlip_8hpp-source.html +138 -0
- data/reference/RotFlip_8hpp.html +77 -0
- data/reference/Sockets_8hpp-source.html +130 -0
- data/reference/Sockets_8hpp.html +66 -0
- data/reference/TextInput_8hpp-source.html +64 -0
- data/reference/TextInput_8hpp.html +41 -0
- data/reference/Text_8hpp-source.html +51 -0
- data/reference/Text_8hpp.html +46 -0
- data/reference/Timing_8hpp-source.html +36 -0
- data/reference/Timing_8hpp.html +42 -0
- data/reference/Utility_8hpp-source.html +44 -0
- data/reference/Utility_8hpp.html +48 -0
- data/reference/WinUtility_8hpp-source.html +79 -0
- data/reference/WinUtility_8hpp.html +64 -0
- data/reference/Window_8hpp-source.html +91 -0
- data/reference/Window_8hpp.html +41 -0
- data/reference/annotated.html +51 -0
- data/reference/classGosu_1_1Audio-members.html +34 -0
- data/reference/classGosu_1_1Audio.html +46 -0
- data/reference/classGosu_1_1Bitmap-members.html +44 -0
- data/reference/classGosu_1_1Bitmap.html +263 -0
- data/reference/classGosu_1_1Buffer-members.html +44 -0
- data/reference/classGosu_1_1Buffer.html +78 -0
- data/reference/classGosu_1_1Buffer.png +0 -0
- data/reference/classGosu_1_1Button-members.html +36 -0
- data/reference/classGosu_1_1Button.html +143 -0
- data/reference/classGosu_1_1Color-members.html +56 -0
- data/reference/classGosu_1_1Color.html +387 -0
- data/reference/classGosu_1_1File-members.html +41 -0
- data/reference/classGosu_1_1File.html +69 -0
- data/reference/classGosu_1_1File.png +0 -0
- data/reference/classGosu_1_1Font-members.html +39 -0
- data/reference/classGosu_1_1Font.html +309 -0
- data/reference/classGosu_1_1Graphics-members.html +50 -0
- data/reference/classGosu_1_1Graphics.html +234 -0
- data/reference/classGosu_1_1Image-members.html +45 -0
- data/reference/classGosu_1_1Image.html +518 -0
- data/reference/classGosu_1_1ImageData-members.html +37 -0
- data/reference/classGosu_1_1ImageData.html +60 -0
- data/reference/classGosu_1_1Input-members.html +44 -0
- data/reference/classGosu_1_1Input.html +223 -0
- data/reference/classGosu_1_1MessageSocket-members.html +40 -0
- data/reference/classGosu_1_1MessageSocket.html +233 -0
- data/reference/classGosu_1_1Resource-members.html +39 -0
- data/reference/classGosu_1_1Resource.html +116 -0
- data/reference/classGosu_1_1Resource.png +0 -0
- data/reference/classGosu_1_1Sample-members.html +37 -0
- data/reference/classGosu_1_1Sample.html +200 -0
- data/reference/classGosu_1_1SampleInstance-members.html +38 -0
- data/reference/classGosu_1_1SampleInstance.html +169 -0
- data/reference/classGosu_1_1Song-members.html +43 -0
- data/reference/classGosu_1_1Song.html +260 -0
- data/reference/classGosu_1_1TextInput-members.html +38 -0
- data/reference/classGosu_1_1TextInput.html +121 -0
- data/reference/classGosu_1_1Window-members.html +50 -0
- data/reference/classGosu_1_1Window.html +271 -0
- data/reference/doxyfile +233 -0
- data/reference/doxygen.css +433 -0
- data/reference/doxygen.png +0 -0
- data/reference/files.html +54 -0
- data/reference/functions.html +236 -0
- data/reference/functions_enum.html +45 -0
- data/reference/functions_func.html +227 -0
- data/reference/functions_vars.html +47 -0
- data/reference/hierarchy.html +53 -0
- data/reference/index.html +26 -0
- data/reference/namespaceGosu.html +2890 -0
- data/reference/namespaceGosu_1_1Colors.html +70 -0
- data/reference/namespaceGosu_1_1Win.html +275 -0
- data/reference/namespacemembers.html +216 -0
- data/reference/namespacemembers_enum.html +52 -0
- data/reference/namespacemembers_eval.html +54 -0
- data/reference/namespacemembers_func.html +185 -0
- data/reference/namespacemembers_type.html +46 -0
- data/reference/namespacemembers_vars.html +46 -0
- data/reference/namespaces.html +35 -0
- data/reference/tab_b.gif +0 -0
- data/reference/tab_l.gif +0 -0
- data/reference/tab_r.gif +0 -0
- data/reference/tabs.css +102 -0
- data/windows/Gosu.sln +29 -0
- data/windows/Gosu.vcproj +553 -0
- data/windows/RubyGosu.vcproj +138 -0
- 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
|
+
}
|