gosu 0.10.9.pre1 → 0.11.0
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.
- 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
|