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.
Files changed (170) hide show
  1. checksums.yaml +4 -4
  2. data/COPYING +2 -1
  3. data/dependencies/SDL/include/SDL_atomic.h +2 -3
  4. data/dependencies/SDL/include/SDL_audio.h +7 -7
  5. data/dependencies/SDL/include/SDL_blendmode.h +1 -1
  6. data/dependencies/SDL/include/SDL_endian.h +3 -3
  7. data/dependencies/SDL/include/SDL_gamecontroller.h +4 -4
  8. data/dependencies/SDL/include/SDL_hints.h +72 -28
  9. data/dependencies/SDL/include/SDL_joystick.h +8 -5
  10. data/dependencies/SDL/include/SDL_keycode.h +1 -1
  11. data/dependencies/SDL/include/SDL_main.h +7 -0
  12. data/dependencies/SDL/include/SDL_mouse.h +6 -7
  13. data/dependencies/SDL/include/SDL_mutex.h +79 -5
  14. data/dependencies/SDL/include/SDL_opengl_glext.h +5 -1
  15. data/dependencies/SDL/include/SDL_power.h +7 -8
  16. data/dependencies/SDL/include/SDL_render.h +5 -0
  17. data/dependencies/SDL/include/SDL_revision.h +2 -2
  18. data/dependencies/SDL/include/SDL_sensor.h +1 -1
  19. data/dependencies/SDL/include/SDL_stdinc.h +19 -11
  20. data/dependencies/SDL/include/SDL_thread.h +2 -2
  21. data/dependencies/SDL/include/SDL_version.h +2 -2
  22. data/dependencies/SDL/include/SDL_video.h +30 -2
  23. data/dependencies/SDL/include/begin_code.h +7 -7
  24. data/dependencies/SDL/include/close_code.h +2 -2
  25. data/dependencies/SDL/lib/x64/libSDL2.dll.a +0 -0
  26. data/dependencies/SDL/lib/x86/libSDL2.dll.a +0 -0
  27. data/dependencies/SDL_sound/SDL_sound.h +1 -1
  28. data/dependencies/SDL_sound/dr_flac.h +48 -23
  29. data/dependencies/SDL_sound/dr_mp3.h +34 -14
  30. data/dependencies/SDL_sound/stb_vorbis.h +3 -2
  31. data/dependencies/mojoAL/mojoal.c +1 -1
  32. data/ext/{gosu → gosu-ffi}/extconf.rb +34 -33
  33. data/ext/gosu-ffi/gosu-ffi.def +464 -0
  34. data/ffi/Gosu.cpp +307 -0
  35. data/ffi/Gosu.h +84 -0
  36. data/ffi/Gosu_Channel.cpp +62 -0
  37. data/ffi/Gosu_Channel.h +17 -0
  38. data/ffi/Gosu_Color.cpp +132 -0
  39. data/ffi/Gosu_Color.h +31 -0
  40. data/ffi/Gosu_Constants.cpp +334 -0
  41. data/ffi/Gosu_FFI.h +34 -0
  42. data/ffi/Gosu_FFI_internal.h +161 -0
  43. data/ffi/Gosu_Font.cpp +92 -0
  44. data/ffi/Gosu_Font.h +32 -0
  45. data/ffi/Gosu_Image.cpp +206 -0
  46. data/ffi/Gosu_Image.h +60 -0
  47. data/ffi/Gosu_Sample.cpp +29 -0
  48. data/ffi/Gosu_Sample.h +14 -0
  49. data/ffi/Gosu_Song.cpp +69 -0
  50. data/ffi/Gosu_Song.h +18 -0
  51. data/ffi/Gosu_TextInput.cpp +94 -0
  52. data/ffi/Gosu_TextInput.h +25 -0
  53. data/ffi/Gosu_Window.cpp +314 -0
  54. data/ffi/Gosu_Window.h +78 -0
  55. data/include/Gosu/Audio.hpp +6 -11
  56. data/include/Gosu/Bitmap.hpp +38 -53
  57. data/include/Gosu/Buffer.hpp +54 -0
  58. data/include/Gosu/Color.hpp +27 -35
  59. data/include/Gosu/Directories.hpp +25 -28
  60. data/include/Gosu/Drawable.hpp +58 -0
  61. data/include/Gosu/Font.hpp +6 -5
  62. data/include/Gosu/Fwd.hpp +4 -6
  63. data/include/Gosu/Gosu.hpp +5 -5
  64. data/include/Gosu/Graphics.hpp +51 -61
  65. data/include/Gosu/GraphicsBase.hpp +1 -11
  66. data/include/Gosu/Image.hpp +11 -14
  67. data/include/Gosu/Math.hpp +50 -72
  68. data/include/Gosu/Transform.hpp +32 -0
  69. data/include/Gosu/Utility.hpp +51 -1
  70. data/include/Gosu/Version.hpp +3 -3
  71. data/include/Gosu/Window.hpp +15 -9
  72. data/lib/SDL2.dll +0 -0
  73. data/lib/gosu/channel.rb +49 -0
  74. data/lib/gosu/color.rb +150 -0
  75. data/lib/gosu/compat.rb +29 -8
  76. data/lib/gosu/constants.rb +386 -0
  77. data/lib/gosu/ffi.rb +258 -0
  78. data/lib/gosu/font.rb +56 -0
  79. data/lib/gosu/gl_tex_info.rb +33 -0
  80. data/lib/gosu/gosu.rb +210 -0
  81. data/lib/gosu/image.rb +141 -0
  82. data/lib/gosu/numeric.rb +17 -0
  83. data/lib/gosu/preview.rb +6 -6
  84. data/lib/gosu/sample.rb +24 -0
  85. data/lib/gosu/song.rb +56 -0
  86. data/lib/gosu/text_input.rb +69 -0
  87. data/lib/gosu/window.rb +228 -0
  88. data/lib/gosu.rb +29 -8
  89. data/lib64/SDL2.dll +0 -0
  90. data/rdoc/gosu.rb +0 -2
  91. data/src/Audio.cpp +12 -12
  92. data/src/AudioFile.hpp +5 -4
  93. data/src/AudioFileAudioToolbox.cpp +8 -8
  94. data/src/AudioFileSDLSound.cpp +7 -10
  95. data/src/BinPacker.cpp +187 -0
  96. data/src/BinPacker.hpp +55 -0
  97. data/src/Bitmap.cpp +166 -144
  98. data/src/BitmapIO.cpp +60 -86
  99. data/src/Buffer.cpp +159 -0
  100. data/src/Color.cpp +75 -80
  101. data/src/Directories.cpp +47 -0
  102. data/src/DirectoriesUIKit.cpp +50 -0
  103. data/src/DrawOp.hpp +9 -4
  104. data/src/DrawOpQueue.hpp +2 -2
  105. data/src/Drawable.cpp +95 -0
  106. data/src/EmptyDrawable.hpp +38 -0
  107. data/src/FPS.cpp +31 -0
  108. data/src/Font.cpp +104 -74
  109. data/src/GosuGLView.cpp +14 -6
  110. data/src/GosuViewController.cpp +2 -10
  111. data/src/Graphics.cpp +60 -126
  112. data/src/GraphicsImpl.hpp +17 -47
  113. data/src/Image.cpp +41 -35
  114. data/src/Input.cpp +7 -8
  115. data/src/Macro.cpp +6 -6
  116. data/src/Macro.hpp +4 -4
  117. data/src/MarkupParser.cpp +5 -5
  118. data/src/Math.cpp +35 -22
  119. data/src/OffScreenTarget.cpp +53 -49
  120. data/src/OffScreenTarget.hpp +13 -11
  121. data/src/OpenGLContext.cpp +117 -0
  122. data/src/OpenGLContext.hpp +41 -0
  123. data/src/RenderState.hpp +21 -19
  124. data/src/Resolution.cpp +23 -21
  125. data/src/TexChunk.cpp +35 -80
  126. data/src/TexChunk.hpp +44 -35
  127. data/src/Text.cpp +1 -1
  128. data/src/TextBuilder.cpp +35 -21
  129. data/src/TextBuilder.hpp +6 -9
  130. data/src/Texture.cpp +62 -80
  131. data/src/Texture.hpp +25 -23
  132. data/src/TiledDrawable.cpp +150 -0
  133. data/src/TiledDrawable.hpp +47 -0
  134. data/src/TimingApple.cpp +1 -1
  135. data/src/Transform.cpp +45 -50
  136. data/src/TransformStack.hpp +16 -16
  137. data/src/TrueTypeFont.cpp +59 -51
  138. data/src/TrueTypeFont.hpp +6 -7
  139. data/src/TrueTypeFontApple.cpp +28 -19
  140. data/src/TrueTypeFontUnix.cpp +27 -23
  141. data/src/TrueTypeFontWin.cpp +30 -30
  142. data/src/Utility.cpp +84 -21
  143. data/src/UtilityWin.cpp +45 -0
  144. data/src/Window.cpp +92 -142
  145. data/src/WindowUIKit.cpp +14 -14
  146. metadata +72 -31
  147. data/include/Gosu/IO.hpp +0 -254
  148. data/include/Gosu/ImageData.hpp +0 -53
  149. data/include/Gosu/Inspection.hpp +0 -7
  150. data/lib/gosu/patches.rb +0 -66
  151. data/lib/gosu/run.rb +0 -20
  152. data/lib/gosu/swig_patches.rb +0 -110
  153. data/src/BlockAllocator.cpp +0 -131
  154. data/src/BlockAllocator.hpp +0 -32
  155. data/src/DirectoriesApple.cpp +0 -69
  156. data/src/DirectoriesUnix.cpp +0 -46
  157. data/src/DirectoriesWin.cpp +0 -65
  158. data/src/EmptyImageData.hpp +0 -52
  159. data/src/FileUnix.cpp +0 -99
  160. data/src/FileWin.cpp +0 -88
  161. data/src/IO.cpp +0 -60
  162. data/src/Iconv.hpp +0 -51
  163. data/src/Inspection.cpp +0 -27
  164. data/src/LargeImageData.cpp +0 -215
  165. data/src/LargeImageData.hpp +0 -39
  166. data/src/Log.hpp +0 -19
  167. data/src/RubyGosu.cxx +0 -13100
  168. data/src/RubyGosu.h +0 -49
  169. data/src/WinUtility.cpp +0 -61
  170. data/src/WinUtility.hpp +0 -27
data/src/Input.cpp CHANGED
@@ -8,21 +8,20 @@
8
8
  #include <SDL.h>
9
9
  #include <utf8proc.h>
10
10
 
11
- #include <cwctype>
12
11
  #include <cstdlib>
13
12
  #include <algorithm>
14
13
  #include <array>
15
- #include <mutex>
16
14
  #include <stdexcept>
17
15
  using namespace std;
18
16
 
19
17
  static void require_sdl_video()
20
18
  {
21
- static std::once_flag initialized;
22
-
23
- std::call_once(initialized, [] {
24
- SDL_InitSubSystem(SDL_INIT_VIDEO);
25
- });
19
+ // Don't bother shutting down the SDL video subsystem because OpenGLContext.cpp keeps it alive
20
+ // forever as well, and it is hard to know when to free things in a Ruby C extension.
21
+ static const int initialized = SDL_Init(SDL_INIT_VIDEO);
22
+ if (initialized < 0) {
23
+ throw std::runtime_error(SDL_GetError());
24
+ }
26
25
  }
27
26
 
28
27
  static const unsigned NUM_BUTTONS_PER_GAMEPAD =
@@ -602,7 +601,7 @@ bool Gosu::Input::down(Gosu::Button btn)
602
601
 
603
602
  double Gosu::Input::axis(Gosu::Button btn)
604
603
  {
605
- unsigned axis_id = btn - GP_LEFT_STICK_X_AXIS;
604
+ unsigned axis_id = btn - static_cast<unsigned>(GP_LEFT_STICK_X_AXIS);
606
605
 
607
606
  if (axis_id >= axis_states.size()) {
608
607
  throw std::out_of_range("Invalid axis ID: " + std::to_string(btn));
data/src/Macro.cpp CHANGED
@@ -132,7 +132,7 @@ struct Gosu::Macro::Impl : private Gosu::Noncopyable
132
132
  for (const auto& vertex_array : vertex_arrays) {
133
133
  glPushMatrix();
134
134
  vertex_array.render_state.apply();
135
- glMultMatrixd(&transform[0]);
135
+ glMultMatrixd(transform.matrix.data());
136
136
  glInterleavedArrays(GL_T2F_C4UB_V3F, 0, &vertex_array.vertices[0]);
137
137
  glDrawArrays(GL_QUADS, 0, (GLsizei) vertex_array.vertices.size());
138
138
  glPopMatrix();
@@ -169,7 +169,7 @@ void Gosu::Macro::draw(double x1, double y1, Color c1, double x2, double y2, Col
169
169
 
170
170
  normalize_coordinates(x1, y1, x2, y2, x3, y3, c3, x4, y4, c4);
171
171
 
172
- Gosu::Graphics::gl(z, [=] { pimpl->draw_vertex_arrays(x1, y1, x2, y2, x3, y3, x4, y4); });
172
+ Gosu::gl(z, [=, this] { pimpl->draw_vertex_arrays(x1, y1, x2, y2, x3, y3, x4, y4); });
173
173
  }
174
174
 
175
175
  const Gosu::GLTexInfo* Gosu::Macro::gl_tex_info() const
@@ -184,15 +184,15 @@ Gosu::Bitmap Gosu::Macro::to_bitmap() const
184
184
  pimpl->width, pimpl->height, Color::WHITE, 0, BM_DEFAULT);
185
185
  };
186
186
 
187
- return Gosu::Graphics::render(pimpl->width, pimpl->height, render_this).data().to_bitmap();
187
+ return Gosu::render(pimpl->width, pimpl->height, render_this).drawable().to_bitmap();
188
188
  }
189
189
 
190
- std::unique_ptr<Gosu::ImageData> Gosu::Macro::subimage(int x, int y, int width, int height) const
190
+ std::unique_ptr<Gosu::Drawable> Gosu::Macro::subimage(const Rect&) const
191
191
  {
192
- return std::unique_ptr<ImageData>{};
192
+ return nullptr;
193
193
  }
194
194
 
195
- void Gosu::Macro::insert(const Bitmap& bitmap, int x, int y)
195
+ void Gosu::Macro::insert(const Bitmap&, int, int)
196
196
  {
197
197
  throw std::logic_error{"Gosu::Macro cannot be updated with a Gosu::Bitmap yet"};
198
198
  }
data/src/Macro.hpp CHANGED
@@ -1,11 +1,11 @@
1
1
  #pragma once
2
2
 
3
3
  #include <Gosu/Fwd.hpp>
4
- #include <Gosu/ImageData.hpp>
4
+ #include <Gosu/Drawable.hpp>
5
5
  #include "GraphicsImpl.hpp"
6
6
  #include <memory>
7
7
 
8
- class Gosu::Macro : public Gosu::ImageData
8
+ class Gosu::Macro : public Gosu::Drawable
9
9
  {
10
10
  struct Impl;
11
11
  std::shared_ptr<Impl> pimpl;
@@ -24,7 +24,7 @@ public:
24
24
 
25
25
  Gosu::Bitmap to_bitmap() const override;
26
26
 
27
- std::unique_ptr<ImageData> subimage(int x, int y, int width, int height) const override;
27
+ std::unique_ptr<Drawable> subimage(const Rect&) const override;
28
28
 
29
- void insert(const Bitmap& bitmap, int x, int y) override;
29
+ void insert(const Bitmap&, int x, int y) override;
30
30
  };
data/src/MarkupParser.cpp CHANGED
@@ -157,29 +157,29 @@ void Gosu::MarkupParser::add_current_substring()
157
157
  void Gosu::MarkupParser::add_composed_substring(u32string&& substring)
158
158
  {
159
159
  FormattedString fstr;
160
- fstr.text = substring;
160
+ fstr.text = std::move(substring);
161
161
  fstr.flags = flags();
162
162
  fstr.color = c.back();
163
163
 
164
164
  if (!substrings.empty() && substrings.back().can_be_merged_with(fstr)) {
165
- substrings.back().text.append(move(fstr.text));
165
+ substrings.back().text.append(fstr.text);
166
166
  }
167
167
  else {
168
- substrings.emplace_back(move(fstr));
168
+ substrings.emplace_back(std::move(fstr));
169
169
  }
170
170
  }
171
171
 
172
172
  void Gosu::MarkupParser::flush_to_consumer()
173
173
  {
174
174
  if (!substrings.empty()) {
175
- consumer(move(substrings));
175
+ consumer(std::move(substrings));
176
176
  substrings.clear();
177
177
  }
178
178
  }
179
179
 
180
180
  Gosu::MarkupParser::MarkupParser(unsigned base_flags, bool split_words,
181
181
  function<void (vector<FormattedString>)> consumer)
182
- : consumer(move(consumer))
182
+ : consumer(std::move(consumer))
183
183
  {
184
184
  word_state = (split_words ? ADDING_WORD : IGNORE_WORDS);
185
185
 
data/src/Math.cpp CHANGED
@@ -1,38 +1,55 @@
1
1
  #include <Gosu/Math.hpp>
2
- #include <cstdlib>
3
- using namespace std;
2
+ #include <cmath>
3
+ #include <limits> // for std::numeric_limits::quiet_NaN
4
+ #include <random>
4
5
 
5
6
  double Gosu::random(double min, double max)
6
7
  {
7
- double rnd = rand();
8
- return rnd / (static_cast<double>(RAND_MAX) + 1) * (max - min) + min;
8
+ if (std::isnan(min) || std::isnan(max)) {
9
+ return std::numeric_limits<double>::quiet_NaN();
10
+ }
11
+
12
+ if (min == max) {
13
+ return min;
14
+ }
15
+
16
+ thread_local std::mt19937_64 generator(std::random_device {}());
17
+ std::uniform_real_distribution<double> distribution(min, max);
18
+ const double result = distribution(generator);
19
+ // Make sure that we do not return "max" even when uniform_real_distribution is buggy.
20
+ // See "Notes": https://en.cppreference.com/w/cpp/numeric/random/uniform_real_distribution
21
+ return result == max ? min : result;
9
22
  }
10
23
 
11
24
  double Gosu::offset_x(double angle, double radius)
12
25
  {
13
- return +sin(angle / 180 * M_PI) * radius;
26
+ return +std::sin(angle / 180 * std::numbers::pi) * radius;
14
27
  }
15
28
 
16
29
  double Gosu::offset_y(double angle, double radius)
17
30
  {
18
- return -cos(angle / 180 * M_PI) * radius;
31
+ return -std::cos(angle / 180 * std::numbers::pi) * radius;
19
32
  }
20
33
 
21
- double Gosu::angle(double from_x, double from_y, double to_x, double to_y, double def)
34
+ double Gosu::angle(double from_x, double from_y, double to_x, double to_y, double fallback)
22
35
  {
23
36
  double dist_x = to_x - from_x;
24
37
  double dist_y = to_y - from_y;
25
38
 
39
+ // Special-case the four cardinal directions values so that we don't run into subtle rounding
40
+ // errors for these obvious values.
26
41
  if (dist_x == 0) {
27
- // Special-case these values so that for a result of 0°/360° we never
28
- // run into subtle precision errors by converting from radian to angles.
29
- if (dist_y < 0) return 0;
30
- if (dist_y > 0) return 180;
31
- // dist_y == 0
32
- return 0;
42
+ if (dist_y == 0) {
43
+ return fallback;
44
+ }
45
+
46
+ return dist_y < 0 ? 0 : 180;
47
+ }
48
+ else if (dist_y == 0) {
49
+ return dist_x < 0 ? 270 : 90;
33
50
  }
34
51
 
35
- return normalize_angle(radians_to_gosu(atan2(dist_y, dist_x)));
52
+ return normalize_angle(radians_to_angle(std::atan2(dist_y, dist_x)));
36
53
  }
37
54
 
38
55
  double Gosu::angle_diff(double from, double to)
@@ -51,19 +68,15 @@ int Gosu::wrap(int value, int min, int max)
51
68
  return result < 0 ? result + max : result + min;
52
69
  }
53
70
 
54
- float Gosu::wrap(float value, float min, float max)
55
- {
56
- float result = fmodf(value - min, max - min);
57
- return result < 0 ? result + max : result + min;
58
- }
59
-
60
71
  double Gosu::wrap(double value, double min, double max)
61
72
  {
62
- double result = fmod(value - min, max - min);
73
+ double result = std::fmod(value - min, max - min);
63
74
  return result < 0 ? result + max : result + min;
64
75
  }
65
76
 
66
77
  double Gosu::distance(double x1, double y1, double x2, double y2)
67
78
  {
68
- return sqrt(distance_sqr(x1, y1, x2, y2));
79
+ double dist_x = (x2 - x1);
80
+ double dist_y = (y2 - y1);
81
+ return std::sqrt(dist_x * dist_x + dist_y * dist_y);
69
82
  }
@@ -1,99 +1,103 @@
1
1
  #include "OffScreenTarget.hpp"
2
- #include "Texture.hpp"
3
2
  #include <Gosu/Image.hpp>
4
3
  #include <Gosu/Platform.hpp>
4
+ #include "OpenGLContext.hpp"
5
+ #include "Texture.hpp"
5
6
  #ifndef GOSU_IS_IPHONE
6
- #include <SDL.h>
7
+ #include <SDL.h> // for SDL_GL_GetProcAddress
7
8
  #endif
8
- using namespace std;
9
9
 
10
10
  #ifdef GOSU_IS_OPENGLES
11
- #define GOSU_LOAD_GL_EXT(fn, type) \
12
- static auto fn = fn ## OES;
13
-
14
- #define GOSU_GL_CONST(name) \
15
- name ## _OES
16
-
17
- #define GOSU_GL_DEPTH_COMPONENT \
18
- GL_DEPTH_COMPONENT16_OES
11
+ #define GOSU_LOAD_GL_EXT(fn, type) static auto fn = fn##OES
12
+ #define GOSU_GL_CONST(name) name##_OES
13
+ #define GOSU_GL_DEPTH_COMPONENT GL_DEPTH_COMPONENT16_OES
19
14
  #else
20
- #define GOSU_LOAD_GL_EXT(fn, type) \
21
- static auto fn = (type) SDL_GL_GetProcAddress(#fn); \
22
- if (!fn) throw runtime_error("Unable to load " #fn);
23
-
24
- #define GOSU_GL_CONST(name) \
25
- name
26
-
27
- #define GOSU_GL_DEPTH_COMPONENT \
28
- GL_DEPTH_COMPONENT
15
+ #define GOSU_LOAD_GL_EXT(fn, type) \
16
+ static auto fn = reinterpret_cast<type>(SDL_GL_GetProcAddress(#fn)); \
17
+ if ((fn) == nullptr) { \
18
+ throw std::runtime_error("Unable to load " #fn); \
19
+ }
20
+ #define GOSU_GL_CONST(name) name
21
+ #define GOSU_GL_DEPTH_COMPONENT GL_DEPTH_COMPONENT
29
22
  #endif
30
23
 
31
24
  Gosu::OffScreenTarget::OffScreenTarget(int width, int height, unsigned image_flags)
25
+ : r_renderbuffer(static_cast<GLuint>(-1)),
26
+ m_framebuffer(static_cast<GLuint>(-1))
32
27
  {
33
28
  #ifndef GOSU_IS_IPHONE
29
+ // GCOV_EXCL_START
34
30
  if (!SDL_GL_ExtensionSupported("GL_EXT_framebuffer_object")) {
35
- throw runtime_error("Missing GL_EXT_framebuffer_object extension");
31
+ throw std::runtime_error("Missing GL_EXT_framebuffer_object extension");
36
32
  }
33
+ // GCOV_EXCL_end
37
34
  #endif
38
-
35
+
39
36
  // Create a new texture that will be our rendering target.
40
- texture = make_shared<Texture>(width, height, image_flags & IF_RETRO);
41
- // Mark the full texture as blocked for our TexChunk.
42
- texture->block(0, 0, width, height);
43
-
37
+ m_texture = std::make_shared<Texture>(width, height, image_flags & IF_RETRO);
38
+
44
39
  // Besides the texture, also create a renderbuffer for depth information.
45
- // Gosu doesn't use this, but custom OpenGL code could might.
40
+ // Gosu doesn't use this, but custom OpenGL code might.
46
41
  GOSU_LOAD_GL_EXT(glGenRenderbuffers, PFNGLGENRENDERBUFFERSPROC);
47
- glGenRenderbuffers(1, &renderbuffer);
48
-
42
+ glGenRenderbuffers(1, &r_renderbuffer);
43
+
49
44
  GOSU_LOAD_GL_EXT(glBindRenderbuffer, PFNGLBINDRENDERBUFFERPROC);
50
- glBindRenderbuffer(GOSU_GL_CONST(GL_RENDERBUFFER), renderbuffer);
51
-
45
+ glBindRenderbuffer(GOSU_GL_CONST(GL_RENDERBUFFER), r_renderbuffer);
46
+
52
47
  GOSU_LOAD_GL_EXT(glRenderbufferStorage, PFNGLRENDERBUFFERSTORAGEPROC);
53
48
  glRenderbufferStorage(GOSU_GL_CONST(GL_RENDERBUFFER), GOSU_GL_DEPTH_COMPONENT, width, height);
54
49
  glBindRenderbuffer(GOSU_GL_CONST(GL_RENDERBUFFER), 0);
55
-
50
+
56
51
  // Now tie everything together.
57
52
  GOSU_LOAD_GL_EXT(glGenFramebuffers, PFNGLGENFRAMEBUFFERSPROC);
58
- glGenFramebuffers(1, &framebuffer);
59
-
53
+ glGenFramebuffers(1, &m_framebuffer);
54
+
60
55
  GOSU_LOAD_GL_EXT(glBindFramebuffer, PFNGLBINDFRAMEBUFFERPROC);
61
- glBindFramebuffer(GOSU_GL_CONST(GL_FRAMEBUFFER), framebuffer);
62
-
56
+ glBindFramebuffer(GOSU_GL_CONST(GL_FRAMEBUFFER), m_framebuffer);
57
+
63
58
  GOSU_LOAD_GL_EXT(glFramebufferTexture2D, PFNGLFRAMEBUFFERTEXTURE2DPROC);
64
59
  glFramebufferTexture2D(GOSU_GL_CONST(GL_FRAMEBUFFER), GOSU_GL_CONST(GL_COLOR_ATTACHMENT0),
65
- GL_TEXTURE_2D, texture->tex_name(), 0);
66
-
60
+ GL_TEXTURE_2D, m_texture->tex_name(), 0);
61
+
67
62
  GOSU_LOAD_GL_EXT(glFramebufferRenderbuffer, PFNGLFRAMEBUFFERRENDERBUFFERPROC);
68
63
  glFramebufferRenderbuffer(GOSU_GL_CONST(GL_FRAMEBUFFER), GOSU_GL_CONST(GL_DEPTH_ATTACHMENT),
69
- GOSU_GL_CONST(GL_RENDERBUFFER), renderbuffer);
64
+ GOSU_GL_CONST(GL_RENDERBUFFER), r_renderbuffer);
70
65
  }
71
66
 
72
67
  Gosu::OffScreenTarget::~OffScreenTarget()
73
68
  {
74
69
  try {
75
70
  GOSU_LOAD_GL_EXT(glDeleteRenderbuffers, PFNGLDELETERENDERBUFFERSPROC);
76
- glDeleteRenderbuffers(1, &renderbuffer);
77
-
71
+ glDeleteRenderbuffers(1, &r_renderbuffer);
72
+
78
73
  GOSU_LOAD_GL_EXT(glDeleteFramebuffers, PFNGLDELETEFRAMEBUFFERSPROC);
79
- glDeleteFramebuffers(1, &framebuffer);
74
+ glDeleteFramebuffers(1, &m_framebuffer);
75
+ // GCOV_EXCL_START
80
76
  } catch (...) {
81
77
  // If we can't load these functions, just accept the resource leak.
82
78
  }
79
+ // GCOV_EXCL_END
83
80
  }
84
81
 
85
82
  Gosu::Image Gosu::OffScreenTarget::render(const std::function<void ()>& f)
86
83
  {
87
84
  GOSU_LOAD_GL_EXT(glBindFramebuffer, PFNGLBINDFRAMEBUFFERPROC);
88
- glBindFramebuffer(GOSU_GL_CONST(GL_FRAMEBUFFER), framebuffer);
89
-
85
+ glBindFramebuffer(GOSU_GL_CONST(GL_FRAMEBUFFER), m_framebuffer);
86
+
90
87
  GOSU_LOAD_GL_EXT(glCheckFramebufferStatus, PFNGLCHECKFRAMEBUFFERSTATUSPROC);
91
88
  GLenum status = glCheckFramebufferStatus(GOSU_GL_CONST(GL_FRAMEBUFFER));
92
- if (status != GOSU_GL_CONST(GL_FRAMEBUFFER_COMPLETE)) throw runtime_error("Incomplete framebuffer");
93
-
94
- f();
89
+ if (status != GOSU_GL_CONST(GL_FRAMEBUFFER_COMPLETE)) {
90
+ throw std::runtime_error("Incomplete framebuffer");
91
+ }
92
+
93
+ try {
94
+ f();
95
+
96
+ } catch (...) {
97
+ glBindFramebuffer(GOSU_GL_CONST(GL_FRAMEBUFFER), 0);
98
+ throw;
99
+ }
95
100
  glBindFramebuffer(GOSU_GL_CONST(GL_FRAMEBUFFER), 0);
96
101
 
97
- unique_ptr<ImageData> tex_chunk(new TexChunk(texture, 0, 0, texture->width(), texture->height(), 0));
98
- return Image(move(tex_chunk));
102
+ return Image(std::make_unique<TexChunk>(m_texture, Rect::covering(*m_texture), nullptr));
99
103
  }
@@ -1,23 +1,25 @@
1
1
  #pragma once
2
2
 
3
- #include "GraphicsImpl.hpp"
3
+ #include <Gosu/Utility.hpp>
4
+ #include <cstdint>
5
+ #include <functional>
6
+ #include <memory>
4
7
 
5
8
  namespace Gosu
6
9
  {
7
- class OffScreenTarget
10
+ class Image;
11
+ class Texture;
12
+
13
+ class OffScreenTarget : private Noncopyable
8
14
  {
9
- std::shared_ptr<Texture> texture;
10
- GLuint renderbuffer;
11
- GLuint framebuffer;
12
-
13
- OffScreenTarget(const OffScreenTarget& other) = delete;
14
- OffScreenTarget& operator=(const OffScreenTarget& other) = delete;
15
- OffScreenTarget(OffScreenTarget&& other) = delete;
16
- OffScreenTarget& operator=(OffScreenTarget&& other) = delete;
17
-
15
+ std::shared_ptr<Texture> m_texture;
16
+ std::uint32_t r_renderbuffer;
17
+ std::uint32_t m_framebuffer;
18
+
18
19
  public:
19
20
  OffScreenTarget(int width, int height, unsigned image_flags);
20
21
  ~OffScreenTarget();
22
+
21
23
  Gosu::Image render(const std::function<void ()>& f);
22
24
  };
23
25
  }
@@ -0,0 +1,117 @@
1
+ #include "OpenGLContext.hpp"
2
+ #if !defined(GOSU_IS_IPHONE) // on iPhone, GosuGLView.cpp implements OpenGLContext.
3
+
4
+ #if defined(GOSU_IS_MAC)
5
+ #include <Foundation/Foundation.h> // for -[NSThread isMainThread]
6
+ #endif
7
+
8
+ #include <stdexcept>
9
+ #include <thread>
10
+
11
+ namespace
12
+ {
13
+ [[noreturn]] void throw_sdl_error(const std::string& operation)
14
+ {
15
+ throw std::runtime_error(operation + ": " + SDL_GetError());
16
+ }
17
+
18
+ /// Groups the global SDL variables into a single struct so that they all either exist, or not.
19
+ struct SDLWindowAndGLContext : Gosu::Noncopyable
20
+ {
21
+ SDL_Window* window;
22
+ /// We only use one OpenGL context, even from background threads. It would be possible to
23
+ /// set up shared OpenGL contexts here (c.f. git history of this file), but according to
24
+ /// various sources on the internet, sharing OpenGL contexts does not help performance.
25
+ /// https://discourse.libsdl.org/t/feasibility-correctness-of-calling-gl-in-another-thread/20292/6
26
+ SDL_GLContext gl_context;
27
+
28
+ SDLWindowAndGLContext()
29
+ {
30
+ static const int initialized = SDL_Init(SDL_INIT_VIDEO);
31
+ if (initialized < 0) {
32
+ throw_sdl_error("Could not initialize SDL");
33
+ }
34
+
35
+ #ifdef GOSU_IS_MAC
36
+ if (![NSThread isMainThread]) {
37
+ throw std::logic_error("Gosu::Window/OpenGL must be initialized on main thread");
38
+ }
39
+ #endif
40
+ #ifdef GOSU_IS_OPENGLES
41
+ // We want to use OpenGL ES 1.1, which does not yet require us to use shaders.
42
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1);
43
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
44
+ #endif
45
+
46
+ window = //
47
+ SDL_CreateWindow("", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 64, 64,
48
+ SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN | SDL_WINDOW_ALLOW_HIGHDPI);
49
+ if (!window) {
50
+ throw_sdl_error("Could not create SDL window");
51
+ }
52
+
53
+ gl_context = SDL_GL_CreateContext(window);
54
+ if (!gl_context) {
55
+ SDL_DestroyWindow(window);
56
+ throw_sdl_error("Could not create main OpenGL context");
57
+ }
58
+ }
59
+
60
+ static SDLWindowAndGLContext& instance()
61
+ {
62
+ static SDLWindowAndGLContext instance;
63
+ return instance;
64
+ }
65
+ };
66
+
67
+ /// The current nesting level of OpenGLContext objects.
68
+ thread_local int current_nesting_depth = 0; // NOLINT(*-avoid-non-const-global-variables)
69
+ }
70
+
71
+ Gosu::OpenGLContext::OpenGLContext(bool for_rendering_to_window)
72
+ {
73
+ static const auto& window = SDLWindowAndGLContext::instance();
74
+
75
+ // All threads use a single mutex to coordinate access to their OpenGL context.
76
+ static std::mutex mutex;
77
+ if (current_nesting_depth == 0) {
78
+ // ...but only the innermost OpenGLContext in a thread owns the lock.
79
+ m_lock = std::unique_lock(mutex);
80
+ }
81
+
82
+ // Explicitly make the context current every time for_rendering_to_window is set, so that we set
83
+ // the current SDL_Window even if we are somehow nested into something else.
84
+ if (for_rendering_to_window) {
85
+ if (SDL_GL_MakeCurrent(window.window, window.gl_context) != 0) {
86
+ throw_sdl_error("Could not set current GL context for rendering to the window");
87
+ }
88
+ }
89
+ else if (current_nesting_depth == 0) {
90
+ // Making a GL context current on a background thread, but with a window, causes a deadlock
91
+ // on macOS because SDL tries to use dispatch_sync onto the main thread.
92
+ // -> Try without a window first (for macOS), then with a window (for other platforms).
93
+ if (SDL_GL_MakeCurrent(nullptr, window.gl_context) != 0
94
+ && SDL_GL_MakeCurrent(window.window, window.gl_context) != 0) {
95
+ throw_sdl_error("Could not set current GL context");
96
+ }
97
+ }
98
+
99
+ ++current_nesting_depth;
100
+ }
101
+
102
+ Gosu::OpenGLContext::~OpenGLContext()
103
+ {
104
+ --current_nesting_depth;
105
+
106
+ if (m_lock) {
107
+ SDL_GL_MakeCurrent(nullptr, nullptr);
108
+ }
109
+ }
110
+
111
+ SDL_Window* Gosu::OpenGLContext::shared_sdl_window()
112
+ {
113
+ static const auto& window = SDLWindowAndGLContext::instance();
114
+ return window.window;
115
+ }
116
+
117
+ #endif
@@ -0,0 +1,41 @@
1
+ #ifndef GOSU_OPENGLCONTEXT_HPP
2
+ #define GOSU_OPENGLCONTEXT_HPP
3
+
4
+ #include <Gosu/Platform.hpp>
5
+ #include <Gosu/Utility.hpp>
6
+
7
+ #if defined(GOSU_IS_IPHONE) || defined(GOSU_IS_OPENGLES)
8
+ #include <OpenGLES/ES1/gl.h>
9
+ #include <OpenGLES/ES1/glext.h>
10
+ #else
11
+ #include <SDL.h>
12
+ #include <SDL_opengl.h>
13
+ #endif
14
+
15
+ #include <mutex>
16
+
17
+ namespace Gosu
18
+ {
19
+ /// Recursive lock/RAII class that makes an OpenGL context the current context, and prevents
20
+ /// other threads from taking over the context until this instance is destroyed.
21
+ class OpenGLContext : Noncopyable
22
+ {
23
+ std::unique_lock<std::mutex> m_lock;
24
+
25
+ public:
26
+ /// Makes an OpenGL context current. The very first call of this constructor may throw, all
27
+ /// other calls can only block.
28
+ explicit OpenGLContext(bool for_rendering_to_window = false);
29
+ ~OpenGLContext();
30
+
31
+ #ifndef GOSU_IS_IPHONE
32
+ // SDL does not allow creation of OpenGL contexts without creating an SDL_Window first.
33
+ // Therefore, this class internally creates a global SDL_Window, and derives OpenGL contexts
34
+ // from it. The Gosu::Window implementation can then show and hide this single SDL_Window
35
+ // to simulate the window lifecycle.
36
+ static SDL_Window* shared_sdl_window();
37
+ #endif
38
+ };
39
+ }
40
+
41
+ #endif