gosu 0.12.1 → 0.13.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 +23 -25
- data/Gosu/Graphics.hpp +16 -12
- data/Gosu/Image.hpp +3 -0
- data/Gosu/Version.hpp +2 -2
- data/lib/gosu.rb +2 -2
- data/lib/gosu/compat.rb +1 -1
- data/lib/gosu/patches.rb +5 -0
- data/lib/gosu/swig_patches.rb +1 -1
- data/rdoc/gosu.rb +10 -10
- data/src/Audio.cpp +93 -228
- data/src/AudioImpl.cpp +94 -0
- data/src/AudioImpl.hpp +33 -0
- data/src/AudioToolboxFile.hpp +14 -18
- data/src/Bitmap.cpp +36 -30
- data/src/BitmapIO.cpp +14 -23
- data/src/BlockAllocator.cpp +7 -10
- data/src/BlockAllocator.hpp +2 -4
- data/src/Channel.cpp +89 -0
- data/src/Color.cpp +4 -9
- data/src/DirectoriesApple.cpp +13 -13
- data/src/DirectoriesUnix.cpp +8 -7
- data/src/DirectoriesWin.cpp +12 -11
- data/src/EmptyImageData.hpp +54 -0
- data/src/FileUnix.cpp +12 -9
- data/src/FileWin.cpp +8 -7
- data/src/Font.cpp +12 -13
- data/src/FormattedString.cpp +237 -0
- data/src/FormattedString.hpp +14 -265
- data/src/GosuViewController.cpp +2 -5
- data/src/Graphics.cpp +38 -39
- data/src/IO.cpp +11 -10
- data/src/Image.cpp +16 -9
- data/src/Input.cpp +16 -15
- data/src/InputUIKit.cpp +8 -7
- data/src/Macro.cpp +11 -11
- data/src/Math.cpp +9 -8
- data/src/RubyGosu.cxx +129 -99
- data/src/TextApple.cpp +19 -13
- data/src/TextInput.cpp +23 -22
- data/src/TextWin.cpp +17 -19
- data/src/Texture.cpp +15 -10
- data/src/Transform.cpp +13 -17
- data/src/Utility.cpp +3 -2
- data/src/UtilityApple.cpp +10 -11
- data/src/UtilityWin.cpp +2 -1
- data/src/Version.cpp +5 -4
- data/src/WinMain.cpp +3 -3
- data/src/WinUtility.cpp +7 -6
- data/src/Window.cpp +11 -10
- data/src/WindowUIKit.cpp +9 -8
- data/src/stb_image.h +782 -480
- data/src/stb_image_write.h +425 -15
- data/src/stb_vorbis.c +82 -32
- metadata +8 -4
- data/src/ALChannelManagement.hpp +0 -119
data/src/AudioImpl.cpp
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
#include "AudioImpl.hpp"
|
2
|
+
#include <stdexcept>
|
3
|
+
#include <string>
|
4
|
+
using namespace std;
|
5
|
+
|
6
|
+
// Per-platform limit for playing OpenAL sources: https://stackoverflow.com/a/3203888
|
7
|
+
#ifdef GOSU_IS_IPHONE
|
8
|
+
static const unsigned CHANNELS = 32;
|
9
|
+
#else
|
10
|
+
static const unsigned CHANNELS = 255;
|
11
|
+
#endif
|
12
|
+
|
13
|
+
static ALCdevice* _device;
|
14
|
+
static ALCcontext* _context;
|
15
|
+
static ALuint _sources[CHANNELS];
|
16
|
+
static int _tokens[CHANNELS];
|
17
|
+
|
18
|
+
void Gosu::al_initialize()
|
19
|
+
{
|
20
|
+
if (_device) return;
|
21
|
+
|
22
|
+
_device = alcOpenDevice(nullptr);
|
23
|
+
_context = alcCreateContext(_device, nullptr);
|
24
|
+
alcMakeContextCurrent(_context);
|
25
|
+
alGenSources(CHANNELS, _sources);
|
26
|
+
}
|
27
|
+
|
28
|
+
bool Gosu::al_initialized()
|
29
|
+
{
|
30
|
+
return _device != nullptr;
|
31
|
+
}
|
32
|
+
|
33
|
+
void Gosu::al_shutdown()
|
34
|
+
{
|
35
|
+
if (_device == nullptr) return;
|
36
|
+
|
37
|
+
alDeleteSources(CHANNELS, _sources);
|
38
|
+
alcMakeContextCurrent(nullptr);
|
39
|
+
alcDestroyContext(_context);
|
40
|
+
_context = nullptr;
|
41
|
+
alcCloseDevice(_device);
|
42
|
+
_device = nullptr;
|
43
|
+
}
|
44
|
+
|
45
|
+
ALCdevice* Gosu::al_device()
|
46
|
+
{
|
47
|
+
al_initialize();
|
48
|
+
|
49
|
+
return _device;
|
50
|
+
}
|
51
|
+
|
52
|
+
ALCcontext* Gosu::al_context()
|
53
|
+
{
|
54
|
+
al_initialize();
|
55
|
+
|
56
|
+
return _context;
|
57
|
+
}
|
58
|
+
|
59
|
+
Gosu::Channel Gosu::allocate_channel()
|
60
|
+
{
|
61
|
+
al_initialize();
|
62
|
+
|
63
|
+
// Start looking at index 1 to keep one free channel for songs.
|
64
|
+
for (int i = 1; i < CHANNELS; ++i) {
|
65
|
+
// Do not interrupt any playing or paused samples.
|
66
|
+
ALint state;
|
67
|
+
alGetSourcei(_sources[i], AL_SOURCE_STATE, &state);
|
68
|
+
if (state == AL_PLAYING || state == AL_PAUSED) continue;
|
69
|
+
|
70
|
+
// Increase the token to invalidate the last playing Channel with this index.
|
71
|
+
return Channel(i, ++_tokens[i]);
|
72
|
+
}
|
73
|
+
|
74
|
+
// No free channel, return an object that is immediately expired.
|
75
|
+
return Channel(NO_CHANNEL, 0);
|
76
|
+
}
|
77
|
+
|
78
|
+
bool Gosu::channel_expired(int channel, int token)
|
79
|
+
{
|
80
|
+
return channel < 0 || channel >= CHANNELS || _tokens[channel] != token;
|
81
|
+
}
|
82
|
+
|
83
|
+
ALuint Gosu::al_source_for_channel(int channel)
|
84
|
+
{
|
85
|
+
if (channel <= 0 || channel >= CHANNELS) {
|
86
|
+
throw invalid_argument("No such channel: " + to_string(channel));
|
87
|
+
}
|
88
|
+
return _sources[channel];
|
89
|
+
}
|
90
|
+
|
91
|
+
ALuint Gosu::al_source_for_songs()
|
92
|
+
{
|
93
|
+
return _sources[0];
|
94
|
+
}
|
data/src/AudioImpl.hpp
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include <Gosu/Audio.hpp>
|
4
|
+
#include <Gosu/Platform.hpp>
|
5
|
+
#ifdef GOSU_IS_MAC
|
6
|
+
#include <OpenAL/al.h>
|
7
|
+
#include <OpenAL/alc.h>
|
8
|
+
#else
|
9
|
+
#include <AL/al.h>
|
10
|
+
#include <AL/alc.h>
|
11
|
+
#endif
|
12
|
+
|
13
|
+
namespace Gosu
|
14
|
+
{
|
15
|
+
void al_initialize();
|
16
|
+
bool al_initialized();
|
17
|
+
void al_shutdown();
|
18
|
+
|
19
|
+
// Will initialize OpenAL if necessary.
|
20
|
+
ALCdevice* al_device();
|
21
|
+
// Will initialize OpenAL if necessary.
|
22
|
+
ALCcontext* al_context();
|
23
|
+
|
24
|
+
const int NO_CHANNEL = -1;
|
25
|
+
|
26
|
+
// Returns an expired Channel if no channel is free.
|
27
|
+
// Will initialize OpenAL if necessary.
|
28
|
+
Channel allocate_channel();
|
29
|
+
|
30
|
+
bool channel_expired(int channel, int token);
|
31
|
+
ALuint al_source_for_channel(int channel);
|
32
|
+
ALuint al_source_for_songs();
|
33
|
+
}
|
data/src/AudioToolboxFile.hpp
CHANGED
@@ -33,7 +33,7 @@ namespace Gosu
|
|
33
33
|
{
|
34
34
|
class AudioToolboxFile : public AudioFile
|
35
35
|
{
|
36
|
-
|
36
|
+
Buffer buffer_;
|
37
37
|
AudioFileID file_id_;
|
38
38
|
ExtAudioFileRef file_;
|
39
39
|
SInt64 position_;
|
@@ -45,10 +45,11 @@ namespace Gosu
|
|
45
45
|
bool big_endian_;
|
46
46
|
|
47
47
|
static OSStatus AudioFile_ReadProc(void* in_client_data, SInt64 in_position,
|
48
|
-
|
48
|
+
UInt32 request_count, void* buffer, UInt32* actual_count)
|
49
49
|
{
|
50
50
|
const Resource& res = *static_cast<Resource*>(in_client_data);
|
51
|
-
*actual_count = std::min<UInt32>(request_count,
|
51
|
+
*actual_count = std::min<UInt32>(request_count,
|
52
|
+
static_cast<UInt32>(res.size() - in_position));
|
52
53
|
res.read(in_position, *actual_count, buffer);
|
53
54
|
return noErr;
|
54
55
|
}
|
@@ -81,7 +82,9 @@ namespace Gosu
|
|
81
82
|
AudioStreamBasicDescription client_data = { 0 };
|
82
83
|
sample_rate_ = client_data.mSampleRate = 22050;
|
83
84
|
client_data.mFormatID = kAudioFormatLinearPCM;
|
84
|
-
client_data.mFormatFlags = kAudioFormatFlagIsSignedInteger |
|
85
|
+
client_data.mFormatFlags = kAudioFormatFlagIsSignedInteger |
|
86
|
+
kAudioFormatFlagsNativeEndian |
|
87
|
+
kAudioFormatFlagIsPacked;
|
85
88
|
client_data.mBitsPerChannel = 16;
|
86
89
|
client_data.mChannelsPerFrame = base.mChannelsPerFrame;
|
87
90
|
client_data.mFramesPerPacket = 1;
|
@@ -119,22 +122,15 @@ namespace Gosu
|
|
119
122
|
|
120
123
|
// Easy formats
|
121
124
|
format_ = 0;
|
122
|
-
if (desc.mChannelsPerFrame == 1) {
|
123
|
-
|
124
|
-
format_ = AL_FORMAT_MONO8;
|
125
|
-
else*/ if (desc.mBitsPerChannel == 16)
|
126
|
-
format_ = AL_FORMAT_MONO16;
|
125
|
+
if (desc.mChannelsPerFrame == 1 && desc.mBitsPerChannel == 16) {
|
126
|
+
format_ = AL_FORMAT_MONO16;
|
127
127
|
}
|
128
|
-
else if (desc.mChannelsPerFrame == 2) {
|
129
|
-
|
130
|
-
format_ = AL_FORMAT_STEREO8;
|
131
|
-
else */if (desc.mBitsPerChannel == 16)
|
132
|
-
format_ = AL_FORMAT_STEREO16;
|
128
|
+
else if (desc.mChannelsPerFrame == 2 && desc.mBitsPerChannel == 16) {
|
129
|
+
format_ = AL_FORMAT_STEREO16;
|
133
130
|
}
|
134
131
|
|
135
132
|
if (format_ == 0 ||
|
136
|
-
// If format not native for OpenAL, set client data format
|
137
|
-
// to enable conversion
|
133
|
+
// If format not native for OpenAL, set client data format to enable conversion
|
138
134
|
desc.mFormatFlags & kAudioFormatFlagIsBigEndian ||
|
139
135
|
desc.mFormatFlags & kAudioFormatFlagIsFloat ||
|
140
136
|
!(desc.mFormatFlags & kAudioFormatFlagIsSignedInteger)) {
|
@@ -159,7 +155,7 @@ namespace Gosu
|
|
159
155
|
init();
|
160
156
|
}
|
161
157
|
|
162
|
-
AudioToolboxFile(
|
158
|
+
AudioToolboxFile(Reader reader)
|
163
159
|
{
|
164
160
|
buffer_.resize(reader.resource().size() - reader.position());
|
165
161
|
reader.read(buffer_.data(), buffer_.size());
|
@@ -204,7 +200,7 @@ namespace Gosu
|
|
204
200
|
AudioBufferList abl;
|
205
201
|
abl.mNumberBuffers = 1;
|
206
202
|
abl.mBuffers[0].mNumberChannels = 1;
|
207
|
-
abl.mBuffers[0].mDataByteSize = length;
|
203
|
+
abl.mBuffers[0].mDataByteSize = static_cast<UInt32>(length);
|
208
204
|
abl.mBuffers[0].mData = dest;
|
209
205
|
UInt32 numFrames = 0xffffffff; // give us as many frames as possible given our buffer
|
210
206
|
CHECK_OS(ExtAudioFileRead(file_, &numFrames, &abl));
|
data/src/Bitmap.cpp
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
#include <Gosu/Bitmap.hpp>
|
2
2
|
#include <cassert>
|
3
3
|
#include <algorithm>
|
4
|
-
#include <vector>
|
4
|
+
#include <vector>
|
5
|
+
using namespace std;
|
5
6
|
|
6
7
|
void Gosu::Bitmap::swap(Bitmap& other)
|
7
8
|
{
|
@@ -26,15 +27,14 @@ void Gosu::Bitmap::insert(const Bitmap& source, int x, int y)
|
|
26
27
|
}
|
27
28
|
|
28
29
|
void Gosu::Bitmap::insert(const Bitmap& source, int x, int y, unsigned src_x, unsigned src_y,
|
29
|
-
|
30
|
+
unsigned src_width, unsigned src_height)
|
30
31
|
{
|
31
32
|
// TODO: This should use memcpy if possible (x == 0 && src_width == this->width())
|
32
33
|
|
33
34
|
if (x < 0) {
|
34
35
|
unsigned clip_left = -x;
|
35
36
|
|
36
|
-
if (clip_left >= src_width)
|
37
|
-
return;
|
37
|
+
if (clip_left >= src_width) return;
|
38
38
|
|
39
39
|
src_x += clip_left;
|
40
40
|
src_width -= clip_left;
|
@@ -44,8 +44,7 @@ void Gosu::Bitmap::insert(const Bitmap& source, int x, int y, unsigned src_x, un
|
|
44
44
|
if (y < 0) {
|
45
45
|
unsigned clip_top = -y;
|
46
46
|
|
47
|
-
if (clip_top >= src_height)
|
48
|
-
return;
|
47
|
+
if (clip_top >= src_height) return;
|
49
48
|
|
50
49
|
src_y += clip_top;
|
51
50
|
src_height -= clip_top;
|
@@ -53,27 +52,27 @@ void Gosu::Bitmap::insert(const Bitmap& source, int x, int y, unsigned src_x, un
|
|
53
52
|
}
|
54
53
|
|
55
54
|
if (x + src_width > w) {
|
56
|
-
if (static_cast<unsigned>(x) >= w)
|
57
|
-
return;
|
55
|
+
if (static_cast<unsigned>(x) >= w) return;
|
58
56
|
|
59
57
|
src_width = w - x;
|
60
58
|
}
|
61
59
|
|
62
60
|
if (y + src_height > h) {
|
63
|
-
if (static_cast<unsigned>(y) >= h)
|
64
|
-
return;
|
61
|
+
if (static_cast<unsigned>(y) >= h) return;
|
65
62
|
|
66
63
|
src_height = h - y;
|
67
64
|
}
|
68
65
|
|
69
|
-
for (unsigned rel_y = 0; rel_y < src_height; ++rel_y)
|
70
|
-
for (unsigned rel_x = 0; rel_x < src_width; ++rel_x)
|
71
|
-
set_pixel(x + rel_x, y + rel_y, source.get_pixel(src_x + rel_x, src_y + rel_y));
|
66
|
+
for (unsigned rel_y = 0; rel_y < src_height; ++rel_y) {
|
67
|
+
for (unsigned rel_x = 0; rel_x < src_width; ++rel_x) {
|
68
|
+
set_pixel(x + rel_x, y + rel_y, source.get_pixel(src_x + rel_x, src_y + rel_y));
|
69
|
+
}
|
70
|
+
}
|
72
71
|
}
|
73
72
|
|
74
73
|
void Gosu::apply_color_key(Bitmap& bitmap, Color key)
|
75
74
|
{
|
76
|
-
|
75
|
+
vector<Color> surrounding_colors;
|
77
76
|
surrounding_colors.reserve(4);
|
78
77
|
|
79
78
|
for (unsigned y = 0; y < bitmap.height(); ++y)
|
@@ -96,31 +95,35 @@ void Gosu::apply_color_key(Bitmap& bitmap, Color key)
|
|
96
95
|
|
97
96
|
unsigned red = 0, green = 0, blue = 0;
|
98
97
|
for (auto& color : surrounding_colors) {
|
99
|
-
red
|
98
|
+
red += color.red();
|
100
99
|
green += color.green();
|
101
|
-
blue
|
100
|
+
blue += color.blue();
|
102
101
|
}
|
103
|
-
bitmap.set_pixel(x, y, Color(0,
|
104
|
-
|
102
|
+
bitmap.set_pixel(x, y, Color(0,
|
103
|
+
red / surrounding_colors.size(),
|
104
|
+
green / surrounding_colors.size(),
|
105
|
+
blue / surrounding_colors.size()));
|
105
106
|
}
|
106
107
|
}
|
107
108
|
|
108
109
|
void Gosu::unapply_color_key(Bitmap& bitmap, Color color)
|
109
110
|
{
|
110
111
|
Color* p = bitmap.data();
|
111
|
-
for (int i = bitmap.width() * bitmap.height(); i > 0; --i, ++p)
|
112
|
-
if (p->alpha() == 0)
|
113
|
-
*p = color;
|
114
|
-
|
115
|
-
|
112
|
+
for (int i = bitmap.width() * bitmap.height(); i > 0; --i, ++p) {
|
113
|
+
if (p->alpha() == 0) {
|
114
|
+
*p = color;
|
115
|
+
}
|
116
|
+
else {
|
117
|
+
p->set_alpha(255);
|
118
|
+
}
|
119
|
+
}
|
116
120
|
}
|
117
121
|
|
118
122
|
void Gosu::apply_border_flags(Bitmap& dest, const Bitmap& source, unsigned src_x, unsigned src_y,
|
119
|
-
|
123
|
+
unsigned src_width, unsigned src_height, unsigned image_flags)
|
120
124
|
{
|
121
125
|
// Backward compatibility: This used to be 'bool tileable'.
|
122
|
-
if (image_flags == 1)
|
123
|
-
image_flags = IF_TILEABLE;
|
126
|
+
if (image_flags == 1) image_flags = IF_TILEABLE;
|
124
127
|
|
125
128
|
dest.resize(src_width + 2, src_height + 2);
|
126
129
|
|
@@ -142,17 +145,20 @@ void Gosu::apply_border_flags(Bitmap& dest, const Bitmap& source, unsigned src_x
|
|
142
145
|
|
143
146
|
// Top left.
|
144
147
|
if ((image_flags & IF_TILEABLE_TOP) && (image_flags & IF_TILEABLE_LEFT))
|
145
|
-
dest.set_pixel(0, 0,
|
148
|
+
dest.set_pixel(0, 0,
|
149
|
+
source.get_pixel(src_x, src_y));
|
146
150
|
// Top right.
|
147
151
|
if ((image_flags & IF_TILEABLE_TOP) && (image_flags & IF_TILEABLE_RIGHT))
|
148
|
-
dest.set_pixel(dest.width() - 1, 0,
|
152
|
+
dest.set_pixel(dest.width() - 1, 0,
|
153
|
+
source.get_pixel(src_x + src_width - 1, src_y));
|
149
154
|
// Bottom left.
|
150
155
|
if ((image_flags & IF_TILEABLE_BOTTOM) && (image_flags & IF_TILEABLE_LEFT))
|
151
|
-
dest.set_pixel(0, dest.height() - 1,
|
156
|
+
dest.set_pixel(0, dest.height() - 1,
|
157
|
+
source.get_pixel(src_x, src_y + src_height - 1));
|
152
158
|
// Bottom right.
|
153
159
|
if ((image_flags & IF_TILEABLE_BOTTOM) && (image_flags & IF_TILEABLE_RIGHT))
|
154
160
|
dest.set_pixel(dest.width() - 1, dest.height() - 1,
|
155
|
-
|
161
|
+
source.get_pixel(src_x + src_width - 1, src_y + src_height - 1));
|
156
162
|
|
157
163
|
// Now put the final image into the prepared borders.
|
158
164
|
dest.insert(source, 1, 1, src_x, src_y, src_width, src_height);
|
data/src/BitmapIO.cpp
CHANGED
@@ -9,21 +9,17 @@
|
|
9
9
|
#define STBI_NO_STDIO
|
10
10
|
#define STBI_NO_LINEAR
|
11
11
|
|
12
|
-
// Work around this bug:
|
13
|
-
// https://bugs.launchpad.net/ubuntu/+source/gcc-5/+bug/1568899
|
14
|
-
#ifdef GOSU_IS_X
|
15
|
-
#define STBI_NO_SIMD
|
16
|
-
#endif
|
17
|
-
|
18
12
|
#include "stb_image.h"
|
19
13
|
|
14
|
+
using namespace std;
|
15
|
+
|
20
16
|
namespace
|
21
17
|
{
|
22
18
|
int read_callback(void* user, char* data, int size)
|
23
19
|
{
|
24
20
|
Gosu::Reader* reader = static_cast<Gosu::Reader*>(user);
|
25
|
-
|
26
|
-
|
21
|
+
size_t remaining = reader->resource().size() - reader->position();
|
22
|
+
size_t actual_size = (size < remaining ? size : remaining);
|
27
23
|
reader->read(data, actual_size);
|
28
24
|
return static_cast<int>(actual_size);
|
29
25
|
}
|
@@ -42,18 +38,15 @@ namespace
|
|
42
38
|
|
43
39
|
bool is_bmp(Gosu::Reader reader)
|
44
40
|
{
|
45
|
-
|
46
|
-
if (remaining < 2)
|
47
|
-
return false;
|
48
|
-
}
|
41
|
+
size_t remaining = reader.resource().size() - reader.position();
|
42
|
+
if (remaining < 2) return false;
|
49
43
|
char magic_bytes[2];
|
50
44
|
reader.read(magic_bytes, sizeof magic_bytes);
|
51
|
-
reader.seek(sizeof magic_bytes);
|
52
45
|
return magic_bytes[0] == 'B' && magic_bytes[1] == 'M';
|
53
46
|
}
|
54
47
|
}
|
55
48
|
|
56
|
-
void Gosu::load_image_file(Gosu::Bitmap& bitmap, const
|
49
|
+
void Gosu::load_image_file(Gosu::Bitmap& bitmap, const string& filename)
|
57
50
|
{
|
58
51
|
Buffer buffer;
|
59
52
|
load_file(buffer, filename);
|
@@ -74,11 +67,11 @@ void Gosu::load_image_file(Gosu::Bitmap& bitmap, Reader input)
|
|
74
67
|
if (bytes == nullptr) {
|
75
68
|
// TODO - stbi_failure_reason is not thread safe. Everything here should be wrapped in a
|
76
69
|
// mutex.
|
77
|
-
throw
|
70
|
+
throw runtime_error("Cannot load image: " + string(stbi_failure_reason()));
|
78
71
|
}
|
79
72
|
|
80
73
|
bitmap.resize(x, y);
|
81
|
-
|
74
|
+
memcpy(bitmap.data(), bytes, x * y * sizeof(Gosu::Color));
|
82
75
|
|
83
76
|
stbi_image_free(bytes);
|
84
77
|
|
@@ -90,7 +83,7 @@ void Gosu::load_image_file(Gosu::Bitmap& bitmap, Reader input)
|
|
90
83
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
91
84
|
#include "stb_image_write.h"
|
92
85
|
|
93
|
-
void Gosu::save_image_file(const Gosu::Bitmap& bitmap, const
|
86
|
+
void Gosu::save_image_file(const Gosu::Bitmap& bitmap, const string& filename)
|
94
87
|
{
|
95
88
|
int ok;
|
96
89
|
|
@@ -104,9 +97,7 @@ void Gosu::save_image_file(const Gosu::Bitmap& bitmap, const std::string& filena
|
|
104
97
|
ok = stbi_write_png(filename.c_str(), bitmap.width(), bitmap.height(), 4, bitmap.data(), 0);
|
105
98
|
}
|
106
99
|
|
107
|
-
if (ok == 0)
|
108
|
-
throw std::runtime_error("Could not save image data to file: " + filename);
|
109
|
-
}
|
100
|
+
if (ok == 0) throw runtime_error("Could not save image data to file: " + filename);
|
110
101
|
}
|
111
102
|
|
112
103
|
static void stbi_write_to_writer(void* context, void* data, int size)
|
@@ -116,7 +107,7 @@ static void stbi_write_to_writer(void* context, void* data, int size)
|
|
116
107
|
}
|
117
108
|
|
118
109
|
void Gosu::save_image_file(const Gosu::Bitmap& bitmap, Gosu::Writer writer,
|
119
|
-
const
|
110
|
+
const string& format_hint)
|
120
111
|
{
|
121
112
|
int ok;
|
122
113
|
|
@@ -135,7 +126,7 @@ void Gosu::save_image_file(const Gosu::Bitmap& bitmap, Gosu::Writer writer,
|
|
135
126
|
}
|
136
127
|
|
137
128
|
if (ok == 0) {
|
138
|
-
throw
|
139
|
-
|
129
|
+
throw runtime_error("Could not save image data to memory (format hint = '" +
|
130
|
+
format_hint + "'");
|
140
131
|
}
|
141
132
|
}
|