gosu 0.9.2 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
- }