gosu 0.9.2 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/Gosu/Bitmap.hpp +3 -3
  3. data/Gosu/Directories.hpp +6 -3
  4. data/Gosu/Gosu.hpp +0 -1
  5. data/Gosu/GraphicsBase.hpp +12 -8
  6. data/Gosu/Input.hpp +5 -16
  7. data/Gosu/Platform.hpp +1 -0
  8. data/Gosu/Version.hpp +3 -5
  9. data/Gosu/Window.hpp +7 -8
  10. data/README.txt +3 -3
  11. data/ext/gosu/extconf.rb +17 -16
  12. data/ext/gosu/gosu_wrap.cxx +59 -58
  13. data/ext/gosu/gosu_wrap.h +1 -1
  14. data/rdoc/gosu.rb +285 -283
  15. data/src/{MacUtility.hpp → AppleUtility.hpp} +24 -42
  16. data/src/Audio/ALChannelManagement.hpp +1 -1
  17. data/src/Audio/{AudioOpenAL.cpp → Audio.cpp} +6 -7
  18. data/src/Audio/Audio.mm +1 -0
  19. data/src/Audio/AudioFile.hpp +2 -2
  20. data/src/Audio/AudioToolboxFile.hpp +5 -20
  21. data/src/Audio/OggFile.hpp +44 -56
  22. data/src/Audio/SndFile.hpp +2 -2
  23. data/src/Bitmap/Bitmap.cpp +98 -2
  24. data/src/Bitmap/BitmapIO.cpp +156 -0
  25. data/src/DirectoriesApple.mm +76 -0
  26. data/src/DirectoriesUnix.cpp +5 -12
  27. data/src/DirectoriesWin.cpp +5 -0
  28. data/src/Graphics/BlockAllocator.hpp +2 -2
  29. data/src/Graphics/ClipRectStack.hpp +2 -2
  30. data/src/Graphics/Common.hpp +2 -2
  31. data/src/Graphics/DrawOp.hpp +2 -2
  32. data/src/Graphics/DrawOpQueue.hpp +2 -2
  33. data/src/Graphics/Graphics.cpp +7 -2
  34. data/src/Graphics/LargeImageData.cpp +6 -6
  35. data/src/Graphics/LargeImageData.hpp +3 -3
  36. data/src/Graphics/Macro.hpp +2 -2
  37. data/src/Graphics/RenderState.hpp +2 -2
  38. data/src/Graphics/Resolution.cpp +1 -1
  39. data/src/Graphics/TexChunk.hpp +2 -2
  40. data/src/Graphics/Texture.cpp +21 -16
  41. data/src/Graphics/Texture.hpp +7 -5
  42. data/src/Graphics/TransformStack.hpp +2 -2
  43. data/src/Iconv.hpp +2 -2
  44. data/src/Input/Input.cpp +3 -1
  45. data/src/Input/{InputTouch.mm → InputUIKit.mm} +32 -26
  46. data/src/Input/TextInput.cpp +1 -1
  47. data/src/Text/FormattedString.hpp +2 -2
  48. data/src/Text/TextApple.mm +8 -8
  49. data/src/Text/TextMac.cpp +1 -1
  50. data/src/Text/TextUnix.cpp +1 -1
  51. data/src/UIKit/GosuAppDelegate.h +8 -0
  52. data/src/UIKit/GosuAppDelegate.mm +24 -0
  53. data/src/UIKit/GosuGLView.h +8 -0
  54. data/src/UIKit/GosuGLView.mm +130 -0
  55. data/src/UIKit/GosuViewController.h +13 -0
  56. data/src/UIKit/GosuViewController.mm +214 -0
  57. data/src/UtilityApple.mm +5 -18
  58. data/src/Window.cpp +1 -3
  59. data/src/WindowUIKit.mm +124 -0
  60. data/src/stb_image.h +6437 -0
  61. data/src/stb_image_write.h +730 -0
  62. data/src/stb_vorbis.c +5459 -0
  63. metadata +18 -26
  64. data/Gosu/Sockets.hpp +0 -156
  65. data/src/Audio/AudioOpenAL.mm +0 -1
  66. data/src/Bitmap/BitmapApple.mm +0 -226
  67. data/src/Bitmap/BitmapBMP.cpp +0 -79
  68. data/src/Bitmap/BitmapColorKey.cpp +0 -50
  69. data/src/Bitmap/BitmapFreeImage.cpp +0 -174
  70. data/src/Bitmap/BitmapGDIplus.cpp +0 -212
  71. data/src/Bitmap/BitmapUtils.cpp +0 -76
  72. data/src/DirectoriesMac.mm +0 -38
  73. data/src/DirectoriesTouch.mm +0 -38
  74. data/src/GosuView.hpp +0 -15
  75. data/src/GosuView.mm +0 -208
  76. data/src/Input/AccelerometerReader.hpp +0 -10
  77. data/src/Input/AccelerometerReader.mm +0 -31
  78. data/src/Sockets/CommSocket.cpp +0 -305
  79. data/src/Sockets/ListenerSocket.cpp +0 -59
  80. data/src/Sockets/MessageSocket.cpp +0 -128
  81. data/src/Sockets/Socket.cpp +0 -145
  82. data/src/Sockets/Socket.hpp +0 -66
  83. data/src/WindowTouch.mm +0 -243
  84. data/src/X11vroot.h +0 -118
@@ -1,76 +0,0 @@
1
- #include <Gosu/Graphics.hpp>
2
- #include <Gosu/Bitmap.hpp>
3
- #include <Gosu/IO.hpp>
4
- #include <Gosu/Platform.hpp>
5
-
6
- Gosu::Reader Gosu::loadFromPNG(Bitmap& bitmap, Reader reader)
7
- {
8
- loadImageFile(bitmap, reader);
9
- reader.setPosition(reader.resource().size());
10
- return reader;
11
- }
12
-
13
- Gosu::Reader Gosu::loadFromBMP(Bitmap& bitmap, Reader reader)
14
- {
15
- return loadFromPNG(bitmap, reader);
16
- }
17
-
18
- Gosu::Writer Gosu::saveToPNG(const Bitmap& bitmap, Writer writer)
19
- {
20
- saveImageFile(bitmap, writer);
21
- return writer.resource().backWriter();
22
- }
23
-
24
- // The iPhone still uses BitmapBMP.cpp because UIImage apparently lacks BMP export.
25
- #ifndef GOSU_IS_IPHONE
26
- Gosu::Writer Gosu::saveToBMP(const Bitmap& bitmap, Writer writer)
27
- {
28
- saveImageFile(bitmap, writer, L"bmp");
29
- return writer.resource().backWriter();
30
- }
31
- #endif
32
-
33
- void Gosu::applyBorderFlags(Bitmap& dest, const Bitmap& source,
34
- unsigned srcX, unsigned srcY, unsigned srcWidth, unsigned srcHeight,
35
- unsigned imageFlags)
36
- {
37
- dest.resize(srcWidth + 2, srcHeight + 2);
38
-
39
- // The borders are made "harder" by duplicating the original bitmap's
40
- // borders.
41
-
42
- // Top.
43
- if (imageFlags & ifTileableTop)
44
- dest.insert(source, 1, 0, srcX, srcY, srcWidth, 1);
45
- // Bottom.
46
- if (imageFlags & ifTileableBottom)
47
- dest.insert(source, 1, dest.height() - 1,
48
- srcX, srcY + srcHeight - 1, srcWidth, 1);
49
- // Left.
50
- if (imageFlags & ifTileableLeft)
51
- dest.insert(source, 0, 1, srcX, srcY, 1, srcHeight);
52
- // Right.
53
- if (imageFlags & ifTileableRight)
54
- dest.insert(source, dest.width() - 1, 1,
55
- srcX + srcWidth - 1, srcY, 1, srcHeight);
56
-
57
- // Top left.
58
- if ((imageFlags & ifTileableTop) && (imageFlags & ifTileableLeft))
59
- dest.setPixel(0, 0,
60
- source.getPixel(srcX, srcY));
61
- // Top right.
62
- if ((imageFlags & ifTileableTop) && (imageFlags & ifTileableRight))
63
- dest.setPixel(dest.width() - 1, 0,
64
- source.getPixel(srcX + srcWidth - 1, srcY));
65
- // Bottom left.
66
- if ((imageFlags & ifTileableBottom) && (imageFlags & ifTileableLeft))
67
- dest.setPixel(0, dest.height() - 1,
68
- source.getPixel(srcX, srcY + srcHeight - 1));
69
- // Bottom right.
70
- if ((imageFlags & ifTileableBottom) && (imageFlags & ifTileableRight))
71
- dest.setPixel(dest.width() - 1, dest.height() - 1,
72
- source.getPixel(srcX + srcWidth - 1, srcY + srcHeight - 1));
73
-
74
- // Now put the final image into the prepared borders.
75
- dest.insert(source, 1, 1, srcX, srcY, srcWidth, srcHeight);
76
- }
@@ -1,38 +0,0 @@
1
- #import <Gosu/Directories.hpp>
2
- #import "MacUtility.hpp"
3
- #import <Gosu/Utility.hpp>
4
- #import <Foundation/NSAutoreleasePool.h>
5
- #import <Foundation/NSBundle.h>
6
- #import <Foundation/NSString.h>
7
- #import <Foundation/NSPathUtilities.h>
8
-
9
- std::wstring Gosu::resourcePrefix()
10
- {
11
- static std::wstring result;
12
- if (result.empty())
13
- {
14
- ObjRef<NSAutoreleasePool> pool([[NSAutoreleasePool alloc] init]);
15
- NSBundle* bundle = [NSBundle mainBundle];
16
- if (bundle == nil)
17
- return L"";
18
- NSString* str = [bundle resourcePath];
19
- result = Gosu::widen([str fileSystemRepresentation]) + L"/";
20
- }
21
- return result;
22
- }
23
-
24
- std::wstring Gosu::sharedResourcePrefix()
25
- {
26
- static std::wstring result;
27
- if (result.empty())
28
- {
29
- ObjRef<NSAutoreleasePool> pool([[NSAutoreleasePool alloc] init]);
30
- NSBundle* bundle = [NSBundle mainBundle];
31
- if (bundle == nil)
32
- return L"";
33
- NSString* str = [bundle bundlePath];
34
- str = [str stringByDeletingLastPathComponent];
35
- result = Gosu::widen([str fileSystemRepresentation]) + L"/";
36
- }
37
- return result;
38
- }
@@ -1,38 +0,0 @@
1
- #import <Gosu/Directories.hpp>
2
- #import <Gosu/Utility.hpp>
3
- #import "MacUtility.hpp"
4
- #import <Foundation/Foundation.h>
5
-
6
- std::wstring Gosu::userSettingsPrefix()
7
- {
8
- static std::wstring result;
9
- if (result.empty())
10
- {
11
- ObjRef<NSAutoreleasePool> pool([[NSAutoreleasePool alloc] init]);
12
- NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
13
- NSString* documentsDirectory = [paths objectAtIndex: 0];
14
- result = utf8ToWstring([documentsDirectory UTF8String]) + L"/";
15
- }
16
- return result;
17
- }
18
-
19
- std::wstring Gosu::userDocsPrefix()
20
- {
21
- return userSettingsPrefix();
22
- }
23
-
24
- std::wstring Gosu::resourcePrefix()
25
- {
26
- static std::wstring result;
27
- if (result.empty())
28
- {
29
- ObjRef<NSAutoreleasePool> pool([[NSAutoreleasePool alloc] init]);
30
- result = utf8ToWstring([[[NSBundle mainBundle] resourcePath] UTF8String]) + L"/";
31
- }
32
- return result;
33
- }
34
-
35
- std::wstring Gosu::sharedResourcePrefix()
36
- {
37
- return resourcePrefix();
38
- }
@@ -1,15 +0,0 @@
1
- #import <UIKit/UIKit.h>
2
- #import <OpenGLES/EAGL.h>
3
- #import <OpenGLES/ES1/gl.h>
4
- #import <OpenGLES/ES1/glext.h>
5
-
6
- // UIViewController subclass that creates a GosuView and helps it manage rotation.
7
-
8
- @interface GosuViewController : UIViewController
9
- @end
10
-
11
- // UIView subclass that contains a CAEAGLLayer.
12
-
13
- @interface GosuView : UIView
14
- - (void)drawView;
15
- @end
@@ -1,208 +0,0 @@
1
- #import <QuartzCore/QuartzCore.h>
2
- #import <OpenGLES/EAGLDrawable.h>
3
- #import <UIKit/UIKit.h>
4
-
5
- #import <Gosu/Graphics.hpp>
6
- #import <Gosu/Window.hpp>
7
- #import "Common.hpp"
8
- #import "GosuView.hpp"
9
-
10
- Gosu::Window& windowInstance();
11
-
12
- namespace Gosu
13
- {
14
- namespace FPS
15
- {
16
- void registerFrame();
17
- }
18
- }
19
-
20
- int Gosu::clipRectBaseFactor()
21
- {
22
- static int result = 0;
23
- if (result == 0)
24
- {
25
- if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)])
26
- result = [UIScreen mainScreen].scale;
27
- else
28
- result = 1;
29
- }
30
- return result;
31
- }
32
-
33
- // A controller to allow for autorotation.
34
- @implementation GosuViewController
35
- - (BOOL)prefersStatusBarHidden
36
- {
37
- return YES;
38
- }
39
-
40
- - (void)loadView
41
- {
42
- self.view = [[GosuView alloc] init];
43
- }
44
-
45
- - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
46
- {
47
- return UIInterfaceOrientationIsLandscape(interfaceOrientation);
48
- }
49
-
50
- - (NSUInteger)supportedInterfaceOrientations
51
- {
52
- return UIInterfaceOrientationMaskLandscape;
53
- }
54
-
55
- - (BOOL)shouldAutorotate
56
- {
57
- return YES;
58
- }
59
-
60
- - (void)didReceiveMemoryWarning
61
- {
62
- windowInstance().releaseMemory();
63
- }
64
- @end
65
-
66
- // A class extension to declare private methods
67
- @interface GosuView ()
68
- @property (nonatomic, strong) EAGLContext *context;
69
- @end
70
-
71
- @implementation GosuView
72
- {
73
- // The pixel dimensions of the backbuffer
74
- GLint backingWidth;
75
- GLint backingHeight;
76
-
77
- // OpenGL names for the renderbuffer and framebuffers used to render to this view
78
- GLuint viewRenderbuffer, viewFramebuffer;
79
-
80
- NSMutableSet* currentTouches;
81
- Gosu::Touches* currentTouchesVector;
82
- }
83
-
84
- + (Class)layerClass
85
- {
86
- return [CAEAGLLayer class];
87
- }
88
-
89
- - (id)init
90
- {
91
- if ((self = [super initWithFrame: [[UIScreen mainScreen] bounds]])) {
92
- CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
93
-
94
- eaglLayer.opaque = YES;
95
- /*eaglLayer.drawableProperties = dictionaryWithObjectsAndKeys:
96
- [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking,
97
- kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];*/
98
-
99
- self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
100
-
101
- if (!self.context || ![EAGLContext setCurrentContext:self.context]) {
102
- [self release];
103
- return nil;
104
- }
105
- }
106
- return self;
107
- }
108
-
109
- - (void)drawView
110
- {
111
- if (not windowInstance().needsRedraw())
112
- return;
113
-
114
- Gosu::FPS::registerFrame();
115
-
116
- [EAGLContext setCurrentContext:self.context];
117
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
118
- glViewport(0, 0, backingWidth, backingHeight);
119
-
120
- if (windowInstance().graphics().begin()) {
121
- windowInstance().draw();
122
- windowInstance().graphics().end();
123
- }
124
-
125
- glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
126
- [self.context presentRenderbuffer:GL_RENDERBUFFER_OES];
127
- }
128
-
129
- - (void)layoutSubviews
130
- {
131
- [EAGLContext setCurrentContext:self.context];
132
- [self destroyFramebuffer];
133
- if ([self respondsToSelector:@selector(contentScaleFactor)])
134
- self.contentScaleFactor = Gosu::clipRectBaseFactor();
135
- [self createFramebuffer];
136
- [self drawView];
137
- }
138
-
139
- - (BOOL)createFramebuffer
140
- {
141
- glGenFramebuffersOES(1, &viewFramebuffer);
142
- glGenRenderbuffersOES(1, &viewRenderbuffer);
143
-
144
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
145
- glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
146
- [self.context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
147
- glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
148
-
149
- glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
150
- glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
151
-
152
- if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
153
- NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
154
- return NO;
155
- }
156
-
157
- return YES;
158
- }
159
-
160
- - (void)destroyFramebuffer
161
- {
162
- glDeleteFramebuffersOES(1, &viewFramebuffer);
163
- viewFramebuffer = 0;
164
- glDeleteRenderbuffersOES(1, &viewRenderbuffer);
165
- viewRenderbuffer = 0;
166
- }
167
-
168
- - (void)dealloc
169
- {
170
- delete currentTouchesVector;
171
- [currentTouches release];
172
- [EAGLContext setCurrentContext:nil];
173
- [self.context release];
174
- [super dealloc];
175
- }
176
-
177
- - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
178
- {
179
- windowInstance().input().feedTouchEvent(0, touches);
180
- }
181
-
182
- - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
183
- {
184
- windowInstance().input().feedTouchEvent(1, touches);
185
- }
186
-
187
- - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
188
- {
189
- windowInstance().input().feedTouchEvent(2, touches);
190
- }
191
-
192
- - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
193
- {
194
- // TODO: Should be differentiated on the Gosu side.
195
- [self touchesEnded:touches withEvent:event];
196
- }
197
-
198
- - (BOOL)isMultipleTouchEnabled
199
- {
200
- return YES;
201
- }
202
-
203
- - (BOOL)isExclusiveTouch
204
- {
205
- return YES;
206
- }
207
-
208
- @end
@@ -1,10 +0,0 @@
1
- #include <UIKit/UIKit.h>
2
-
3
- typedef UIAccelerationValue Acceleration[3];
4
-
5
- @interface AccelerometerReader : NSObject <UIAccelerometerDelegate> {
6
- Acceleration acceleration;
7
- }
8
- -(AccelerometerReader*)initWithUpdateInterval:(float)updateInterval;
9
- -(const Acceleration&)acceleration;
10
- @end
@@ -1,31 +0,0 @@
1
- // Thanks for inspiration to Phil Cooper-King.
2
- // This is adapted from his MIT-licensed Gosu fork
3
- // on GitHub.
4
-
5
- #import "AccelerometerReader.hpp"
6
-
7
- @implementation AccelerometerReader
8
- - (AccelerometerReader*)initWithUpdateInterval: (float)updateInterval
9
- {
10
- if (self = [super init])
11
- {
12
- [[UIAccelerometer sharedAccelerometer] setUpdateInterval: updateInterval];
13
- [[UIAccelerometer sharedAccelerometer] setDelegate:self];
14
- acceleration[0] = acceleration[1] = acceleration[2] = 0.0f;
15
- }
16
- return self;
17
- }
18
-
19
- - (void)accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)uiAccel
20
- {
21
- float factor = 0.3f;
22
- acceleration[0] = (uiAccel.x * factor) + (acceleration[0] * (1 - factor));
23
- acceleration[1] = (uiAccel.y * factor) + (acceleration[1] * (1 - factor));
24
- acceleration[2] = (uiAccel.z * factor) + (acceleration[2] * (1 - factor));
25
- }
26
-
27
- - (const Acceleration&)acceleration
28
- {
29
- return acceleration;
30
- }
31
- @end
@@ -1,305 +0,0 @@
1
- #include <Gosu/Sockets.hpp>
2
- #include <Gosu/TR1.hpp>
3
- #include "Socket.hpp"
4
- #include <cassert>
5
- #include <cstring>
6
- #include <stdexcept>
7
- #include <vector>
8
-
9
- struct Gosu::CommSocket::Impl
10
- {
11
- Socket socket;
12
- CommMode mode;
13
-
14
- typedef std::vector<char> Buffer;
15
- Buffer inbox, outbox;
16
-
17
- void appendBuffer(const char* buffer, std::size_t size,
18
- std::tr1::function<void (const void*, std::size_t)>& event)
19
- {
20
- switch (mode)
21
- {
22
- case cmRaw:
23
- {
24
- // Raw = simple! Yay.
25
- if (event)
26
- event(buffer, size);
27
-
28
- break;
29
- }
30
-
31
- case cmManaged:
32
- {
33
- // Append new data to inbox.
34
- inbox.insert(inbox.end(), buffer, buffer + size);
35
-
36
- for (;;) // IMPR.
37
- {
38
- const size_t sizeSize = 4;
39
-
40
- // Not even enough bytes there to determine the size of the
41
- // incoming message.
42
- if (inbox.size() < sizeSize)
43
- break;
44
-
45
- // Message size is already here, convert it.
46
- std::tr1::uint32_t msgSize = *reinterpret_cast<std::tr1::uint32_t*>(&inbox[0]);
47
- msgSize = ntohl(msgSize);
48
-
49
- // Can't really handle zero-size messages. IMPR?!
50
- if (msgSize == 0)
51
- throw std::logic_error("Cannot handle empty messages");
52
-
53
- // Has the current message arrived completely?
54
- if (inbox.size() < sizeSize + msgSize)
55
- break;
56
-
57
- // Current message is here: Call event...
58
- if (event)
59
- event(&inbox[sizeSize], msgSize);
60
-
61
- // ...and delete it from the inbox.
62
- inbox.erase(inbox.begin(),
63
- inbox.begin() + sizeSize + msgSize);
64
- }
65
-
66
- break;
67
- }
68
- }
69
- }
70
- };
71
-
72
- Gosu::CommSocket::CommSocket(CommMode mode, SocketAddress targetAddress,
73
- SocketPort targetPort)
74
- : pimpl(new Impl)
75
- {
76
- pimpl->mode = mode;
77
-
78
- sockaddr_in addr;
79
- std::memset(&addr, 0, sizeof addr);
80
- addr.sin_family = AF_INET;
81
- addr.sin_addr.s_addr = htonl(targetAddress);
82
- addr.sin_port = htons(targetPort);
83
-
84
- pimpl->socket.setHandle(socketCheck(::socket(AF_INET, SOCK_STREAM, 0)));
85
- pimpl->socket.setBlocking(true);
86
- socketCheck(::connect(pimpl->socket.handle(), reinterpret_cast<sockaddr*>(&addr),
87
- sizeof addr));
88
- pimpl->socket.setBlocking(false);
89
- }
90
-
91
- Gosu::CommSocket::CommSocket(CommMode mode, Socket& socket)
92
- : pimpl(new Impl)
93
- {
94
- pimpl->mode = mode;
95
-
96
- pimpl->socket.swap(socket);
97
- pimpl->socket.setBlocking(false);
98
- }
99
-
100
- Gosu::CommSocket::~CommSocket()
101
- {
102
- }
103
-
104
- Gosu::SocketAddress Gosu::CommSocket::address() const
105
- {
106
- return pimpl->socket.address();
107
- }
108
-
109
- Gosu::SocketPort Gosu::CommSocket::port() const
110
- {
111
- return pimpl->socket.port();
112
- }
113
-
114
- Gosu::SocketAddress Gosu::CommSocket::remoteAddress() const
115
- {
116
- assert(connected());
117
-
118
- sockaddr_in addr;
119
- int size = sizeof addr;
120
- socketCheck(::getpeername(pimpl->socket.handle(),
121
- reinterpret_cast<sockaddr*>(&addr),
122
- reinterpret_cast<socklen_t*>(&size)));
123
-
124
- return ntohl(addr.sin_addr.s_addr);
125
- }
126
-
127
- Gosu::SocketPort Gosu::CommSocket::remotePort() const
128
- {
129
- assert(connected());
130
-
131
- sockaddr_in addr;
132
- int size = sizeof addr;
133
- socketCheck(::getpeername(pimpl->socket.handle(),
134
- reinterpret_cast<sockaddr*>(&addr),
135
- reinterpret_cast<socklen_t*>(&size)));
136
- return ntohs(addr.sin_port);
137
- }
138
-
139
- Gosu::CommMode Gosu::CommSocket::mode() const
140
- {
141
- return pimpl->mode;
142
- }
143
-
144
- bool Gosu::CommSocket::connected() const
145
- {
146
- return pimpl->socket.handle() != INVALID_SOCKET;
147
- }
148
-
149
- void Gosu::CommSocket::disconnect()
150
- {
151
- pimpl->socket.setHandle(INVALID_SOCKET);
152
- // IMPR: Mmmmh. A full-blown sockets library should probably try to send
153
- // the remaining contents of the outbox. This is annoying to implement,
154
- // though...
155
- pimpl->outbox.clear();
156
- if (onDisconnection)
157
- onDisconnection();
158
- }
159
-
160
- bool Gosu::CommSocket::keepAlive() const
161
- {
162
- int buf;
163
- int size = sizeof buf;
164
- socketCheck(::getsockopt(pimpl->socket.handle(), SOL_SOCKET, SO_KEEPALIVE,
165
- reinterpret_cast<char*>(&buf),
166
- reinterpret_cast<socklen_t*>(&size)));
167
- return buf != 0;
168
- }
169
-
170
- void Gosu::CommSocket::setKeepAlive(bool value)
171
- {
172
- int buf = value;
173
- socketCheck(::setsockopt(pimpl->socket.handle(), SOL_SOCKET, SO_KEEPALIVE,
174
- reinterpret_cast<char*>(&buf), sizeof buf));
175
- }
176
-
177
- void Gosu::CommSocket::update()
178
- {
179
- sendPendingData();
180
-
181
- if (!connected())
182
- return;
183
-
184
- for (;;)
185
- {
186
- char buffer[1024];
187
- int received = ::recv(pimpl->socket.handle(), buffer, sizeof buffer, 0);
188
-
189
- if (received > 0 && received <= static_cast<int>(sizeof buffer))
190
- {
191
- // Data arrived and fit into the buffer.
192
- pimpl->appendBuffer(buffer, received, onReceive);
193
- }
194
- else if (received == 0)
195
- {
196
- // The other side has gracefully closed the connection.
197
- disconnect();
198
- return;
199
- }
200
- else if (received == SOCKET_ERROR)
201
- {
202
- switch (lastSocketError())
203
- {
204
- // Arriving data didn't fit into the buffer.
205
- case GOSU_SOCK_ERR(EMSGSIZE):
206
- pimpl->appendBuffer(buffer, sizeof buffer, onReceive);
207
- break;
208
-
209
- // There simply was no data.
210
- case GOSU_SOCK_ERR(EWOULDBLOCK):
211
- return;
212
-
213
- // Connection was reset or is invalid.
214
- case GOSU_SOCK_ERR(ENETDOWN):
215
- case GOSU_SOCK_ERR(ENOTCONN):
216
- case GOSU_SOCK_ERR(ENETRESET):
217
- case GOSU_SOCK_ERR(ECONNABORTED):
218
- case GOSU_SOCK_ERR(ETIMEDOUT):
219
- case GOSU_SOCK_ERR(ECONNRESET):
220
- #ifndef GOSU_IS_WIN
221
- // UNIX specific, rare error
222
- case GOSU_SOCK_ERR(EPIPE):
223
- #endif
224
- disconnect();
225
- return;
226
-
227
- // Everything else is unexpected.
228
- default:
229
- throwLastSocketError();
230
- }
231
- }
232
- else assert(false);
233
- }
234
- }
235
-
236
- void Gosu::CommSocket::send(const void* buffer, std::size_t size)
237
- {
238
- if (!connected())
239
- return;
240
-
241
- // In managed mode, also send the length of the buffer.
242
- if (mode() == cmManaged)
243
- {
244
- std::tr1::uint32_t netSize = htonl(size);
245
- const char* charBuf = reinterpret_cast<const char*>(&netSize);
246
- pimpl->outbox.insert(pimpl->outbox.end(), charBuf,
247
- charBuf + sizeof netSize);
248
- }
249
-
250
- const char* charBuf = reinterpret_cast<const char*>(buffer);
251
- pimpl->outbox.insert(pimpl->outbox.end(), charBuf, charBuf + size);
252
- }
253
-
254
- void Gosu::CommSocket::sendPendingData()
255
- {
256
- if (pendingBytes() == 0 || !connected())
257
- return;
258
-
259
- int sent = ::send(pimpl->socket.handle(), &pimpl->outbox.front(),
260
- pendingBytes(), 0);
261
-
262
- if (sent >= 0)
263
- {
264
- // Remove sent data from the outbox.
265
- if (sent >= static_cast<int>(pendingBytes()))
266
- pimpl->outbox.clear();
267
- else
268
- pimpl->outbox.erase(pimpl->outbox.begin(),
269
- pimpl->outbox.begin() + sent);
270
- }
271
- else
272
- {
273
- switch (lastSocketError())
274
- {
275
- // These error codes basically mean "try again later".
276
- case GOSU_SOCK_ERR(ENOBUFS):
277
- case GOSU_SOCK_ERR(EWOULDBLOCK):
278
- case GOSU_SOCK_ERR(EHOSTUNREACH):
279
- break;
280
-
281
- // And these tell us we're disconnected.
282
- case GOSU_SOCK_ERR(ENETDOWN):
283
- case GOSU_SOCK_ERR(ENETRESET):
284
- case GOSU_SOCK_ERR(ENOTCONN):
285
- case GOSU_SOCK_ERR(ECONNABORTED):
286
- case GOSU_SOCK_ERR(ECONNRESET):
287
- case GOSU_SOCK_ERR(ETIMEDOUT):
288
- #ifndef GOSU_IS_WIN
289
- // UNIX-specific, rare error
290
- case GOSU_SOCK_ERR(EPIPE):
291
- #endif
292
- disconnect();
293
- break;
294
-
295
- // Everything else is unexpected.
296
- default:
297
- throwLastSocketError();
298
- }
299
- }
300
- }
301
-
302
- std::size_t Gosu::CommSocket::pendingBytes() const
303
- {
304
- return pimpl->outbox.size();
305
- }