gosu 0.7.50 → 0.8.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
@@ -38,7 +38,7 @@ namespace Gosu
38
38
  assert (verticesOrBlockIndex >= 2);
39
39
  assert (verticesOrBlockIndex <= 4);
40
40
 
41
- #ifdef GOSU_IS_IPHONE
41
+ #ifdef GOSU_IS_OPENGLES
42
42
  static const unsigned MAX_AUTOGROUP = 24;
43
43
 
44
44
  static int spriteCounter = 0;
@@ -61,9 +61,7 @@ namespace Gosu
61
61
 
62
62
  isSetup = true;
63
63
  }
64
- #endif
65
64
 
66
- #ifdef GOSU_IS_IPHONE
67
65
  if (renderState.texture)
68
66
  {
69
67
  spriteTexcoords[spriteCounter*12 + 0] = left;
@@ -80,9 +78,29 @@ namespace Gosu
80
78
  spriteTexcoords[spriteCounter*12 + 10] = right;
81
79
  spriteTexcoords[spriteCounter*12 + 11] = bottom;
82
80
  }
83
- #endif
81
+
82
+ for (int i = 0; i < 3; ++i)
83
+ {
84
+ spriteVertices[spriteCounter*12 + i*2] = vertices[i].x;
85
+ spriteVertices[spriteCounter*12 + i*2+1] = vertices[i].y;
86
+ spriteColors[spriteCounter*6 + i] = vertices[i].c.abgr();
87
+ }
88
+ for (int i = 0; i < 3; ++i)
89
+ {
90
+ spriteVertices[spriteCounter*12 + 6 + i*2] = vertices[i + 1].x;
91
+ spriteVertices[spriteCounter*12 + 6 + i*2+1] = vertices[i + 1].y;
92
+ spriteColors[spriteCounter*6 + 3 + i] = vertices[i + 1].c.abgr();
93
+ }
84
94
 
85
- #ifndef GOSU_IS_IPHONE
95
+ ++spriteCounter;
96
+ if (spriteCounter == MAX_AUTOGROUP || next == 0 || !(next->renderState == renderState))
97
+ {
98
+ glDrawArrays(GL_TRIANGLES, 0, 6 * spriteCounter);
99
+ //if (spriteCounter > 1)
100
+ // printf("grouped %d quads\n", spriteCounter);
101
+ spriteCounter = 0;
102
+ }
103
+ #else
86
104
  if (verticesOrBlockIndex == 2)
87
105
  glBegin(GL_LINES);
88
106
  else if (verticesOrBlockIndex == 3)
@@ -113,28 +131,6 @@ namespace Gosu
113
131
  }
114
132
 
115
133
  glEnd();
116
- #else
117
- for (int i = 0; i < 3; ++i)
118
- {
119
- spriteVertices[spriteCounter*12 + i*2] = vertices[i].x;
120
- spriteVertices[spriteCounter*12 + i*2+1] = vertices[i].y;
121
- spriteColors[spriteCounter*6 + i] = vertices[i].c.abgr();
122
- }
123
- for (int i = 0; i < 3; ++i)
124
- {
125
- spriteVertices[spriteCounter*12 + 6 + i*2] = vertices[i + 1].x;
126
- spriteVertices[spriteCounter*12 + 6 + i*2+1] = vertices[i + 1].y;
127
- spriteColors[spriteCounter*6 + 3 + i] = vertices[i + 1].c.abgr();
128
- }
129
-
130
- ++spriteCounter;
131
- if (spriteCounter == MAX_AUTOGROUP || next == 0 || !(next->renderState == renderState))
132
- {
133
- glDrawArrays(GL_TRIANGLES, 0, 6 * spriteCounter);
134
- //if (spriteCounter > 1)
135
- // printf("grouped %d quads\n", spriteCounter);
136
- spriteCounter = 0;
137
- }
138
134
  #endif
139
135
  }
140
136
 
@@ -28,7 +28,7 @@ public:
28
28
  if (clipRectStack.clippedWorldAway())
29
29
  return;
30
30
 
31
- #ifdef GOSU_IS_IPHONE
31
+ #ifdef GOSU_IS_OPENGLES
32
32
  // No triangles, no lines supported
33
33
  assert (op.verticesOrBlockIndex == 4);
34
34
  #endif
@@ -104,7 +104,7 @@ public:
104
104
  std::stable_sort(ops.begin(), ops.end());
105
105
 
106
106
  RenderStateManager manager;
107
- #ifdef GOSU_IS_IPHONE
107
+ #ifdef GOSU_IS_OPENGLES
108
108
  if (ops.empty())
109
109
  return;
110
110
 
@@ -16,6 +16,7 @@ struct Gosu::Graphics::Impl
16
16
  {
17
17
  unsigned virtWidth, virtHeight;
18
18
  unsigned physWidth, physHeight;
19
+ double blackWidth, blackHeight;
19
20
  bool fullscreen;
20
21
  DrawOpQueueStack queues;
21
22
  typedef std::vector<std::tr1::shared_ptr<Texture> > Textures;
@@ -30,13 +31,14 @@ Gosu::Graphics::Graphics(unsigned physWidth, unsigned physHeight, bool fullscree
30
31
  pimpl->virtWidth = physWidth;
31
32
  pimpl->virtHeight = physHeight;
32
33
  pimpl->fullscreen = fullscreen;
34
+ pimpl->blackWidth = 0;
35
+ pimpl->blackHeight = 0;
33
36
 
34
- // Should be merged into RenderState altogether.
35
-
37
+ // TODO: Should be merged into RenderState and removed from Graphics.
36
38
  glMatrixMode(GL_PROJECTION);
37
39
  glLoadIdentity();
38
40
  glViewport(0, 0, physWidth, physHeight);
39
- #ifdef GOSU_IS_IPHONE
41
+ #ifdef GOSU_IS_OPENGLES
40
42
  glOrthof(0, physWidth, physHeight, 0, -1, 1);
41
43
  #else
42
44
  glOrtho(0, physWidth, physHeight, 0, -1, 1);
@@ -70,15 +72,26 @@ bool Gosu::Graphics::fullscreen() const
70
72
  return pimpl->fullscreen;
71
73
  }
72
74
 
73
- void Gosu::Graphics::setResolution(unsigned virtualWidth, unsigned virtualHeight)
75
+ void Gosu::Graphics::setResolution(unsigned virtualWidth, unsigned virtualHeight,
76
+ double horizontalBlackBarWidth, double verticalBlackBarHeight)
74
77
  {
75
78
  if (virtualWidth == 0 || virtualHeight == 0)
76
79
  throw std::invalid_argument("Invalid virtual resolution.");
77
80
 
78
- pimpl->virtWidth = virtualWidth, pimpl->virtHeight = virtualHeight;
79
- double scaleX = 1.0 / virtualWidth * pimpl->physWidth;
80
- double scaleY = 1.0 / virtualHeight * pimpl->physHeight;
81
- pimpl->queues.front().setBaseTransform(scale(scaleX, scaleY));
81
+ pimpl->virtWidth = virtualWidth;
82
+ pimpl->virtHeight = virtualHeight;
83
+ pimpl->blackWidth = horizontalBlackBarWidth;
84
+ pimpl->blackHeight = verticalBlackBarHeight;
85
+
86
+ double scaleX = 1.0 * pimpl->physWidth / virtualWidth;
87
+ double scaleY = 1.0 * pimpl->physHeight / virtualHeight;
88
+ double scaleFactor = std::min(scaleX, scaleY);
89
+
90
+ Transform scaleTransform = scale(scaleFactor);
91
+ Transform translateTransform = translate(pimpl->blackWidth, pimpl->blackHeight);
92
+ Transform baseTransform = concat(translateTransform, scaleTransform);
93
+
94
+ pimpl->queues.front().setBaseTransform(baseTransform);
82
95
  }
83
96
 
84
97
  bool Gosu::Graphics::begin(Gosu::Color clearWithColor)
@@ -99,11 +112,34 @@ bool Gosu::Graphics::begin(Gosu::Color clearWithColor)
99
112
  void Gosu::Graphics::end()
100
113
  {
101
114
  // If recording is in process, cancel it.
102
- assert (pimpl->queues.size() == 1);
103
115
  pimpl->queues.resize(1);
104
116
 
105
117
  flush();
106
118
 
119
+ if (pimpl->blackHeight || pimpl->blackWidth) {
120
+ if (pimpl->blackHeight) {
121
+ drawQuad(0, -pimpl->blackHeight, Color::BLACK,
122
+ width(), -pimpl->blackHeight, Color::BLACK,
123
+ 0, 0, Color::BLACK,
124
+ width(), 0, Color::BLACK, 0);
125
+ drawQuad(0, height(), Color::BLACK,
126
+ width(), height(), Color::BLACK,
127
+ 0, height() + pimpl->blackHeight, Color::BLACK,
128
+ width(), height() + pimpl->blackHeight, Color::BLACK, 0);
129
+ }
130
+ else if (pimpl->blackWidth) {
131
+ drawQuad(-pimpl->blackWidth, 0, Color::BLACK,
132
+ 0, 0, Color::BLACK,
133
+ -pimpl->blackWidth, height(), Color::BLACK,
134
+ 0, height(), Color::BLACK, 0);
135
+ drawQuad(width(), 0, Color::BLACK,
136
+ width() + pimpl->blackWidth, 0, Color::BLACK,
137
+ width(), height(), Color::BLACK,
138
+ width() + pimpl->blackWidth, height(), Color::BLACK, 0);
139
+ }
140
+ flush();
141
+ }
142
+
107
143
  glFlush();
108
144
  }
109
145
 
@@ -121,8 +157,8 @@ void Gosu::Graphics::beginGL()
121
157
  if (pimpl->queues.size() > 1)
122
158
  throw std::logic_error("Custom OpenGL is not allowed while creating a macro");
123
159
 
124
- #ifdef GOSU_IS_IPHONE
125
- throw std::logic_error("Custom OpenGL is unsupported on the iPhone");
160
+ #ifdef GOSU_IS_OPENGLES
161
+ throw std::logic_error("Custom OpenGL ES is not supported yet");
126
162
  #else
127
163
  flush();
128
164
  glPushAttrib(GL_ALL_ATTRIB_BITS);
@@ -133,13 +169,14 @@ void Gosu::Graphics::beginGL()
133
169
 
134
170
  void Gosu::Graphics::endGL()
135
171
  {
136
- #ifdef GOSU_IS_IPHONE
137
- throw std::logic_error("Custom OpenGL is unsupported on the iPhone");
172
+ #ifdef GOSU_IS_OPENGLES
173
+ throw std::logic_error("Custom OpenGL ES is not supported yet");
138
174
  #else
139
175
  glPopAttrib();
140
176
 
141
177
  // Restore matrices.
142
-
178
+ // TODO: Should be merged into RenderState and removed from Graphics.
179
+
143
180
  glMatrixMode(GL_PROJECTION);
144
181
  glLoadIdentity();
145
182
  glViewport(0, 0, pimpl->physWidth, pimpl->physHeight);
@@ -151,10 +188,10 @@ void Gosu::Graphics::endGL()
151
188
  #endif
152
189
  }
153
190
 
154
- #ifdef GOSU_IS_IPHONE
191
+ #ifdef GOSU_IS_OPENGLES
155
192
  void Gosu::Graphics::scheduleGL(const std::tr1::function<void()>& functor, Gosu::ZPos z)
156
193
  {
157
- throw std::logic_error("Custom OpenGL is unsupported on the iPhone");
194
+ throw std::logic_error("Custom OpenGL ES is not supported yet");
158
195
  }
159
196
  #else
160
197
  namespace Gosu
@@ -250,7 +287,7 @@ void Gosu::Graphics::drawTriangle(double x1, double y1, Color c1,
250
287
  op.vertices[0] = DrawOp::Vertex(x1, y1, c1);
251
288
  op.vertices[1] = DrawOp::Vertex(x2, y2, c2);
252
289
  op.vertices[2] = DrawOp::Vertex(x3, y3, c3);
253
- #ifdef GOSU_IS_IPHONE
290
+ #ifdef GOSU_IS_OPENGLES
254
291
  op.verticesOrBlockIndex = 4;
255
292
  op.vertices[3] = op.vertices[2];
256
293
  #endif
@@ -270,7 +307,7 @@ void Gosu::Graphics::drawQuad(double x1, double y1, Color c1,
270
307
  op.vertices[0] = DrawOp::Vertex(x1, y1, c1);
271
308
  op.vertices[1] = DrawOp::Vertex(x2, y2, c2);
272
309
  // TODO: Should be harmonized
273
- #ifdef GOSU_IS_IPHONE
310
+ #ifdef GOSU_IS_OPENGLES
274
311
  op.vertices[2] = DrawOp::Vertex(x3, y3, c3);
275
312
  op.vertices[3] = DrawOp::Vertex(x4, y4, c4);
276
313
  #else
@@ -170,7 +170,7 @@ class Gosu::Macro : public Gosu::ImageData
170
170
  // They should be premultiplied and have the same transform by definition. Then, the transformation
171
171
  // only had to be performed here once.
172
172
 
173
- #ifndef GOSU_IS_IPHONE
173
+ #ifndef GOSU_IS_OPENGLES
174
174
  glEnable(GL_BLEND);
175
175
  glMatrixMode(GL_MODELVIEW);
176
176
 
@@ -58,7 +58,7 @@ struct Gosu::RenderState
58
58
  }
59
59
 
60
60
  // Only used by Macro so far
61
- #ifndef GOSU_IS_IPHONE
61
+ #ifndef GOSU_IS_OPENGLES
62
62
  void apply() const
63
63
  {
64
64
  applyTexture();
@@ -81,7 +81,7 @@ class Gosu::RenderStateManager : private Gosu::RenderState
81
81
  glMatrixMode(GL_MODELVIEW);
82
82
  glLoadIdentity();
83
83
 
84
- #ifndef GOSU_IS_IPHONE
84
+ #ifndef GOSU_IS_OPENGLES
85
85
  glMultMatrixd(&(*transform)[0]);
86
86
  #else
87
87
  // TODO: Ouch, should always use floats!
@@ -50,7 +50,7 @@ void Gosu::TexChunk::draw(double x1, double y1, Color c1,
50
50
  op.vertices[0] = DrawOp::Vertex(x1, y1, c1);
51
51
  op.vertices[1] = DrawOp::Vertex(x2, y2, c2);
52
52
  // TODO: Should be harmonized
53
- #ifdef GOSU_IS_IPHONE
53
+ #ifdef GOSU_IS_OPENGLES
54
54
  op.vertices[2] = DrawOp::Vertex(x3, y3, c3);
55
55
  op.vertices[3] = DrawOp::Vertex(x4, y4, c4);
56
56
  #else
@@ -5,7 +5,7 @@
5
5
  #include <pango/pango.h>
6
6
  #include <pango/pangoft2.h>
7
7
  #include <glib.h>
8
- #include <SDL/SDL_ttf.h>
8
+ #include <SDL2/SDL_ttf.h>
9
9
 
10
10
  #include <string>
11
11
  #include <cstring>
@@ -20,7 +20,7 @@ Gosu::Texture::Texture(unsigned size)
20
20
 
21
21
  // Create empty texture.
22
22
  glBindTexture(GL_TEXTURE_2D, name);
23
- #ifdef GOSU_IS_IPHONE
23
+ #ifdef GOSU_IS_OPENGLES
24
24
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, allocator.width(), allocator.height(), 0,
25
25
  GL_RGBA, GL_UNSIGNED_BYTE, 0);
26
26
  #else
@@ -95,7 +95,7 @@ void Gosu::Texture::free(unsigned x, unsigned y, unsigned width, unsigned height
95
95
 
96
96
  Gosu::Bitmap Gosu::Texture::toBitmap(unsigned x, unsigned y, unsigned width, unsigned height) const
97
97
  {
98
- #ifdef GOSU_IS_IPHONE
98
+ #ifdef GOSU_IS_OPENGLES
99
99
  throw std::logic_error("Texture::toBitmap not supported on iOS");
100
100
  #else
101
101
  Gosu::Bitmap fullTexture(size(), size());
@@ -1,7 +1,7 @@
1
1
  // Default matrices, adapted from original Transform support
2
2
  // contribution by erisdiscord. Thank you!
3
3
 
4
- #include <Gosu/Graphics.hpp>
4
+ #include <Gosu/GraphicsBase.hpp>
5
5
  #include <Gosu/Math.hpp>
6
6
  #include "Common.hpp"
7
7
  #include <cmath>
@@ -18,7 +18,7 @@ Gosu::rotate(double angle, double aroundX, double aroundY)
18
18
  0, 0, 0, 1
19
19
  };
20
20
  if (aroundX != 0 || aroundY != 0)
21
- result = multiply(multiply(translate(-aroundX, -aroundY), result), translate(aroundX, aroundY));
21
+ result = concat(concat(translate(-aroundX, -aroundY), result), translate(aroundX, aroundY));
22
22
  return result;
23
23
  }
24
24
 
@@ -56,6 +56,18 @@ Gosu::scale(double factorX, double factorY, double aroundX, double aroundY)
56
56
  0, 0, 0, 1
57
57
  };
58
58
  if (aroundX != 0 || aroundY != 0)
59
- result = multiply(multiply(translate(-aroundX, -aroundY), result), translate(aroundX, aroundY));
59
+ result = concat(concat(translate(-aroundX, -aroundY), result), translate(aroundX, aroundY));
60
+ return result;
61
+ }
62
+
63
+ Gosu::Transform
64
+ Gosu::concat(const Transform& left, const Transform& right)
65
+ {
66
+ Gosu::Transform result;
67
+ for (int i = 0; i < 16; ++i) {
68
+ result[i] = 0;
69
+ for (int j = 0; j < 4; ++j)
70
+ result[i] += left[i / 4 * 4 + j] * right[i % 4 + j * 4];
71
+ }
60
72
  return result;
61
73
  }
@@ -79,7 +79,7 @@ namespace Gosu
79
79
  void push(const Transform& transform)
80
80
  {
81
81
  individual.push_back(transform);
82
- Transform result = multiply(transform, current());
82
+ Transform result = concat(transform, current());
83
83
  makeCurrent(result);
84
84
  }
85
85
 
@@ -91,7 +91,7 @@ namespace Gosu
91
91
  Transform result = scale(1);
92
92
  for (Transforms::reverse_iterator it = individual.rbegin(),
93
93
  end = individual.rend(); it != end; ++it)
94
- result = multiply(result, *it);
94
+ result = concat(result, *it);
95
95
  makeCurrent(result);
96
96
  }
97
97
  };
@@ -0,0 +1,329 @@
1
+ #include <Gosu/Input.hpp>
2
+ #include <Gosu/TextInput.hpp>
3
+ #include <Gosu/TR1.hpp>
4
+ #include <Gosu/Utility.hpp>
5
+ #include <SDL2/SDL.h>
6
+ #include <algorithm>
7
+ #include <cwctype>
8
+
9
+ struct Gosu::Input::Impl
10
+ {
11
+ Input& input;
12
+ TextInput* textInput;
13
+ std::tr1::array<bool, Gosu::numButtons> buttonStates;
14
+ double mouseX, mouseY;
15
+ double mouseFactorX, mouseFactorY;
16
+ double mouseOffsetX, mouseOffsetY;
17
+
18
+ Impl(Input& input)
19
+ : input(input), textInput(NULL)
20
+ {
21
+ std::fill(buttonStates.begin(), buttonStates.end(), false);
22
+
23
+ mouseFactorX = mouseFactorY = 1;
24
+ mouseOffsetX = mouseOffsetY = 0;
25
+ }
26
+
27
+ void updateMousePosition()
28
+ {
29
+ int x, y;
30
+ SDL_GetMouseState(&x, &y);
31
+ mouseX = x, mouseY = y;
32
+ }
33
+
34
+ void enqueueEvent(int id, bool down)
35
+ {
36
+ eventQueue.push_back(down ? id : ~id);
37
+ }
38
+
39
+ void dispatchEnqueuedEvents()
40
+ {
41
+ for (unsigned i = 0; i < eventQueue.size(); ++i) {
42
+ int event = eventQueue[i];
43
+ bool down = (event >= 0);
44
+ Button button(down ? event : ~event);
45
+
46
+ buttonStates[button.id()] = down;
47
+ if (down && input.onButtonDown) {
48
+ input.onButtonDown(button);
49
+ }
50
+ else if (!down && input.onButtonUp) {
51
+ input.onButtonUp(button);
52
+ }
53
+ }
54
+ eventQueue.clear();
55
+ }
56
+
57
+ void initializeGamepads()
58
+ {
59
+ int numGamepads = std::min<int>(Gosu::numGamepads, SDL_NumJoysticks());
60
+
61
+ for (int i = 0; i < numGamepads; ++i) {
62
+ SDL_Joystick *joystick = SDL_JoystickOpen(i);
63
+ if (joystick) {
64
+ joysticks.push_back(joystick);
65
+ }
66
+ }
67
+ }
68
+
69
+ void pollGamepads()
70
+ {
71
+ std::tr1::array<bool, gpNumPerGamepad> anyGamepad = { false };
72
+
73
+ for (int i = 0; i < joysticks.size(); ++i) {
74
+ std::tr1::array<bool, gpNumPerGamepad> currentGamepad = { false };
75
+
76
+ int axes = SDL_JoystickNumAxes(joysticks[i]),
77
+ hats = SDL_JoystickNumHats(joysticks[i]),
78
+ buttons = std::min<int>(gpNumPerGamepad - 4, SDL_JoystickNumButtons(joysticks[i]));
79
+
80
+ for (int axis = 0; axis < axes; ++axis) {
81
+ Sint16 value = SDL_JoystickGetAxis(joysticks[i], axis);
82
+
83
+ if (value < -(1 << 14)) {
84
+ if (axis % 2 == 0)
85
+ currentGamepad[gpLeft - gpRangeBegin] = true;
86
+ else
87
+ currentGamepad[gpUp - gpRangeBegin] = true;
88
+ }
89
+ else if (value > +(1 << 14)) {
90
+ if (axis % 2 == 0)
91
+ currentGamepad[gpRight - gpRangeBegin] = true;
92
+ else
93
+ currentGamepad[gpDown - gpRangeBegin] = true;
94
+ }
95
+ }
96
+
97
+ for (int hat = 0; hat < hats; ++hat) {
98
+ Uint8 value = SDL_JoystickGetHat(joysticks[i], hat);
99
+
100
+ if (value == SDL_HAT_LEFT || value == SDL_HAT_LEFTUP || value == SDL_HAT_LEFTDOWN)
101
+ currentGamepad[gpLeft - gpRangeBegin] = true;
102
+ if (value == SDL_HAT_RIGHT || value == SDL_HAT_RIGHTUP || value == SDL_HAT_RIGHTDOWN)
103
+ currentGamepad[gpRight - gpRangeBegin] = true;
104
+ if (value == SDL_HAT_UP || value == SDL_HAT_LEFTUP || value == SDL_HAT_RIGHTUP)
105
+ currentGamepad[gpUp - gpRangeBegin] = true;
106
+ if (value == SDL_HAT_DOWN || value == SDL_HAT_LEFTDOWN || value == SDL_HAT_RIGHTDOWN)
107
+ currentGamepad[gpDown - gpRangeBegin] = true;
108
+ }
109
+
110
+ for (int button = 0; button < buttons; ++button) {
111
+ if (SDL_JoystickGetButton(joysticks[i], button)) {
112
+ currentGamepad[gpButton0 + button - gpRangeBegin] = true;
113
+ }
114
+ }
115
+
116
+ int offset = gpRangeBegin + gpNumPerGamepad * (i + 1);
117
+
118
+ for (int j = 0; j < currentGamepad.size(); ++j) {
119
+ anyGamepad[j] = anyGamepad[j] || currentGamepad[j];
120
+
121
+ if (currentGamepad[j] && !buttonStates[j + offset]) {
122
+ buttonStates[j + offset] = true;
123
+ enqueueEvent(j + offset, true);
124
+ }
125
+ else if (!currentGamepad[j] && buttonStates[j + offset]) {
126
+ buttonStates[j + offset] = false;
127
+ enqueueEvent(j + offset, false);
128
+ }
129
+ }
130
+ }
131
+
132
+ for (int j = 0; j < anyGamepad.size(); ++j) {
133
+ if (anyGamepad[j] && !buttonStates[j + gpRangeBegin]) {
134
+ buttonStates[j + gpRangeBegin] = true;
135
+ enqueueEvent(j + gpRangeBegin, true);
136
+ }
137
+ else if (!anyGamepad[j] && buttonStates[j + gpRangeBegin]) {
138
+ buttonStates[j + gpRangeBegin] = false;
139
+ enqueueEvent(j + gpRangeBegin, false);
140
+ }
141
+ }
142
+ }
143
+
144
+ private:
145
+ // For button down event: Button name value (>= 0)
146
+ // For button up event: ~Button name value (< 0)
147
+ std::vector<int> eventQueue;
148
+
149
+ std::vector<SDL_Joystick*> joysticks;
150
+ };
151
+
152
+ Gosu::Input::Input()
153
+ : pimpl(new Impl(*this))
154
+ {
155
+ SDL_InitSubSystem(SDL_INIT_JOYSTICK);
156
+
157
+ pimpl->initializeGamepads();
158
+ }
159
+
160
+ Gosu::Input::~Input()
161
+ {
162
+ SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
163
+ }
164
+
165
+ bool Gosu::Input::feedSDLEvent(void* event)
166
+ {
167
+ const SDL_Event* e = static_cast<SDL_Event*>(event);
168
+
169
+ if (pimpl->textInput && pimpl->textInput->feedSDLEvent(event)) {
170
+ return true;
171
+ }
172
+
173
+ switch (e->type) {
174
+ case SDL_KEYDOWN:
175
+ case SDL_KEYUP: {
176
+ if (e->key.repeat == 0 && e->key.keysym.scancode <= kbRangeEnd) {
177
+ pimpl->enqueueEvent(e->key.keysym.scancode, e->type == SDL_KEYDOWN);
178
+ return true;
179
+ }
180
+ break;
181
+ }
182
+ case SDL_MOUSEBUTTONDOWN:
183
+ case SDL_MOUSEBUTTONUP: {
184
+ if (e->button.button >= 1 && e->button.button <= 3) {
185
+ pimpl->enqueueEvent(msLeft + e->button.button - 1, e->type == SDL_MOUSEBUTTONDOWN);
186
+ return true;
187
+ }
188
+ break;
189
+ }
190
+ case SDL_MOUSEWHEEL: {
191
+ if (e->wheel.y < 0) {
192
+ pimpl->enqueueEvent(msWheelUp, true);
193
+ return true;
194
+ }
195
+ else if (e->wheel.y > 0) {
196
+ pimpl->enqueueEvent(msWheelDown, false);
197
+ return true;
198
+ }
199
+ break;
200
+ }
201
+ }
202
+ return false;
203
+ }
204
+
205
+ wchar_t Gosu::Input::idToChar(Button btn)
206
+ {
207
+ if (btn.id() > kbRangeEnd)
208
+ return 0;
209
+
210
+ // SDL_GetKeyName would return "Space" for this value.
211
+ if (btn.id() == kbSpace)
212
+ return L' ';
213
+
214
+ SDL_Keycode keycode = SDL_GetKeyFromScancode(static_cast<SDL_Scancode>(btn.id()));
215
+ if (keycode == SDLK_UNKNOWN)
216
+ return 0;
217
+
218
+ const char* name = SDL_GetKeyName(keycode);
219
+ if (name == NULL)
220
+ return 0;
221
+
222
+ std::wstring wname = utf8ToWstring(name);
223
+ if (wname.length() != 1)
224
+ return 0;
225
+
226
+ // Convert to lower case to be consistent with previous versions of Gosu.
227
+ // Also, German umlauts are already reported in lower-case by the SDL, so
228
+ // this makes everything a little more consistent.
229
+ //
230
+ // This should handle Turkish i/I just fine because it uses the current
231
+ // locale, but if we ever receive bug reports from Turkish users, they are
232
+ // likely caused by a combination of this line and an invalid locale :)
233
+ return std::towlower(wname[0]);
234
+ }
235
+
236
+ Gosu::Button Gosu::Input::charToId(wchar_t ch)
237
+ {
238
+ std::wstring string(1, ch);
239
+ SDL_Keycode keycode = SDL_GetKeyFromName(wstringToUTF8(string).c_str());
240
+
241
+ if (keycode == SDLK_UNKNOWN) {
242
+ return noButton;
243
+ }
244
+ else {
245
+ return Button(SDL_GetScancodeFromKey(keycode));
246
+ }
247
+ }
248
+
249
+ bool Gosu::Input::down(Gosu::Button btn) const
250
+ {
251
+ if (btn == noButton || btn.id() >= numButtons)
252
+ return false;
253
+
254
+ return pimpl->buttonStates[btn.id()];
255
+ }
256
+
257
+ double Gosu::Input::mouseX() const
258
+ {
259
+ return pimpl->mouseX * pimpl->mouseFactorX + pimpl->mouseOffsetX;
260
+ }
261
+
262
+ double Gosu::Input::mouseY() const
263
+ {
264
+ return pimpl->mouseY * pimpl->mouseFactorY + pimpl->mouseOffsetY;
265
+ }
266
+
267
+ void Gosu::Input::setMousePosition(double x, double y)
268
+ {
269
+ // TODO - Input needs SDL Window handle to pass into this
270
+ SDL_WarpMouseInWindow(NULL,
271
+ (x - pimpl->mouseOffsetX) / pimpl->mouseFactorX,
272
+ (y - pimpl->mouseOffsetY) / pimpl->mouseFactorY);
273
+ }
274
+
275
+ void Gosu::Input::setMouseFactors(double factorX, double factorY,
276
+ double blackBarWidth, double blackBarHeight)
277
+ {
278
+ pimpl->mouseFactorX = factorX;
279
+ pimpl->mouseFactorY = factorY;
280
+ pimpl->mouseOffsetX = -blackBarWidth;
281
+ pimpl->mouseOffsetY = -blackBarHeight;
282
+ }
283
+
284
+ const Gosu::Touches& Gosu::Input::currentTouches() const
285
+ {
286
+ // Note: We can actually use the SDL's touch API to implement this, even on OS X! Neat.
287
+
288
+ static Gosu::Touches none;
289
+ return none;
290
+ }
291
+
292
+ double Gosu::Input::accelerometerX() const
293
+ {
294
+ return 0.0;
295
+ }
296
+
297
+ double Gosu::Input::accelerometerY() const
298
+ {
299
+ return 0.0;
300
+ }
301
+
302
+ double Gosu::Input::accelerometerZ() const
303
+ {
304
+ return 0.0;
305
+ }
306
+
307
+ void Gosu::Input::update()
308
+ {
309
+ pimpl->updateMousePosition();
310
+ pimpl->dispatchEnqueuedEvents();
311
+ pimpl->pollGamepads();
312
+ }
313
+
314
+ Gosu::TextInput* Gosu::Input::textInput() const
315
+ {
316
+ return pimpl->textInput;
317
+ }
318
+
319
+ void Gosu::Input::setTextInput(TextInput* textInput)
320
+ {
321
+ if (pimpl->textInput && textInput == NULL) {
322
+ SDL_StopTextInput();
323
+ }
324
+ else if (pimpl->textInput == NULL && textInput) {
325
+ SDL_StartTextInput();
326
+ }
327
+
328
+ pimpl->textInput = textInput;
329
+ }