gosu 0.7.38 → 0.7.39

Sign up to get free protection for your applications and to get access to all the features.
@@ -67,7 +67,7 @@ int Gosu::clipRectBaseFactor()
67
67
  CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
68
68
 
69
69
  eaglLayer.opaque = YES;
70
- /*eaglLayer.drawableProperties = [NSDictionary new]; /*dictionaryWithObjectsAndKeys:
70
+ /*eaglLayer.drawableProperties = dictionaryWithObjectsAndKeys:
71
71
  [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking,
72
72
  kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];*/
73
73
 
@@ -83,7 +83,9 @@ Gosu::Graphics::Graphics(unsigned physWidth, unsigned physHeight, bool fullscree
83
83
  std::swap(pimpl->virtWidth, pimpl->virtHeight);
84
84
  #endif
85
85
  pimpl->fullscreen = fullscreen;
86
-
86
+
87
+ // Should be merged into RenderState altogether.
88
+
87
89
  glMatrixMode(GL_PROJECTION);
88
90
  glLoadIdentity();
89
91
  glViewport(0, 0, physWidth, physHeight);
@@ -252,14 +254,14 @@ namespace
252
254
 
253
255
  void Gosu::Graphics::scheduleGL(const std::tr1::function<void()>& functor, Gosu::ZPos z)
254
256
  {
255
- pimpl->queues.back().scheduleGL(RunGLFunctor(*this, functor), z);
257
+ pimpl->queues.back().scheduleGL(pimpl->absoluteTransforms.back(), RunGLFunctor(*this, functor), z);
256
258
  }
257
259
  #endif
258
260
 
259
261
  void Gosu::Graphics::beginClipping(double x, double y, double width, double height)
260
262
  {
261
263
  if (pimpl->queues.size() > 1)
262
- throw std::logic_error("Clipping not allowed while creating a macro");
264
+ throw std::logic_error("Clipping not allowed while creating a macro yet");
263
265
 
264
266
  // Apply current transformation.
265
267
 
@@ -293,12 +295,12 @@ void Gosu::Graphics::beginRecording()
293
295
  pimpl->queues.resize(pimpl->queues.size() + 1);
294
296
  }
295
297
 
296
- std::auto_ptr<Gosu::ImageData> Gosu::Graphics::endRecording()
298
+ std::auto_ptr<Gosu::ImageData> Gosu::Graphics::endRecording(int width, int height)
297
299
  {
298
300
  if (pimpl->queues.size() == 1)
299
301
  throw std::logic_error("No macro recording in progress that can be captured");
300
302
 
301
- std::auto_ptr<ImageData> result(new Macro(*this, pimpl->queues.back()));
303
+ std::auto_ptr<ImageData> result(new Macro(*this, pimpl->queues.back(), width, height));
302
304
  pimpl->queues.pop_back();
303
305
  return result;
304
306
  }
@@ -318,6 +320,9 @@ namespace
318
320
 
319
321
  void Gosu::Graphics::pushTransform(const Gosu::Transform& transform)
320
322
  {
323
+ if (pimpl->queues.size() > 1)
324
+ throw std::logic_error("Transforms not allowed while creating a macro yet");
325
+
321
326
  pimpl->currentTransforms.push_back(transform);
322
327
  Transform result = multiply(transform, pimpl->absoluteTransforms.back());
323
328
  ensureBackOfList(pimpl->absoluteTransforms, result);
@@ -339,14 +344,14 @@ void Gosu::Graphics::drawLine(double x1, double y1, Color c1,
339
344
  double x2, double y2, Color c2,
340
345
  ZPos z, AlphaMode mode)
341
346
  {
342
- DrawOp op(pimpl->absoluteTransforms.back());
343
-
344
- op.mode = mode;
345
- op.usedVertices = 2;
347
+ DrawOp op;
348
+ op.renderState.transform = &pimpl->absoluteTransforms.back();
349
+ op.renderState.mode = mode;
350
+ op.verticesOrBlockIndex = 2;
346
351
  op.vertices[0] = DrawOp::Vertex(x1, y1, c1);
347
352
  op.vertices[1] = DrawOp::Vertex(x2, y2, c2);
348
-
349
- pimpl->queues.back().scheduleDrawOp(op, z);
353
+ op.z = z;
354
+ pimpl->queues.back().scheduleDrawOp(op);
350
355
  }
351
356
 
352
357
  void Gosu::Graphics::drawTriangle(double x1, double y1, Color c1,
@@ -354,19 +359,19 @@ void Gosu::Graphics::drawTriangle(double x1, double y1, Color c1,
354
359
  double x3, double y3, Color c3,
355
360
  ZPos z, AlphaMode mode)
356
361
  {
357
- DrawOp op(pimpl->absoluteTransforms.back());
358
-
359
- op.mode = mode;
360
- op.usedVertices = 3;
362
+ DrawOp op;
363
+ op.renderState.transform = &pimpl->absoluteTransforms.back();
364
+ op.renderState.mode = mode;
365
+ op.verticesOrBlockIndex = 3;
361
366
  op.vertices[0] = DrawOp::Vertex(x1, y1, c1);
362
367
  op.vertices[1] = DrawOp::Vertex(x2, y2, c2);
363
368
  op.vertices[2] = DrawOp::Vertex(x3, y3, c3);
364
369
  #ifdef GOSU_IS_IPHONE
365
- op.usedVertices = 4;
370
+ op.verticesOrBlockIndex = 4;
366
371
  op.vertices[3] = op.vertices[2];
367
372
  #endif
368
-
369
- pimpl->queues.back().scheduleDrawOp(op, z);
373
+ op.z = z;
374
+ pimpl->queues.back().scheduleDrawOp(op);
370
375
  }
371
376
 
372
377
  void Gosu::Graphics::drawQuad(double x1, double y1, Color c1,
@@ -377,10 +382,10 @@ void Gosu::Graphics::drawQuad(double x1, double y1, Color c1,
377
382
  {
378
383
  reorderCoordinatesIfNecessary(x1, y1, x2, y2, x3, y3, c3, x4, y4, c4);
379
384
 
380
- DrawOp op(pimpl->absoluteTransforms.back());
381
-
382
- op.mode = mode;
383
- op.usedVertices = 4;
385
+ DrawOp op;
386
+ op.renderState.transform = &pimpl->absoluteTransforms.back();
387
+ op.renderState.mode = mode;
388
+ op.verticesOrBlockIndex = 4;
384
389
  op.vertices[0] = DrawOp::Vertex(x1, y1, c1);
385
390
  op.vertices[1] = DrawOp::Vertex(x2, y2, c2);
386
391
  // TODO: Should be harmonized
@@ -391,8 +396,8 @@ void Gosu::Graphics::drawQuad(double x1, double y1, Color c1,
391
396
  op.vertices[3] = DrawOp::Vertex(x3, y3, c3);
392
397
  op.vertices[2] = DrawOp::Vertex(x4, y4, c4);
393
398
  #endif
394
-
395
- pimpl->queues.back().scheduleDrawOp(op, z);
399
+ op.z = z;
400
+ pimpl->queues.back().scheduleDrawOp(op);
396
401
  }
397
402
 
398
403
  std::auto_ptr<Gosu::ImageData> Gosu::Graphics::createImage(
@@ -48,12 +48,12 @@ Gosu::LargeImageData::LargeImageData(Graphics& graphics,
48
48
  }
49
49
  }
50
50
 
51
- unsigned Gosu::LargeImageData::width() const
51
+ int Gosu::LargeImageData::width() const
52
52
  {
53
53
  return fullWidth;
54
54
  }
55
55
 
56
- unsigned Gosu::LargeImageData::height() const
56
+ int Gosu::LargeImageData::height() const
57
57
  {
58
58
  return fullHeight;
59
59
  }
@@ -17,8 +17,8 @@ namespace Gosu
17
17
  LargeImageData(Graphics& graphics, const Bitmap& source,
18
18
  unsigned partWidth, unsigned partHeight, unsigned borderFlags);
19
19
 
20
- unsigned width() const;
21
- unsigned height() const;
20
+ int width() const;
21
+ int height() const;
22
22
 
23
23
  void draw(double x1, double y1, Color c1,
24
24
  double x2, double y2, Color c2,
@@ -9,82 +9,85 @@
9
9
  #include <cmath>
10
10
  #include <algorithm>
11
11
  #include <memory>
12
+ #include <stdexcept>
12
13
 
13
14
  class Gosu::Macro : public Gosu::ImageData
14
15
  {
15
- VertexArray vertexArray;
16
- unsigned w, h;
17
-
18
16
  Graphics& graphics;
19
- public:
20
- Macro(Graphics& graphics, DrawOpQueue& queue)
21
- : graphics(graphics)
17
+ VertexArrays vertexArrays;
18
+ std::vector<Transform> embeddedTransforms;
19
+ int givenWidth, givenHeight;
20
+
21
+ void realDraw(double x1, double y1, double x2, double y3) const
22
22
  {
23
- queue.compileTo(vertexArray);
24
- double left = 0, right = 0, top = 0, bottom = 0;
25
- for (VertexArray::const_iterator it = vertexArray.begin(),
26
- end = vertexArray.end(); it != end; ++it)
23
+ // TODO: Macros should not be split up because they have different transforms! This is insane.
24
+ // They should be premultiplied and have the same transform by definition. Then, the transformation
25
+ // only had to be performed here once.
26
+
27
+ #ifndef GOSU_IS_IPHONE
28
+ glEnable(GL_BLEND);
29
+ glMatrixMode(GL_MODELVIEW);
30
+
31
+ for (VertexArrays::const_iterator it = vertexArrays.begin(), end = vertexArrays.end(); it != end; ++it)
27
32
  {
28
- left = std::min<double>(left, it->vertices[0]);
29
- right = std::max<double>(right, it->vertices[0]);
30
- top = std::min<double>(top, it->vertices[1]);
31
- bottom = std::max<double>(bottom, it->vertices[1]);
33
+ glPushMatrix();
34
+ it->renderState.apply();
35
+
36
+ glTranslated(x1, y1, 0);
37
+ glScaled((x2 - x1) / width(), (y3 - y1) / height(), 1);
38
+
39
+ glInterleavedArrays(GL_T2F_C4UB_V3F, 0, &it->vertices[0]);
40
+ glDrawArrays(GL_QUADS, 0, it->vertices.size());
41
+ glPopMatrix();
32
42
  }
33
- w = std::ceil(right - left);
34
- h = std::ceil(bottom - top);
43
+ #endif
35
44
  }
36
45
 
37
- unsigned int width() const
46
+ public:
47
+ Macro(Graphics& graphics, DrawOpQueue& queue, int width, int height)
48
+ : graphics(graphics), givenWidth(width), givenHeight(height)
38
49
  {
39
- return w;
50
+ queue.compileTo(vertexArrays);
51
+
52
+ // Very important fix: RenderState only contains a (non-owned) pointer to a Transform.
53
+ // If we want to use this Macro in more than a single frame, the pointer would be
54
+ // invalidated. Hence, we copy the transform into this macro and just let the
55
+ // RenderState refer to that one.
56
+
57
+ // TODO: As the next step, we should flatten all the transforms into a single one. But
58
+ // maybe not here, as the VertexArrays are already split up, possibly because their
59
+ // transforms differed.
60
+
61
+ embeddedTransforms.reserve(vertexArrays.size());
62
+ for (VertexArrays::iterator it = vertexArrays.begin(), end = vertexArrays.end(); it != end; ++it)
63
+ {
64
+ embeddedTransforms.push_back(*it->renderState.transform);
65
+ it->renderState.transform = &embeddedTransforms.back();
66
+ }
40
67
  }
41
68
 
42
- unsigned int height() const
69
+ int width() const
43
70
  {
44
- return h;
71
+ return givenWidth;
45
72
  }
46
73
 
47
- void draw(double x1, double y1, Color c1,
48
- double x2, double y2, Color c2,
49
- double x3, double y3, Color c3,
50
- double x4, double y4, Color c4,
51
- ZPos z, AlphaMode mode) const
74
+ int height() const
52
75
  {
53
- std::tr1::function<void()> f = std::tr1::bind(&Macro::realDraw, this, x1, y1, x2, y2, x3, y3);
54
- graphics.scheduleGL(f, z);
76
+ return givenHeight;
55
77
  }
56
78
 
57
- void realDraw(double x1, double y1,
58
- double x2, double y2,
59
- double x3, double y3) const
79
+ void draw(double x1, double y1, Color c1,
80
+ double x2, double y2, Color c2,
81
+ double x3, double y3, Color c3,
82
+ double x4, double y4, Color c4,
83
+ ZPos z, AlphaMode mode) const
60
84
  {
61
- // Empty record- avoid division by zero.
62
- if (vertexArray.empty())
63
- return;
64
-
65
- // TODO: Commented out for now on the iPhone.
66
- // To work, it would need to reset the VertexPointer etc. after doing its work.
67
- #ifndef GOSU_IS_IPHONE
68
- glEnable(GL_BLEND);
69
- RenderState rs;
70
- rs.setTexName(1);
71
- rs.setAlphaMode(amDefault);
72
-
73
- // TODO: We should apply current transformations either here or in draw(), or both.
74
- // TODO: Also, calculate the transform as a matrix and use RenderState::setTransform.
75
-
76
- glMatrixMode(GL_MODELVIEW);
77
- //glPushMatrix();
78
- glTranslated(x1, y1, 0);
79
- glScaled((x2 - x1) / width(), (y3 - y1) / height(), 1);
80
-
81
- glInterleavedArrays(GL_T2F_C4UB_V3F, 0, &vertexArray[0]);
82
-
83
- glDrawArrays(GL_QUADS, 0, vertexArray.size());
84
- glFlush();
85
-
86
- //glPopMatrix();
87
- #endif
85
+ if (x1 != x3 || x2 != x4 || y1 != y2 || y3 != y4)
86
+ throw std::invalid_argument("Macros cannot be rotated yet");
87
+ if (c1 != 0xffffffff || c2 != 0xffffffff || c3 != 0xffffffff || c4 != 0xffffffff)
88
+ throw std::invalid_argument("Macros cannot be tinted with colors yet");
89
+ std::tr1::function<void()> f = std::tr1::bind(&Macro::realDraw, this, x1, y1, x2, y3);
90
+ graphics.scheduleGL(f, z);
88
91
  }
89
92
 
90
93
  const Gosu::GLTexInfo* glTexInfo() const
@@ -94,14 +97,13 @@ public:
94
97
 
95
98
  Gosu::Bitmap toBitmap() const
96
99
  {
97
- throw std::logic_error("Gosu::Macro cannot be rendered as Gosu::Bitmap");
100
+ throw std::logic_error("Gosu::Macro cannot be rendered as Gosu::Bitmap yet");
98
101
  }
99
102
 
100
103
  void insert(const Bitmap& bitmap, int x, int y)
101
104
  {
102
- throw std::logic_error("Gosu::Macro cannot be updated with a Gosu::Bitmap");
105
+ throw std::logic_error("Gosu::Macro cannot be updated with a Gosu::Bitmap yet");
103
106
  }
104
107
  };
105
108
 
106
109
  #endif
107
-
@@ -3,47 +3,121 @@
3
3
 
4
4
  #include <GosuImpl/Graphics/Common.hpp>
5
5
 
6
- class Gosu::RenderState
6
+ // Properties that potentially need to be changed between each draw operation.
7
+ // This does not include the color or vertex data of the actual quads.
8
+ struct Gosu::RenderState
7
9
  {
8
10
  GLuint texName;
9
11
  Transform* transform;
10
- unsigned clipX, clipY, clipWidth, clipHeight;
12
+ ClipRect clipRect;
11
13
  AlphaMode mode;
12
14
 
13
- public:
14
15
  RenderState()
15
- : texName(NO_TEXTURE), transform(0), clipWidth(NO_CLIPPING), mode(amDefault)
16
+ : texName(NO_TEXTURE), transform(0), mode(amDefault)
16
17
  {
17
- glMatrixMode(GL_MODELVIEW);
18
- glPushMatrix();
19
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
18
+ clipRect.width = NO_CLIPPING;
20
19
  }
21
20
 
22
- ~RenderState()
21
+ bool operator==(const RenderState& rhs) const
23
22
  {
24
- setClipRect(NO_CLIPPING, NO_CLIPPING, NO_CLIPPING, NO_CLIPPING);
25
- setTexName(NO_TEXTURE);
26
- glPopMatrix();
23
+ return texName == rhs.texName && transform == rhs.transform &&
24
+ clipRect == rhs.clipRect && mode == rhs.mode;
27
25
  }
28
26
 
29
- void setTransform(Transform* newTransform)
27
+ void applyTexture() const
30
28
  {
31
- if (newTransform == transform)
32
- return;
33
-
29
+ if (texName == NO_TEXTURE)
30
+ glDisable(GL_TEXTURE_2D);
31
+ else
32
+ {
33
+ glEnable(GL_TEXTURE_2D);
34
+ glBindTexture(GL_TEXTURE_2D, texName);
35
+ }
36
+ }
37
+
38
+ void applyAlphaMode() const
39
+ {
40
+ if (mode == amAdd)
41
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE);
42
+ else if (mode == amMultiply)
43
+ glBlendFunc(GL_DST_COLOR, GL_ZERO);
44
+ else
45
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
46
+ }
47
+
48
+ void applyClipRect() const
49
+ {
50
+ if (clipRect.width == NO_CLIPPING)
51
+ glDisable(GL_SCISSOR_TEST);
52
+ else
53
+ {
54
+ glEnable(GL_SCISSOR_TEST);
55
+ glScissor(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
56
+ }
57
+ }
58
+
59
+ // Only used by Macro so far
60
+ #ifndef GOSU_IS_IPHONE
61
+ void apply() const
62
+ {
63
+ applyTexture();
64
+ glMultMatrixd(&(*transform)[0]);
65
+ // cliprect from the outside is okay
66
+ applyAlphaMode();
67
+ }
68
+ #endif
69
+ };
70
+
71
+ // Manages the OpenGL rendering state. It caches the current state, only forwarding the
72
+ // changes to OpenGL if the new state is really different.
73
+ class Gosu::RenderStateManager : private Gosu::RenderState
74
+ {
75
+ // Not copyable
76
+ RenderStateManager(const RenderStateManager&);
77
+ RenderStateManager& operator=(const RenderStateManager&);
78
+
79
+ void applyTransform() const
80
+ {
81
+ glMatrixMode(GL_MODELVIEW);
34
82
  glPopMatrix();
35
83
  glPushMatrix();
84
+
36
85
  #ifndef GOSU_IS_IPHONE
37
- glMultMatrixd(&(*newTransform)[0]);
86
+ glMultMatrixd(&(*transform)[0]);
38
87
  #else
39
- float matrix[16];
88
+ // TODO: Ouch, should always use floats!
89
+ GLfloat matrix[16];
40
90
  for (int i = 0; i < 16; ++i)
41
- matrix[i] = (*newTransform)[i];
91
+ matrix[i] = (*transform)[i];
42
92
  glMultMatrixf(matrix);
43
93
  #endif
44
- transform = newTransform;
45
94
  }
46
-
95
+
96
+ public:
97
+ RenderStateManager()
98
+ {
99
+ glMatrixMode(GL_MODELVIEW);
100
+ glPushMatrix();
101
+ applyAlphaMode();
102
+ }
103
+
104
+ ~RenderStateManager()
105
+ {
106
+ ClipRect noClipping;
107
+ noClipping.width = NO_CLIPPING;
108
+ setClipRect(noClipping);
109
+ setTexName(NO_TEXTURE);
110
+ glPopMatrix();
111
+ }
112
+
113
+ void setRenderState(const RenderState& rs)
114
+ {
115
+ setTexName(rs.texName);
116
+ setTransform(rs.transform);
117
+ setClipRect(rs.clipRect);
118
+ setAlphaMode(rs.mode);
119
+ }
120
+
47
121
  void setTexName(GLuint newTexName)
48
122
  {
49
123
  if (newTexName == texName)
@@ -60,33 +134,40 @@ public:
60
134
  texName = newTexName;
61
135
  }
62
136
 
63
- void setClipRect(unsigned newClipX, unsigned newClipY,
64
- unsigned newClipWidth, unsigned newClipHeight)
137
+ void setTransform(Transform* newTransform)
65
138
  {
66
- if (newClipWidth == NO_CLIPPING)
139
+ if (newTransform == transform)
140
+ return;
141
+ transform = newTransform;
142
+
143
+ applyTransform();
144
+ }
145
+
146
+ void setClipRect(const ClipRect& newClipRect)
147
+ {
148
+ if (newClipRect.width == NO_CLIPPING)
67
149
  {
68
150
  // Disable clipping
69
- if (clipWidth != NO_CLIPPING)
151
+ if (clipRect.width != NO_CLIPPING)
70
152
  {
71
153
  glDisable(GL_SCISSOR_TEST);
72
- clipWidth = NO_CLIPPING;
154
+ clipRect.width = NO_CLIPPING;
73
155
  }
74
156
  }
75
157
  else
76
158
  {
77
159
  // Enable clipping if off
78
- if (clipWidth == NO_CLIPPING)
160
+ if (clipRect.width == NO_CLIPPING)
79
161
  {
80
162
  glEnable(GL_SCISSOR_TEST);
81
- glScissor(clipX = newClipX, clipY = newClipY,
82
- clipWidth = newClipWidth, clipHeight = newClipHeight);
163
+ clipRect = newClipRect;
164
+ glScissor(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
83
165
  }
84
166
  // Adjust clipping if necessary
85
- else if (clipX != newClipX || clipY != newClipY ||
86
- clipWidth != newClipWidth || clipHeight != newClipHeight)
167
+ else if (!(clipRect == newClipRect))
87
168
  {
88
- glScissor(clipX = newClipX, clipY = newClipY,
89
- clipWidth = newClipWidth, clipHeight = newClipHeight);
169
+ clipRect = newClipRect;
170
+ glScissor(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
90
171
  }
91
172
  }
92
173
  }
@@ -96,12 +177,19 @@ public:
96
177
  if (newMode == mode)
97
178
  return;
98
179
  mode = newMode;
99
- if (mode == amAdd)
100
- glBlendFunc(GL_SRC_ALPHA, GL_ONE);
101
- else if (mode == amMultiply)
102
- glBlendFunc(GL_DST_COLOR, GL_ZERO);
103
- else
104
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
180
+ applyAlphaMode();
181
+ }
182
+
183
+ // The cached values may have been messed with. Reset them again.
184
+ void enforceAfterUntrustedGL() const
185
+ {
186
+ // TODO: Actually, we don't have to worry about anything pushed
187
+ // using glPushAttribs because beginGL/endGL will take care of that.
188
+
189
+ applyTexture();
190
+ applyTransform();
191
+ applyClipRect();
192
+ applyAlphaMode();
105
193
  }
106
194
  };
107
195