gosu 1.4.6 → 2.0.0.pre6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/COPYING +2 -1
- data/dependencies/SDL/include/SDL_atomic.h +2 -3
- data/dependencies/SDL/include/SDL_audio.h +7 -7
- data/dependencies/SDL/include/SDL_blendmode.h +1 -1
- data/dependencies/SDL/include/SDL_endian.h +3 -3
- data/dependencies/SDL/include/SDL_gamecontroller.h +4 -4
- data/dependencies/SDL/include/SDL_hints.h +72 -28
- data/dependencies/SDL/include/SDL_joystick.h +8 -5
- data/dependencies/SDL/include/SDL_keycode.h +1 -1
- data/dependencies/SDL/include/SDL_main.h +7 -0
- data/dependencies/SDL/include/SDL_mouse.h +6 -7
- data/dependencies/SDL/include/SDL_mutex.h +79 -5
- data/dependencies/SDL/include/SDL_opengl_glext.h +5 -1
- data/dependencies/SDL/include/SDL_power.h +7 -8
- data/dependencies/SDL/include/SDL_render.h +5 -0
- data/dependencies/SDL/include/SDL_revision.h +2 -2
- data/dependencies/SDL/include/SDL_sensor.h +1 -1
- data/dependencies/SDL/include/SDL_stdinc.h +19 -11
- data/dependencies/SDL/include/SDL_thread.h +2 -2
- data/dependencies/SDL/include/SDL_version.h +2 -2
- data/dependencies/SDL/include/SDL_video.h +30 -2
- data/dependencies/SDL/include/begin_code.h +7 -7
- data/dependencies/SDL/include/close_code.h +2 -2
- data/dependencies/SDL/lib/x64/libSDL2.dll.a +0 -0
- data/dependencies/SDL/lib/x86/libSDL2.dll.a +0 -0
- data/dependencies/SDL_sound/SDL_sound.h +1 -1
- data/dependencies/SDL_sound/dr_flac.h +48 -23
- data/dependencies/SDL_sound/dr_mp3.h +34 -14
- data/dependencies/SDL_sound/stb_vorbis.h +3 -2
- data/dependencies/mojoAL/mojoal.c +1 -1
- data/ext/{gosu → gosu-ffi}/extconf.rb +34 -33
- data/ext/gosu-ffi/gosu-ffi.def +464 -0
- data/ffi/Gosu.cpp +307 -0
- data/ffi/Gosu.h +84 -0
- data/ffi/Gosu_Channel.cpp +62 -0
- data/ffi/Gosu_Channel.h +17 -0
- data/ffi/Gosu_Color.cpp +132 -0
- data/ffi/Gosu_Color.h +31 -0
- data/ffi/Gosu_Constants.cpp +334 -0
- data/ffi/Gosu_FFI.h +34 -0
- data/ffi/Gosu_FFI_internal.h +161 -0
- data/ffi/Gosu_Font.cpp +92 -0
- data/ffi/Gosu_Font.h +32 -0
- data/ffi/Gosu_Image.cpp +206 -0
- data/ffi/Gosu_Image.h +60 -0
- data/ffi/Gosu_Sample.cpp +29 -0
- data/ffi/Gosu_Sample.h +14 -0
- data/ffi/Gosu_Song.cpp +69 -0
- data/ffi/Gosu_Song.h +18 -0
- data/ffi/Gosu_TextInput.cpp +94 -0
- data/ffi/Gosu_TextInput.h +25 -0
- data/ffi/Gosu_Window.cpp +314 -0
- data/ffi/Gosu_Window.h +78 -0
- data/include/Gosu/Audio.hpp +6 -11
- data/include/Gosu/Bitmap.hpp +38 -53
- data/include/Gosu/Buffer.hpp +54 -0
- data/include/Gosu/Color.hpp +27 -35
- data/include/Gosu/Directories.hpp +25 -28
- data/include/Gosu/Drawable.hpp +58 -0
- data/include/Gosu/Font.hpp +6 -5
- data/include/Gosu/Fwd.hpp +4 -6
- data/include/Gosu/Gosu.hpp +5 -5
- data/include/Gosu/Graphics.hpp +51 -61
- data/include/Gosu/GraphicsBase.hpp +1 -11
- data/include/Gosu/Image.hpp +11 -14
- data/include/Gosu/Math.hpp +50 -72
- data/include/Gosu/Transform.hpp +32 -0
- data/include/Gosu/Utility.hpp +51 -1
- data/include/Gosu/Version.hpp +3 -3
- data/include/Gosu/Window.hpp +15 -9
- data/lib/SDL2.dll +0 -0
- data/lib/gosu/channel.rb +49 -0
- data/lib/gosu/color.rb +150 -0
- data/lib/gosu/compat.rb +29 -8
- data/lib/gosu/constants.rb +386 -0
- data/lib/gosu/ffi.rb +258 -0
- data/lib/gosu/font.rb +56 -0
- data/lib/gosu/gl_tex_info.rb +33 -0
- data/lib/gosu/gosu.rb +210 -0
- data/lib/gosu/image.rb +141 -0
- data/lib/gosu/numeric.rb +17 -0
- data/lib/gosu/preview.rb +6 -6
- data/lib/gosu/sample.rb +24 -0
- data/lib/gosu/song.rb +56 -0
- data/lib/gosu/text_input.rb +69 -0
- data/lib/gosu/window.rb +228 -0
- data/lib/gosu.rb +29 -8
- data/lib64/SDL2.dll +0 -0
- data/rdoc/gosu.rb +0 -2
- data/src/Audio.cpp +12 -12
- data/src/AudioFile.hpp +5 -4
- data/src/AudioFileAudioToolbox.cpp +8 -8
- data/src/AudioFileSDLSound.cpp +7 -10
- data/src/BinPacker.cpp +187 -0
- data/src/BinPacker.hpp +55 -0
- data/src/Bitmap.cpp +166 -144
- data/src/BitmapIO.cpp +60 -86
- data/src/Buffer.cpp +159 -0
- data/src/Color.cpp +75 -80
- data/src/Directories.cpp +47 -0
- data/src/DirectoriesUIKit.cpp +50 -0
- data/src/DrawOp.hpp +9 -4
- data/src/DrawOpQueue.hpp +2 -2
- data/src/Drawable.cpp +95 -0
- data/src/EmptyDrawable.hpp +38 -0
- data/src/FPS.cpp +31 -0
- data/src/Font.cpp +104 -74
- data/src/GosuGLView.cpp +14 -6
- data/src/GosuViewController.cpp +2 -10
- data/src/Graphics.cpp +60 -126
- data/src/GraphicsImpl.hpp +17 -47
- data/src/Image.cpp +41 -35
- data/src/Input.cpp +7 -8
- data/src/Macro.cpp +6 -6
- data/src/Macro.hpp +4 -4
- data/src/MarkupParser.cpp +5 -5
- data/src/Math.cpp +35 -22
- data/src/OffScreenTarget.cpp +53 -49
- data/src/OffScreenTarget.hpp +13 -11
- data/src/OpenGLContext.cpp +117 -0
- data/src/OpenGLContext.hpp +41 -0
- data/src/RenderState.hpp +21 -19
- data/src/Resolution.cpp +23 -21
- data/src/TexChunk.cpp +35 -80
- data/src/TexChunk.hpp +44 -35
- data/src/Text.cpp +1 -1
- data/src/TextBuilder.cpp +35 -21
- data/src/TextBuilder.hpp +6 -9
- data/src/Texture.cpp +62 -80
- data/src/Texture.hpp +25 -23
- data/src/TiledDrawable.cpp +150 -0
- data/src/TiledDrawable.hpp +47 -0
- data/src/TimingApple.cpp +1 -1
- data/src/Transform.cpp +45 -50
- data/src/TransformStack.hpp +16 -16
- data/src/TrueTypeFont.cpp +59 -51
- data/src/TrueTypeFont.hpp +6 -7
- data/src/TrueTypeFontApple.cpp +28 -19
- data/src/TrueTypeFontUnix.cpp +27 -23
- data/src/TrueTypeFontWin.cpp +30 -30
- data/src/Utility.cpp +84 -21
- data/src/UtilityWin.cpp +45 -0
- data/src/Window.cpp +92 -142
- data/src/WindowUIKit.cpp +14 -14
- metadata +72 -31
- data/include/Gosu/IO.hpp +0 -254
- data/include/Gosu/ImageData.hpp +0 -53
- data/include/Gosu/Inspection.hpp +0 -7
- data/lib/gosu/patches.rb +0 -66
- data/lib/gosu/run.rb +0 -20
- data/lib/gosu/swig_patches.rb +0 -110
- data/src/BlockAllocator.cpp +0 -131
- data/src/BlockAllocator.hpp +0 -32
- data/src/DirectoriesApple.cpp +0 -69
- data/src/DirectoriesUnix.cpp +0 -46
- data/src/DirectoriesWin.cpp +0 -65
- data/src/EmptyImageData.hpp +0 -52
- data/src/FileUnix.cpp +0 -99
- data/src/FileWin.cpp +0 -88
- data/src/IO.cpp +0 -60
- data/src/Iconv.hpp +0 -51
- data/src/Inspection.cpp +0 -27
- data/src/LargeImageData.cpp +0 -215
- data/src/LargeImageData.hpp +0 -39
- data/src/Log.hpp +0 -19
- data/src/RubyGosu.cxx +0 -13100
- data/src/RubyGosu.h +0 -49
- data/src/WinUtility.cpp +0 -61
- data/src/WinUtility.hpp +0 -27
data/src/Buffer.cpp
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
#include <Gosu/Buffer.hpp>
|
2
|
+
#include <Gosu/Platform.hpp>
|
3
|
+
#include <limits>
|
4
|
+
#include <memory>
|
5
|
+
#include <stdexcept>
|
6
|
+
|
7
|
+
#ifdef GOSU_IS_IPHONE
|
8
|
+
#include <filesystem>
|
9
|
+
#include <fstream>
|
10
|
+
#else
|
11
|
+
#include <SDL.h>
|
12
|
+
#endif
|
13
|
+
|
14
|
+
Gosu::Buffer::Buffer(void* buffer, std::size_t size, std::function<void(void*)> deleter)
|
15
|
+
: m_buffer(buffer),
|
16
|
+
m_size(size),
|
17
|
+
m_deleter(std::move(deleter))
|
18
|
+
{
|
19
|
+
if (buffer == nullptr && size > 0) {
|
20
|
+
throw std::invalid_argument("Tried to create non-empty Gosu::Buffer from nullptr");
|
21
|
+
}
|
22
|
+
if (size >= std::numeric_limits<std::ptrdiff_t>::max()) {
|
23
|
+
throw std::length_error("Tried to create Gosu::Buffer with a negative size");
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
Gosu::Buffer::Buffer(Gosu::Buffer&& other) noexcept
|
28
|
+
: m_buffer(nullptr),
|
29
|
+
m_size(0),
|
30
|
+
m_deleter(nullptr)
|
31
|
+
{
|
32
|
+
*this = std::move(other);
|
33
|
+
}
|
34
|
+
|
35
|
+
Gosu::Buffer& Gosu::Buffer::operator=(Gosu::Buffer&& other) noexcept
|
36
|
+
{
|
37
|
+
if (this == &other) {
|
38
|
+
return *this;
|
39
|
+
}
|
40
|
+
|
41
|
+
if (m_buffer && m_deleter) {
|
42
|
+
m_deleter(m_buffer);
|
43
|
+
}
|
44
|
+
|
45
|
+
m_buffer = other.m_buffer;
|
46
|
+
m_size = other.m_size;
|
47
|
+
// In theory, this could throw. In that case, we are fine with a full crash of the current
|
48
|
+
// process (as this function is marked noexcept) because throwing deleters are a user error.
|
49
|
+
m_deleter = std::move(other.m_deleter);
|
50
|
+
|
51
|
+
other.m_buffer = nullptr;
|
52
|
+
other.m_size = 0;
|
53
|
+
other.m_deleter = nullptr;
|
54
|
+
|
55
|
+
return *this;
|
56
|
+
}
|
57
|
+
|
58
|
+
Gosu::Buffer::~Buffer()
|
59
|
+
{
|
60
|
+
if (m_buffer && m_deleter) {
|
61
|
+
m_deleter(m_buffer);
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
Gosu::Buffer::Buffer(std::size_t size)
|
66
|
+
: m_buffer(nullptr),
|
67
|
+
m_size(size),
|
68
|
+
m_deleter([](void* p) { delete[] static_cast<std::uint8_t*>(p); })
|
69
|
+
{
|
70
|
+
if (size >= std::numeric_limits<std::ptrdiff_t>::max()) {
|
71
|
+
throw std::length_error("Tried to create Gosu::Buffer with a negative size");
|
72
|
+
}
|
73
|
+
|
74
|
+
if (m_size) {
|
75
|
+
m_buffer = new std::uint8_t[m_size];
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
Gosu::Buffer::Buffer(std::vector<std::uint8_t>&& vector) noexcept
|
80
|
+
: m_buffer(vector.data()),
|
81
|
+
m_size(vector.size()),
|
82
|
+
// Absorb the vector into this Gosu::Buffer by moving it into the deleter lambda.
|
83
|
+
// This is safe because the vector move constructor guarantees that pointers remain stable.
|
84
|
+
m_deleter([vector = std::move(vector)](void*) mutable { vector.clear(); })
|
85
|
+
{
|
86
|
+
}
|
87
|
+
|
88
|
+
Gosu::Buffer::Buffer(const Gosu::Buffer& other)
|
89
|
+
: Buffer(std::vector<std::uint8_t>(other.data(), other.data() + other.size()))
|
90
|
+
{
|
91
|
+
}
|
92
|
+
|
93
|
+
Gosu::Buffer& Gosu::Buffer::operator=(const Gosu::Buffer& other)
|
94
|
+
{
|
95
|
+
if (this == &other) {
|
96
|
+
return *this;
|
97
|
+
}
|
98
|
+
|
99
|
+
// Delegate to copy constructor + move assignment operator.
|
100
|
+
return *this = Buffer(other);
|
101
|
+
}
|
102
|
+
|
103
|
+
#ifdef GOSU_IS_IPHONE
|
104
|
+
Gosu::Buffer Gosu::load_file(const std::string& filename)
|
105
|
+
{
|
106
|
+
Buffer buffer(std::filesystem::file_size(filename));
|
107
|
+
char* ptr = reinterpret_cast<char*>(buffer.data());
|
108
|
+
std::ifstream file(filename, std::ios::binary);
|
109
|
+
// GCOV_EXCL_START: It is hard to set up a file where file_size works but reading doesn't.
|
110
|
+
if (!file || !file.read(ptr, static_cast<std::streamoff>(buffer.size()))) {
|
111
|
+
throw std::runtime_error("Could not read file '" + filename + "'");
|
112
|
+
}
|
113
|
+
// GCOV_EXCL_END
|
114
|
+
return buffer;
|
115
|
+
}
|
116
|
+
|
117
|
+
void Gosu::save_file(const Buffer& buffer, const std::string& filename)
|
118
|
+
{
|
119
|
+
std::ofstream file(filename, std::ios::binary | std::ios::trunc);
|
120
|
+
const char* ptr = reinterpret_cast<const char*>(buffer.data());
|
121
|
+
if (!file || !file.write(ptr, static_cast<std::streamoff>(buffer.size()))) {
|
122
|
+
throw std::runtime_error("Could not write file '" + filename + "'");
|
123
|
+
}
|
124
|
+
}
|
125
|
+
#else
|
126
|
+
Gosu::Buffer Gosu::load_file(const std::string& filename)
|
127
|
+
{
|
128
|
+
std::size_t size = 0;
|
129
|
+
void* contents = SDL_LoadFile(filename.c_str(), &size);
|
130
|
+
if (contents == nullptr) {
|
131
|
+
throw std::runtime_error("Could not read '" + filename + "', error: " + SDL_GetError());
|
132
|
+
}
|
133
|
+
return Buffer(contents, size, &SDL_free);
|
134
|
+
}
|
135
|
+
|
136
|
+
void Gosu::save_file(const Buffer& buffer, const std::string& filename)
|
137
|
+
{
|
138
|
+
struct RWopsDeleter
|
139
|
+
{
|
140
|
+
void operator()(SDL_RWops* p) const
|
141
|
+
{
|
142
|
+
// SDL_RWclose will crash if given nullptr.
|
143
|
+
if (p) {
|
144
|
+
SDL_RWclose(p);
|
145
|
+
}
|
146
|
+
}
|
147
|
+
};
|
148
|
+
std::unique_ptr<SDL_RWops, RWopsDeleter> rwops(SDL_RWFromFile(filename.c_str(), "w"));
|
149
|
+
if (rwops == nullptr) {
|
150
|
+
throw std::runtime_error("Could not open '" + filename + "', error: " + SDL_GetError());
|
151
|
+
}
|
152
|
+
std::size_t written = SDL_RWwrite(rwops.get(), buffer.data(), buffer.size(), 1);
|
153
|
+
// GCOV_EXCL_START: It is hard to set up a file where opening works but writing doesn't.
|
154
|
+
if (written == 0) {
|
155
|
+
throw std::runtime_error("Could not write to '" + filename + "', error: " + SDL_GetError());
|
156
|
+
}
|
157
|
+
// GCOV_EXCL_END
|
158
|
+
}
|
159
|
+
#endif
|
data/src/Color.cpp
CHANGED
@@ -1,56 +1,8 @@
|
|
1
1
|
#include <Gosu/Color.hpp>
|
2
2
|
#include <Gosu/Math.hpp>
|
3
|
-
#include <algorithm>
|
3
|
+
#include <algorithm> // for std::min, std::max
|
4
4
|
#include <cmath>
|
5
|
-
|
6
|
-
namespace
|
7
|
-
{
|
8
|
-
struct HSV
|
9
|
-
{
|
10
|
-
double h, s, v;
|
11
|
-
};
|
12
|
-
|
13
|
-
HSV color_to_hsv(const Gosu::Color& c)
|
14
|
-
{
|
15
|
-
double r = c.red / 255.0;
|
16
|
-
double g = c.green / 255.0;
|
17
|
-
double b = c.blue / 255.0;
|
18
|
-
|
19
|
-
double min = std::min(std::min(r, g), b);
|
20
|
-
double max = std::max(std::max(r, g), b);
|
21
|
-
double delta = max - min;
|
22
|
-
|
23
|
-
if (max == 0) {
|
24
|
-
HSV hsv = {0, 0, 0};
|
25
|
-
return hsv;
|
26
|
-
}
|
27
|
-
|
28
|
-
HSV hsv{};
|
29
|
-
|
30
|
-
// Value.
|
31
|
-
hsv.v = max;
|
32
|
-
|
33
|
-
// Saturation.
|
34
|
-
hsv.s = delta / max;
|
35
|
-
|
36
|
-
// Hue.
|
37
|
-
if (delta == 0) {
|
38
|
-
hsv.h = 0;
|
39
|
-
}
|
40
|
-
else if (r == max) {
|
41
|
-
hsv.h = (g - b) / delta + (g < b ? 6 : 0);
|
42
|
-
}
|
43
|
-
else if (g == max) {
|
44
|
-
hsv.h = (b - r) / delta + 2;
|
45
|
-
}
|
46
|
-
else {
|
47
|
-
hsv.h = (r - g) / delta + 4;
|
48
|
-
}
|
49
|
-
hsv.h *= 60;
|
50
|
-
|
51
|
-
return hsv;
|
52
|
-
}
|
53
|
-
}
|
5
|
+
#include <iomanip> // for std::setw
|
54
6
|
|
55
7
|
Gosu::Color Gosu::Color::from_hsv(double h, double s, double v)
|
56
8
|
{
|
@@ -60,32 +12,51 @@ Gosu::Color Gosu::Color::from_hsv(double h, double s, double v)
|
|
60
12
|
s = std::clamp(s, 0.0, 1.0);
|
61
13
|
v = std::clamp(v, 0.0, 1.0);
|
62
14
|
|
15
|
+
const auto to_channel = [](double d) { return static_cast<Channel>(std::round(255.0 * d)); };
|
16
|
+
|
63
17
|
int sector = static_cast<int>(h / 60);
|
64
|
-
double
|
18
|
+
double remainder = h / 60 - sector;
|
65
19
|
|
66
|
-
Channel p =
|
67
|
-
Channel q =
|
68
|
-
Channel t =
|
20
|
+
Channel p = to_channel(v * (1 - s));
|
21
|
+
Channel q = to_channel(v * (1 - s * remainder));
|
22
|
+
Channel t = to_channel(v * (1 - s * (1 - remainder)));
|
69
23
|
|
70
24
|
switch (sector) {
|
71
25
|
case 0:
|
72
|
-
return Color{
|
26
|
+
return Color { to_channel(v), t, p };
|
73
27
|
case 1:
|
74
|
-
return Color{q,
|
28
|
+
return Color { q, to_channel(v), p };
|
75
29
|
case 2:
|
76
|
-
return Color{p,
|
30
|
+
return Color { p, to_channel(v), t };
|
77
31
|
case 3:
|
78
|
-
return Color{p, q,
|
32
|
+
return Color { p, q, to_channel(v) };
|
79
33
|
case 4:
|
80
|
-
return Color{t, p,
|
34
|
+
return Color { t, p, to_channel(v) };
|
81
35
|
default: // sector 5
|
82
|
-
return Color{
|
36
|
+
return Color { to_channel(v), p, q };
|
83
37
|
}
|
84
38
|
}
|
85
39
|
|
86
40
|
double Gosu::Color::hue() const
|
87
41
|
{
|
88
|
-
|
42
|
+
double max = std::max({ red, green, blue });
|
43
|
+
double min = std::min({ red, green, blue });
|
44
|
+
|
45
|
+
if (min == max) {
|
46
|
+
return 0;
|
47
|
+
}
|
48
|
+
|
49
|
+
double factor = 60 / (max - min);
|
50
|
+
|
51
|
+
if (green == max) {
|
52
|
+
return (blue - red) * factor + 120; // 60...180
|
53
|
+
} else if (blue == max) {
|
54
|
+
return (red - green) * factor + 240; // 180...300
|
55
|
+
} else if (blue > green) {
|
56
|
+
return (green - blue) * factor + 360; // 300...360
|
57
|
+
} else {
|
58
|
+
return (green - blue) * factor + 0; // 0...60
|
59
|
+
}
|
89
60
|
}
|
90
61
|
|
91
62
|
void Gosu::Color::set_hue(double h)
|
@@ -95,7 +66,15 @@ void Gosu::Color::set_hue(double h)
|
|
95
66
|
|
96
67
|
double Gosu::Color::saturation() const
|
97
68
|
{
|
98
|
-
|
69
|
+
double max = std::max({ red, green, blue });
|
70
|
+
|
71
|
+
if (max == 0) {
|
72
|
+
return 0;
|
73
|
+
}
|
74
|
+
|
75
|
+
double min = std::min({ red, green, blue });
|
76
|
+
|
77
|
+
return 1 - (min / max);
|
99
78
|
}
|
100
79
|
|
101
80
|
void Gosu::Color::set_saturation(double s)
|
@@ -105,7 +84,7 @@ void Gosu::Color::set_saturation(double s)
|
|
105
84
|
|
106
85
|
double Gosu::Color::value() const
|
107
86
|
{
|
108
|
-
return
|
87
|
+
return std::max({ red, green, blue }) / 255.0;
|
109
88
|
}
|
110
89
|
|
111
90
|
void Gosu::Color::set_value(double v)
|
@@ -113,10 +92,23 @@ void Gosu::Color::set_value(double v)
|
|
113
92
|
*this = from_hsv(hue(), saturation(), v).with_alpha(alpha);
|
114
93
|
}
|
115
94
|
|
95
|
+
const Gosu::Color Gosu::Color::NONE { 0x00'000000 };
|
96
|
+
const Gosu::Color Gosu::Color::BLACK { 0, 0, 0 };
|
97
|
+
const Gosu::Color Gosu::Color::GRAY { 128, 128, 128 };
|
98
|
+
const Gosu::Color Gosu::Color::WHITE { 255, 255, 255 };
|
99
|
+
|
100
|
+
const Gosu::Color Gosu::Color::AQUA { 0, 255, 255 };
|
101
|
+
const Gosu::Color Gosu::Color::RED { 255, 0, 0 };
|
102
|
+
const Gosu::Color Gosu::Color::GREEN { 0, 255, 0 };
|
103
|
+
const Gosu::Color Gosu::Color::BLUE { 0, 0, 255 };
|
104
|
+
const Gosu::Color Gosu::Color::YELLOW { 255, 255, 0 };
|
105
|
+
const Gosu::Color Gosu::Color::FUCHSIA { 255, 0, 255 };
|
106
|
+
const Gosu::Color Gosu::Color::CYAN { 0, 255, 255 };
|
107
|
+
|
116
108
|
Gosu::Color Gosu::lerp(Color a, Color b, double t)
|
117
109
|
{
|
118
110
|
const auto lerp_channel = [](Color::Channel a, Color::Channel b, double t) {
|
119
|
-
return static_cast<Color::Channel>(std::clamp(std::round(lerp(a, b, t)), 0.0, 255.0));
|
111
|
+
return static_cast<Color::Channel>(std::clamp(std::round(std::lerp(a, b, t)), 0.0, 255.0));
|
120
112
|
};
|
121
113
|
|
122
114
|
Color result;
|
@@ -129,23 +121,26 @@ Gosu::Color Gosu::lerp(Color a, Color b, double t)
|
|
129
121
|
|
130
122
|
Gosu::Color Gosu::multiply(Color a, Color b)
|
131
123
|
{
|
124
|
+
const auto multiply_channel = [](Color::Channel a, Color::Channel b) {
|
125
|
+
return static_cast<Color::Channel>(std::round(a * b / 255.0));
|
126
|
+
};
|
127
|
+
|
132
128
|
Color result;
|
133
|
-
result.red =
|
134
|
-
result.green =
|
135
|
-
result.blue =
|
136
|
-
result.alpha =
|
129
|
+
result.red = multiply_channel(a.red, b.red);
|
130
|
+
result.green = multiply_channel(a.green, b.green);
|
131
|
+
result.blue = multiply_channel(a.blue, b.blue);
|
132
|
+
result.alpha = multiply_channel(a.alpha, b.alpha);
|
137
133
|
return result;
|
138
134
|
}
|
139
135
|
|
140
|
-
|
141
|
-
|
142
|
-
const
|
143
|
-
const
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
const Gosu::Color Gosu::Color::CYAN{0, 255, 255};
|
136
|
+
std::ostream& Gosu::operator<<(std::ostream& stream, Gosu::Color color)
|
137
|
+
{
|
138
|
+
const auto previous_flags = stream.flags();
|
139
|
+
const char previous_fill = stream.fill();
|
140
|
+
stream << std::setfill('0');
|
141
|
+
stream << "0x" << std::hex << std::setw(2) << static_cast<int>(color.alpha);
|
142
|
+
stream << '\'' << std::setw(6) << static_cast<int>(color.argb() & 0x00'ffffff);
|
143
|
+
stream.flags(previous_flags);
|
144
|
+
stream.fill(previous_fill);
|
145
|
+
return stream;
|
146
|
+
}
|
data/src/Directories.cpp
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
#include <Gosu/Directories.hpp>
|
2
|
+
#include <Gosu/Platform.hpp>
|
3
|
+
|
4
|
+
#ifdef GOSU_IS_WIN
|
5
|
+
#include <Gosu/Utility.hpp>
|
6
|
+
#include <windows.h>
|
7
|
+
#else
|
8
|
+
#include <unistd.h>
|
9
|
+
#endif
|
10
|
+
|
11
|
+
void Gosu::use_resource_directory()
|
12
|
+
{
|
13
|
+
#ifdef GOSU_IS_WIN
|
14
|
+
SetCurrentDirectoryW(utf8_to_utf16(resource_path()).c_str());
|
15
|
+
#else
|
16
|
+
chdir(resource_path().c_str());
|
17
|
+
#endif
|
18
|
+
}
|
19
|
+
|
20
|
+
#ifndef GOSU_IS_IPHONE
|
21
|
+
#include <SDL.h>
|
22
|
+
#include <memory>
|
23
|
+
#include <stdexcept>
|
24
|
+
#endif
|
25
|
+
|
26
|
+
#ifndef GOSU_IS_IPHONE
|
27
|
+
std::string Gosu::resource_path(const std::string& relative_filename)
|
28
|
+
{
|
29
|
+
static const char* resource_prefix = SDL_GetBasePath(); // never freed, doesn't matter
|
30
|
+
return relative_filename.empty() ? resource_prefix : resource_prefix + relative_filename;
|
31
|
+
}
|
32
|
+
|
33
|
+
std::string Gosu::user_settings_path(const std::string& organization,
|
34
|
+
const std::string& application,
|
35
|
+
const std::string& relative_filename)
|
36
|
+
{
|
37
|
+
char* settings_prefix = SDL_GetPrefPath(organization.c_str(), application.c_str());
|
38
|
+
// GCOV_EXCL_START: Hard to simulate errors here because even creating "/:\\/:\\" works (macOS).
|
39
|
+
if (!settings_prefix) {
|
40
|
+
throw std::runtime_error("Could not create settings directory: "
|
41
|
+
+ std::string(SDL_GetError()));
|
42
|
+
}
|
43
|
+
// GCOV_EXCL_END
|
44
|
+
const std::unique_ptr<char, decltype(&SDL_free)> guard(settings_prefix, &SDL_free);
|
45
|
+
return relative_filename.empty() ? settings_prefix : settings_prefix + relative_filename;
|
46
|
+
}
|
47
|
+
#endif
|
@@ -0,0 +1,50 @@
|
|
1
|
+
#include <Gosu/Directories.hpp>
|
2
|
+
#include <Gosu/Platform.hpp>
|
3
|
+
#if defined(GOSU_IS_IPHONE)
|
4
|
+
|
5
|
+
#import <Foundation/Foundation.h>
|
6
|
+
#include <filesystem>
|
7
|
+
|
8
|
+
std::string Gosu::resource_path(const std::string& relative_filename)
|
9
|
+
{
|
10
|
+
static const std::string resource_prefix = [] {
|
11
|
+
@autoreleasepool {
|
12
|
+
NSString* resources = [NSBundle mainBundle].resourcePath;
|
13
|
+
return std::string(resources.UTF8String ?: ".");
|
14
|
+
}
|
15
|
+
}();
|
16
|
+
|
17
|
+
return relative_filename.empty() ? resource_prefix : resource_prefix + "/" + relative_filename;
|
18
|
+
}
|
19
|
+
|
20
|
+
std::string Gosu::user_settings_path(const std::string& organization,
|
21
|
+
const std::string& application,
|
22
|
+
const std::string& relative_filename)
|
23
|
+
{
|
24
|
+
static const std::string user_settings_prefix = [] {
|
25
|
+
@autoreleasepool {
|
26
|
+
NSString* library
|
27
|
+
= NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)
|
28
|
+
.firstObject;
|
29
|
+
NSString* preferences = [library stringByAppendingPathComponent:@"Application Support"];
|
30
|
+
return std::string(preferences.UTF8String ?: ".");
|
31
|
+
}
|
32
|
+
}();
|
33
|
+
|
34
|
+
std::string directory = user_settings_prefix;
|
35
|
+
if (!organization.empty()) {
|
36
|
+
directory += '/';
|
37
|
+
directory += organization;
|
38
|
+
}
|
39
|
+
if (!application.empty()) {
|
40
|
+
directory += '/';
|
41
|
+
directory += application;
|
42
|
+
}
|
43
|
+
if (!std::filesystem::is_directory(directory)) {
|
44
|
+
std::filesystem::create_directories(directory);
|
45
|
+
}
|
46
|
+
|
47
|
+
return relative_filename.empty() ? directory : directory + '/' + relative_filename;
|
48
|
+
}
|
49
|
+
|
50
|
+
#endif
|
data/src/DrawOp.hpp
CHANGED
@@ -17,7 +17,9 @@ namespace Gosu
|
|
17
17
|
RenderState render_state;
|
18
18
|
// Only valid if render_state.tex_name != NO_TEXTURE
|
19
19
|
GLfloat top, left, bottom, right;
|
20
|
-
|
20
|
+
// Used to keep TexChunk rectangles on shared textures alive until the end of the frame.
|
21
|
+
std::shared_ptr<const Rect> rect_handle;
|
22
|
+
|
21
23
|
// TODO: Merge with Gosu::ArrayVertex.
|
22
24
|
struct Vertex
|
23
25
|
{
|
@@ -30,7 +32,7 @@ namespace Gosu
|
|
30
32
|
|
31
33
|
// Number of vertices used, or: complement index of code block
|
32
34
|
int vertices_or_block_index;
|
33
|
-
|
35
|
+
|
34
36
|
void perform(const DrawOp* next) const
|
35
37
|
{
|
36
38
|
// This should not be called on GL code ops.
|
@@ -141,8 +143,11 @@ namespace Gosu
|
|
141
143
|
result[i].vertices[1] = vertices[i].y;
|
142
144
|
result[i].vertices[2] = 0;
|
143
145
|
result[i].color = vertices[i].c.abgr();
|
144
|
-
|
145
|
-
|
146
|
+
double x = result[i].vertices[0];
|
147
|
+
double y = result[i].vertices[1];
|
148
|
+
render_state.transform->apply(x, y);
|
149
|
+
result[i].vertices[0] = static_cast<float>(x);
|
150
|
+
result[i].vertices[1] = static_cast<float>(y);
|
146
151
|
}
|
147
152
|
RenderState va_render_state = render_state;
|
148
153
|
va_render_state.transform = 0;
|
data/src/DrawOpQueue.hpp
CHANGED
@@ -77,8 +77,8 @@ public:
|
|
77
77
|
double left = x, right = x + width;
|
78
78
|
double top = y, bottom = y + height;
|
79
79
|
|
80
|
-
|
81
|
-
|
80
|
+
transform_stack.current().apply(left, top);
|
81
|
+
transform_stack.current().apply(right, bottom);
|
82
82
|
|
83
83
|
double phys_x = std::min(left, right);
|
84
84
|
double phys_y = std::min(top, bottom);
|
data/src/Drawable.cpp
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
#include <Gosu/Drawable.hpp>
|
2
|
+
#include <Gosu/Utility.hpp>
|
3
|
+
#include "EmptyDrawable.hpp"
|
4
|
+
#include "Texture.hpp"
|
5
|
+
#include "TiledDrawable.hpp"
|
6
|
+
#include <list>
|
7
|
+
#include <mutex>
|
8
|
+
|
9
|
+
namespace Gosu
|
10
|
+
{
|
11
|
+
// This variable has been declared in multiple places. Define it here, where it will be used.
|
12
|
+
// This is a compatibility hack for old versions of Ruby/Gosu that didn't yet support :retro.
|
13
|
+
bool undocumented_retrofication = false; // NOLINT(*-avoid-non-const-global-variables)
|
14
|
+
}
|
15
|
+
|
16
|
+
std::unique_ptr<Gosu::Drawable> Gosu::create_drawable(const Bitmap& source, const Rect& source_rect,
|
17
|
+
unsigned image_flags)
|
18
|
+
{
|
19
|
+
if (!Rect::covering(source).contains(source_rect)) {
|
20
|
+
throw std::invalid_argument("Source rectangle exceeds bitmap");
|
21
|
+
}
|
22
|
+
|
23
|
+
if (source_rect.empty()) {
|
24
|
+
// It can happen that Gosu::Font wants us to create an empty drawable when rendering
|
25
|
+
// invisible characters (e.g. '\r'). In this case, return an empty drawable that is not
|
26
|
+
// backed by any kind of OpenGL texture.
|
27
|
+
return std::make_unique<EmptyDrawable>(source_rect.width, source_rect.height);
|
28
|
+
}
|
29
|
+
|
30
|
+
// Backward compatibility: This used to be 'bool tileable', help users that still pass 'true'.
|
31
|
+
if (image_flags == 1) {
|
32
|
+
image_flags = IF_TILEABLE;
|
33
|
+
}
|
34
|
+
|
35
|
+
bool wants_retro = (image_flags & IF_RETRO) || undocumented_retrofication;
|
36
|
+
|
37
|
+
// Special case: If the texture is supposed to be tileable, is quadratic, has a size that is at
|
38
|
+
// least 64 pixels but no more than MAX_TEXTURE_SIZE pixels and a power of two, create a single
|
39
|
+
// texture just for this image.
|
40
|
+
// This is not just an optimization, but a feature of Gosu so that one can use Gosu for loading
|
41
|
+
// textures for use in 3D scenes, where it is important that the full u/v range is dedicated to
|
42
|
+
// a single image so that texture repetition works as expected.
|
43
|
+
if ((image_flags & IF_TILEABLE) == IF_TILEABLE && source_rect.width == source_rect.height
|
44
|
+
&& (source_rect.width & (source_rect.width - 1)) == 0 && source_rect.width >= 64
|
45
|
+
&& source_rect.width <= MAX_TEXTURE_SIZE) {
|
46
|
+
|
47
|
+
const std::shared_ptr<Texture> texture
|
48
|
+
= std::make_shared<Texture>(source_rect.width, source_rect.height, wants_retro);
|
49
|
+
|
50
|
+
// Use the source bitmap directly if the source area completely covers it.
|
51
|
+
if (source_rect == Rect::covering(source)) {
|
52
|
+
return texture->try_alloc(source, 0);
|
53
|
+
}
|
54
|
+
else {
|
55
|
+
Bitmap trimmed_source(source_rect.width, source_rect.height);
|
56
|
+
trimmed_source.insert(source, 0, 0, source_rect);
|
57
|
+
return texture->try_alloc(trimmed_source, 0);
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
const int max_size = MAX_TEXTURE_SIZE;
|
62
|
+
|
63
|
+
// Too large to fit on a single texture? -> Create a tiled representation.
|
64
|
+
if (source_rect.width > max_size - 2 || source_rect.height > max_size - 2) {
|
65
|
+
return std::make_unique<TiledDrawable>(source, source_rect, max_size - 2, image_flags);
|
66
|
+
}
|
67
|
+
|
68
|
+
Bitmap source_with_borders = apply_border_flags(image_flags, source, source_rect);
|
69
|
+
|
70
|
+
// Try to put the bitmap into one of the already allocated textures.
|
71
|
+
static std::list<std::weak_ptr<Texture>> texture_pool;
|
72
|
+
static std::mutex mutex;
|
73
|
+
std::scoped_lock lock(mutex);
|
74
|
+
|
75
|
+
texture_pool.remove_if([](const auto& weak_ptr) { return weak_ptr.expired(); });
|
76
|
+
|
77
|
+
for (const std::weak_ptr<Texture>& weak_texture : texture_pool) {
|
78
|
+
const auto texture = weak_texture.lock();
|
79
|
+
if (!texture || texture->retro() != wants_retro) {
|
80
|
+
continue;
|
81
|
+
}
|
82
|
+
|
83
|
+
std::unique_ptr<Drawable> data = texture->try_alloc(source_with_borders, 1);
|
84
|
+
if (data) {
|
85
|
+
return data;
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
// All textures are full: Create a new one.
|
90
|
+
|
91
|
+
std::shared_ptr<Texture> texture
|
92
|
+
= std::make_shared<Texture>(MAX_TEXTURE_SIZE, MAX_TEXTURE_SIZE, wants_retro);
|
93
|
+
texture_pool.push_back(texture);
|
94
|
+
return texture->try_alloc(source_with_borders, 1);
|
95
|
+
}
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include <Gosu/Bitmap.hpp>
|
4
|
+
#include <Gosu/Drawable.hpp>
|
5
|
+
#include <memory>
|
6
|
+
|
7
|
+
namespace Gosu
|
8
|
+
{
|
9
|
+
class EmptyDrawable : public Drawable
|
10
|
+
{
|
11
|
+
int m_width, m_height;
|
12
|
+
|
13
|
+
public:
|
14
|
+
EmptyDrawable(int width, int height)
|
15
|
+
: m_width(width),
|
16
|
+
m_height(height)
|
17
|
+
{
|
18
|
+
}
|
19
|
+
|
20
|
+
int width() const override { return m_width; }
|
21
|
+
|
22
|
+
int height() const override { return m_height; }
|
23
|
+
|
24
|
+
void draw(double, double, Color, double, double, Color, //
|
25
|
+
double, double, Color, double, double, Color, //
|
26
|
+
ZPos, BlendMode) const override
|
27
|
+
{
|
28
|
+
}
|
29
|
+
|
30
|
+
GLTexInfo* gl_tex_info() const override { return nullptr; }
|
31
|
+
|
32
|
+
Bitmap to_bitmap() const override { return Bitmap(m_width, m_height); }
|
33
|
+
|
34
|
+
std::unique_ptr<Drawable> subimage(const Rect&) const override { return nullptr; }
|
35
|
+
|
36
|
+
void insert(const Bitmap&, int, int) override { }
|
37
|
+
};
|
38
|
+
}
|
data/src/FPS.cpp
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#include <Gosu/Timing.hpp>
|
2
|
+
#include "GraphicsImpl.hpp"
|
3
|
+
|
4
|
+
namespace Gosu
|
5
|
+
{
|
6
|
+
namespace
|
7
|
+
{
|
8
|
+
int current_fps = 0;
|
9
|
+
}
|
10
|
+
|
11
|
+
void register_frame()
|
12
|
+
{
|
13
|
+
static unsigned long current_second = Gosu::milliseconds() / 1000;
|
14
|
+
static int frames_in_current_second = 0;
|
15
|
+
|
16
|
+
unsigned long new_sec = Gosu::milliseconds() / 1000;
|
17
|
+
if (current_second != new_sec) {
|
18
|
+
current_second = new_sec;
|
19
|
+
current_fps = frames_in_current_second;
|
20
|
+
frames_in_current_second = 0;
|
21
|
+
}
|
22
|
+
else {
|
23
|
+
++frames_in_current_second;
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
int fps()
|
28
|
+
{
|
29
|
+
return current_fps;
|
30
|
+
}
|
31
|
+
}
|