gosu 0.10.9.pre1 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gosu/Audio.hpp +35 -66
- data/Gosu/AutoLink.hpp +14 -16
- data/Gosu/Bitmap.hpp +50 -37
- data/Gosu/Buttons.hpp +246 -265
- data/Gosu/Color.hpp +32 -76
- data/Gosu/Directories.hpp +14 -17
- data/Gosu/Font.hpp +28 -34
- data/Gosu/Fwd.hpp +27 -31
- data/Gosu/Gosu.hpp +2 -5
- data/Gosu/Graphics.hpp +31 -48
- data/Gosu/GraphicsBase.hpp +27 -58
- data/Gosu/IO.hpp +44 -56
- data/Gosu/Image.hpp +29 -73
- data/Gosu/ImageData.hpp +13 -17
- data/Gosu/Input.hpp +42 -57
- data/Gosu/Inspection.hpp +2 -6
- data/Gosu/Math.hpp +32 -38
- data/Gosu/Platform.hpp +10 -29
- data/Gosu/Text.hpp +30 -39
- data/Gosu/TextInput.hpp +29 -36
- data/Gosu/Timing.hpp +14 -16
- data/Gosu/Utility.hpp +10 -15
- data/Gosu/Version.hpp +13 -14
- data/Gosu/Window.hpp +53 -68
- data/README.md +23 -11
- data/ext/gosu/extconf.rb +31 -81
- data/lib/gosu/patches.rb +35 -19
- data/lib/gosu/run.rb +13 -4
- data/rdoc/gosu.rb +24 -20
- data/src/ALChannelManagement.hpp +119 -0
- data/src/{Audio/Audio.cpp → Audio.cpp} +177 -211
- data/src/AudioFile.hpp +57 -0
- data/src/AudioToolboxFile.hpp +214 -0
- data/src/Bitmap.cpp +159 -0
- data/src/BitmapIO.cpp +141 -0
- data/src/BlockAllocator.cpp +133 -0
- data/src/{Graphics/BlockAllocator.hpp → BlockAllocator.hpp} +34 -35
- data/src/ClipRectStack.hpp +87 -0
- data/src/{Graphics/Color.cpp → Color.cpp} +30 -28
- data/src/DirectoriesApple.cpp +68 -0
- data/src/DirectoriesUnix.cpp +20 -18
- data/src/DirectoriesWin.cpp +40 -41
- data/src/DrawOp.hpp +168 -0
- data/src/DrawOpQueue.hpp +190 -0
- data/src/FileUnix.cpp +40 -46
- data/src/FileWin.cpp +42 -38
- data/src/Font.cpp +165 -0
- data/src/{Text/FormattedString.hpp → FormattedString.hpp} +114 -114
- data/src/GosuAppDelegate.cpp +30 -0
- data/src/{UIKit/GosuAppDelegate.h → GosuAppDelegate.h} +0 -0
- data/src/{UIKit/GosuGLView.mm → GosuGLView.cpp} +22 -17
- data/src/{UIKit/GosuGLView.h → GosuGLView.h} +0 -0
- data/src/GosuViewController.cpp +231 -0
- data/src/{UIKit/GosuViewController.h → GosuViewController.h} +0 -0
- data/src/Graphics.cpp +464 -0
- data/src/{Graphics/Common.hpp → GraphicsImpl.hpp} +29 -32
- data/src/IO.cpp +17 -16
- data/src/Iconv.hpp +13 -22
- data/src/Image.cpp +142 -0
- data/src/Input.cpp +459 -0
- data/src/InputUIKit.cpp +197 -0
- data/src/Inspection.cpp +4 -5
- data/src/LargeImageData.cpp +151 -0
- data/src/LargeImageData.hpp +43 -0
- data/src/{Graphics/Macro.cpp → Macro.cpp} +77 -78
- data/src/Macro.hpp +30 -0
- data/src/Math.cpp +17 -29
- data/src/{Audio/OggFile.hpp → OggFile.hpp} +19 -24
- data/src/RenderState.hpp +205 -0
- data/src/Resolution.cpp +86 -0
- data/src/ResolutionApple.cpp +25 -0
- data/{ext/gosu/gosu_wrap.cxx → src/RubyGosu.cxx} +2256 -1707
- data/{ext/gosu/gosu_wrap.h → src/RubyGosu.h} +9 -9
- data/src/{Audio/SndFile.hpp → SndFile.hpp} +54 -43
- data/src/TexChunk.cpp +117 -0
- data/src/{Graphics/TexChunk.hpp → TexChunk.hpp} +13 -18
- data/src/Text.cpp +371 -0
- data/src/TextApple.cpp +209 -0
- data/src/TextInput.cpp +278 -0
- data/src/TextTTFWin.cpp +251 -0
- data/src/{Text/TextUnix.cpp → TextUnix.cpp} +96 -92
- data/src/TextWin.cpp +194 -0
- data/src/{Graphics/Texture.cpp → Texture.cpp} +35 -38
- data/src/{Graphics/Texture.hpp → Texture.hpp} +9 -13
- data/src/TimingApple.cpp +11 -7
- data/src/TimingUnix.cpp +13 -7
- data/src/TimingWin.cpp +6 -1
- data/src/{Graphics/Transform.cpp → Transform.cpp} +17 -12
- data/src/{Graphics/TransformStack.hpp → TransformStack.hpp} +24 -25
- data/src/Utility.cpp +29 -70
- data/src/UtilityApple.cpp +52 -0
- data/src/UtilityWin.cpp +7 -4
- data/src/Version.cpp +22 -0
- data/src/WinMain.cpp +30 -33
- data/src/WinUtility.cpp +24 -22
- data/src/WinUtility.hpp +11 -20
- data/src/Window.cpp +142 -112
- data/src/WindowUIKit.cpp +155 -0
- data/src/stb_image.h +384 -173
- data/src/stb_vorbis.c +20 -18
- metadata +60 -62
- data/Gosu/TR1.hpp +0 -56
- data/src/AppleUtility.hpp +0 -66
- data/src/Audio/ALChannelManagement.hpp +0 -114
- data/src/Audio/Audio.mm +0 -1
- data/src/Audio/AudioFile.hpp +0 -53
- data/src/Audio/AudioToolboxFile.hpp +0 -207
- data/src/Bitmap/Bitmap.cpp +0 -183
- data/src/Bitmap/BitmapIO.cpp +0 -176
- data/src/DirectoriesApple.mm +0 -71
- data/src/Graphics/BlockAllocator.cpp +0 -142
- data/src/Graphics/ClipRectStack.hpp +0 -93
- data/src/Graphics/DrawOp.hpp +0 -175
- data/src/Graphics/DrawOpQueue.hpp +0 -188
- data/src/Graphics/Graphics.cpp +0 -478
- data/src/Graphics/Image.cpp +0 -193
- data/src/Graphics/LargeImageData.cpp +0 -133
- data/src/Graphics/LargeImageData.hpp +0 -46
- data/src/Graphics/Macro.hpp +0 -36
- data/src/Graphics/RenderState.hpp +0 -211
- data/src/Graphics/Resolution.cpp +0 -91
- data/src/Graphics/ResolutionApple.mm +0 -19
- data/src/Graphics/TexChunk.cpp +0 -112
- data/src/Input/Input.cpp +0 -463
- data/src/Input/InputUIKit.mm +0 -190
- data/src/Input/TextInput.cpp +0 -261
- data/src/Text/Font.cpp +0 -175
- data/src/Text/Text.cpp +0 -391
- data/src/Text/TextApple.mm +0 -227
- data/src/Text/TextTTFWin.cpp +0 -249
- data/src/Text/TextWin.cpp +0 -186
- data/src/UIKit/GosuAppDelegate.mm +0 -24
- data/src/UIKit/GosuViewController.mm +0 -211
- data/src/UtilityApple.mm +0 -63
- data/src/WindowUIKit.mm +0 -139
@@ -0,0 +1,30 @@
|
|
1
|
+
#include <Gosu/Platform.hpp>
|
2
|
+
#if defined(GOSU_IS_IPHONE)
|
3
|
+
|
4
|
+
#import "GosuAppDelegate.h"
|
5
|
+
#import <Gosu/Gosu.hpp>
|
6
|
+
|
7
|
+
Gosu::Window& window_instance();
|
8
|
+
|
9
|
+
@implementation GosuAppDelegate
|
10
|
+
|
11
|
+
- (BOOL)application:(UIApplication*)application
|
12
|
+
didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
|
13
|
+
{
|
14
|
+
self.window = (__bridge UIWindow*) window_instance().UIWindow();
|
15
|
+
[self.window makeKeyAndVisible];
|
16
|
+
|
17
|
+
return YES;
|
18
|
+
}
|
19
|
+
|
20
|
+
@end
|
21
|
+
|
22
|
+
int main(int argc, char* argv[])
|
23
|
+
{
|
24
|
+
@autoreleasepool {
|
25
|
+
Gosu::use_resource_directory();
|
26
|
+
return UIApplicationMain(argc, argv, nil, NSStringFromClass([GosuAppDelegate class]));
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
#endif
|
File without changes
|
@@ -1,33 +1,33 @@
|
|
1
|
+
#include <Gosu/Platform.hpp>
|
2
|
+
#if defined(GOSU_IS_IPHONE)
|
3
|
+
|
1
4
|
#import "GosuGLView.h"
|
2
5
|
|
3
|
-
#import <QuartzCore/QuartzCore.h>
|
4
|
-
#import <OpenGLES/EAGLDrawable.h>
|
5
6
|
#import <OpenGLES/EAGL.h>
|
7
|
+
#import <OpenGLES/EAGLDrawable.h>
|
6
8
|
#import <OpenGLES/ES1/gl.h>
|
7
9
|
#import <OpenGLES/ES1/glext.h>
|
10
|
+
#import <QuartzCore/QuartzCore.h>
|
8
11
|
|
9
|
-
|
10
|
-
static EAGLContext __weak *globalContext;
|
11
|
-
|
12
|
+
static EAGLContext __weak* globalContext;
|
12
13
|
|
13
14
|
namespace Gosu
|
14
15
|
{
|
15
|
-
void
|
16
|
+
void ensure_current_context()
|
16
17
|
{
|
17
18
|
[EAGLContext setCurrentContext:globalContext];
|
18
19
|
}
|
19
20
|
|
20
|
-
int
|
21
|
+
int clip_rect_base_factor()
|
21
22
|
{
|
22
23
|
static int result = [UIScreen mainScreen].scale;
|
23
24
|
return result;
|
24
25
|
}
|
25
26
|
}
|
26
27
|
|
27
|
-
|
28
28
|
@implementation GosuGLView
|
29
29
|
{
|
30
|
-
EAGLContext
|
30
|
+
EAGLContext* _context;
|
31
31
|
|
32
32
|
GLint _backingWidth;
|
33
33
|
GLint _backingHeight;
|
@@ -35,7 +35,7 @@ namespace Gosu
|
|
35
35
|
GLuint _viewRenderbuffer;
|
36
36
|
GLuint _viewFramebuffer;
|
37
37
|
}
|
38
|
-
|
38
|
+
|
39
39
|
+ (Class)layerClass
|
40
40
|
{
|
41
41
|
return [CAEAGLLayer class];
|
@@ -50,7 +50,7 @@ namespace Gosu
|
|
50
50
|
return self;
|
51
51
|
}
|
52
52
|
|
53
|
-
- (id)initWithCoder:(NSCoder
|
53
|
+
- (id)initWithCoder:(NSCoder*)aDecoder
|
54
54
|
{
|
55
55
|
if ((self = [super initWithCoder:aDecoder])) {
|
56
56
|
[self initializeGosuGLView];
|
@@ -61,7 +61,7 @@ namespace Gosu
|
|
61
61
|
|
62
62
|
- (void)initializeGosuGLView
|
63
63
|
{
|
64
|
-
CAEAGLLayer
|
64
|
+
CAEAGLLayer* layer = (CAEAGLLayer*)self.layer;
|
65
65
|
layer.opaque = YES;
|
66
66
|
|
67
67
|
globalContext = _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
|
@@ -97,8 +97,8 @@ namespace Gosu
|
|
97
97
|
{
|
98
98
|
[EAGLContext setCurrentContext:_context];
|
99
99
|
[self destroyFramebuffer];
|
100
|
-
self.contentScaleFactor = Gosu::clipRectBaseFactor();
|
101
100
|
[self createFramebuffer];
|
101
|
+
self.contentScaleFactor = Gosu::clip_rect_base_factor();
|
102
102
|
}
|
103
103
|
|
104
104
|
- (BOOL)createFramebuffer
|
@@ -108,11 +108,14 @@ namespace Gosu
|
|
108
108
|
|
109
109
|
glBindFramebufferOES(GL_FRAMEBUFFER_OES, _viewFramebuffer);
|
110
110
|
glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer);
|
111
|
-
[_context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer
|
112
|
-
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES,
|
111
|
+
[_context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
|
112
|
+
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES,
|
113
|
+
_viewRenderbuffer);
|
113
114
|
|
114
|
-
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES,
|
115
|
-
|
115
|
+
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES,
|
116
|
+
&_backingWidth);
|
117
|
+
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES,
|
118
|
+
&_backingHeight);
|
116
119
|
|
117
120
|
return (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) == GL_FRAMEBUFFER_COMPLETE_OES);
|
118
121
|
}
|
@@ -126,3 +129,5 @@ namespace Gosu
|
|
126
129
|
}
|
127
130
|
|
128
131
|
@end
|
132
|
+
|
133
|
+
#endif
|
File without changes
|
@@ -0,0 +1,231 @@
|
|
1
|
+
#include <Gosu/Platform.hpp>
|
2
|
+
#if defined(GOSU_IS_IPHONE)
|
3
|
+
|
4
|
+
#import "GosuGLView.h"
|
5
|
+
#import "GosuViewController.h"
|
6
|
+
#import "GraphicsImpl.hpp"
|
7
|
+
#import <Gosu/Gosu.hpp>
|
8
|
+
|
9
|
+
#import <AudioToolbox/AudioSession.h>
|
10
|
+
#import <OpenAL/alc.h>
|
11
|
+
|
12
|
+
namespace Gosu
|
13
|
+
{
|
14
|
+
namespace FPS
|
15
|
+
{
|
16
|
+
void register_frame();
|
17
|
+
}
|
18
|
+
|
19
|
+
ALCcontext* shared_openal_context();
|
20
|
+
}
|
21
|
+
|
22
|
+
// TODO: This has been written on iOS 3.x.
|
23
|
+
// Is this still the best way to handle interruptions?
|
24
|
+
static void handle_audio_interruption(void* unused, UInt32 inInterruptionState)
|
25
|
+
{
|
26
|
+
if (inInterruptionState == kAudioSessionBeginInterruption) {
|
27
|
+
alcMakeContextCurrent(nullptr);
|
28
|
+
}
|
29
|
+
else if (inInterruptionState == kAudioSessionEndInterruption) {
|
30
|
+
alcMakeContextCurrent(Gosu::shared_openal_context());
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
@implementation GosuViewController
|
35
|
+
{
|
36
|
+
BOOL _paused;
|
37
|
+
BOOL _musicPaused;
|
38
|
+
id _timerOrDisplayLink;
|
39
|
+
}
|
40
|
+
|
41
|
+
#pragma mark - UIViewController
|
42
|
+
|
43
|
+
- (void)loadView
|
44
|
+
{
|
45
|
+
self.view = [[GosuGLView alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
46
|
+
}
|
47
|
+
|
48
|
+
- (BOOL)prefersStatusBarHidden
|
49
|
+
{
|
50
|
+
return YES;
|
51
|
+
}
|
52
|
+
|
53
|
+
- (BOOL)shouldAutorotate
|
54
|
+
{
|
55
|
+
return YES;
|
56
|
+
}
|
57
|
+
|
58
|
+
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
59
|
+
{
|
60
|
+
return UIInterfaceOrientationIsLandscape(interfaceOrientation);
|
61
|
+
}
|
62
|
+
|
63
|
+
- (NSUInteger)supportedInterfaceOrientations
|
64
|
+
{
|
65
|
+
return UIInterfaceOrientationMaskLandscape;
|
66
|
+
}
|
67
|
+
|
68
|
+
- (GosuGLView*)GLView
|
69
|
+
{
|
70
|
+
return (GosuGLView*)self.view;
|
71
|
+
}
|
72
|
+
|
73
|
+
- (Gosu::Window&)gosuWindowReference
|
74
|
+
{
|
75
|
+
NSAssert(self.gosuWindow, @"gosuWindow needs to be set before showing GosuViewController");
|
76
|
+
|
77
|
+
return *(Gosu::Window*)self.gosuWindow;
|
78
|
+
}
|
79
|
+
|
80
|
+
#pragma mark - Notifications (handle pausing)
|
81
|
+
|
82
|
+
- (void)viewDidLoad
|
83
|
+
{
|
84
|
+
[super viewDidLoad];
|
85
|
+
|
86
|
+
AudioSessionInitialize(nullptr, nullptr, handle_audio_interruption, nullptr);
|
87
|
+
|
88
|
+
[[NSNotificationCenter defaultCenter] addObserver:self
|
89
|
+
selector:@selector(applicationDidBecomeActive:)
|
90
|
+
name:UIApplicationDidBecomeActiveNotification
|
91
|
+
object:nil];
|
92
|
+
[[NSNotificationCenter defaultCenter] addObserver:self
|
93
|
+
selector:@selector(applicationWillResignActive:)
|
94
|
+
name:UIApplicationWillResignActiveNotification
|
95
|
+
object:nil];
|
96
|
+
[[NSNotificationCenter defaultCenter] addObserver:self
|
97
|
+
selector:@selector(applicationWillEnterForeground:)
|
98
|
+
name:UIApplicationWillEnterForegroundNotification
|
99
|
+
object:nil];
|
100
|
+
[[NSNotificationCenter defaultCenter] addObserver:self
|
101
|
+
selector:@selector(applicationDidEnterBackground:)
|
102
|
+
name:UIApplicationDidEnterBackgroundNotification
|
103
|
+
object:nil];
|
104
|
+
}
|
105
|
+
|
106
|
+
- (void)dealloc
|
107
|
+
{
|
108
|
+
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
109
|
+
}
|
110
|
+
|
111
|
+
- (void)applicationDidBecomeActive:(NSNotification*)notification
|
112
|
+
{
|
113
|
+
if (_musicPaused) {
|
114
|
+
if (Gosu::Song::current_song()) {
|
115
|
+
Gosu::Song::current_song()->play();
|
116
|
+
}
|
117
|
+
_musicPaused = NO;
|
118
|
+
}
|
119
|
+
_paused = NO;
|
120
|
+
}
|
121
|
+
|
122
|
+
- (void)applicationWillResignActive:(NSNotification*)notification
|
123
|
+
{
|
124
|
+
if (Gosu::Song::current_song()) {
|
125
|
+
Gosu::Song::current_song()->pause();
|
126
|
+
_musicPaused = YES;
|
127
|
+
}
|
128
|
+
_paused = YES;
|
129
|
+
|
130
|
+
self.gosuWindowReference.lose_focus();
|
131
|
+
}
|
132
|
+
|
133
|
+
- (void)applicationWillEnterForeground:(NSNotification*)notification
|
134
|
+
{
|
135
|
+
[self setupTimerOrDisplayLink];
|
136
|
+
}
|
137
|
+
|
138
|
+
- (void)applicationDidEnterBackground:(NSNotification*)notification
|
139
|
+
{
|
140
|
+
[_timerOrDisplayLink invalidate];
|
141
|
+
_timerOrDisplayLink = nil;
|
142
|
+
}
|
143
|
+
|
144
|
+
#pragma mark - Redraw & update "loop"
|
145
|
+
|
146
|
+
- (void)viewWillAppear:(BOOL)animated
|
147
|
+
{
|
148
|
+
[super viewWillAppear:animated];
|
149
|
+
|
150
|
+
[self setupTimerOrDisplayLink];
|
151
|
+
|
152
|
+
[UIApplication sharedApplication].statusBarHidden = YES;
|
153
|
+
}
|
154
|
+
|
155
|
+
- (void)setupTimerOrDisplayLink
|
156
|
+
{
|
157
|
+
if (_timerOrDisplayLink) {
|
158
|
+
return;
|
159
|
+
}
|
160
|
+
|
161
|
+
NSInteger targetFPS = round(1000.0 / self.gosuWindowReference.update_interval());
|
162
|
+
|
163
|
+
if (60 % targetFPS != 0) {
|
164
|
+
NSTimeInterval interval = self.gosuWindowReference.update_interval() / 1000.0;
|
165
|
+
NSTimer* timer = [NSTimer scheduledTimerWithTimeInterval:interval
|
166
|
+
target:self
|
167
|
+
selector:@selector(updateAndDraw:)
|
168
|
+
userInfo:nil
|
169
|
+
repeats:YES];
|
170
|
+
|
171
|
+
_timerOrDisplayLink = timer;
|
172
|
+
}
|
173
|
+
else {
|
174
|
+
CADisplayLink* displayLink =
|
175
|
+
[CADisplayLink displayLinkWithTarget:self selector:@selector(updateAndDraw:)];
|
176
|
+
displayLink.frameInterval = 60 / targetFPS;
|
177
|
+
[displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
|
178
|
+
|
179
|
+
_timerOrDisplayLink = displayLink;
|
180
|
+
}
|
181
|
+
}
|
182
|
+
|
183
|
+
- (void)updateAndDraw:(id)sender
|
184
|
+
{
|
185
|
+
Gosu::Window& window = self.gosuWindowReference;
|
186
|
+
|
187
|
+
window.input().update();
|
188
|
+
|
189
|
+
if (!_paused) {
|
190
|
+
window.update();
|
191
|
+
}
|
192
|
+
|
193
|
+
if (window.needs_redraw()) {
|
194
|
+
[self.GLView redrawGL:^{
|
195
|
+
if (window.graphics().begin()) {
|
196
|
+
window.draw();
|
197
|
+
window.graphics().end();
|
198
|
+
|
199
|
+
Gosu::FPS::register_frame();
|
200
|
+
}
|
201
|
+
}];
|
202
|
+
}
|
203
|
+
|
204
|
+
Gosu::Song::update();
|
205
|
+
}
|
206
|
+
|
207
|
+
#pragma mark - Touch forwarding
|
208
|
+
|
209
|
+
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
|
210
|
+
{
|
211
|
+
self.gosuWindowReference.input().feed_touch_event(0, (__bridge void*) touches);
|
212
|
+
}
|
213
|
+
|
214
|
+
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
|
215
|
+
{
|
216
|
+
self.gosuWindowReference.input().feed_touch_event(1, (__bridge void*) touches);
|
217
|
+
}
|
218
|
+
|
219
|
+
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
|
220
|
+
{
|
221
|
+
self.gosuWindowReference.input().feed_touch_event(2, (__bridge void*) touches);
|
222
|
+
}
|
223
|
+
|
224
|
+
- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event
|
225
|
+
{
|
226
|
+
self.gosuWindowReference.input().feed_touch_event(3, (__bridge void*) touches);
|
227
|
+
}
|
228
|
+
|
229
|
+
@end
|
230
|
+
|
231
|
+
#endif
|
File without changes
|
data/src/Graphics.cpp
ADDED
@@ -0,0 +1,464 @@
|
|
1
|
+
#include <Gosu/Graphics.hpp>
|
2
|
+
#include "DrawOp.hpp"
|
3
|
+
#include "DrawOpQueue.hpp"
|
4
|
+
#include "GraphicsImpl.hpp"
|
5
|
+
#include "LargeImageData.hpp"
|
6
|
+
#include "Macro.hpp"
|
7
|
+
#include "TexChunk.hpp"
|
8
|
+
#include "Texture.hpp"
|
9
|
+
#include <Gosu/Bitmap.hpp>
|
10
|
+
#include <Gosu/Image.hpp>
|
11
|
+
#include <Gosu/Platform.hpp>
|
12
|
+
#include <cmath>
|
13
|
+
#include <algorithm>
|
14
|
+
#include <functional>
|
15
|
+
#include <memory>
|
16
|
+
|
17
|
+
namespace Gosu
|
18
|
+
{
|
19
|
+
namespace
|
20
|
+
{
|
21
|
+
Graphics* current_graphics_pointer = nullptr;
|
22
|
+
|
23
|
+
Graphics& current_graphics()
|
24
|
+
{
|
25
|
+
if (current_graphics_pointer == nullptr) {
|
26
|
+
throw std::logic_error("Gosu::Graphics can only be drawn to while rendering");
|
27
|
+
}
|
28
|
+
|
29
|
+
return *current_graphics_pointer;
|
30
|
+
}
|
31
|
+
|
32
|
+
std::vector<std::shared_ptr<Texture>> textures;
|
33
|
+
|
34
|
+
DrawOpQueueStack queues;
|
35
|
+
|
36
|
+
DrawOpQueue& current_queue()
|
37
|
+
{
|
38
|
+
if (queues.empty()) {
|
39
|
+
throw std::logic_error("There is no rendering queue for this operation");
|
40
|
+
}
|
41
|
+
return queues.back();
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
struct Gosu::Graphics::Impl
|
47
|
+
{
|
48
|
+
unsigned virt_width, virt_height;
|
49
|
+
unsigned phys_width, phys_height;
|
50
|
+
double black_width, black_height;
|
51
|
+
Transform base_transform;
|
52
|
+
|
53
|
+
DrawOpQueueStack warmed_up_queues;
|
54
|
+
|
55
|
+
void update_base_transform()
|
56
|
+
{
|
57
|
+
double scale_x = 1.0 * phys_width / virt_width;
|
58
|
+
double scale_y = 1.0 * phys_height / virt_height;
|
59
|
+
double scale_factor = std::min(scale_x, scale_y);
|
60
|
+
|
61
|
+
Transform scale_transform = scale(scale_factor);
|
62
|
+
Transform translate_transform = translate(black_width, black_height);
|
63
|
+
base_transform = concat(translate_transform, scale_transform);
|
64
|
+
}
|
65
|
+
};
|
66
|
+
|
67
|
+
Gosu::Graphics::Graphics(unsigned phys_width, unsigned phys_height)
|
68
|
+
: pimpl(new Impl)
|
69
|
+
{
|
70
|
+
pimpl->virt_width = phys_width;
|
71
|
+
pimpl->virt_height = phys_height;
|
72
|
+
pimpl->black_width = 0;
|
73
|
+
pimpl->black_height = 0;
|
74
|
+
|
75
|
+
// TODO: Should be merged into RenderState and removed from Graphics.
|
76
|
+
glMatrixMode(GL_MODELVIEW);
|
77
|
+
glLoadIdentity();
|
78
|
+
glEnable(GL_BLEND);
|
79
|
+
|
80
|
+
set_physical_resolution(phys_width, phys_height);
|
81
|
+
}
|
82
|
+
|
83
|
+
Gosu::Graphics::~Graphics()
|
84
|
+
{
|
85
|
+
if (current_graphics_pointer == this) {
|
86
|
+
current_graphics_pointer = nullptr;
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
unsigned Gosu::Graphics::width() const
|
91
|
+
{
|
92
|
+
return pimpl->virt_width;
|
93
|
+
}
|
94
|
+
|
95
|
+
unsigned Gosu::Graphics::height() const
|
96
|
+
{
|
97
|
+
return pimpl->virt_height;
|
98
|
+
}
|
99
|
+
|
100
|
+
void Gosu::Graphics::set_resolution(unsigned virtual_width, unsigned virtual_height,
|
101
|
+
double horizontal_black_bar_width, double vertical_black_bar_height)
|
102
|
+
{
|
103
|
+
if (virtual_width == 0 || virtual_height == 0) {
|
104
|
+
throw std::invalid_argument("Invalid virtual resolution.");
|
105
|
+
}
|
106
|
+
|
107
|
+
pimpl->virt_width = virtual_width;
|
108
|
+
pimpl->virt_height = virtual_height;
|
109
|
+
pimpl->black_width = horizontal_black_bar_width;
|
110
|
+
pimpl->black_height = vertical_black_bar_height;
|
111
|
+
|
112
|
+
pimpl->update_base_transform();
|
113
|
+
}
|
114
|
+
|
115
|
+
bool Gosu::Graphics::begin(Gosu::Color clear_with_color)
|
116
|
+
{
|
117
|
+
if (current_graphics_pointer != nullptr) {
|
118
|
+
throw std::logic_error("Cannot nest calls to Gosu::Graphics::begin()");
|
119
|
+
}
|
120
|
+
|
121
|
+
// Cancel all recording or whatever that might still be in progress...
|
122
|
+
queues.clear();
|
123
|
+
|
124
|
+
if (pimpl->warmed_up_queues.size() == 1) {
|
125
|
+
// If we already have a "warmed up" queue, use that instead.
|
126
|
+
// -> All internals std::vectors will already have a lot of capacity.
|
127
|
+
// This helps reduce allocations during normal operation.
|
128
|
+
queues.clear();
|
129
|
+
queues.swap(pimpl->warmed_up_queues);
|
130
|
+
}
|
131
|
+
else {
|
132
|
+
// Create default draw-op queue.
|
133
|
+
queues.resize(1);
|
134
|
+
}
|
135
|
+
|
136
|
+
queues.back().set_base_transform(pimpl->base_transform);
|
137
|
+
|
138
|
+
glClearColor(clear_with_color.red() / 255.f, clear_with_color.green() / 255.f,
|
139
|
+
clear_with_color.blue() / 255.f, clear_with_color.alpha() / 255.f);
|
140
|
+
glClear(GL_COLOR_BUFFER_BIT);
|
141
|
+
|
142
|
+
current_graphics_pointer = this;
|
143
|
+
|
144
|
+
return true;
|
145
|
+
}
|
146
|
+
|
147
|
+
void Gosu::Graphics::end()
|
148
|
+
{
|
149
|
+
// If recording is in process, cancel it.
|
150
|
+
while (current_queue().recording()) {
|
151
|
+
queues.pop_back();
|
152
|
+
}
|
153
|
+
|
154
|
+
flush();
|
155
|
+
|
156
|
+
if (pimpl->black_height || pimpl->black_width) {
|
157
|
+
if (pimpl->black_height) {
|
158
|
+
draw_quad(0, -pimpl->black_height, Color::BLACK,
|
159
|
+
width(), -pimpl->black_height, Color::BLACK,
|
160
|
+
0, 0, Color::BLACK,
|
161
|
+
width(), 0, Color::BLACK, 0);
|
162
|
+
draw_quad(0, height(), Color::BLACK,
|
163
|
+
width(), height(), Color::BLACK,
|
164
|
+
0, height() + pimpl->black_height, Color::BLACK,
|
165
|
+
width(), height() + pimpl->black_height, Color::BLACK, 0);
|
166
|
+
}
|
167
|
+
else if (pimpl->black_width) {
|
168
|
+
draw_quad(-pimpl->black_width, 0, Color::BLACK,
|
169
|
+
0, 0, Color::BLACK,
|
170
|
+
-pimpl->black_width, height(), Color::BLACK,
|
171
|
+
0, height(), Color::BLACK, 0);
|
172
|
+
draw_quad(width(), 0, Color::BLACK,
|
173
|
+
width() + pimpl->black_width, 0, Color::BLACK,
|
174
|
+
width(), height(), Color::BLACK,
|
175
|
+
width() + pimpl->black_width, height(), Color::BLACK, 0);
|
176
|
+
}
|
177
|
+
flush();
|
178
|
+
}
|
179
|
+
|
180
|
+
glFlush();
|
181
|
+
|
182
|
+
current_graphics_pointer = nullptr;
|
183
|
+
|
184
|
+
// Clear leftover transforms, clip rects etc.
|
185
|
+
if (queues.size() == 1) {
|
186
|
+
queues.swap(pimpl->warmed_up_queues);
|
187
|
+
pimpl->warmed_up_queues.back().reset();
|
188
|
+
}
|
189
|
+
else {
|
190
|
+
queues.clear();
|
191
|
+
}
|
192
|
+
}
|
193
|
+
|
194
|
+
void Gosu::Graphics::flush()
|
195
|
+
{
|
196
|
+
current_queue().perform_draw_ops_andCode();
|
197
|
+
current_queue().clear_queue();
|
198
|
+
}
|
199
|
+
|
200
|
+
void Gosu::Graphics::begin_gl()
|
201
|
+
{
|
202
|
+
if (current_queue().recording()) {
|
203
|
+
throw std::logic_error("Custom OpenGL is not allowed while creating a macro");
|
204
|
+
}
|
205
|
+
|
206
|
+
#ifdef GOSU_IS_OPENGLES
|
207
|
+
throw std::logic_error("Custom OpenGL ES is not supported yet");
|
208
|
+
#else
|
209
|
+
flush();
|
210
|
+
glPushAttrib(GL_ALL_ATTRIB_BITS);
|
211
|
+
glDisable(GL_BLEND);
|
212
|
+
while (glGetError() != GL_NO_ERROR);
|
213
|
+
#endif
|
214
|
+
}
|
215
|
+
|
216
|
+
void Gosu::Graphics::end_gl()
|
217
|
+
{
|
218
|
+
#ifdef GOSU_IS_OPENGLES
|
219
|
+
throw std::logic_error("Custom OpenGL ES is not supported yet");
|
220
|
+
#else
|
221
|
+
Graphics& cg = current_graphics();
|
222
|
+
|
223
|
+
glPopAttrib();
|
224
|
+
|
225
|
+
// Restore matrices.
|
226
|
+
// TODO: Should be merged into RenderState and removed from Graphics.
|
227
|
+
|
228
|
+
glMatrixMode(GL_PROJECTION);
|
229
|
+
glLoadIdentity();
|
230
|
+
glViewport(0, 0, cg.pimpl->phys_width, cg.pimpl->phys_height);
|
231
|
+
glOrtho(0, cg.pimpl->phys_width, cg.pimpl->phys_height, 0, -1, 1);
|
232
|
+
|
233
|
+
glMatrixMode(GL_MODELVIEW);
|
234
|
+
glLoadIdentity();
|
235
|
+
glEnable(GL_BLEND);
|
236
|
+
#endif
|
237
|
+
}
|
238
|
+
|
239
|
+
#ifdef GOSU_IS_OPENGLES
|
240
|
+
void Gosu::Graphics::gl(const std::function<void ()>& functor, Gosu::ZPos z)
|
241
|
+
{
|
242
|
+
throw std::logic_error("Custom OpenGL ES is not supported yet");
|
243
|
+
}
|
244
|
+
#else
|
245
|
+
namespace Gosu
|
246
|
+
{
|
247
|
+
struct RunGLFunctor
|
248
|
+
{
|
249
|
+
Graphics& graphics;
|
250
|
+
std::function<void ()> functor;
|
251
|
+
|
252
|
+
RunGLFunctor(Graphics& graphics, const std::function<void ()>& functor)
|
253
|
+
: graphics(graphics), functor(functor)
|
254
|
+
{
|
255
|
+
}
|
256
|
+
|
257
|
+
void operator()() const
|
258
|
+
{
|
259
|
+
// Inlined begin_gl() to avoid flushing.
|
260
|
+
glPushAttrib(GL_ALL_ATTRIB_BITS);
|
261
|
+
glDisable(GL_BLEND);
|
262
|
+
while (glGetError() != GL_NO_ERROR);
|
263
|
+
|
264
|
+
functor();
|
265
|
+
|
266
|
+
graphics.end_gl();
|
267
|
+
}
|
268
|
+
};
|
269
|
+
}
|
270
|
+
|
271
|
+
void Gosu::Graphics::gl(const std::function<void ()>& functor, Gosu::ZPos z)
|
272
|
+
{
|
273
|
+
current_queue().gl(RunGLFunctor(current_graphics(), functor), z);
|
274
|
+
}
|
275
|
+
#endif
|
276
|
+
|
277
|
+
void Gosu::Graphics::begin_clipping(double x, double y, double width, double height)
|
278
|
+
{
|
279
|
+
double screen_height = current_graphics().pimpl->phys_height;
|
280
|
+
current_queue().begin_clipping(x, y, width, height, screen_height);
|
281
|
+
}
|
282
|
+
|
283
|
+
void Gosu::Graphics::end_clipping()
|
284
|
+
{
|
285
|
+
current_queue().end_clipping();
|
286
|
+
}
|
287
|
+
|
288
|
+
void Gosu::Graphics::begin_recording()
|
289
|
+
{
|
290
|
+
queues.resize(queues.size() + 1);
|
291
|
+
current_queue().set_recording();
|
292
|
+
}
|
293
|
+
|
294
|
+
std::unique_ptr<Gosu::ImageData> Gosu::Graphics::end_recording(int width, int height)
|
295
|
+
{
|
296
|
+
if (!current_queue().recording()) {
|
297
|
+
throw std::logic_error("No macro recording in progress that can be captured");
|
298
|
+
}
|
299
|
+
|
300
|
+
std::unique_ptr<ImageData> result(new Macro(current_queue(), width, height));
|
301
|
+
queues.pop_back();
|
302
|
+
return result;
|
303
|
+
}
|
304
|
+
|
305
|
+
void Gosu::Graphics::push_transform(const Gosu::Transform& transform)
|
306
|
+
{
|
307
|
+
current_queue().push_transform(transform);
|
308
|
+
}
|
309
|
+
|
310
|
+
void Gosu::Graphics::pop_transform()
|
311
|
+
{
|
312
|
+
current_queue().pop_transform();
|
313
|
+
}
|
314
|
+
|
315
|
+
void Gosu::Graphics::draw_line(double x1, double y1, Color c1,
|
316
|
+
double x2, double y2, Color c2, ZPos z, AlphaMode mode)
|
317
|
+
{
|
318
|
+
DrawOp op;
|
319
|
+
op.render_state.mode = mode;
|
320
|
+
op.vertices_or_block_index = 2;
|
321
|
+
op.vertices[0] = DrawOp::Vertex(x1, y1, c1);
|
322
|
+
op.vertices[1] = DrawOp::Vertex(x2, y2, c2);
|
323
|
+
op.z = z;
|
324
|
+
|
325
|
+
current_queue().schedule_draw_op(op);
|
326
|
+
}
|
327
|
+
|
328
|
+
void Gosu::Graphics::draw_triangle(double x1, double y1, Color c1, double x2, double y2, Color c2,
|
329
|
+
double x3, double y3, Color c3, ZPos z, AlphaMode mode)
|
330
|
+
{
|
331
|
+
DrawOp op;
|
332
|
+
op.render_state.mode = mode;
|
333
|
+
op.vertices_or_block_index = 3;
|
334
|
+
op.vertices[0] = DrawOp::Vertex(x1, y1, c1);
|
335
|
+
op.vertices[1] = DrawOp::Vertex(x2, y2, c2);
|
336
|
+
op.vertices[2] = DrawOp::Vertex(x3, y3, c3);
|
337
|
+
#ifdef GOSU_IS_OPENGLES
|
338
|
+
op.vertices_or_block_index = 4;
|
339
|
+
op.vertices[3] = op.vertices[2];
|
340
|
+
#endif
|
341
|
+
op.z = z;
|
342
|
+
|
343
|
+
current_queue().schedule_draw_op(op);
|
344
|
+
}
|
345
|
+
|
346
|
+
void Gosu::Graphics::draw_quad(double x1, double y1, Color c1, double x2, double y2, Color c2,
|
347
|
+
double x3, double y3, Color c3, double x4, double y4, Color c4, ZPos z, AlphaMode mode)
|
348
|
+
{
|
349
|
+
normalize_coordinates(x1, y1, x2, y2, x3, y3, c3, x4, y4, c4);
|
350
|
+
|
351
|
+
DrawOp op;
|
352
|
+
op.render_state.mode = mode;
|
353
|
+
op.vertices_or_block_index = 4;
|
354
|
+
op.vertices[0] = DrawOp::Vertex(x1, y1, c1);
|
355
|
+
op.vertices[1] = DrawOp::Vertex(x2, y2, c2);
|
356
|
+
// TODO: Should be harmonized
|
357
|
+
#ifdef GOSU_IS_OPENGLES
|
358
|
+
op.vertices[2] = DrawOp::Vertex(x3, y3, c3);
|
359
|
+
op.vertices[3] = DrawOp::Vertex(x4, y4, c4);
|
360
|
+
#else
|
361
|
+
op.vertices[3] = DrawOp::Vertex(x3, y3, c3);
|
362
|
+
op.vertices[2] = DrawOp::Vertex(x4, y4, c4);
|
363
|
+
#endif
|
364
|
+
op.z = z;
|
365
|
+
|
366
|
+
current_queue().schedule_draw_op(op);
|
367
|
+
}
|
368
|
+
|
369
|
+
void Gosu::Graphics::schedule_draw_op(const Gosu::DrawOp& op)
|
370
|
+
{
|
371
|
+
current_queue().schedule_draw_op(op);
|
372
|
+
}
|
373
|
+
|
374
|
+
void Gosu::Graphics::set_physical_resolution(unsigned phys_width, unsigned phys_height)
|
375
|
+
{
|
376
|
+
pimpl->phys_width = phys_width;
|
377
|
+
pimpl->phys_height = phys_height;
|
378
|
+
// TODO: Should be merged into RenderState and removed from Graphics.
|
379
|
+
glMatrixMode(GL_PROJECTION);
|
380
|
+
glLoadIdentity();
|
381
|
+
glViewport(0, 0, phys_width, phys_height);
|
382
|
+
#ifdef GOSU_IS_OPENGLES
|
383
|
+
glOrthof(0, phys_width, phys_height, 0, -1, 1);
|
384
|
+
#else
|
385
|
+
glOrtho(0, phys_width, phys_height, 0, -1, 1);
|
386
|
+
#endif
|
387
|
+
|
388
|
+
pimpl->update_base_transform();
|
389
|
+
}
|
390
|
+
|
391
|
+
std::unique_ptr<Gosu::ImageData> Gosu::Graphics::create_image(const Bitmap& src,
|
392
|
+
unsigned src_x, unsigned src_y, unsigned src_width, unsigned src_height, unsigned flags)
|
393
|
+
{
|
394
|
+
static const unsigned max_size = MAX_TEXTURE_SIZE;
|
395
|
+
|
396
|
+
// Backwards compatibility: This used to be 'bool tileable'.
|
397
|
+
if (flags == 1) flags = IF_TILEABLE;
|
398
|
+
|
399
|
+
bool wants_retro = (flags & IF_RETRO);
|
400
|
+
|
401
|
+
// Special case: If the texture is supposed to have hard borders, is
|
402
|
+
// quadratic, has a size that is at least 64 pixels but no more than max_size
|
403
|
+
// pixels and a power of two, create a single texture just for this image.
|
404
|
+
if ((flags & IF_TILEABLE) == IF_TILEABLE &&
|
405
|
+
src_width == src_height &&
|
406
|
+
(src_width & (src_width - 1)) == 0 &&
|
407
|
+
src_width >= 64 && src_width <= max_size) {
|
408
|
+
std::shared_ptr<Texture> texture(new Texture(src_width, wants_retro));
|
409
|
+
std::unique_ptr<ImageData> data;
|
410
|
+
|
411
|
+
// Use the source bitmap directly if the source area completely covers
|
412
|
+
// it.
|
413
|
+
if (src_x == 0 && src_width == src.width() && src_y == 0 && src_height == src.height()) {
|
414
|
+
data = texture->try_alloc(texture, src, 0);
|
415
|
+
}
|
416
|
+
else {
|
417
|
+
Bitmap bmp(src_width, src_height);
|
418
|
+
bmp.insert(src, 0, 0, src_x, src_y, src_width, src_height);
|
419
|
+
data = texture->try_alloc(texture, bmp, 0);
|
420
|
+
}
|
421
|
+
|
422
|
+
if (!data.get()) {
|
423
|
+
throw std::logic_error("Internal texture block allocation error");
|
424
|
+
}
|
425
|
+
return std::move(data);
|
426
|
+
}
|
427
|
+
|
428
|
+
// Too large to fit on a single texture.
|
429
|
+
if (src_width > max_size - 2 || src_height > max_size - 2) {
|
430
|
+
Bitmap bmp(src_width, src_height);
|
431
|
+
bmp.insert(src, 0, 0, src_x, src_y, src_width, src_height);
|
432
|
+
std::unique_ptr<ImageData> lidi;
|
433
|
+
lidi.reset(new LargeImageData(bmp, max_size - 2, max_size - 2, flags));
|
434
|
+
return std::move(lidi);
|
435
|
+
}
|
436
|
+
|
437
|
+
Bitmap bmp;
|
438
|
+
apply_border_flags(bmp, src, src_x, src_y, src_width, src_height, flags);
|
439
|
+
|
440
|
+
// Try to put the bitmap into one of the already allocated textures.
|
441
|
+
for (auto texture : textures) {
|
442
|
+
if (texture->retro() != wants_retro) continue;
|
443
|
+
|
444
|
+
std::unique_ptr<ImageData> data;
|
445
|
+
data = texture->try_alloc(texture, bmp, 1);
|
446
|
+
if (data.get()) {
|
447
|
+
return std::move(data);
|
448
|
+
}
|
449
|
+
}
|
450
|
+
|
451
|
+
// All textures are full: Create a new one.
|
452
|
+
|
453
|
+
std::shared_ptr<Texture> texture;
|
454
|
+
texture.reset(new Texture(max_size, wants_retro));
|
455
|
+
textures.push_back(texture);
|
456
|
+
|
457
|
+
std::unique_ptr<ImageData> data;
|
458
|
+
data = texture->try_alloc(texture, bmp, 1);
|
459
|
+
if (!data.get()) {
|
460
|
+
throw std::logic_error("Internal texture block allocation error");
|
461
|
+
}
|
462
|
+
|
463
|
+
return std::move(data);
|
464
|
+
}
|