gosu 1.0.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/COPYING +1 -1
  3. data/ext/gosu/extconf.rb +5 -1
  4. data/include/Gosu/Font.hpp +7 -9
  5. data/include/Gosu/Graphics.hpp +6 -4
  6. data/include/Gosu/GraphicsBase.hpp +6 -6
  7. data/include/Gosu/Image.hpp +3 -3
  8. data/include/Gosu/ImageData.hpp +1 -1
  9. data/include/Gosu/Text.hpp +4 -4
  10. data/include/Gosu/Utility.hpp +10 -8
  11. data/include/Gosu/Version.hpp +1 -1
  12. data/include/Gosu/Window.hpp +23 -9
  13. data/lib/gosu/compat.rb +4 -0
  14. data/lib/gosu/swig_patches.rb +11 -10
  15. data/rdoc/gosu.rb +14 -1
  16. data/src/EmptyImageData.hpp +1 -1
  17. data/src/Font.cpp +4 -4
  18. data/src/Graphics.cpp +4 -4
  19. data/src/Image.cpp +4 -3
  20. data/src/Input.cpp +1 -10
  21. data/src/LargeImageData.cpp +1 -1
  22. data/src/LargeImageData.hpp +1 -1
  23. data/src/Macro.cpp +100 -143
  24. data/src/Macro.hpp +1 -1
  25. data/src/RenderState.hpp +5 -5
  26. data/src/Resolution.cpp +111 -63
  27. data/src/RubyGosu.cxx +222 -124
  28. data/src/RubyGosu.h +2 -2
  29. data/src/TexChunk.cpp +1 -1
  30. data/src/TexChunk.hpp +1 -1
  31. data/src/TrueTypeFontApple.cpp +10 -2
  32. data/src/TrueTypeFontWin.cpp +3 -3
  33. data/src/Utility.cpp +52 -23
  34. data/src/Window.cpp +60 -31
  35. data/src/WindowUIKit.cpp +21 -9
  36. metadata +3 -25
  37. data/include/Gosu/Channel.h +0 -25
  38. data/include/Gosu/Color.h +0 -38
  39. data/include/Gosu/Font.h +0 -36
  40. data/include/Gosu/Gosu.h +0 -82
  41. data/include/Gosu/Image.h +0 -54
  42. data/include/Gosu/Sample.h +0 -19
  43. data/include/Gosu/Song.h +0 -24
  44. data/include/Gosu/TextInput.h +0 -30
  45. data/include/Gosu/Window.h +0 -63
  46. data/src/ChannelWrapper.cpp +0 -50
  47. data/src/ColorWrapper.cpp +0 -126
  48. data/src/Constants.cpp +0 -338
  49. data/src/FontWrapper.cpp +0 -74
  50. data/src/GosuWrapper.cpp +0 -251
  51. data/src/ImageWrapper.cpp +0 -168
  52. data/src/MPEGFile.hpp +0 -90
  53. data/src/SampleWrapper.cpp +0 -30
  54. data/src/SongWrapper.cpp +0 -52
  55. data/src/TextInputWrapper.cpp +0 -101
  56. data/src/UtilityApple.cpp +0 -16
  57. data/src/UtilityWin.cpp +0 -17
  58. data/src/WindowWrapper.cpp +0 -317
data/src/Image.cpp CHANGED
@@ -57,7 +57,7 @@ unsigned Gosu::Image::height() const
57
57
  }
58
58
 
59
59
  void Gosu::Image::draw(double x, double y, ZPos z, double scale_x, double scale_y, Color c,
60
- AlphaMode mode) const
60
+ BlendMode mode) const
61
61
  {
62
62
  double x2 = x + width() * scale_x;
63
63
  double y2 = y + height() * scale_y;
@@ -66,7 +66,7 @@ void Gosu::Image::draw(double x, double y, ZPos z, double scale_x, double scale_
66
66
  }
67
67
 
68
68
  void Gosu::Image::draw_mod(double x, double y, ZPos z, double scale_x, double scale_y, Color c1,
69
- Color c2, Color c3, Color c4, AlphaMode mode) const
69
+ Color c2, Color c3, Color c4, BlendMode mode) const
70
70
  {
71
71
  double x2 = x + width() * scale_x;
72
72
  double y2 = y + height() * scale_y;
@@ -75,7 +75,8 @@ void Gosu::Image::draw_mod(double x, double y, ZPos z, double scale_x, double sc
75
75
  }
76
76
 
77
77
  void Gosu::Image::draw_rot(double x, double y, ZPos z, double angle,
78
- double center_x, double center_y, double scale_x, double scale_y, Color c, AlphaMode mode) const
78
+ double center_x, double center_y, double scale_x, double scale_y, Color c,
79
+ BlendMode mode) const
79
80
  {
80
81
  double size_x = width() * scale_x;
81
82
  double size_y = height() * scale_y;
data/src/Input.cpp CHANGED
@@ -78,20 +78,11 @@ struct Gosu::Input::Impl
78
78
 
79
79
  void update_mouse_position()
80
80
  {
81
- #if SDL_VERSION_ATLEAST(2, 0, 5)
82
- // SDL_GetGlobalMouseState was added in SDL 2.0.4, but it only started using the same
83
- // coordinate system as SDL_GetWindowPosition on X11 in 2.0.5.
84
81
  int x, y, window_x, window_y;
85
82
  SDL_GetWindowPosition(window, &window_x, &window_y);
86
83
  SDL_GetGlobalMouseState(&x, &y);
87
84
  mouse_x = x - window_x;
88
85
  mouse_y = y - window_y;
89
- #else
90
- int x, y;
91
- SDL_GetMouseState(&x, &y);
92
- mouse_x = x;
93
- mouse_y = y;
94
- #endif
95
86
  }
96
87
 
97
88
  void set_mouse_position(double x, double y)
@@ -100,7 +91,7 @@ struct Gosu::Input::Impl
100
91
  static_cast<int>((x - mouse_offset_x) / mouse_scale_x),
101
92
  static_cast<int>((y - mouse_offset_y) / mouse_scale_y));
102
93
 
103
- #if SDL_VERSION_ATLEAST(2, 0, 4) && !defined(GOSU_IS_X)
94
+ #if !defined(GOSU_IS_X)
104
95
  // On systems where we have a working GetGlobalMouseState, we can warp the mouse and
105
96
  // retrieve its position directly afterwards.
106
97
  update_mouse_position();
@@ -69,7 +69,7 @@ void Gosu::LargeImageData::draw(double x1, double y1, Color c1,
69
69
  double x2, double y2, Color c2,
70
70
  double x3, double y3, Color c3,
71
71
  double x4, double y4, Color c4,
72
- ZPos z, AlphaMode mode) const
72
+ ZPos z, BlendMode mode) const
73
73
  {
74
74
  normalize_coordinates(x1, y1, x2, y2, x3, y3, c3, x4, y4, c4);
75
75
 
@@ -25,7 +25,7 @@ public:
25
25
  double x2, double y2, Color c2,
26
26
  double x3, double y3, Color c3,
27
27
  double x4, double y4, Color c4,
28
- ZPos z, AlphaMode mode) const override;
28
+ ZPos z, BlendMode mode) const override;
29
29
 
30
30
  const GLTexInfo* gl_tex_info() const override { return nullptr; }
31
31
 
data/src/Macro.cpp CHANGED
@@ -1,168 +1,125 @@
1
1
  #include "Macro.hpp"
2
2
  #include "DrawOpQueue.hpp"
3
3
  #include <Gosu/Image.hpp>
4
- #include <cmath>
5
- #include <algorithm>
6
- #include <functional>
7
- #include <memory>
8
4
  #include <stdexcept>
9
5
  using namespace std;
10
6
 
11
7
  struct Gosu::Macro::Impl
12
8
  {
13
- typedef double Float;
14
-
15
9
  VertexArrays vertex_arrays;
16
10
  int width, height;
17
-
18
- Transform find_transform_for_target(Float x1, Float y1, Float x2, Float y2,
19
- Float x3, Float y3, Float x4, Float y4) const
11
+
12
+ // Solves the 2x2 linear system for x:
13
+ // (a11 a12) (x1) = (b1)
14
+ // (a21 a22) (x2) = (b2)
15
+ // x1, x2 are output parameters. Returns false if the matrix is singular.
16
+ static bool solve_2x2(double a11, double a12, double a21, double a22, double b1, double b2,
17
+ double& x1, double& x2)
18
+ {
19
+ const double det = a11 * a22 - a21 * a12;
20
+ if (det == 0) return false;
21
+ x1 = (a22 * b1 - a12 * b2) / det;
22
+ x2 = (a11 * b2 - a21 * b1) / det;
23
+ return true;
24
+ }
25
+
26
+ Transform find_transform_for_target(double x1, double y1, double x2, double y2,
27
+ double x3, double y3, double x4, double y4) const
20
28
  {
21
29
  // Transformation logic follows a discussion on the ImageMagick mailing
22
30
  // list (on which ImageMagick's perspective_transform.pl is based).
23
-
31
+
24
32
  // To draw a macro at an arbitrary position, we solve the following system:
25
-
26
- // 0, 0, 1, 0, 0, 0, 0, 0 | x1
27
- // 0, 0, 0, 0, 0, 1, 0, 0 | y1
28
- // w, 0, 1, 0, 0, 0, -x2w, 0 | x2
29
- // 0, 0, 0, w, 0, 1, -y2w, 0 | y2
30
- // 0, h, 1, 0, 0, 0, 0, -x3h | x3
31
- // 0, 0, 0, 0, h, 1, 0, -y3h | y3
32
- // w, h, 1, 0, 0, 0, -x4w, -x4h | x4
33
- // 0, 0, 0, w, h, 1, -y4w, -y4h | y4
34
-
33
+
34
+ // 0, 0, 1, 0, 0, 0, 0, 0 | x1
35
+ // 0, 0, 0, 0, 0, 1, 0, 0 | y1
36
+ // w, 0, 1, 0, 0, 0, -x2 w, 0 | x2
37
+ // 0, 0, 0, w, 0, 1, -y2 w, 0 | y2
38
+ // 0, h, 1, 0, 0, 0, 0, -x3 h | x3
39
+ // 0, 0, 0, 0, h, 1, 0, -y3 h | y3
40
+ // w, h, 1, 0, 0, 0, -x4 w, -x4 h | x4
41
+ // 0, 0, 0, w, h, 1, -y4 w, -y4 h | y4
42
+
35
43
  // Equivalent:
36
-
37
- // 0, 0, 1, 0, 0, 0, 0, 0 | x1
38
- // 0, 0, 0, 0, 0, 1, 0, 0 | y1
39
- // w, 0, 0, 0, 0, 0, -x2w, 0 | x2-x1
40
- // 0, 0, 0, w, 0, 0, -y2w, 0 | y2-y1
41
- // 0, h, 0, 0, 0, 0, 0, -x3h | x3-x1
42
- // 0, 0, 0, 0, h, 0, 0, -y3h | y3-y1
43
- // 0, 0, 0, 0, 0, 0, (x2-x4)w, (x3-x4)h | x1-x2-x3+x4
44
- // 0, 0, 0, 0, 0, 0, (y2-y4)w, (y3-y4)h | y1-y2-y3+y4
45
-
46
- // Since this matrix is relatively sparse, we unroll all three solving paths.
47
-
48
- static const Transform null_transform = {{ 0 }};
49
-
50
- // Row 7 is completely useless
51
- if (x2 == x4 && x3 == x4) return null_transform;
52
- // Row 8 is completely useless
53
- if (y2 == y3 && y3 == y4) return null_transform;
54
- // Col 7 is completely useless
55
- if (x2 == x4 && y2 == y4) return null_transform;
56
- // Col 8 is completely useless
57
- if (x3 == x4 && y3 == y4) return null_transform;
58
-
59
- Float c[8];
60
-
61
- // Rows 1, 2
44
+
45
+ // 0, 0, 1, 0, 0, 0, 0, 0 | x1
46
+ // 0, 0, 0, 0, 0, 1, 0, 0 | y1
47
+ // w, 0, 0, 0, 0, 0, -x2 w, 0 | x2-x1
48
+ // 0, 0, 0, w, 0, 0, -y2 w, 0 | y2-y1
49
+ // 0, h, 0, 0, 0, 0, 0, -x3 h | x3-x1
50
+ // 0, 0, 0, 0, h, 0, 0, -y3 h | y3-y1
51
+ // 0, 0, 0, 0, 0, 0, (x2-x4) w, (x3-x4) h | x1-x2-x3+x4
52
+ // 0, 0, 0, 0, 0, 0, (y2-y4) w, (y3-y4) h | y1-y2-y3+y4
53
+
54
+ // The last two rows only involve the last two variables.
55
+ // We can directly solve this as a separate 2x2 linear system.
56
+
57
+ // Set up 2x2 linear system of the lower right corner entries.
58
+ const double a11 = (x2 - x4) * width;
59
+ const double a12 = (x3 - x4) * height;
60
+ const double a21 = (y2 - y4) * width;
61
+ const double a22 = (y3 - y4) * height;
62
+ const double b1 = x1 - x2 - x3 + x4;
63
+ const double b2 = y1 - y2 - y3 + y4;
64
+
65
+ // Solve:
66
+ double qx, qy;
67
+ if (!solve_2x2(a11, a12, a21, a22, b1, b2, qx, qy)) return Transform{{0}};
68
+
69
+ // Updating the last two rows with the computed solution yields
70
+
71
+ // 0, 0, 1, 0, 0, 0, 0, 0 | x1
72
+ // 0, 0, 0, 0, 0, 1, 0, 0 | y1
73
+ // w, 0, 0, 0, 0, 0, -x2 w, 0 | x2-x1
74
+ // 0, 0, 0, w, 0, 0, -y2 w, 0 | y2-y1
75
+ // 0, h, 0, 0, 0, 0, 0, -x3 h | x3-x1
76
+ // 0, 0, 0, 0, h, 0, 0, -y3 h | y3-y1
77
+ // 0, 0, 0, 0, 0, 0, 1, 0 | qx
78
+ // 0, 0, 0, 0, 0, 0, 0, 1 | qy
79
+
80
+ // We can use the last two rows to eliminate entries in rows 3, 4, 5, and 6:
81
+
82
+ // 0, 0, 1, 0, 0, 0, 0, 0 | x1
83
+ // 0, 0, 0, 0, 0, 1, 0, 0 | y1
84
+ // w, 0, 0, 0, 0, 0, 0, 0 | x2-x1 + qx x2 w
85
+ // 0, 0, 0, w, 0, 0, 0, 0 | y2-y1 + qx y2 w
86
+ // 0, h, 0, 0, 0, 0, 0, 0 | x3-x1 + qy x3 h
87
+ // 0, 0, 0, 0, h, 0, 0, 0 | y3-y1 + qy y3 h
88
+ // 0, 0, 0, 0, 0, 0, 1, 0 | qx
89
+ // 0, 0, 0, 0, 0, 0, 0, 1 | qy
90
+
91
+ // Normalize and reorder rows so we can read off the solution:
92
+
93
+ // 1, 0, 0, 0, 0, 0, 0, 0 | (x2-x1) / w + qx x2
94
+ // 0, 1, 0, 0, 0, 0, 0, 0 | (x3-x1) / h + qy x3
95
+ // 0, 0, 1, 0, 0, 0, 0, 0 | x1
96
+ // 0, 0, 0, 1, 0, 0, 0, 0 | (y2-y1) / w + qx y2
97
+ // 0, 0, 0, 0, 1, 0, 0, 0 | (y3-y1) / h + qy y3
98
+ // 0, 0, 0, 0, 0, 1, 0, 0 | y1
99
+ // 0, 0, 0, 0, 0, 0, 1, 0 | qx
100
+ // 0, 0, 0, 0, 0, 0, 0, 1 | qy
101
+
102
+ double c[8];
103
+ c[0] = (x2 - x1) / width + qx * x2;
104
+ c[1] = (x3 - x1) / height + qy * x3;
62
105
  c[2] = x1;
106
+ c[3] = (y2 - y1) / width + qx * y2;
107
+ c[4] = (y3 - y1) / height + qy * y3;
63
108
  c[5] = y1;
64
-
65
- // The logic below assumes x2 != x4, i.e. row7 can be used to eliminate
66
- // the leftmost value in row 8 and afterwards the values in rows 3 & 4.
67
- // If x2 == x4, we need to exchange rows 7 and 8.
68
-
69
- // TODO: x2==x4 is the normal case where an image is
70
- // drawn upright; the code should rather swap in the rare case that x3==x4!
71
-
72
- Float left_cell7 = (x2 - x4) * width;
73
- Float right_cell7 = (x3 - x4) * height;
74
- Float orig_right_side7 = (x1 - x2 - x3 + x4);
75
- Float left_cell8 = (y2 - y4) * width;
76
- Float right_cell8 = (y3 - y4) * height;
77
- Float orig_right_side8 = (y1 - y2 - y3 + y4);
78
-
79
- bool swap_rows78 = x2 == x4;
80
- if (swap_rows78) {
81
- swap(left_cell7, left_cell8);
82
- swap(right_cell7, right_cell8);
83
- swap(orig_right_side7, orig_right_side8);
84
- }
85
-
86
- // 0, 0, 1, 0, 0, 0, 0, 0 | x1
87
- // 0, 0, 0, 0, 0, 1, 0, 0 | y1
88
- // w, 0, 0, 0, 0, 0, -x2w, 0 | x2-x1
89
- // 0, 0, 0, w, 0, 0, -y2w, 0 | y2-y1
90
- // 0, h, 0, 0, 0, 0, 0, -x3h | x3-x1
91
- // 0, 0, 0, 0, h, 0, 0, -y3h | y3-y1
92
- // 0, 0, 0, 0, 0, 0, left_cell7, right_cell7 | orig_right_side7
93
- // 0, 0, 0, 0, 0, 0, left_cell8, right_cell8 | orig_right_side8
94
-
95
- // Use row 7 to eliminate the left cell in row 8
96
- // Row8 = Row8 - factor78 * Row7
97
- Float factor78 = left_cell8 / left_cell7;
98
- Float rem_cell8 = right_cell8 - right_cell7 * factor78;
99
- Float right_side8 = orig_right_side8 - orig_right_side7 * factor78;
100
- c[7] = right_side8 / rem_cell8;
101
-
102
- // 0, 0, 1, 0, 0, 0, 0, 0 | x1
103
- // 0, 0, 0, 0, 0, 1, 0, 0 | y1
104
- // w, 0, 0, 0, 0, 0, -x2w, 0 | x2-x1
105
- // 0, 0, 0, w, 0, 0, -y2w, 0 | y2-y1
106
- // 0, h, 0, 0, 0, 0, 0, -x3h | x3-x1
107
- // 0, 0, 0, 0, h, 0, 0, -y3h | y3-y1
108
- // 0, 0, 0, 0, 0, 0, left_cell7, right_cell7 | orig_right_side7
109
- // 0, 0, 0, 0, 0, 0, 0, rem_cell8 | right_side8
110
-
111
- // Use the remaining value in row 8 to eliminate the right value in row 7.
112
- // Row7 = Row7 - factor87 * Row8
113
- Float factor87 = right_cell7 / rem_cell8;
114
- Float rem_cell7 = left_cell7;
115
- Float right_side7 = orig_right_side7 - right_side8 * factor87;
116
- c[6] = right_side7 / rem_cell7;
117
-
118
- // 0, 0, 1, 0, 0, 0, 0, 0 | x1
119
- // 0, 0, 0, 0, 0, 1, 0, 0 | y1
120
- // w, 0, 0, 0, 0, 0, -x2w, 0 | x2-x1
121
- // 0, 0, 0, w, 0, 0, -y2w, 0 | y2-y1
122
- // 0, h, 0, 0, 0, 0, 0, -x3h | x3-x1
123
- // 0, 0, 0, 0, h, 0, 0, -y3h | y3-y1
124
- // 0, 0, 0, 0, 0, 0, rem_cell7, 0 | right_side7
125
- // 0, 0, 0, 0, 0, 0, 0, rem_cell8 | right_side8
126
-
127
- // Use the new rows 7 and 8 to calculate c0, c1, c3 & c4.
128
- // Row3 = Row3 - factor73 * Row7
129
- Float factor73 = -x2 * width / rem_cell7;
130
- Float rem_cell3 = width;
131
- Float right_side3 = (x2 - x1) - right_side7 * factor73;
132
- c[0] = right_side3 / rem_cell3;
133
- // Row4 = Row4 - factor74 * Row7
134
- Float factor74 = -y2 * width / rem_cell7;
135
- Float rem_cell4 = width;
136
- Float right_side4 = (y2 - y1) - right_side7 * factor74;
137
- c[3] = right_side4 / rem_cell4;
138
- // Row5 = Row5 - factor85 * Row7
139
- Float factor85 = -x3 * height / rem_cell8;
140
- Float rem_cell5 = height;
141
- Float right_side5 = (x3 - x1) - right_side8 * factor85;
142
- c[1] = right_side5 / rem_cell5;
143
- // Row6 = Row6 - factor86 * Row8
144
- Float factor86 = -y3 * height / rem_cell8;
145
- Float rem_cell6 = height;
146
- Float right_side6 = (y3 - y1) - right_side8 * factor86;
147
- c[4] = right_side6 / rem_cell6;
148
-
149
- if (swap_rows78) {
150
- swap(c[6], c[7]);
151
- }
152
-
153
- // Let's hope I never have to debug/understand this again! :D
154
-
109
+ c[6] = qx;
110
+ c[7] = qy;
111
+
155
112
  Transform result = {{
156
113
  c[0], c[3], 0, c[6],
157
114
  c[1], c[4], 0, c[7],
158
- 0, 0, 1, 0,
115
+ 0, 0, 1, 0,
159
116
  c[2], c[5], 0, 1
160
117
  }};
161
118
  return result;
162
119
  }
163
-
164
- void draw_vertex_arrays(Float x1, Float y1, Float x2, Float y2, Float x3, Float y3,
165
- Float x4, Float y4) const
120
+
121
+ void draw_vertex_arrays(double x1, double y1, double x2, double y2, double x3, double y3,
122
+ double x4, double y4) const
166
123
  {
167
124
  // TODO: Macros should not be split up just because they have different transforms.
168
125
  // They should be premultiplied and have the same transform by definition. Then the
@@ -205,7 +162,7 @@ int Gosu::Macro::height() const
205
162
  }
206
163
 
207
164
  void Gosu::Macro::draw(double x1, double y1, Color c1, double x2, double y2, Color c2,
208
- double x3, double y3, Color c3, double x4, double y4, Color c4, ZPos z, AlphaMode mode) const
165
+ double x3, double y3, Color c3, double x4, double y4, Color c4, ZPos z, BlendMode mode) const
209
166
  {
210
167
  if (c1 != Color::WHITE || c2 != Color::WHITE || c3 != Color::WHITE || c4 != Color::WHITE) {
211
168
  throw invalid_argument("Macros cannot be tinted with colors");
@@ -228,7 +185,7 @@ Gosu::Bitmap Gosu::Macro::to_bitmap() const
228
185
  pimpl->width, 0, Color::WHITE,
229
186
  0, pimpl->height, Color::WHITE,
230
187
  pimpl->width, pimpl->height, Color::WHITE,
231
- 0, AM_DEFAULT);
188
+ 0, BM_DEFAULT);
232
189
  }).data().to_bitmap();
233
190
  }
234
191
 
data/src/Macro.hpp CHANGED
@@ -18,7 +18,7 @@ public:
18
18
 
19
19
  void draw(double x1, double y1, Color c1, double x2, double y2, Color c2,
20
20
  double x3, double y3, Color c3, double x4, double y4, Color c4, ZPos z,
21
- AlphaMode mode) const override;
21
+ BlendMode mode) const override;
22
22
 
23
23
  const Gosu::GLTexInfo* gl_tex_info() const override;
24
24
 
data/src/RenderState.hpp CHANGED
@@ -10,10 +10,10 @@ struct Gosu::RenderState
10
10
  std::shared_ptr<Texture> texture;
11
11
  const Transform* transform;
12
12
  ClipRect clip_rect;
13
- AlphaMode mode;
13
+ BlendMode mode;
14
14
 
15
15
  RenderState()
16
- : transform(0), mode(AM_DEFAULT)
16
+ : transform(0), mode(BM_DEFAULT)
17
17
  {
18
18
  clip_rect.width = NO_CLIPPING;
19
19
  }
@@ -39,10 +39,10 @@ struct Gosu::RenderState
39
39
 
40
40
  void apply_alpha_mode() const
41
41
  {
42
- if (mode == AM_ADD) {
42
+ if (mode == BM_ADD) {
43
43
  glBlendFunc(GL_SRC_ALPHA, GL_ONE);
44
44
  }
45
- else if (mode == AM_MULTIPLY) {
45
+ else if (mode == BM_MULTIPLY) {
46
46
  glBlendFunc(GL_DST_COLOR, GL_ZERO);
47
47
  }
48
48
  else {
@@ -174,7 +174,7 @@ public:
174
174
  }
175
175
  }
176
176
 
177
- void set_alpha_mode(AlphaMode new_mode)
177
+ void set_alpha_mode(BlendMode new_mode)
178
178
  {
179
179
  if (new_mode == mode) return;
180
180
 
data/src/Resolution.cpp CHANGED
@@ -11,19 +11,19 @@ static SDL_DisplayMode display_mode(Gosu::Window* window)
11
11
  VideoSubsystem() { SDL_InitSubSystem(SDL_INIT_VIDEO); };
12
12
  ~VideoSubsystem() { SDL_QuitSubSystem(SDL_INIT_VIDEO); };
13
13
  } subsystem;
14
-
14
+
15
15
  int index = window ? SDL_GetWindowDisplayIndex(Gosu::shared_window()) : 0;
16
16
  SDL_DisplayMode result;
17
17
  SDL_GetDesktopDisplayMode(index, &result);
18
18
  return result;
19
19
  }
20
20
 
21
- unsigned Gosu::screen_width(Window* window)
21
+ int Gosu::screen_width(Window* window)
22
22
  {
23
23
  return display_mode(window).w;
24
24
  }
25
25
 
26
- unsigned Gosu::screen_height(Window* window)
26
+ int Gosu::screen_height(Window* window)
27
27
  {
28
28
  return display_mode(window).h;
29
29
  }
@@ -31,88 +31,136 @@ unsigned Gosu::screen_height(Window* window)
31
31
  #ifdef GOSU_IS_MAC
32
32
  #import <AppKit/AppKit.h>
33
33
 
34
- static NSSize max_window_size(Gosu::Window* window)
34
+ static SDL_Rect max_window_size(Gosu::Window* window)
35
35
  {
36
- // Keep in sync with SDL_cocoawindow.m.
37
- auto style = NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask;
36
+ // The extra size that a window needs depends on its style.
37
+ // This logic must be kept in sync with SDL_cocoawindow.m to be 100% accurate.
38
+ NSUInteger style;
39
+ if (window && window->borderless()) {
40
+ style = NSWindowStyleMaskBorderless;
41
+ }
42
+ else {
43
+ style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;
44
+ }
45
+ if (window && window->resizable()) {
46
+ style |= NSWindowStyleMaskResizable;
47
+ }
38
48
 
39
49
  auto index = window ? SDL_GetWindowDisplayIndex(Gosu::shared_window()) : 0;
40
- auto screen_frame = NSScreen.screens[index].visibleFrame;
41
- return [NSWindow contentRectForFrameRect:screen_frame styleMask:style].size;
42
- }
43
-
44
- unsigned Gosu::available_width(Window* window)
45
- {
46
- return max_window_size(window).width;
47
- }
48
-
49
- unsigned Gosu::available_height(Window* window)
50
- {
51
- return max_window_size(window).height;
50
+ NSRect screen_frame = NSScreen.screens[index].visibleFrame;
51
+ NSRect content_rect = [NSWindow contentRectForFrameRect:screen_frame styleMask:style];
52
+
53
+ SDL_Rect result;
54
+ result.x = 0;
55
+ result.y = 0;
56
+ result.w = content_rect.size.width;
57
+ result.h = content_rect.size.height;
58
+ return result;
52
59
  }
53
60
  #endif
54
61
 
62
+ // TODO: Remove this implementation and remove ifdef for GOSU_IS_X once WIN_GetWindowBordersSize is patched
55
63
  #ifdef GOSU_IS_WIN
56
64
  #include <windows.h>
57
65
  #include <SDL_syswm.h>
66
+ #include <dwmapi.h>
67
+ #pragma comment (lib, "Dwmapi.lib")
58
68
 
59
- static SIZE max_window_size(Gosu::Window* window)
69
+ static SDL_Rect max_window_size(Gosu::Window* window)
60
70
  {
61
- RECT work_area;
62
-
63
- if (window == nullptr) {
64
- // Easy case: Return the work area of the primary monitor.
65
- SystemParametersInfo(SPI_GETWORKAREA, 0, &work_area, 0);
66
- }
67
- else {
68
- // Return the work area of the monitor the window is on.
69
- SDL_SysWMinfo wm_info;
70
- SDL_VERSION(&wm_info.version);
71
- SDL_GetWindowWMInfo(Gosu::shared_window(), &wm_info);
72
- HMONITOR monitor = MonitorFromWindow(wm_info.info.win.window, MONITOR_DEFAULTTONEAREST);
73
-
74
- MONITORINFO monitor_info;
75
- monitor_info.cbSize = sizeof(monitor_info);
76
- GetMonitorInfo(monitor, &monitor_info);
77
- work_area = monitor_info.rcWork;
71
+ // Replicate SDL's WIN_GetWindowBordersSize implementation (https://github.com/libsdl-org/SDL/blob/9f71a809e9bd6fbb5fa401a45c1537fc26abc1b4/src/video/windows/SDL_windowswindow.c#L514-L554)
72
+ // until it's patched to ignore the window drop shadow (window border is 1px but with drop shadow it's reported as 8px)
73
+ // REF: https://github.com/libsdl-org/SDL/issues/3835
74
+
75
+ static struct VideoSubsystem {
76
+ VideoSubsystem() { SDL_InitSubSystem(SDL_INIT_VIDEO); };
77
+ ~VideoSubsystem() { SDL_QuitSubSystem(SDL_INIT_VIDEO); };
78
+ } subsystem;
79
+
80
+ int index = window ? SDL_GetWindowDisplayIndex(Gosu::shared_window()) : 0;
81
+ SDL_Rect rect;
82
+ SDL_GetDisplayUsableBounds(index, &rect);
83
+
84
+ if (window) {
85
+ SDL_SysWMinfo info;
86
+ SDL_VERSION(&info.version);
87
+ SDL_GetWindowWMInfo(Gosu::shared_window(), &info);
88
+ HWND hwnd = info.info.win.window;
89
+
90
+ RECT rcClient, rcWindow;
91
+ POINT ptDiff;
92
+ int top = 0, left = 0, bottom = 0, right = 0;
93
+
94
+ /* rcClient stores the size of the inner window, while rcWindow stores the outer size relative to the top-left
95
+ * screen position; so the top/left values of rcClient are always {0,0} and bottom/right are {height,width} */
96
+ GetClientRect(hwnd, &rcClient);
97
+ DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &rcWindow, sizeof(rcWindow));
98
+
99
+ /* convert the top/left values to make them relative to
100
+ * the window; they will end up being slightly negative */
101
+ ptDiff.y = rcWindow.top;
102
+ ptDiff.x = rcWindow.left;
103
+
104
+ ScreenToClient(hwnd, &ptDiff);
105
+
106
+ rcWindow.top = ptDiff.y;
107
+ rcWindow.left = ptDiff.x;
108
+
109
+ /* convert the bottom/right values to make them relative to the window,
110
+ * these will be slightly bigger than the inner width/height */
111
+ ptDiff.y = rcWindow.bottom;
112
+ ptDiff.x = rcWindow.right;
113
+
114
+ ScreenToClient(hwnd, &ptDiff);
115
+
116
+ rcWindow.bottom = ptDiff.y;
117
+ rcWindow.right = ptDiff.x;
118
+
119
+ /* Now that both the inner and outer rects use the same coordinate system we can substract them to get the border size.
120
+ * Keep in mind that the top/left coordinates of rcWindow are negative because the border lies slightly before {0,0},
121
+ * so switch them around because SDL2 wants them in positive. */
122
+ top = rcClient.top - rcWindow.top;
123
+ left = rcClient.left - rcWindow.left;
124
+ bottom = rcWindow.bottom - rcClient.bottom;
125
+ right = rcWindow.right - rcClient.right;
126
+
127
+ rect.w -= left + right;
128
+ rect.h -= top + bottom;
78
129
  }
79
-
80
- RECT window_size = work_area;
81
- // Keep in sync with STYLE_NORMAL in SDL_windowswindow.c.
82
- DWORD style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
83
- AdjustWindowRectEx(&window_size, style, FALSE, 0);
84
-
85
- // Because AdjustWindowRectEx will make our rect larger, not smaller, we need to perform some
86
- // unintuitive math here.
87
- SIZE size;
88
- size.cx = 2 * (work_area.right - work_area.left) - (window_size.right - window_size.left);
89
- size.cy = 2 * (work_area.bottom - work_area.top) - (window_size.bottom - window_size.top);
90
- return size;
91
- }
92
130
 
93
- unsigned Gosu::available_width(Window* window)
94
- {
95
- return max_window_size(window).cx;
131
+ // Return a rect to have one less Gosu::available_width/height implementation.
132
+ return rect;
96
133
  }
134
+ #endif
97
135
 
98
- unsigned Gosu::available_height(Window* window)
136
+ #ifdef GOSU_IS_X
137
+ static SDL_Rect max_window_size(Gosu::Window* window)
99
138
  {
100
- return max_window_size(window).cy;
139
+ static struct VideoSubsystem {
140
+ VideoSubsystem() { SDL_InitSubSystem(SDL_INIT_VIDEO); };
141
+ ~VideoSubsystem() { SDL_QuitSubSystem(SDL_INIT_VIDEO); };
142
+ } subsystem;
143
+
144
+ int index = window ? SDL_GetWindowDisplayIndex(Gosu::shared_window()) : 0;
145
+ SDL_Rect rect;
146
+ int top, left, bottom, right;
147
+ SDL_GetDisplayUsableBounds(index, &rect);
148
+ SDL_GetWindowBordersSize(Gosu::shared_window(), &top, &left, &bottom, &right);
149
+
150
+ rect.w -= left + right;
151
+ rect.h -= top + bottom;
152
+
153
+ return rect;
101
154
  }
102
155
  #endif
103
156
 
104
- #ifdef GOSU_IS_X
105
- // Pessimistic fallback implementation for available_width / available_height.
106
- // TODO: Look at this NET_WORKAREA based implementation: https://github.com/glfw/glfw/pull/989/files
107
- unsigned Gosu::available_width(Window* window)
157
+ int Gosu::available_width(Window* window)
108
158
  {
109
- return static_cast<unsigned>(Gosu::screen_width(window) * 0.9);
159
+ return max_window_size(window).w;
110
160
  }
111
161
 
112
- unsigned Gosu::available_height(Window* window)
162
+ int Gosu::available_height(Window* window)
113
163
  {
114
- return static_cast<unsigned>(Gosu::screen_height(window) * 0.8);
164
+ return max_window_size(window).h;
115
165
  }
116
166
  #endif
117
-
118
- #endif