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.
- checksums.yaml +4 -4
- data/COPYING +1 -1
- data/Gosu/Buttons.hpp +97 -97
- data/Gosu/Graphics.hpp +5 -26
- data/Gosu/GraphicsBase.hpp +27 -4
- data/Gosu/Input.hpp +8 -19
- data/Gosu/Platform.hpp +5 -1
- data/Gosu/TextInput.hpp +5 -11
- data/Gosu/Version.hpp +3 -3
- data/GosuImpl/Graphics/Common.hpp +2 -11
- data/GosuImpl/Graphics/DrawOp.hpp +23 -27
- data/GosuImpl/Graphics/DrawOpQueue.hpp +2 -2
- data/GosuImpl/Graphics/Graphics.cpp +55 -18
- data/GosuImpl/Graphics/Macro.hpp +1 -1
- data/GosuImpl/Graphics/RenderState.hpp +2 -2
- data/GosuImpl/Graphics/TexChunk.cpp +1 -1
- data/GosuImpl/Graphics/TextUnix.cpp +1 -1
- data/GosuImpl/Graphics/Texture.cpp +2 -2
- data/GosuImpl/Graphics/Transform.cpp +15 -3
- data/GosuImpl/Graphics/TransformStack.hpp +2 -2
- data/GosuImpl/Input.cpp +329 -0
- data/GosuImpl/TextInput.cpp +239 -0
- data/GosuImpl/Window.cpp +215 -0
- data/lib/gosu/swig_patches.rb +1 -0
- data/linux/extconf.rb +10 -16
- metadata +8 -6
- data/GosuImpl/WindowMac.mm +0 -574
@@ -38,7 +38,7 @@ namespace Gosu
|
|
38
38
|
assert (verticesOrBlockIndex >= 2);
|
39
39
|
assert (verticesOrBlockIndex <= 4);
|
40
40
|
|
41
|
-
#ifdef
|
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
|
-
|
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
|
-
|
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
|
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
|
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
|
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
|
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
|
79
|
-
|
80
|
-
|
81
|
-
pimpl->
|
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
|
125
|
-
throw std::logic_error("Custom OpenGL is
|
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
|
137
|
-
throw std::logic_error("Custom OpenGL is
|
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
|
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
|
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
|
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
|
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
|
data/GosuImpl/Graphics/Macro.hpp
CHANGED
@@ -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
|
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
|
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
|
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
|
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
|
@@ -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
|
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
|
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/
|
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 =
|
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 =
|
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 =
|
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 =
|
94
|
+
result = concat(result, *it);
|
95
95
|
makeCurrent(result);
|
96
96
|
}
|
97
97
|
};
|
data/GosuImpl/Input.cpp
ADDED
@@ -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
|
+
}
|