gosu 0.10.9.pre1 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gosu/Audio.hpp +35 -66
- data/Gosu/AutoLink.hpp +14 -16
- data/Gosu/Bitmap.hpp +50 -37
- data/Gosu/Buttons.hpp +246 -265
- data/Gosu/Color.hpp +32 -76
- data/Gosu/Directories.hpp +14 -17
- data/Gosu/Font.hpp +28 -34
- data/Gosu/Fwd.hpp +27 -31
- data/Gosu/Gosu.hpp +2 -5
- data/Gosu/Graphics.hpp +31 -48
- data/Gosu/GraphicsBase.hpp +27 -58
- data/Gosu/IO.hpp +44 -56
- data/Gosu/Image.hpp +29 -73
- data/Gosu/ImageData.hpp +13 -17
- data/Gosu/Input.hpp +42 -57
- data/Gosu/Inspection.hpp +2 -6
- data/Gosu/Math.hpp +32 -38
- data/Gosu/Platform.hpp +10 -29
- data/Gosu/Text.hpp +30 -39
- data/Gosu/TextInput.hpp +29 -36
- data/Gosu/Timing.hpp +14 -16
- data/Gosu/Utility.hpp +10 -15
- data/Gosu/Version.hpp +13 -14
- data/Gosu/Window.hpp +53 -68
- data/README.md +23 -11
- data/ext/gosu/extconf.rb +31 -81
- data/lib/gosu/patches.rb +35 -19
- data/lib/gosu/run.rb +13 -4
- data/rdoc/gosu.rb +24 -20
- data/src/ALChannelManagement.hpp +119 -0
- data/src/{Audio/Audio.cpp → Audio.cpp} +177 -211
- data/src/AudioFile.hpp +57 -0
- data/src/AudioToolboxFile.hpp +214 -0
- data/src/Bitmap.cpp +159 -0
- data/src/BitmapIO.cpp +141 -0
- data/src/BlockAllocator.cpp +133 -0
- data/src/{Graphics/BlockAllocator.hpp → BlockAllocator.hpp} +34 -35
- data/src/ClipRectStack.hpp +87 -0
- data/src/{Graphics/Color.cpp → Color.cpp} +30 -28
- data/src/DirectoriesApple.cpp +68 -0
- data/src/DirectoriesUnix.cpp +20 -18
- data/src/DirectoriesWin.cpp +40 -41
- data/src/DrawOp.hpp +168 -0
- data/src/DrawOpQueue.hpp +190 -0
- data/src/FileUnix.cpp +40 -46
- data/src/FileWin.cpp +42 -38
- data/src/Font.cpp +165 -0
- data/src/{Text/FormattedString.hpp → FormattedString.hpp} +114 -114
- data/src/GosuAppDelegate.cpp +30 -0
- data/src/{UIKit/GosuAppDelegate.h → GosuAppDelegate.h} +0 -0
- data/src/{UIKit/GosuGLView.mm → GosuGLView.cpp} +22 -17
- data/src/{UIKit/GosuGLView.h → GosuGLView.h} +0 -0
- data/src/GosuViewController.cpp +231 -0
- data/src/{UIKit/GosuViewController.h → GosuViewController.h} +0 -0
- data/src/Graphics.cpp +464 -0
- data/src/{Graphics/Common.hpp → GraphicsImpl.hpp} +29 -32
- data/src/IO.cpp +17 -16
- data/src/Iconv.hpp +13 -22
- data/src/Image.cpp +142 -0
- data/src/Input.cpp +459 -0
- data/src/InputUIKit.cpp +197 -0
- data/src/Inspection.cpp +4 -5
- data/src/LargeImageData.cpp +151 -0
- data/src/LargeImageData.hpp +43 -0
- data/src/{Graphics/Macro.cpp → Macro.cpp} +77 -78
- data/src/Macro.hpp +30 -0
- data/src/Math.cpp +17 -29
- data/src/{Audio/OggFile.hpp → OggFile.hpp} +19 -24
- data/src/RenderState.hpp +205 -0
- data/src/Resolution.cpp +86 -0
- data/src/ResolutionApple.cpp +25 -0
- data/{ext/gosu/gosu_wrap.cxx → src/RubyGosu.cxx} +2256 -1707
- data/{ext/gosu/gosu_wrap.h → src/RubyGosu.h} +9 -9
- data/src/{Audio/SndFile.hpp → SndFile.hpp} +54 -43
- data/src/TexChunk.cpp +117 -0
- data/src/{Graphics/TexChunk.hpp → TexChunk.hpp} +13 -18
- data/src/Text.cpp +371 -0
- data/src/TextApple.cpp +209 -0
- data/src/TextInput.cpp +278 -0
- data/src/TextTTFWin.cpp +251 -0
- data/src/{Text/TextUnix.cpp → TextUnix.cpp} +96 -92
- data/src/TextWin.cpp +194 -0
- data/src/{Graphics/Texture.cpp → Texture.cpp} +35 -38
- data/src/{Graphics/Texture.hpp → Texture.hpp} +9 -13
- data/src/TimingApple.cpp +11 -7
- data/src/TimingUnix.cpp +13 -7
- data/src/TimingWin.cpp +6 -1
- data/src/{Graphics/Transform.cpp → Transform.cpp} +17 -12
- data/src/{Graphics/TransformStack.hpp → TransformStack.hpp} +24 -25
- data/src/Utility.cpp +29 -70
- data/src/UtilityApple.cpp +52 -0
- data/src/UtilityWin.cpp +7 -4
- data/src/Version.cpp +22 -0
- data/src/WinMain.cpp +30 -33
- data/src/WinUtility.cpp +24 -22
- data/src/WinUtility.hpp +11 -20
- data/src/Window.cpp +142 -112
- data/src/WindowUIKit.cpp +155 -0
- data/src/stb_image.h +384 -173
- data/src/stb_vorbis.c +20 -18
- metadata +60 -62
- data/Gosu/TR1.hpp +0 -56
- data/src/AppleUtility.hpp +0 -66
- data/src/Audio/ALChannelManagement.hpp +0 -114
- data/src/Audio/Audio.mm +0 -1
- data/src/Audio/AudioFile.hpp +0 -53
- data/src/Audio/AudioToolboxFile.hpp +0 -207
- data/src/Bitmap/Bitmap.cpp +0 -183
- data/src/Bitmap/BitmapIO.cpp +0 -176
- data/src/DirectoriesApple.mm +0 -71
- data/src/Graphics/BlockAllocator.cpp +0 -142
- data/src/Graphics/ClipRectStack.hpp +0 -93
- data/src/Graphics/DrawOp.hpp +0 -175
- data/src/Graphics/DrawOpQueue.hpp +0 -188
- data/src/Graphics/Graphics.cpp +0 -478
- data/src/Graphics/Image.cpp +0 -193
- data/src/Graphics/LargeImageData.cpp +0 -133
- data/src/Graphics/LargeImageData.hpp +0 -46
- data/src/Graphics/Macro.hpp +0 -36
- data/src/Graphics/RenderState.hpp +0 -211
- data/src/Graphics/Resolution.cpp +0 -91
- data/src/Graphics/ResolutionApple.mm +0 -19
- data/src/Graphics/TexChunk.cpp +0 -112
- data/src/Input/Input.cpp +0 -463
- data/src/Input/InputUIKit.mm +0 -190
- data/src/Input/TextInput.cpp +0 -261
- data/src/Text/Font.cpp +0 -175
- data/src/Text/Text.cpp +0 -391
- data/src/Text/TextApple.mm +0 -227
- data/src/Text/TextTTFWin.cpp +0 -249
- data/src/Text/TextWin.cpp +0 -186
- data/src/UIKit/GosuAppDelegate.mm +0 -24
- data/src/UIKit/GosuViewController.mm +0 -211
- data/src/UtilityApple.mm +0 -63
- data/src/WindowUIKit.mm +0 -139
data/src/FileUnix.cpp
CHANGED
@@ -1,100 +1,94 @@
|
|
1
|
+
#include <Gosu/Platform.hpp>
|
2
|
+
#if !defined(GOSU_IS_WIN)
|
3
|
+
|
1
4
|
#include <Gosu/IO.hpp>
|
2
5
|
#include <Gosu/Utility.hpp>
|
3
|
-
#include <stdexcept>
|
4
6
|
#include <cstring>
|
5
7
|
#include <fcntl.h>
|
6
|
-
#include <
|
7
|
-
#include <sys/types.h>
|
8
|
+
#include <stdexcept>
|
8
9
|
#include <sys/mman.h>
|
10
|
+
#include <sys/types.h>
|
11
|
+
#include <unistd.h>
|
9
12
|
|
10
13
|
#ifdef HAVE_SYS_STAT_H
|
11
14
|
#include <sys/stat.h>
|
12
15
|
#endif
|
13
16
|
|
14
|
-
namespace
|
15
|
-
{
|
16
|
-
// According to my man page, Unix folks just don't trust the 0, it's got to be a crippled -1.
|
17
|
-
void* const noMapping = reinterpret_cast<void*>(-1);
|
18
|
-
}
|
19
|
-
|
20
17
|
struct Gosu::File::Impl
|
21
18
|
{
|
22
|
-
int fd;
|
23
|
-
void* mapping;
|
19
|
+
int fd = -1;
|
20
|
+
void* mapping = MAP_FAILED;
|
24
21
|
|
25
|
-
Impl() : fd(-1), mapping(noMapping) {}
|
26
22
|
~Impl()
|
27
23
|
{
|
28
|
-
if (fd
|
24
|
+
if (fd >= 0) {
|
29
25
|
close(fd);
|
26
|
+
}
|
30
27
|
}
|
31
28
|
};
|
32
29
|
|
33
|
-
Gosu::File::File(const std::
|
30
|
+
Gosu::File::File(const std::string& filename, FileMode mode)
|
34
31
|
: pimpl(new Impl)
|
35
32
|
{
|
36
33
|
int flags;
|
37
34
|
|
38
|
-
switch (mode)
|
39
|
-
|
40
|
-
case fmRead:
|
35
|
+
switch (mode) {
|
36
|
+
case FM_READ:
|
41
37
|
flags = O_RDONLY;
|
42
38
|
break;
|
43
|
-
case
|
39
|
+
case FM_REPLACE:
|
44
40
|
flags = O_RDWR | O_TRUNC | O_CREAT;
|
45
41
|
break;
|
46
|
-
case
|
42
|
+
case FM_ALTER:
|
47
43
|
flags = O_RDWR | O_CREAT;
|
48
44
|
break;
|
49
45
|
}
|
50
46
|
|
51
47
|
// TODO: Locking flags?
|
52
48
|
|
53
|
-
pimpl->fd = open(
|
54
|
-
|
55
|
-
|
56
|
-
|
49
|
+
pimpl->fd = open(filename.c_str(), flags, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
|
50
|
+
if (pimpl->fd < 0) {
|
51
|
+
throw std::runtime_error("Cannot open file " + filename);
|
52
|
+
}
|
57
53
|
|
58
|
-
if (mode ==
|
59
|
-
pimpl->mapping = mmap(
|
54
|
+
if (mode == FM_READ && size() > 0) {
|
55
|
+
pimpl->mapping = mmap(nullptr, size(), PROT_READ, 0, pimpl->fd, 0);
|
56
|
+
}
|
60
57
|
}
|
61
58
|
|
62
59
|
Gosu::File::~File()
|
63
60
|
{
|
64
|
-
if (pimpl->mapping !=
|
61
|
+
if (pimpl->mapping != MAP_FAILED) {
|
65
62
|
munmap(pimpl->mapping, size());
|
63
|
+
}
|
66
64
|
}
|
67
65
|
|
68
66
|
std::size_t Gosu::File::size() const
|
69
67
|
{
|
70
|
-
//
|
68
|
+
// TODO: Error checking?
|
71
69
|
return lseek(pimpl->fd, 0, SEEK_END);
|
72
70
|
}
|
73
71
|
|
74
|
-
void Gosu::File::resize(std::size_t
|
75
|
-
{
|
76
|
-
ftruncate(pimpl->fd, newSize);
|
77
|
-
}
|
72
|
+
void Gosu::File::resize(std::size_t new_size) { ftruncate(pimpl->fd, new_size); }
|
78
73
|
|
79
|
-
void Gosu::File::read(std::size_t offset, std::size_t length,
|
80
|
-
void* destBuffer) const
|
74
|
+
void Gosu::File::read(std::size_t offset, std::size_t length, void* dest_buffer) const
|
81
75
|
{
|
82
|
-
// TODO:
|
83
|
-
if (pimpl->mapping !=
|
84
|
-
|
85
|
-
|
86
|
-
|
76
|
+
// TODO: Bounds checks?
|
77
|
+
if (pimpl->mapping != MAP_FAILED) {
|
78
|
+
std::memcpy(dest_buffer, static_cast<const char*>(pimpl->mapping) + offset, length);
|
79
|
+
}
|
80
|
+
else {
|
81
|
+
// TODO: Error checking?
|
82
|
+
lseek(pimpl->fd, offset, SEEK_SET);
|
83
|
+
::read(pimpl->fd, dest_buffer, length);
|
87
84
|
}
|
88
|
-
|
89
|
-
// IMPR: Error checking?
|
90
|
-
lseek(pimpl->fd, offset, SEEK_SET);
|
91
|
-
::read(pimpl->fd, destBuffer, length);
|
92
85
|
}
|
93
86
|
|
94
|
-
void Gosu::File::write(std::size_t offset, std::size_t length,
|
95
|
-
const void* sourceBuffer)
|
87
|
+
void Gosu::File::write(std::size_t offset, std::size_t length, const void* source_buffer)
|
96
88
|
{
|
97
|
-
//
|
89
|
+
// TODO: Error checking?
|
98
90
|
lseek(pimpl->fd, offset, SEEK_SET);
|
99
|
-
::write(pimpl->fd,
|
91
|
+
::write(pimpl->fd, source_buffer, length);
|
100
92
|
}
|
93
|
+
|
94
|
+
#endif
|
data/src/FileWin.cpp
CHANGED
@@ -1,51 +1,52 @@
|
|
1
|
+
#include <Gosu/Platform.hpp>
|
2
|
+
#if defined(GOSU_IS_WIN)
|
3
|
+
|
4
|
+
#include "WinUtility.hpp"
|
1
5
|
#include <Gosu/IO.hpp>
|
2
6
|
#include <Gosu/Utility.hpp>
|
3
|
-
#include "WinUtility.hpp"
|
4
7
|
#include <windows.h>
|
5
8
|
|
6
|
-
//
|
9
|
+
// TODO: Error checking
|
7
10
|
|
8
11
|
struct Gosu::File::Impl
|
9
12
|
{
|
10
|
-
HANDLE handle;
|
11
|
-
|
12
|
-
Impl()
|
13
|
-
: handle(INVALID_HANDLE_VALUE)
|
14
|
-
{
|
15
|
-
}
|
13
|
+
HANDLE handle = INVALID_HANDLE_VALUE;
|
16
14
|
|
17
15
|
~Impl()
|
18
16
|
{
|
19
|
-
if (handle != INVALID_HANDLE_VALUE)
|
20
|
-
|
17
|
+
if (handle != INVALID_HANDLE_VALUE) {
|
18
|
+
CloseHandle(handle);
|
19
|
+
}
|
21
20
|
}
|
22
21
|
};
|
23
22
|
|
24
|
-
Gosu::File::File(const std::
|
23
|
+
Gosu::File::File(const std::string& filename, FileMode mode)
|
25
24
|
: pimpl(new Impl)
|
26
25
|
{
|
27
26
|
DWORD access;
|
28
|
-
switch (mode)
|
29
|
-
|
30
|
-
case fmRead:
|
27
|
+
switch (mode) {
|
28
|
+
case FM_READ:
|
31
29
|
access = GENERIC_READ;
|
32
30
|
break;
|
33
|
-
case
|
31
|
+
case FM_REPLACE:
|
34
32
|
access = GENERIC_WRITE;
|
35
33
|
break;
|
36
|
-
case
|
34
|
+
case FM_ALTER:
|
37
35
|
access = GENERIC_READ | GENERIC_WRITE;
|
38
36
|
break;
|
39
37
|
}
|
40
|
-
DWORD
|
41
|
-
DWORD
|
38
|
+
DWORD share_mode = FILE_SHARE_READ;
|
39
|
+
DWORD creation_disp = (mode == FM_READ) ? OPEN_EXISTING : OPEN_ALWAYS;
|
42
40
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
41
|
+
std::wstring wfilename = utf8_to_wstring(filename);
|
42
|
+
pimpl->handle = CreateFileW(wfilename.c_str(), access, share_mode, 0, creation_disp,
|
43
|
+
FILE_ATTRIBUTE_NORMAL, 0);
|
44
|
+
if (pimpl->handle == INVALID_HANDLE_VALUE) {
|
45
|
+
throw_last_winapi_error("opening " + filename);
|
46
|
+
}
|
47
|
+
if (mode == FM_REPLACE) {
|
48
48
|
resize(0);
|
49
|
+
}
|
49
50
|
}
|
50
51
|
|
51
52
|
Gosu::File::~File()
|
@@ -54,30 +55,33 @@ Gosu::File::~File()
|
|
54
55
|
|
55
56
|
std::size_t Gosu::File::size() const
|
56
57
|
{
|
57
|
-
return
|
58
|
+
return GetFileSize(pimpl->handle, 0);
|
58
59
|
}
|
59
60
|
|
60
|
-
void Gosu::File::resize(std::size_t
|
61
|
+
void Gosu::File::resize(std::size_t new_size)
|
61
62
|
{
|
62
|
-
if (
|
63
|
-
|
64
|
-
|
63
|
+
if (SetFilePointer(pimpl->handle, new_size, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
|
64
|
+
throw_last_winapi_error("setting the file pointer");
|
65
|
+
}
|
66
|
+
winapi_check(SetEndOfFile(pimpl->handle), "resizing a file");
|
65
67
|
}
|
66
68
|
|
67
|
-
void Gosu::File::read(std::size_t offset, std::size_t length,
|
68
|
-
void* destBuffer) const
|
69
|
+
void Gosu::File::read(std::size_t offset, std::size_t length, void* dest_buffer) const
|
69
70
|
{
|
70
|
-
if (
|
71
|
-
|
71
|
+
if (SetFilePointer(pimpl->handle, offset, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
|
72
|
+
throw_last_winapi_error("setting the file pointer");
|
73
|
+
}
|
72
74
|
DWORD dummy;
|
73
|
-
|
75
|
+
winapi_check(ReadFile(pimpl->handle, dest_buffer, length, &dummy, 0));
|
74
76
|
}
|
75
77
|
|
76
|
-
void Gosu::File::write(std::size_t offset, std::size_t length,
|
77
|
-
const void* sourceBuffer)
|
78
|
+
void Gosu::File::write(std::size_t offset, std::size_t length, const void* source_buffer)
|
78
79
|
{
|
79
|
-
if (
|
80
|
-
|
80
|
+
if (SetFilePointer(pimpl->handle, offset, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
|
81
|
+
throw_last_winapi_error("setting the file pointer");
|
82
|
+
}
|
81
83
|
DWORD dummy;
|
82
|
-
|
84
|
+
winapi_check(WriteFile(pimpl->handle, source_buffer, length, &dummy, 0));
|
83
85
|
}
|
86
|
+
|
87
|
+
#endif
|
data/src/Font.cpp
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
#include "FormattedString.hpp"
|
2
|
+
#include "GraphicsImpl.hpp"
|
3
|
+
#include <Gosu/Font.hpp>
|
4
|
+
#include <Gosu/Graphics.hpp>
|
5
|
+
#include <Gosu/Image.hpp>
|
6
|
+
#include <Gosu/Math.hpp>
|
7
|
+
#include <Gosu/Text.hpp>
|
8
|
+
#include <array>
|
9
|
+
#include <cassert>
|
10
|
+
#include <map>
|
11
|
+
using namespace std;
|
12
|
+
|
13
|
+
struct Gosu::Font::Impl
|
14
|
+
{
|
15
|
+
string name;
|
16
|
+
unsigned height, flags;
|
17
|
+
|
18
|
+
// Unicode planes of 2^16 characters each. On Windows, where wchar_t is only 16 bits wide, only
|
19
|
+
// the first plane will ever be touched.
|
20
|
+
struct CharInfo
|
21
|
+
{
|
22
|
+
std::unique_ptr<Image> image;
|
23
|
+
double factor;
|
24
|
+
};
|
25
|
+
typedef array<CharInfo, 65536> Plane;
|
26
|
+
std::unique_ptr<Plane> planes[16][FF_COMBINATIONS];
|
27
|
+
|
28
|
+
map<string, shared_ptr<Image>> entity_cache;
|
29
|
+
|
30
|
+
CharInfo& char_info(wchar_t wc, unsigned flags)
|
31
|
+
{
|
32
|
+
size_t plane_index = wc / 65536;
|
33
|
+
size_t char_index = wc % 65536;
|
34
|
+
|
35
|
+
if (plane_index >= 16) throw invalid_argument("Unicode plane out of reach");
|
36
|
+
if (flags >= FF_COMBINATIONS) throw invalid_argument("Font flags out of range");
|
37
|
+
|
38
|
+
if (!planes[plane_index][flags].get()) {
|
39
|
+
planes[plane_index][flags].reset(new Plane);
|
40
|
+
}
|
41
|
+
return (*planes[plane_index][flags])[char_index];
|
42
|
+
}
|
43
|
+
|
44
|
+
const Image& image_at(const FormattedString& fs, unsigned i)
|
45
|
+
{
|
46
|
+
if (const char* entity = fs.entity_at(i)) {
|
47
|
+
shared_ptr<Image>& ptr = entity_cache[entity];
|
48
|
+
if (!ptr) {
|
49
|
+
ptr.reset(new Image(entity_bitmap(fs.entity_at(i)), IF_SMOOTH));
|
50
|
+
}
|
51
|
+
return *ptr;
|
52
|
+
}
|
53
|
+
|
54
|
+
wchar_t wc = fs.char_at(i);
|
55
|
+
unsigned flags = fs.flags_at(i);
|
56
|
+
CharInfo& info = char_info(wc, flags);
|
57
|
+
|
58
|
+
if (info.image.get()) return *info.image;
|
59
|
+
|
60
|
+
std::string char_string = wstring_to_utf8(std::wstring(1, wc));
|
61
|
+
// TODO: Would be nice to have.
|
62
|
+
// if (is_formatting_char(wc))
|
63
|
+
// char_string.clear();
|
64
|
+
unsigned char_width = Gosu::text_width(char_string, name, height, flags);
|
65
|
+
|
66
|
+
Bitmap bitmap(char_width, height, 0x00ffffff);
|
67
|
+
draw_text(bitmap, char_string, 0, 0, Color::WHITE, name, height, flags);
|
68
|
+
info.image.reset(new Image(bitmap));
|
69
|
+
info.factor = 0.5;
|
70
|
+
return *info.image;
|
71
|
+
}
|
72
|
+
|
73
|
+
double factor_at(const FormattedString& fs, unsigned index)
|
74
|
+
{
|
75
|
+
if (fs.entity_at(index)) return 1;
|
76
|
+
return char_info(fs.char_at(index), fs.flags_at(index)).factor;
|
77
|
+
}
|
78
|
+
};
|
79
|
+
|
80
|
+
Gosu::Font::Font(unsigned font_height, const string& font_name, unsigned font_flags)
|
81
|
+
: pimpl(new Impl)
|
82
|
+
{
|
83
|
+
pimpl->name = font_name;
|
84
|
+
pimpl->height = font_height * 2;
|
85
|
+
pimpl->flags = font_flags;
|
86
|
+
}
|
87
|
+
|
88
|
+
string Gosu::Font::name() const
|
89
|
+
{
|
90
|
+
return pimpl->name;
|
91
|
+
}
|
92
|
+
|
93
|
+
unsigned Gosu::Font::height() const
|
94
|
+
{
|
95
|
+
return pimpl->height / 2;
|
96
|
+
}
|
97
|
+
|
98
|
+
unsigned Gosu::Font::flags() const
|
99
|
+
{
|
100
|
+
return pimpl->flags;
|
101
|
+
}
|
102
|
+
|
103
|
+
double Gosu::Font::text_width(const string& text, double scale_x) const
|
104
|
+
{
|
105
|
+
std::wstring wtext = utf8_to_wstring(text);
|
106
|
+
FormattedString fs(wtext.c_str(), flags());
|
107
|
+
double result = 0;
|
108
|
+
for (unsigned i = 0; i < fs.length(); ++i) {
|
109
|
+
const Image& image = pimpl->image_at(fs, i);
|
110
|
+
double factor = pimpl->factor_at(fs, i);
|
111
|
+
result += image.width() * factor;
|
112
|
+
}
|
113
|
+
return result * scale_x;
|
114
|
+
}
|
115
|
+
|
116
|
+
void Gosu::Font::draw(const string& text, double x, double y, ZPos z,
|
117
|
+
double scale_x, double scale_y, Color c, AlphaMode mode) const
|
118
|
+
{
|
119
|
+
std::wstring wtext = utf8_to_wstring(text);
|
120
|
+
FormattedString fs(wtext.c_str(), flags());
|
121
|
+
|
122
|
+
for (unsigned i = 0; i < fs.length(); ++i) {
|
123
|
+
const Image& image = pimpl->image_at(fs, i);
|
124
|
+
double factor = pimpl->factor_at(fs, i);
|
125
|
+
Gosu::Color color = fs.entity_at(i)
|
126
|
+
? Gosu::Color(fs.color_at(i).alpha() * c.alpha() / 255, 255, 255, 255)
|
127
|
+
: Gosu::multiply(fs.color_at(i), c);
|
128
|
+
image.draw(x, y, z, scale_x * factor, scale_y * factor, color, mode);
|
129
|
+
x += image.width() * scale_x * factor;
|
130
|
+
}
|
131
|
+
}
|
132
|
+
|
133
|
+
void Gosu::Font::draw_rel(const string& text, double x, double y, ZPos z,
|
134
|
+
double rel_x, double rel_y, double scale_x, double scale_y, Color c, AlphaMode mode) const
|
135
|
+
{
|
136
|
+
x -= text_width(text) * scale_x * rel_x;
|
137
|
+
y -= height() * scale_y * rel_y;
|
138
|
+
|
139
|
+
draw(text, x, y, z, scale_x, scale_y, c, mode);
|
140
|
+
}
|
141
|
+
|
142
|
+
void Gosu::Font::set_image(wchar_t wc, const Image& image)
|
143
|
+
{
|
144
|
+
for (unsigned flags = 0; flags < FF_COMBINATIONS; ++flags) {
|
145
|
+
set_image(wc, flags, image);
|
146
|
+
}
|
147
|
+
}
|
148
|
+
|
149
|
+
void Gosu::Font::set_image(wchar_t wc, unsigned font_flags, const Image& image)
|
150
|
+
{
|
151
|
+
Impl::CharInfo& ci = pimpl->char_info(wc, font_flags);
|
152
|
+
if (ci.image.get()) {
|
153
|
+
throw logic_error("Cannot set image for the same character twice");
|
154
|
+
}
|
155
|
+
ci.image.reset(new Gosu::Image(image));
|
156
|
+
ci.factor = 1.0;
|
157
|
+
}
|
158
|
+
|
159
|
+
void Gosu::Font::draw_rot(const string& text, double x, double y, ZPos z, double angle,
|
160
|
+
double scale_x, double scale_y, Color c, AlphaMode mode) const
|
161
|
+
{
|
162
|
+
Gosu::Graphics::push_transform(rotate(angle, x, y));
|
163
|
+
draw(text, x, y, z, scale_x, scale_y, c, mode);
|
164
|
+
Gosu::Graphics::pop_transform();
|
165
|
+
}
|
@@ -1,10 +1,11 @@
|
|
1
|
-
#
|
2
|
-
#define GOSU_SRC_GRAPHICS_TEXTFORMATTING
|
1
|
+
#pragma once
|
3
2
|
|
3
|
+
#include "GraphicsImpl.hpp"
|
4
4
|
#include <Gosu/Color.hpp>
|
5
|
+
#include <Gosu/GraphicsBase.hpp>
|
5
6
|
#include <Gosu/Utility.hpp>
|
6
|
-
#include <Gosu/TR1.hpp>
|
7
7
|
#include <cassert>
|
8
|
+
#include <cstdint>
|
8
9
|
#include <cwchar>
|
9
10
|
#include <cwctype>
|
10
11
|
#include <stdexcept>
|
@@ -20,26 +21,26 @@ namespace Gosu
|
|
20
21
|
wchar_t wc;
|
21
22
|
Gosu::Color color;
|
22
23
|
unsigned flags;
|
23
|
-
std::
|
24
|
+
std::string entity;
|
24
25
|
|
25
|
-
bool
|
26
|
+
bool same_style_as(const FormattedChar& other) const
|
26
27
|
{
|
27
28
|
return wc && other.wc && color == other.color && flags == other.flags;
|
28
29
|
}
|
29
30
|
};
|
30
31
|
|
31
32
|
// If characters.empty(), use these for the whole string.
|
32
|
-
std::wstring
|
33
|
-
unsigned
|
33
|
+
std::wstring simple_string;
|
34
|
+
unsigned simple_flags;
|
34
35
|
// If not characters.empty(), ignore above fields and use this.
|
35
36
|
std::vector<FormattedChar> characters;
|
36
37
|
|
37
38
|
static unsigned flags(int b, int u, int i)
|
38
39
|
{
|
39
40
|
unsigned flags = 0;
|
40
|
-
if (b > 0) flags |=
|
41
|
-
if (u > 0) flags |=
|
42
|
-
if (i > 0) flags |=
|
41
|
+
if (b > 0) flags |= FF_BOLD;
|
42
|
+
if (u > 0) flags |= FF_UNDERLINE;
|
43
|
+
if (i > 0) flags |= FF_ITALIC;
|
43
44
|
return flags;
|
44
45
|
}
|
45
46
|
|
@@ -48,17 +49,17 @@ namespace Gosu
|
|
48
49
|
{
|
49
50
|
}
|
50
51
|
|
51
|
-
explicit FormattedString(const wchar_t* html, unsigned
|
52
|
+
explicit FormattedString(const wchar_t* html, unsigned base_flags)
|
52
53
|
{
|
53
54
|
// Remove \r characters if existent. Avoid a copy if we don't need one.
|
54
55
|
std::wstring unixified;
|
55
56
|
if (std::wcschr(html, L'\r')) {
|
56
57
|
unixified.resize(std::wcslen(html));
|
57
58
|
unsigned pos = 0;
|
58
|
-
while (*html)
|
59
|
-
|
60
|
-
if (*html != '\r')
|
59
|
+
while (*html) {
|
60
|
+
if (*html != '\r') {
|
61
61
|
unixified[pos++] = *html;
|
62
|
+
}
|
62
63
|
++html;
|
63
64
|
}
|
64
65
|
unixified.resize(pos);
|
@@ -68,127 +69,114 @@ namespace Gosu
|
|
68
69
|
std::size_t len = std::wcslen(html);
|
69
70
|
|
70
71
|
// Just skip all this if there are entities or formatting tags in the string.
|
71
|
-
if (std::wcscspn(html, L"<&") == len)
|
72
|
-
|
73
|
-
|
74
|
-
simpleFlags = baseFlags;
|
72
|
+
if (std::wcscspn(html, L"<&") == len) {
|
73
|
+
simple_string = html;
|
74
|
+
simple_flags = base_flags;
|
75
75
|
return;
|
76
76
|
}
|
77
77
|
|
78
78
|
unsigned pos = 0;
|
79
|
-
int b = (
|
80
|
-
u = (
|
81
|
-
i = (
|
79
|
+
int b = (base_flags & FF_BOLD) ? 1 : 0,
|
80
|
+
u = (base_flags & FF_UNDERLINE) ? 1 : 0,
|
81
|
+
i = (base_flags & FF_ITALIC) ? 1 : 0;
|
82
82
|
std::vector<Gosu::Color> c;
|
83
83
|
c.push_back(0xffffffff);
|
84
|
-
while (pos < len)
|
85
|
-
|
86
|
-
if (!std::wcsncmp(html + pos, L"<b>", 3))
|
87
|
-
{
|
84
|
+
while (pos < len) {
|
85
|
+
if (!std::wcsncmp(html + pos, L"<b>", 3)) {
|
88
86
|
b += 1;
|
89
87
|
pos += 3;
|
90
88
|
continue;
|
91
89
|
}
|
92
|
-
if (!std::wcsncmp(html + pos, L"</b>", 4))
|
93
|
-
{
|
90
|
+
if (!std::wcsncmp(html + pos, L"</b>", 4)) {
|
94
91
|
b -= 1;
|
95
92
|
pos += 4;
|
96
93
|
continue;
|
97
94
|
}
|
98
|
-
if (!std::wcsncmp(html + pos, L"<u>", 3))
|
99
|
-
{
|
95
|
+
if (!std::wcsncmp(html + pos, L"<u>", 3)) {
|
100
96
|
u += 1;
|
101
97
|
pos += 3;
|
102
98
|
continue;
|
103
99
|
}
|
104
|
-
if (!std::wcsncmp(html + pos, L"</u>", 4))
|
105
|
-
{
|
100
|
+
if (!std::wcsncmp(html + pos, L"</u>", 4)) {
|
106
101
|
u -= 1;
|
107
102
|
pos += 4;
|
108
103
|
continue;
|
109
104
|
}
|
110
|
-
if (!std::wcsncmp(html + pos, L"<i>", 3))
|
111
|
-
{
|
105
|
+
if (!std::wcsncmp(html + pos, L"<i>", 3)) {
|
112
106
|
i += 1;
|
113
107
|
pos += 3;
|
114
108
|
continue;
|
115
109
|
}
|
116
|
-
if (!std::wcsncmp(html + pos, L"</i>", 4))
|
117
|
-
{
|
110
|
+
if (!std::wcsncmp(html + pos, L"</i>", 4)) {
|
118
111
|
i -= 1;
|
119
112
|
pos += 4;
|
120
113
|
continue;
|
121
114
|
}
|
122
|
-
if (!std::wcsncmp(html + pos, L"<c=", 3) &&
|
123
|
-
|
124
|
-
{
|
115
|
+
if (!std::wcsncmp(html + pos, L"<c=", 3) && len >= pos + 10
|
116
|
+
&& html[pos + 9] == L'>') {
|
125
117
|
using namespace std;
|
126
|
-
unsigned rgb = static_cast<std::
|
118
|
+
unsigned rgb = static_cast<std::uint32_t>(wcstoul(html + pos + 3, 0, 16));
|
127
119
|
c.push_back(0xff000000 | rgb);
|
128
120
|
pos += 10;
|
129
121
|
continue;
|
130
122
|
}
|
131
|
-
if (!std::wcsncmp(html + pos, L"<c=", 3) &&
|
132
|
-
|
133
|
-
{
|
123
|
+
if (!std::wcsncmp(html + pos, L"<c=", 3) && len >= pos + 12
|
124
|
+
&& html[pos + 11] == L'>') {
|
134
125
|
using namespace std;
|
135
|
-
unsigned argb = static_cast<std::
|
126
|
+
unsigned argb = static_cast<std::uint32_t>(wcstoul(html + pos + 3, 0, 16));
|
136
127
|
c.push_back(argb);
|
137
128
|
pos += 12;
|
138
129
|
continue;
|
139
130
|
}
|
140
|
-
if (!std::wcsncmp(html + pos, L"</c>", 4))
|
141
|
-
|
142
|
-
if (c.size() > 1)
|
131
|
+
if (!std::wcsncmp(html + pos, L"</c>", 4)) {
|
132
|
+
if (c.size() > 1) {
|
143
133
|
c.pop_back();
|
134
|
+
}
|
144
135
|
pos += 4;
|
145
136
|
continue;
|
146
137
|
}
|
147
|
-
if (!std::wcsncmp(html + pos, L"<", 4))
|
148
|
-
|
149
|
-
FormattedChar fc = { L'<', c.back(), flags(b,u,i) };
|
138
|
+
if (!std::wcsncmp(html + pos, L"<", 4)) {
|
139
|
+
FormattedChar fc = { L'<', c.back(), flags(b, u, i) };
|
150
140
|
characters.push_back(fc);
|
151
141
|
pos += 4;
|
152
142
|
continue;
|
153
143
|
}
|
154
|
-
if (!std::wcsncmp(html + pos, L">", 4))
|
155
|
-
|
156
|
-
FormattedChar fc = { L'>', c.back(), flags(b,u,i) };
|
144
|
+
if (!std::wcsncmp(html + pos, L">", 4)) {
|
145
|
+
FormattedChar fc = { L'>', c.back(), flags(b, u, i) };
|
157
146
|
characters.push_back(fc);
|
158
147
|
pos += 4;
|
159
148
|
continue;
|
160
149
|
}
|
161
|
-
if (!std::wcsncmp(html + pos, L"&", 5))
|
162
|
-
|
163
|
-
FormattedChar fc = { L'&', c.back(), flags(b,u,i) };
|
150
|
+
if (!std::wcsncmp(html + pos, L"&", 5)) {
|
151
|
+
FormattedChar fc = { L'&', c.back(), flags(b, u, i) };
|
164
152
|
characters.push_back(fc);
|
165
153
|
pos += 5;
|
166
154
|
continue;
|
167
155
|
}
|
168
|
-
if (html[pos] == L'&' && html[pos + 1])
|
169
|
-
|
170
|
-
|
171
|
-
while (html[endOfEntity] != L';')
|
172
|
-
{
|
173
|
-
// Never know where the wchar_t stuff is...what a mess!
|
156
|
+
if (html[pos] == L'&' && html[pos + 1]) {
|
157
|
+
int end_of_entity = pos + 1;
|
158
|
+
while (html[end_of_entity] != L';') {
|
174
159
|
using namespace std;
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
if (
|
180
|
-
goto
|
160
|
+
if (!iswalnum(static_cast<wint_t>(html[end_of_entity]))) {
|
161
|
+
goto normal_character;
|
162
|
+
}
|
163
|
+
end_of_entity += 1;
|
164
|
+
if (end_of_entity >= len) {
|
165
|
+
goto normal_character;
|
166
|
+
}
|
167
|
+
}
|
168
|
+
std::wstring entity(html + pos + 1, html + end_of_entity);
|
169
|
+
FormattedChar fc = { 0, c.back(), 0, wstring_to_utf8(entity) };
|
170
|
+
if (!is_entity(fc.entity)) {
|
171
|
+
goto normal_character;
|
181
172
|
}
|
182
|
-
FormattedChar fc = { 0, c.back(), 0, std::wstring(html + pos + 1, html + endOfEntity) };
|
183
|
-
if (!isEntity(fc.entity))
|
184
|
-
goto normalCharacter;
|
185
173
|
characters.push_back(fc);
|
186
|
-
pos =
|
174
|
+
pos = end_of_entity + 1;
|
187
175
|
continue;
|
188
176
|
}
|
189
|
-
|
190
|
-
|
191
|
-
FormattedChar fc = { html[pos], c.back(), flags(b,u,i) };
|
177
|
+
|
178
|
+
normal_character:
|
179
|
+
FormattedChar fc = { html[pos], c.back(), flags(b, u, i) };
|
192
180
|
characters.push_back(fc);
|
193
181
|
pos += 1;
|
194
182
|
}
|
@@ -196,103 +184,115 @@ namespace Gosu
|
|
196
184
|
|
197
185
|
std::wstring unformat() const
|
198
186
|
{
|
199
|
-
if (characters.empty())
|
200
|
-
return
|
187
|
+
if (characters.empty()) {
|
188
|
+
return simple_string;
|
189
|
+
}
|
201
190
|
|
202
191
|
std::wstring result(characters.size(), 0);
|
203
|
-
for (int i = 0; i < characters.size(); ++i)
|
192
|
+
for (int i = 0; i < characters.size(); ++i) {
|
204
193
|
result[i] = characters[i].wc;
|
194
|
+
}
|
205
195
|
return result;
|
206
196
|
}
|
207
197
|
|
208
|
-
const
|
198
|
+
const char* entity_at(unsigned index) const
|
209
199
|
{
|
210
|
-
if (characters.empty())
|
211
|
-
return
|
200
|
+
if (characters.empty()) {
|
201
|
+
return nullptr;
|
202
|
+
}
|
212
203
|
|
213
|
-
|
204
|
+
if (characters[index].wc != 0 || characters[index].entity.empty()) {
|
205
|
+
return nullptr;
|
206
|
+
}
|
214
207
|
|
215
|
-
if (characters[index].wc != 0 || characters[index].entity.empty())
|
216
|
-
return 0;
|
217
208
|
return characters[index].entity.c_str();
|
218
209
|
}
|
219
210
|
|
220
|
-
wchar_t
|
211
|
+
wchar_t char_at(unsigned index) const
|
221
212
|
{
|
222
|
-
if (characters.empty())
|
223
|
-
return
|
224
|
-
|
213
|
+
if (characters.empty()) {
|
214
|
+
return simple_string[index];
|
215
|
+
}
|
216
|
+
else {
|
225
217
|
return characters[index].wc;
|
218
|
+
}
|
226
219
|
}
|
227
220
|
|
228
|
-
unsigned
|
221
|
+
unsigned flags_at(unsigned index) const
|
229
222
|
{
|
230
|
-
if (characters.empty())
|
231
|
-
return
|
232
|
-
|
223
|
+
if (characters.empty()) {
|
224
|
+
return simple_flags;
|
225
|
+
}
|
226
|
+
else {
|
233
227
|
return characters[index].flags;
|
228
|
+
}
|
234
229
|
}
|
235
230
|
|
236
|
-
Gosu::Color
|
231
|
+
Gosu::Color color_at(unsigned index) const
|
237
232
|
{
|
238
|
-
if (characters.empty())
|
233
|
+
if (characters.empty()) {
|
239
234
|
return Color::WHITE;
|
240
|
-
|
235
|
+
}
|
236
|
+
else {
|
241
237
|
return characters[index].color;
|
238
|
+
}
|
242
239
|
}
|
243
240
|
|
244
241
|
std::size_t length() const
|
245
242
|
{
|
246
|
-
if (std::size_t len = characters.size())
|
243
|
+
if (std::size_t len = characters.size()) {
|
247
244
|
return len;
|
248
|
-
|
249
|
-
|
245
|
+
}
|
246
|
+
else {
|
247
|
+
return simple_string.length();
|
248
|
+
}
|
250
249
|
}
|
251
250
|
|
252
251
|
FormattedString range(std::size_t begin, std::size_t end) const
|
253
252
|
{
|
254
253
|
FormattedString result;
|
255
|
-
if (characters.empty())
|
256
|
-
|
257
|
-
|
258
|
-
result.
|
254
|
+
if (characters.empty()) {
|
255
|
+
result.simple_string.assign(simple_string.begin() + begin,
|
256
|
+
simple_string.begin() + end);
|
257
|
+
result.simple_flags = simple_flags;
|
258
|
+
}
|
259
|
+
else {
|
260
|
+
result.characters.assign(characters.begin() + begin,
|
261
|
+
characters.begin() + end);
|
259
262
|
}
|
260
|
-
else
|
261
|
-
result.characters.assign(characters.begin() + begin, characters.begin() + end);
|
262
263
|
return result;
|
263
264
|
}
|
264
265
|
|
265
|
-
std::vector<FormattedString>
|
266
|
+
std::vector<FormattedString> split_lines() const
|
266
267
|
{
|
267
268
|
std::vector<FormattedString> result;
|
268
269
|
unsigned begin = 0;
|
269
|
-
for (unsigned cur = 0; cur < length(); ++cur)
|
270
|
-
if (
|
271
|
-
{
|
270
|
+
for (unsigned cur = 0; cur < length(); ++cur) {
|
271
|
+
if (char_at(cur) == L'\n') {
|
272
272
|
result.push_back(range(begin, cur));
|
273
273
|
begin = cur + 1;
|
274
274
|
}
|
275
|
+
}
|
275
276
|
result.push_back(range(begin, length()));
|
276
277
|
return result;
|
277
278
|
}
|
278
279
|
|
279
|
-
std::vector<FormattedString>
|
280
|
+
std::vector<FormattedString> split_parts() const
|
280
281
|
{
|
281
|
-
if (characters.empty())
|
282
|
+
if (characters.empty()) {
|
282
283
|
return std::vector<FormattedString>(1, *this);
|
284
|
+
}
|
283
285
|
|
284
286
|
std::vector<FormattedString> result;
|
285
287
|
unsigned begin = 0;
|
286
|
-
for (unsigned cur = 1; cur < length(); ++cur)
|
287
|
-
if (!characters[begin].
|
288
|
-
{
|
288
|
+
for (unsigned cur = 1; cur < length(); ++cur) {
|
289
|
+
if (!characters[begin].same_style_as(characters[cur])) {
|
289
290
|
result.push_back(range(begin, cur));
|
290
291
|
begin = cur;
|
291
292
|
}
|
293
|
+
}
|
292
294
|
result.push_back(range(begin, length()));
|
293
295
|
return result;
|
294
296
|
}
|
295
297
|
};
|
296
298
|
}
|
297
|
-
|
298
|
-
#endif
|