gosu 0.7.22 → 0.7.23

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/Gosu/Audio.hpp +2 -0
  2. data/Gosu/Fwd.hpp +0 -1
  3. data/Gosu/Gosu.hpp +1 -1
  4. data/Gosu/Graphics.hpp +12 -11
  5. data/Gosu/GraphicsBase.hpp +5 -0
  6. data/Gosu/Image.hpp +0 -14
  7. data/Gosu/Input.hpp +32 -18
  8. data/Gosu/Text.hpp +3 -2
  9. data/Gosu/Version.hpp +2 -2
  10. data/Gosu/Window.hpp +21 -8
  11. data/GosuImpl/Audio/AudioOpenAL.mm +74 -8
  12. data/GosuImpl/Graphics/Common.hpp +25 -1
  13. data/GosuImpl/Graphics/DrawOp.hpp +54 -222
  14. data/GosuImpl/Graphics/DrawOpQueue.hpp +127 -0
  15. data/GosuImpl/Graphics/FormattedString.hpp +63 -20
  16. data/GosuImpl/Graphics/GosuView.hpp +5 -8
  17. data/GosuImpl/Graphics/GosuView.mm +36 -65
  18. data/GosuImpl/Graphics/Graphics.cpp +121 -110
  19. data/GosuImpl/Graphics/Image.cpp +0 -51
  20. data/GosuImpl/Graphics/Macro.hpp +1 -0
  21. data/GosuImpl/Graphics/RenderState.hpp +107 -0
  22. data/GosuImpl/Graphics/TexChunk.cpp +1 -10
  23. data/GosuImpl/Graphics/Text.cpp +22 -10
  24. data/GosuImpl/Graphics/TextMac.cpp +2 -4
  25. data/GosuImpl/Graphics/TextTouch.mm +14 -21
  26. data/GosuImpl/Graphics/TextWin.cpp +5 -2
  27. data/GosuImpl/Graphics/Texture.cpp +11 -10
  28. data/GosuImpl/Graphics/Transform.cpp +3 -1
  29. data/GosuImpl/Input/AccelerometerReader.hpp +10 -0
  30. data/GosuImpl/Input/AccelerometerReader.mm +31 -0
  31. data/GosuImpl/InputMac.mm +51 -24
  32. data/GosuImpl/InputTouch.mm +112 -1
  33. data/GosuImpl/InputWin.cpp +27 -3
  34. data/GosuImpl/InputX.cpp +21 -0
  35. data/GosuImpl/MacUtility.hpp +33 -0
  36. data/GosuImpl/Orientation.hpp +15 -0
  37. data/GosuImpl/Orientation.mm +34 -0
  38. data/GosuImpl/RubyGosu.swg +7 -9
  39. data/GosuImpl/RubyGosu_wrap.cxx +328 -82
  40. data/GosuImpl/RubyGosu_wrap.h +3 -0
  41. data/GosuImpl/TextInputWin.cpp +2 -0
  42. data/GosuImpl/Utility.cpp +2 -0
  43. data/GosuImpl/WindowMac.mm +13 -19
  44. data/GosuImpl/WindowTouch.mm +44 -32
  45. data/GosuImpl/WindowWin.cpp +20 -12
  46. data/GosuImpl/WindowX.cpp +33 -23
  47. data/examples/CptnRuby.rb +8 -9
  48. data/lib/gosu.rb +0 -0
  49. data/lib/gosu/swig_patches.rb +0 -12
  50. data/linux/extconf.rb +2 -2
  51. metadata +11 -7
  52. data/Gosu/RotFlip.hpp +0 -125
  53. data/GosuImpl/Graphics/RotFlip.cpp +0 -184
@@ -5,7 +5,9 @@
5
5
  #include <Gosu/Utility.hpp>
6
6
  #include <boost/cstdint.hpp>
7
7
  #include <boost/foreach.hpp>
8
+ #include <boost/variant.hpp>
8
9
  #include <stdexcept>
10
+ #include <utility>
9
11
  #include <vector>
10
12
  #include <cwchar>
11
13
 
@@ -25,7 +27,11 @@ namespace Gosu
25
27
  return wc && other.wc && color == other.color && flags == other.flags;
26
28
  }
27
29
  };
28
- std::vector<FormattedChar> chars;
30
+
31
+ typedef std::pair<std::wstring, unsigned> SimpleImpl;
32
+ typedef std::vector<FormattedChar> FancyImpl;
33
+
34
+ boost::variant<SimpleImpl, FancyImpl> impl;
29
35
 
30
36
  static unsigned flags(int b, int u, int i)
31
37
  {
@@ -43,6 +49,14 @@ namespace Gosu
43
49
 
44
50
  explicit FormattedString(const std::wstring& html, unsigned baseFlags)
45
51
  {
52
+ if (html.find_first_of(L"<&") == std::wstring::npos)
53
+ {
54
+ impl = SimpleImpl(html, baseFlags);
55
+ return;
56
+ }
57
+
58
+ FancyImpl chars;
59
+
46
60
  unsigned pos = 0;
47
61
  int b = (baseFlags & ffBold) ? 1 : 0,
48
62
  u = (baseFlags & ffUnderline) ? 1 : 0,
@@ -89,7 +103,8 @@ namespace Gosu
89
103
  pos += 4;
90
104
  continue;
91
105
  }
92
- if (html.substr(pos, 3) == L"<c=" &&
106
+ if (html.length() >= pos + 10 &&
107
+ html.substr(pos, 3) == L"<c=" &&
93
108
  html.at(pos + 9) == L'>')
94
109
  {
95
110
  using namespace std;
@@ -99,7 +114,8 @@ namespace Gosu
99
114
  pos += 10;
100
115
  continue;
101
116
  }
102
- if (html.substr(pos, 3) == L"<c=" &&
117
+ if (html.length() >= pos + 12 &&
118
+ html.substr(pos, 3) == L"<c=" &&
103
119
  html.at(pos + 11) == L'>')
104
120
  {
105
121
  using namespace std;
@@ -149,6 +165,8 @@ namespace Gosu
149
165
  goto normalCharacter;
150
166
  }
151
167
  FormattedChar fc = { 0, c.back(), 0, std::wstring(html.begin() + pos + 1, html.begin() + endOfEntity) };
168
+ if (!isEntity(fc.entity))
169
+ goto normalCharacter;
152
170
  chars.push_back(fc);
153
171
  pos = endOfEntity + 1;
154
172
  continue;
@@ -159,10 +177,16 @@ namespace Gosu
159
177
  chars.push_back(fc);
160
178
  pos += 1;
161
179
  }
180
+
181
+ impl = chars;
162
182
  }
163
183
 
164
184
  std::wstring unformat() const
165
185
  {
186
+ if (const SimpleImpl* simpl = boost::get<SimpleImpl>(&impl))
187
+ return simpl->first;
188
+
189
+ const FancyImpl& chars = boost::get<FancyImpl>(impl);
166
190
  std::wstring result(length(), L' ');
167
191
  for (int i = 0; i < chars.size(); ++i)
168
192
  result[i] = chars[i].wc;
@@ -171,6 +195,10 @@ namespace Gosu
171
195
 
172
196
  const wchar_t* entityAt(unsigned index) const
173
197
  {
198
+ if (impl.which() == 0)
199
+ return 0;
200
+
201
+ const FancyImpl& chars = boost::get<FancyImpl>(impl);
174
202
  if (chars[index].wc != 0 || chars[index].entity.empty())
175
203
  return 0;
176
204
  return chars[index].entity.c_str();
@@ -178,28 +206,51 @@ namespace Gosu
178
206
 
179
207
  wchar_t charAt(unsigned index) const
180
208
  {
209
+ if (const SimpleImpl* simpl = boost::get<SimpleImpl>(&impl))
210
+ return simpl->first[index];
211
+
212
+ const FancyImpl& chars = boost::get<FancyImpl>(impl);
181
213
  return chars[index].wc;
182
214
  }
183
215
 
184
216
  unsigned flagsAt(unsigned index) const
185
217
  {
218
+ if (const SimpleImpl* simpl = boost::get<SimpleImpl>(&impl))
219
+ return simpl->second;
220
+
221
+ const FancyImpl& chars = boost::get<FancyImpl>(impl);
186
222
  return chars[index].flags;
187
223
  }
188
224
 
189
225
  Gosu::Color colorAt(unsigned index) const
190
226
  {
227
+ if (impl.which() == 0)
228
+ return Color::WHITE;
229
+
230
+ const FancyImpl& chars = boost::get<FancyImpl>(impl);
191
231
  return chars[index].color;
192
232
  }
193
233
 
194
234
  unsigned length() const
195
235
  {
236
+ if (const SimpleImpl* simpl = boost::get<SimpleImpl>(&impl))
237
+ return simpl->first.size();
238
+
239
+ const FancyImpl& chars = boost::get<FancyImpl>(impl);
196
240
  return chars.size();
197
241
  }
198
242
 
199
243
  FormattedString range(unsigned begin, unsigned end) const
200
244
  {
201
245
  FormattedString result;
202
- result.chars.assign(chars.begin() + begin, chars.begin() + end);
246
+
247
+ if (const SimpleImpl* simpl = boost::get<SimpleImpl>(&impl))
248
+ result.impl = SimpleImpl(std::wstring(simpl->first.begin() + begin, simpl->first.begin() + end), simpl->second);
249
+ else
250
+ {
251
+ const FancyImpl& chars = boost::get<FancyImpl>(impl);
252
+ result.impl = FancyImpl(chars.begin() + begin, chars.begin() + end);
253
+ }
203
254
  return result;
204
255
  }
205
256
 
@@ -208,38 +259,30 @@ namespace Gosu
208
259
  std::vector<FormattedString> result;
209
260
  unsigned begin = 0;
210
261
  for (unsigned cur = 0; cur < length(); ++cur)
211
- {
212
262
  if (charAt(cur) == L'\n')
213
263
  {
214
- FormattedString line;
215
- line.chars.assign(chars.begin() + begin, chars.begin() + cur);
216
- result.push_back(line);
264
+ result.push_back(range(begin, cur));
217
265
  begin = cur + 1;
218
266
  }
219
- }
220
- FormattedString line;
221
- line.chars.assign(chars.begin() + begin, chars.end());
222
- result.push_back(line);
267
+ result.push_back(range(begin, length()));
223
268
  return result;
224
269
  }
225
270
 
226
271
  std::vector<FormattedString> splitParts() const
227
272
  {
273
+ if (impl.which() == 0)
274
+ return std::vector<FormattedString>(1, *this);
275
+
276
+ const FancyImpl& chars = boost::get<FancyImpl>(impl);
228
277
  std::vector<FormattedString> result;
229
278
  unsigned begin = 0;
230
279
  for (unsigned cur = 1; cur < length(); ++cur)
231
- {
232
280
  if (!chars[begin].sameStyleAs(chars[cur]))
233
281
  {
234
- FormattedString line;
235
- line.chars.assign(chars.begin() + begin, chars.begin() + cur);
236
- result.push_back(line);
282
+ result.push_back(range(begin, cur));
237
283
  begin = cur;
238
284
  }
239
- }
240
- FormattedString line;
241
- line.chars.assign(chars.begin() + begin, chars.end());
242
- result.push_back(line);
285
+ result.push_back(range(begin, length()));
243
286
  return result;
244
287
  }
245
288
  };
@@ -4,6 +4,11 @@
4
4
  #import <OpenGLES/ES1/glext.h>
5
5
  #import <Gosu/Window.hpp>
6
6
 
7
+ // UIViewController subclass that creates a GosuView and helps it manage rotation.
8
+
9
+ @interface GosuViewController : UIViewController
10
+ @end
11
+
7
12
  // UIView subclass that contains a CAEAGLLayer.
8
13
 
9
14
  @interface GosuView : UIView {
@@ -22,13 +27,5 @@
22
27
  Gosu::Touches* currentTouchesVector;
23
28
  }
24
29
 
25
- - (const Gosu::Touches&)currentTouches;
26
-
27
30
  - (void)drawView;
28
-
29
- // This method is necessary because if pressing a LOT of touches, some
30
- // of them may end up not being sent to touchesEnded(), which is confusing
31
- // to application programmers.
32
- - (void)removeDeadTouches;
33
-
34
31
  @end
@@ -3,24 +3,39 @@
3
3
  #import <UIKit/UIKit.h>
4
4
 
5
5
  #import <Gosu/Graphics.hpp>
6
+ #import <GosuImpl/Graphics/Common.hpp>
6
7
  #import <GosuImpl/Graphics/GosuView.hpp>
7
8
 
8
9
  Gosu::Window& windowInstance();
9
10
 
10
- namespace {
11
- Gosu::Touches translateTouches(NSSet* touches, UIView* view)
11
+ int Gosu::clipRectBaseFactor()
12
+ {
13
+ static int result = 0;
14
+ if (result == 0)
12
15
  {
13
- Gosu::Touches result;
14
- for (UITouch* uiTouch in touches)
15
- {
16
- CGPoint point = [uiTouch locationInView: view];
17
- Gosu::Touch touch = { uiTouch, point.y, [view bounds].size.width - point.x };
18
- result.push_back(touch);
19
- }
20
- return result;
16
+ if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)])
17
+ result = [UIScreen mainScreen].scale;
18
+ else
19
+ result = 1;
21
20
  }
21
+ return result;
22
+ }
23
+
24
+ // A controller to allow for autorotation.
25
+ @implementation GosuViewController
26
+ - (void)loadView {
27
+ self.view = [[GosuView alloc] init];
22
28
  }
23
29
 
30
+ - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
31
+ return NO;//UIInterfaceOrientationIsLandscape(interfaceOrientation);
32
+ }
33
+
34
+ - (void)didReceiveMemoryWarning {
35
+ windowInstance().releaseMemory();
36
+ }
37
+ @end
38
+
24
39
  // A class extension to declare private methods
25
40
  @interface GosuView ()
26
41
 
@@ -40,8 +55,8 @@ namespace {
40
55
  return [CAEAGLLayer class];
41
56
  }
42
57
 
43
- - (id)initWithFrame:(CGRect)frame {
44
- if ((self = [super initWithFrame:frame])) {
58
+ - (id)init {
59
+ if ((self = [super initWithFrame: [[UIScreen mainScreen] bounds]])) {
45
60
  CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
46
61
 
47
62
  eaglLayer.opaque = YES;
@@ -76,15 +91,15 @@ namespace {
76
91
  [context presentRenderbuffer:GL_RENDERBUFFER_OES];
77
92
  }
78
93
 
79
-
80
94
  - (void)layoutSubviews {
81
95
  [EAGLContext setCurrentContext:context];
82
96
  [self destroyFramebuffer];
97
+ if ([self respondsToSelector:@selector(contentScaleFactor)])
98
+ self.contentScaleFactor = Gosu::clipRectBaseFactor();
83
99
  [self createFramebuffer];
84
100
  [self drawView];
85
101
  }
86
102
 
87
-
88
103
  - (BOOL)createFramebuffer {
89
104
  glGenFramebuffersOES(1, &viewFramebuffer);
90
105
  glGenRenderbuffersOES(1, &viewRenderbuffer);
@@ -116,38 +131,20 @@ namespace {
116
131
  delete currentTouchesVector;
117
132
  [currentTouches release];
118
133
  [EAGLContext setCurrentContext:nil];
119
- [context release];
134
+ [context release];
120
135
  [super dealloc];
121
136
  }
122
137
 
123
- - (const Gosu::Touches&)currentTouches {
124
- if (!currentTouchesVector)
125
- currentTouchesVector = new Gosu::Touches(translateTouches(currentTouches, self));
126
- return *currentTouchesVector;
127
- }
128
-
129
- - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
130
- delete currentTouchesVector; currentTouchesVector = 0;
131
- if (!currentTouches) currentTouches = [[NSMutableSet alloc] init];
132
-
133
- [currentTouches unionSet: touches];
134
-
135
- windowInstance().touchesBegan(translateTouches(touches, self));
138
+ - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
139
+ windowInstance().input().feedTouchEvent(0, touches);
136
140
  }
137
141
 
138
142
  - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
139
- delete currentTouchesVector; currentTouchesVector = 0;
140
-
141
- windowInstance().touchesMoved(translateTouches(touches, self));
143
+ windowInstance().input().feedTouchEvent(1, touches);
142
144
  }
143
145
 
144
146
  - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
145
- delete currentTouchesVector; currentTouchesVector = 0;
146
- if (!currentTouches) currentTouches = [[NSMutableSet alloc] init];
147
-
148
- [currentTouches minusSet: touches];
149
-
150
- windowInstance().touchesEnded(translateTouches(touches, self));
147
+ windowInstance().input().feedTouchEvent(2, touches);
151
148
  }
152
149
 
153
150
  - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
@@ -155,37 +152,11 @@ namespace {
155
152
  [self touchesEnded: touches withEvent: event];
156
153
  }
157
154
 
158
- - (void)removeDeadTouches {
159
- NSMutableSet* deadTouches = 0;
160
-
161
- for (UITouch* touch in currentTouches)
162
- {
163
- UITouchPhase phase = [touch phase];
164
- if (phase == UITouchPhaseBegan ||
165
- phase == UITouchPhaseMoved ||
166
- phase == UITouchPhaseStationary)
167
- continue;
168
-
169
- // Something was deleted, we will need the set.
170
- if (deadTouches == 0)
171
- deadTouches = [[NSMutableSet alloc] init];
172
- [deadTouches addObject:touch];
173
- }
174
-
175
- // Has something been deleted?
176
- if (deadTouches)
177
- {
178
- delete currentTouchesVector;
179
- [currentTouches minusSet: deadTouches];
180
- windowInstance().touchesEnded(translateTouches(deadTouches, self));
181
- }
182
- }
183
-
184
- - (bool)isMultipleTouchEnabled {
155
+ - (BOOL)isMultipleTouchEnabled {
185
156
  return YES;
186
157
  }
187
158
 
188
- - (bool)isExclusiveTouch {
159
+ - (BOOL)isExclusiveTouch {
189
160
  return YES;
190
161
  }
191
162
 
@@ -7,6 +7,7 @@
7
7
  #include <GosuImpl/Graphics/Macro.hpp>
8
8
  #include <Gosu/Bitmap.hpp>
9
9
  #include <Gosu/Image.hpp>
10
+ #include <Gosu/Platform.hpp>
10
11
  #include <boost/foreach.hpp>
11
12
  #if 0
12
13
  #include <boost/thread.hpp>
@@ -15,11 +16,15 @@
15
16
  #include <algorithm>
16
17
  #include <limits>
17
18
 
19
+ #ifdef GOSU_IS_IPHONE
20
+ #import <UIKit/UIKit.h>
21
+ #include <GosuImpl/Orientation.hpp>
22
+ #endif
23
+
18
24
  struct Gosu::Graphics::Impl
19
25
  {
20
- unsigned physWidth, physHeight;
21
26
  unsigned virtWidth, virtHeight;
22
- double factorX, factorY;
27
+ unsigned physWidth, physHeight;
23
28
  bool fullscreen;
24
29
  DrawOpQueueStack queues;
25
30
  typedef std::vector<boost::shared_ptr<Texture> > Textures;
@@ -30,47 +35,75 @@ struct Gosu::Graphics::Impl
30
35
  #if 0
31
36
  boost::mutex texMutex;
32
37
  #endif
38
+
39
+ #ifdef GOSU_IS_IPHONE
40
+ Transform transformForOrientation(Orientation orientation)
41
+ {
42
+ Transform result;
43
+ switch (orientation)
44
+ {
45
+ case orLandscapeLeft:
46
+ result = translate(physWidth, 0);
47
+ result = multiply(rotate(90), result);
48
+ result = multiply(scale(1.0 * physHeight / virtWidth, 1.0 * physWidth / virtHeight), result);
49
+ return result;
50
+ default:
51
+ result = translate(0, physHeight);
52
+ result = multiply(rotate(-90), result);
53
+ result = multiply(scale(1.0 * physHeight / virtWidth, 1.0 * physWidth / virtHeight), result);
54
+ return result;
55
+ }
56
+ }
33
57
 
34
- void calculateAbsoluteTransform()
58
+ Orientation orientation;
59
+
60
+ Impl()
61
+ : orientation(currentOrientation())
35
62
  {
36
- Transform result = scale(1);
37
- BOOST_REVERSE_FOREACH (const Transform& tf, currentTransforms)
38
- result = multiply(result, tf);
39
- absoluteTransforms.push_back(result);
40
63
  }
64
+
65
+ void updateBaseTransform()
66
+ {
67
+ if (orientation != currentOrientation())
68
+ {
69
+ orientation = currentOrientation();
70
+ currentTransforms.front() = transformForOrientation(orientation);
71
+ }
72
+ }
73
+ #endif
41
74
  };
42
75
 
43
76
  Gosu::Graphics::Graphics(unsigned physWidth, unsigned physHeight, bool fullscreen)
44
77
  : pimpl(new Impl)
45
78
  {
46
- pimpl->virtWidth = pimpl->physWidth = physWidth;
47
- pimpl->virtHeight = pimpl->physHeight = physHeight;
48
- pimpl->factorX = pimpl->factorY = 1.0;
79
+ pimpl->physWidth = physWidth;
80
+ pimpl->physHeight = physHeight;
81
+ pimpl->virtWidth = physWidth;
82
+ pimpl->virtHeight = physHeight;
83
+ #ifdef GOSU_IS_IPHONE
84
+ std::swap(pimpl->virtWidth, pimpl->virtHeight);
85
+ #endif
49
86
  pimpl->fullscreen = fullscreen;
50
87
 
51
88
  glMatrixMode(GL_PROJECTION);
52
89
  glLoadIdentity();
53
- glViewport(0, 0, pimpl->physWidth, pimpl->physHeight);
90
+ glViewport(0, 0, physWidth, physHeight);
54
91
  #ifdef GOSU_IS_IPHONE
55
- glOrthof(0, pimpl->physWidth, pimpl->physHeight, 0, -1, 1);
92
+ glOrthof(0, physWidth, physHeight, 0, -1, 1);
56
93
  #else
57
- glOrtho(0, pimpl->physWidth, pimpl->physHeight, 0, -1, 1);
94
+ glOrtho(0, physWidth, physHeight, 0, -1, 1);
58
95
  #endif
59
96
 
60
97
  glMatrixMode(GL_MODELVIEW);
61
98
  glLoadIdentity();
62
- #ifdef GOSU_IS_IPHONE
63
- glTranslatef(physWidth, 0, 0);
64
- glRotatef(90, 0, 0, 1);
65
- glScalef(3.0/2, 2.0/3, 0);
66
- #endif
67
-
99
+
68
100
  glEnable(GL_BLEND);
69
101
 
70
102
  // Create default draw-op queue.
71
103
  pimpl->queues.resize(1);
72
104
 
73
105
  // Push one identity matrix as the default transform.
106
+ pimpl->currentTransforms.push_back(scale(1));
74
107
  pimpl->absoluteTransforms.push_back(scale(1));
75
108
  }
76
109
 
@@ -80,12 +113,14 @@ Gosu::Graphics::~Graphics()
80
113
 
81
114
  unsigned Gosu::Graphics::width() const
82
115
  {
83
- return pimpl->virtWidth;
116
+ double size[2] = { pimpl->virtWidth, pimpl->virtHeight };
117
+ return size[0];
84
118
  }
85
119
 
86
120
  unsigned Gosu::Graphics::height() const
87
121
  {
88
- return pimpl->virtHeight;
122
+ double size[2] = { pimpl->virtWidth, pimpl->virtHeight };
123
+ return size[1];
89
124
  }
90
125
 
91
126
  bool Gosu::Graphics::fullscreen() const
@@ -93,30 +128,20 @@ bool Gosu::Graphics::fullscreen() const
93
128
  return pimpl->fullscreen;
94
129
  }
95
130
 
96
- double Gosu::Graphics::factorX() const
97
- {
98
- return pimpl->factorX;
99
- }
100
-
101
- double Gosu::Graphics::factorY() const
102
- {
103
- return pimpl->factorY;
104
- }
105
-
106
131
  void Gosu::Graphics::setResolution(unsigned virtualWidth, unsigned virtualHeight)
107
132
  {
108
- if (virtualWidth * virtualHeight < 1)
133
+ if (virtualWidth == 0 || virtualHeight == 0)
109
134
  throw std::invalid_argument("Invalid virtual resolution.");
110
-
111
- pimpl->virtWidth = virtualWidth;
112
- pimpl->virtHeight = virtualHeight;
113
- /*
114
- pimpl->factorX = pimpl->factorY =
115
- std::min(1.0 / virtualWidth * pimpl->physWidth,
116
- 1.0 / virtualHeight * pimpl->physHeight);
117
- */
118
- pimpl->factorX = 1.0 / virtualWidth * pimpl->physWidth;
119
- pimpl->factorY = 1.0 / virtualHeight * pimpl->physHeight;
135
+
136
+ pimpl->virtWidth = virtualWidth, pimpl->virtHeight = virtualHeight;
137
+ #ifdef GOSU_IS_IPHONE
138
+ pimpl->orientation = static_cast<Gosu::Orientation>(-1);
139
+ #else
140
+ Transform baseTransform;
141
+ baseTransform = scale(1.0 / virtualWidth * pimpl->physWidth,
142
+ 1.0 / virtualHeight * pimpl->physHeight);
143
+ pimpl->currentTransforms.front() = pimpl->absoluteTransforms.front() = baseTransform;
144
+ #endif
120
145
  }
121
146
 
122
147
  bool Gosu::Graphics::begin(Gosu::Color clearWithColor)
@@ -124,14 +149,15 @@ bool Gosu::Graphics::begin(Gosu::Color clearWithColor)
124
149
  // If there is a recording in process, stop it.
125
150
  // TODO: Raise exception?
126
151
  pimpl->queues.resize(1);
152
+ // Clear leftover clippings.
153
+ pimpl->queues.front().clear();
154
+
155
+ pimpl->currentTransforms.resize(1);
156
+ #ifdef GOSU_IS_IPHONE
157
+ pimpl->updateBaseTransform();
158
+ #endif
159
+ pimpl->absoluteTransforms = pimpl->currentTransforms;
127
160
 
128
- // If there are transformations in progress, clear them.
129
- pimpl->currentTransforms.resize(0);
130
- pimpl->absoluteTransforms.resize(1);
131
-
132
- // Flush leftover clippings
133
- endClipping();
134
-
135
161
  glClearColor(clearWithColor.red()/255.0,
136
162
  clearWithColor.green()/255.0,
137
163
  clearWithColor.blue()/255.0,
@@ -143,29 +169,18 @@ bool Gosu::Graphics::begin(Gosu::Color clearWithColor)
143
169
 
144
170
  void Gosu::Graphics::end()
145
171
  {
146
- /*double vBarWidth = pimpl->physWidth / factorX() - width();
147
- if (vBarWidth > 0)
148
- {
149
- drawQuad(0, 0, 0x00000000, vBarWidth, 0, 0x00000000,
150
- 0, height(), 0x00000000, vBarWidth, height(), 0x00000000,
151
- std::numeric_limits<double>::max());
152
- }
153
-
154
- double hBarHeight = pimpl->physHeight / factorY() - height();
155
- if (hBarHeight > 0)
156
- {
157
- drawQuad(0, 0, 0x00000000, width(), 0, 0x00000000,
158
- 0, hBarHeight, 0x00000000, width(), hBarHeight, 0x00000000,
159
- std::numeric_limits<double>::max());
160
- }*/
161
-
162
- // If there is a recording in process, stop it.
172
+ flush();
173
+
174
+ glFlush();
175
+ }
176
+
177
+ void Gosu::Graphics::flush()
178
+ {
179
+ // If there is a recording in process, cancel it.
163
180
  pimpl->queues.resize(1);
164
181
 
165
182
  pimpl->queues.at(0).performDrawOps();
166
183
  pimpl->queues.at(0).clear();
167
-
168
- glFlush();
169
184
  }
170
185
 
171
186
  void Gosu::Graphics::beginGL()
@@ -176,8 +191,7 @@ void Gosu::Graphics::beginGL()
176
191
  #ifdef GOSU_IS_IPHONE
177
192
  throw std::logic_error("Custom OpenGL is unsupported on the iPhone");
178
193
  #else
179
- pimpl->queues.at(0).performDrawOps();
180
- pimpl->queues.at(0).clear();
194
+ flush();
181
195
  glPushAttrib(GL_ALL_ATTRIB_BITS);
182
196
  glDisable(GL_BLEND);
183
197
  #endif
@@ -195,7 +209,7 @@ void Gosu::Graphics::endGL()
195
209
  glMatrixMode(GL_PROJECTION);
196
210
  glLoadIdentity();
197
211
  glViewport(0, 0, pimpl->physWidth, pimpl->physHeight);
198
- glOrtho(0, pimpl->virtWidth, pimpl->virtHeight, 0, -1, 1);
212
+ glOrtho(0, pimpl->physWidth, pimpl->physHeight, 0, -1, 1);
199
213
 
200
214
  glMatrixMode(GL_MODELVIEW);
201
215
  glLoadIdentity();
@@ -208,21 +222,22 @@ void Gosu::Graphics::beginClipping(int x, int y, unsigned width, unsigned height
208
222
  if (pimpl->queues.size() > 1)
209
223
  throw std::logic_error("Clipping not allowed while creating a macro");
210
224
 
211
- // In doubt, make the clipping region smaller than requested.
225
+ // Apply current transformation.
226
+
227
+ double left = x, right = x + width;
228
+ double top = y, bottom = y + height;
229
+
230
+ applyTransform(pimpl->absoluteTransforms.back(), left, top);
231
+ applyTransform(pimpl->absoluteTransforms.back(), right, bottom);
232
+
233
+ int physX = std::min(left, right);
234
+ int physY = std::min(top, bottom);
235
+ int physWidth = std::abs(left - right);
236
+ int physHeight = std::abs(top - bottom);
237
+
238
+ // Apply OpenGL's counting from the wrong side ;)
239
+ physY = pimpl->physHeight - physY - physHeight;
212
240
 
213
- #ifndef GOSU_IS_IPHONE
214
- int physX = static_cast<int>(std::ceil(x * factorX()));
215
- int physY = static_cast<int>(std::ceil((0.0 + this->height() - y - height) * factorY()));
216
- unsigned physWidth = static_cast<unsigned>(width * factorX());
217
- unsigned physHeight = static_cast<unsigned>(height * factorY());
218
- #else
219
- // Make up for rotation
220
- int physX = 320 - static_cast<int>(std::ceil(320.0 * (0.0 + y + height) / this->height()));
221
- int physY = 480 - static_cast<int>(std::ceil(480.0 * (0.0 + x + width) / this->width()));
222
- unsigned physWidth = static_cast<unsigned>(320.0 * height / this->height());
223
- unsigned physHeight = static_cast<unsigned>(480.0 * width / this->width());
224
- #endif
225
-
226
241
  pimpl->queues.back().beginClipping(physX, physY, physWidth, physHeight);
227
242
  }
228
243
 
@@ -249,16 +264,33 @@ std::auto_ptr<Gosu::ImageData> Gosu::Graphics::endRecording()
249
264
  return result;
250
265
  }
251
266
 
267
+ namespace
268
+ {
269
+ void ensureBackOfList(Gosu::Transforms& list, const Gosu::Transform& transform)
270
+ {
271
+ Gosu::Transforms::iterator oldPosition =
272
+ std::find(list.begin(), list.end(), transform);
273
+ if (oldPosition == list.end())
274
+ list.push_back(transform);
275
+ else
276
+ list.splice(list.end(), list, oldPosition);
277
+ }
278
+ }
279
+
252
280
  void Gosu::Graphics::pushTransform(const Gosu::Transform& transform)
253
281
  {
254
282
  pimpl->currentTransforms.push_back(transform);
255
- pimpl->calculateAbsoluteTransform();
283
+ Transform result = multiply(transform, pimpl->absoluteTransforms.back());
284
+ ensureBackOfList(pimpl->absoluteTransforms, result);
256
285
  }
257
286
 
258
287
  void Gosu::Graphics::popTransform()
259
288
  {
260
289
  pimpl->currentTransforms.pop_back();
261
- pimpl->calculateAbsoluteTransform();
290
+ Transform result = scale(1);
291
+ BOOST_REVERSE_FOREACH (const Transform& tf, pimpl->currentTransforms)
292
+ result = multiply(result, tf);
293
+ ensureBackOfList(pimpl->absoluteTransforms, result);
262
294
  }
263
295
 
264
296
  void Gosu::Graphics::drawLine(double x1, double y1, Color c1,
@@ -267,11 +299,6 @@ void Gosu::Graphics::drawLine(double x1, double y1, Color c1,
267
299
  {
268
300
  DrawOp op(pimpl->absoluteTransforms.back());
269
301
 
270
- x1 *= factorX();
271
- y1 *= factorY();
272
- x2 *= factorX();
273
- y2 *= factorY();
274
-
275
302
  op.mode = mode;
276
303
  op.usedVertices = 2;
277
304
  op.vertices[0] = DrawOp::Vertex(x1, y1, c1);
@@ -286,14 +313,7 @@ void Gosu::Graphics::drawTriangle(double x1, double y1, Color c1,
286
313
  ZPos z, AlphaMode mode)
287
314
  {
288
315
  DrawOp op(pimpl->absoluteTransforms.back());
289
-
290
- x1 *= factorX();
291
- y1 *= factorY();
292
- x2 *= factorX();
293
- y2 *= factorY();
294
- x3 *= factorX();
295
- y3 *= factorY();
296
-
316
+
297
317
  op.mode = mode;
298
318
  op.usedVertices = 3;
299
319
  op.vertices[0] = DrawOp::Vertex(x1, y1, c1);
@@ -316,16 +336,7 @@ void Gosu::Graphics::drawQuad(double x1, double y1, Color c1,
316
336
  reorderCoordinatesIfNecessary(x1, y1, x2, y2, x3, y3, c3, x4, y4, c4);
317
337
 
318
338
  DrawOp op(pimpl->absoluteTransforms.back());
319
-
320
- x1 *= factorX();
321
- y1 *= factorY();
322
- x2 *= factorX();
323
- y2 *= factorY();
324
- x3 *= factorX();
325
- y3 *= factorY();
326
- x4 *= factorX();
327
- y4 *= factorY();
328
-
339
+
329
340
  op.mode = mode;
330
341
  op.usedVertices = 4;
331
342
  op.vertices[0] = DrawOp::Vertex(x1, y1, c1);