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.
Files changed (136) hide show
  1. checksums.yaml +4 -4
  2. data/Gosu/Audio.hpp +35 -66
  3. data/Gosu/AutoLink.hpp +14 -16
  4. data/Gosu/Bitmap.hpp +50 -37
  5. data/Gosu/Buttons.hpp +246 -265
  6. data/Gosu/Color.hpp +32 -76
  7. data/Gosu/Directories.hpp +14 -17
  8. data/Gosu/Font.hpp +28 -34
  9. data/Gosu/Fwd.hpp +27 -31
  10. data/Gosu/Gosu.hpp +2 -5
  11. data/Gosu/Graphics.hpp +31 -48
  12. data/Gosu/GraphicsBase.hpp +27 -58
  13. data/Gosu/IO.hpp +44 -56
  14. data/Gosu/Image.hpp +29 -73
  15. data/Gosu/ImageData.hpp +13 -17
  16. data/Gosu/Input.hpp +42 -57
  17. data/Gosu/Inspection.hpp +2 -6
  18. data/Gosu/Math.hpp +32 -38
  19. data/Gosu/Platform.hpp +10 -29
  20. data/Gosu/Text.hpp +30 -39
  21. data/Gosu/TextInput.hpp +29 -36
  22. data/Gosu/Timing.hpp +14 -16
  23. data/Gosu/Utility.hpp +10 -15
  24. data/Gosu/Version.hpp +13 -14
  25. data/Gosu/Window.hpp +53 -68
  26. data/README.md +23 -11
  27. data/ext/gosu/extconf.rb +31 -81
  28. data/lib/gosu/patches.rb +35 -19
  29. data/lib/gosu/run.rb +13 -4
  30. data/rdoc/gosu.rb +24 -20
  31. data/src/ALChannelManagement.hpp +119 -0
  32. data/src/{Audio/Audio.cpp → Audio.cpp} +177 -211
  33. data/src/AudioFile.hpp +57 -0
  34. data/src/AudioToolboxFile.hpp +214 -0
  35. data/src/Bitmap.cpp +159 -0
  36. data/src/BitmapIO.cpp +141 -0
  37. data/src/BlockAllocator.cpp +133 -0
  38. data/src/{Graphics/BlockAllocator.hpp → BlockAllocator.hpp} +34 -35
  39. data/src/ClipRectStack.hpp +87 -0
  40. data/src/{Graphics/Color.cpp → Color.cpp} +30 -28
  41. data/src/DirectoriesApple.cpp +68 -0
  42. data/src/DirectoriesUnix.cpp +20 -18
  43. data/src/DirectoriesWin.cpp +40 -41
  44. data/src/DrawOp.hpp +168 -0
  45. data/src/DrawOpQueue.hpp +190 -0
  46. data/src/FileUnix.cpp +40 -46
  47. data/src/FileWin.cpp +42 -38
  48. data/src/Font.cpp +165 -0
  49. data/src/{Text/FormattedString.hpp → FormattedString.hpp} +114 -114
  50. data/src/GosuAppDelegate.cpp +30 -0
  51. data/src/{UIKit/GosuAppDelegate.h → GosuAppDelegate.h} +0 -0
  52. data/src/{UIKit/GosuGLView.mm → GosuGLView.cpp} +22 -17
  53. data/src/{UIKit/GosuGLView.h → GosuGLView.h} +0 -0
  54. data/src/GosuViewController.cpp +231 -0
  55. data/src/{UIKit/GosuViewController.h → GosuViewController.h} +0 -0
  56. data/src/Graphics.cpp +464 -0
  57. data/src/{Graphics/Common.hpp → GraphicsImpl.hpp} +29 -32
  58. data/src/IO.cpp +17 -16
  59. data/src/Iconv.hpp +13 -22
  60. data/src/Image.cpp +142 -0
  61. data/src/Input.cpp +459 -0
  62. data/src/InputUIKit.cpp +197 -0
  63. data/src/Inspection.cpp +4 -5
  64. data/src/LargeImageData.cpp +151 -0
  65. data/src/LargeImageData.hpp +43 -0
  66. data/src/{Graphics/Macro.cpp → Macro.cpp} +77 -78
  67. data/src/Macro.hpp +30 -0
  68. data/src/Math.cpp +17 -29
  69. data/src/{Audio/OggFile.hpp → OggFile.hpp} +19 -24
  70. data/src/RenderState.hpp +205 -0
  71. data/src/Resolution.cpp +86 -0
  72. data/src/ResolutionApple.cpp +25 -0
  73. data/{ext/gosu/gosu_wrap.cxx → src/RubyGosu.cxx} +2256 -1707
  74. data/{ext/gosu/gosu_wrap.h → src/RubyGosu.h} +9 -9
  75. data/src/{Audio/SndFile.hpp → SndFile.hpp} +54 -43
  76. data/src/TexChunk.cpp +117 -0
  77. data/src/{Graphics/TexChunk.hpp → TexChunk.hpp} +13 -18
  78. data/src/Text.cpp +371 -0
  79. data/src/TextApple.cpp +209 -0
  80. data/src/TextInput.cpp +278 -0
  81. data/src/TextTTFWin.cpp +251 -0
  82. data/src/{Text/TextUnix.cpp → TextUnix.cpp} +96 -92
  83. data/src/TextWin.cpp +194 -0
  84. data/src/{Graphics/Texture.cpp → Texture.cpp} +35 -38
  85. data/src/{Graphics/Texture.hpp → Texture.hpp} +9 -13
  86. data/src/TimingApple.cpp +11 -7
  87. data/src/TimingUnix.cpp +13 -7
  88. data/src/TimingWin.cpp +6 -1
  89. data/src/{Graphics/Transform.cpp → Transform.cpp} +17 -12
  90. data/src/{Graphics/TransformStack.hpp → TransformStack.hpp} +24 -25
  91. data/src/Utility.cpp +29 -70
  92. data/src/UtilityApple.cpp +52 -0
  93. data/src/UtilityWin.cpp +7 -4
  94. data/src/Version.cpp +22 -0
  95. data/src/WinMain.cpp +30 -33
  96. data/src/WinUtility.cpp +24 -22
  97. data/src/WinUtility.hpp +11 -20
  98. data/src/Window.cpp +142 -112
  99. data/src/WindowUIKit.cpp +155 -0
  100. data/src/stb_image.h +384 -173
  101. data/src/stb_vorbis.c +20 -18
  102. metadata +60 -62
  103. data/Gosu/TR1.hpp +0 -56
  104. data/src/AppleUtility.hpp +0 -66
  105. data/src/Audio/ALChannelManagement.hpp +0 -114
  106. data/src/Audio/Audio.mm +0 -1
  107. data/src/Audio/AudioFile.hpp +0 -53
  108. data/src/Audio/AudioToolboxFile.hpp +0 -207
  109. data/src/Bitmap/Bitmap.cpp +0 -183
  110. data/src/Bitmap/BitmapIO.cpp +0 -176
  111. data/src/DirectoriesApple.mm +0 -71
  112. data/src/Graphics/BlockAllocator.cpp +0 -142
  113. data/src/Graphics/ClipRectStack.hpp +0 -93
  114. data/src/Graphics/DrawOp.hpp +0 -175
  115. data/src/Graphics/DrawOpQueue.hpp +0 -188
  116. data/src/Graphics/Graphics.cpp +0 -478
  117. data/src/Graphics/Image.cpp +0 -193
  118. data/src/Graphics/LargeImageData.cpp +0 -133
  119. data/src/Graphics/LargeImageData.hpp +0 -46
  120. data/src/Graphics/Macro.hpp +0 -36
  121. data/src/Graphics/RenderState.hpp +0 -211
  122. data/src/Graphics/Resolution.cpp +0 -91
  123. data/src/Graphics/ResolutionApple.mm +0 -19
  124. data/src/Graphics/TexChunk.cpp +0 -112
  125. data/src/Input/Input.cpp +0 -463
  126. data/src/Input/InputUIKit.mm +0 -190
  127. data/src/Input/TextInput.cpp +0 -261
  128. data/src/Text/Font.cpp +0 -175
  129. data/src/Text/Text.cpp +0 -391
  130. data/src/Text/TextApple.mm +0 -227
  131. data/src/Text/TextTTFWin.cpp +0 -249
  132. data/src/Text/TextWin.cpp +0 -186
  133. data/src/UIKit/GosuAppDelegate.mm +0 -24
  134. data/src/UIKit/GosuViewController.mm +0 -211
  135. data/src/UtilityApple.mm +0 -63
  136. 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
@@ -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 ensureCurrentContext()
16
+ void ensure_current_context()
16
17
  {
17
18
  [EAGLContext setCurrentContext:globalContext];
18
19
  }
19
20
 
20
- int clipRectBaseFactor()
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 *_context;
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 *)aDecoder
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 *layer = (CAEAGLLayer *)self.layer;
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 *)self.layer];
112
- glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, _viewRenderbuffer);
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, &_backingWidth);
115
- glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &_backingHeight);
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
@@ -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
+ }