|
Custom Canvas Optimization |
DanielH
Member #934
January 2001
|
Hello all, I'm looking for advice/comments for a canvas class I created. Back story: I was playing a game on my phone and during the game you could zoom in/out and could wrap the viewing portion. I thought about creating a class that could do the same. Here is the result: 1#ifndef dLibraryCanvasHeader
2#define dLibraryCanvasHeader
3
4#include <allegro5/allegro.h>
5
6#define dMin( x, y ) ((x)<(y)?(x):(y))
7#define dMax( x, y ) ((x)>(y)?(x):(y))
8
9namespace dLibrary
10{
11 class dCanvas
12 {
13 public:
14 enum dDistinguishers
15 {
16 dWidth,
17 dHeight,
18 dXPos,
19 dYPos,
20 };
21
22 dCanvas()
23 {
24 this->mDelete = false;
25 this->mZoom = 0.0f;
26 this->mWrap = false;
27 this->mBitmapSize[ dCanvas::dWidth ] = 0;
28 this->mBitmapSize[ dCanvas::dHeight ] = 0;
29 this->mCamera[ dCanvas::dXPos ] = 0;
30 this->mCamera[ dCanvas::dYPos ] = 0;
31 this->mCamera[ dCanvas::dWidth ] = 0;
32 this->mCamera[ dCanvas::dHeight ] = 0;
33 this->mBitmap = 0;
34 this->mDrawBitmap = al_draw_scaled_bitmap;
35 }
36
37 dCanvas( const int width, const int height )
38 {
39 this->mDelete = false;
40 this->mZoom = 0.0f;
41 this->mWrap = false;
42 this->mBitmapSize[ dCanvas::dWidth ] = 0;
43 this->mBitmapSize[ dCanvas::dHeight ] = 0;
44 this->mCamera[ dCanvas::dXPos ] = 0;
45 this->mCamera[ dCanvas::dYPos ] = 0;
46 this->mCamera[ dCanvas::dWidth ] = 0;
47 this->mCamera[ dCanvas::dHeight ] = 0;
48
49 int flags = al_get_new_bitmap_flags();
50
51 al_set_new_bitmap_flags( ALLEGRO_VIDEO_BITMAP | ALLEGRO_MAG_LINEAR | ALLEGRO_MIN_LINEAR );
52
53 this->mBitmap = al_create_bitmap( width, height );
54
55 al_set_new_bitmap_flags( flags );
56
57 this->mDrawBitmap = al_draw_scaled_bitmap;
58
59 if ( this->mBitmap )
60 {
61 this->mBitmapSize[ dCanvas::dWidth ] = width;
62 this->mBitmapSize[ dCanvas::dHeight ] = height;
63 this->mCamera[ dCanvas::dXPos ] = 0;
64 this->mCamera[ dCanvas::dYPos ] = 0;
65 this->mCamera[ dCanvas::dWidth ] = this->mBitmapSize[ dCanvas::dWidth ];
66 this->mCamera[ dCanvas::dHeight ] = this->mBitmapSize[ dCanvas::dHeight ];
67 this->mZoom = 1.0f;
68 this->mDelete = true;
69 }
70 }
71
72 dCanvas( ALLEGRO_BITMAP *bitmap, bool doDelete = false )
73 {
74 this->mDelete = doDelete;
75 this->mZoom = 0.0f;
76 this->mWrap = false;
77 this->mBitmapSize[ dCanvas::dWidth ] = 0;
78 this->mBitmapSize[ dCanvas::dHeight ] = 0;
79 this->mCamera[ dCanvas::dXPos ] = 0;
80 this->mCamera[ dCanvas::dYPos ] = 0;
81 this->mCamera[ dCanvas::dWidth ] = 0;
82 this->mCamera[ dCanvas::dHeight ] = 0;
83 this->mBitmap = bitmap;
84 this->mDrawBitmap = al_draw_scaled_bitmap;
85
86 if ( this->mBitmap )
87 {
88 this->mBitmapSize[ dCanvas::dWidth ] = al_get_bitmap_width( this->mBitmap );
89 this->mBitmapSize[ dCanvas::dHeight ] = al_get_bitmap_height( this->mBitmap );
90 this->mCamera[ dCanvas::dXPos ] = 0;
91 this->mCamera[ dCanvas::dYPos ] = 0;
92 this->mCamera[ dCanvas::dWidth ] = this->mBitmapSize[ dCanvas::dWidth ];
93 this->mCamera[ dCanvas::dHeight ] = this->mBitmapSize[ dCanvas::dHeight ];
94 this->mZoom = 1.0f;
95 this->mDelete = true;
96 }
97 }
98
99 ~dCanvas()
100 {
101 if ( this->mBitmap && this->mDelete )
102 {
103 al_destroy_bitmap( this->mBitmap );
104 }
105 }
106
107 void beginDrawing()
108 {
109 al_set_target_bitmap( this->mBitmap );
110 }
111
112 void flipToDisplay( ALLEGRO_DISPLAY *display )
113 {
114 al_set_target_backbuffer( display );
115
116 int targetBitmapSize[ 2 ] = { al_get_display_width( display ), al_get_display_height( display ) };
117
118 if ( this->mWrap )
119 {
120 if ( this->mCamera[ dCanvas::dXPos ] >= 0 &&
121 this->mCamera[ dCanvas::dXPos ] <= ( this->mBitmapSize[ dCanvas::dWidth ] - this->mCamera[ dCanvas::dWidth ] ) )
122 {
123 if ( this->mCamera[ dCanvas::dYPos ] >= 0 &&
124 this->mCamera[ dCanvas::dYPos ] <= ( this->mBitmapSize[ dCanvas::dHeight ] - this->mCamera[ dCanvas::dHeight ] ) )
125 {
126 this->mDrawBitmap( this->mBitmap,
127 this->mCamera[ dCanvas::dXPos ], this->mCamera[ dCanvas::dYPos ], this->mCamera[ dCanvas::dWidth ], this->mCamera[ dCanvas::dHeight ],
128 0, 0, targetBitmapSize[ dCanvas::dWidth ], targetBitmapSize[ dCanvas::dHeight ],
129 0 );
130 }
131 else
132 {
133 int h1 = this->mBitmapSize[ dCanvas::dHeight ] - this->mCamera[ dCanvas::dYPos ];
134 int h2 = this->mCamera[ dCanvas::dHeight ] - h1;
135 int y2 = ( targetBitmapSize[ dCanvas::dHeight ] * h1 ) / this->mCamera[ dCanvas::dHeight ];
136
137
138 this->mDrawBitmap( this->mBitmap,
139 this->mCamera[ dCanvas::dXPos ], this->mCamera[ dCanvas::dYPos ], this->mCamera[ dCanvas::dWidth ], h1,
140 0, 0, targetBitmapSize[ dCanvas::dWidth ], y2,
141 0 );
142
143 this->mDrawBitmap( this->mBitmap,
144 this->mCamera[ dCanvas::dXPos ], 0, this->mCamera[ dCanvas::dWidth ], h2,
145 0, y2, targetBitmapSize[ dCanvas::dWidth ], targetBitmapSize[ dCanvas::dHeight ] - y2,
146 0 );
147 }
148 }
149 else
150 {
151 if ( this->mCamera[ dCanvas::dYPos ] >= 0 &&
152 this->mCamera[ dCanvas::dYPos ] <= ( this->mBitmapSize[ dCanvas::dHeight ] - this->mCamera[ dCanvas::dHeight ] ) )
153 {
154 int w1 = this->mBitmapSize[ dCanvas::dWidth ] - this->mCamera[ dCanvas::dXPos ];
155 int w2 = this->mCamera[ dCanvas::dWidth ] - w1;
156
157 int x2 = ( targetBitmapSize[ dCanvas::dWidth ] * w1 ) / this->mCamera[ dCanvas::dWidth ];
158
159
160 this->mDrawBitmap( this->mBitmap,
161 this->mCamera[ dCanvas::dXPos ], this->mCamera[ dCanvas::dYPos ], w1, this->mCamera[ dCanvas::dHeight ],
162 0, 0, x2, targetBitmapSize[ dCanvas::dHeight ],
163 0 );
164
165 this->mDrawBitmap( this->mBitmap,
166 0, this->mCamera[ dCanvas::dYPos ], w2, this->mCamera[ dCanvas::dHeight ],
167 x2, 0, targetBitmapSize[ dCanvas::dWidth ] - x2, targetBitmapSize[ dCanvas::dHeight ],
168 0 );
169 }
170 else
171 {
172 int w1 = this->mBitmapSize[ dCanvas::dWidth ] - this->mCamera[ dCanvas::dXPos ];
173 int w2 = this->mCamera[ dCanvas::dWidth ] - w1;
174 int h1 = this->mBitmapSize[ dCanvas::dHeight ] - this->mCamera[ dCanvas::dYPos ];
175 int h2 = this->mCamera[ dCanvas::dHeight ] - h1;
176
177 int y2 = ( targetBitmapSize[ dCanvas::dHeight ] * h1 ) / this->mCamera[ dCanvas::dHeight ];
178 int x2 = ( targetBitmapSize[ dCanvas::dWidth ] * w1 ) / this->mCamera[ dCanvas::dWidth ];
179
180
181 this->mDrawBitmap( this->mBitmap,
182 this->mCamera[ dCanvas::dXPos ], this->mCamera[ dCanvas::dYPos ], w1, h1,
183 0, 0, x2, y2,
184 0 );
185
186 this->mDrawBitmap( this->mBitmap,
187 this->mCamera[ dCanvas::dXPos ], 0, w1, h2,
188 0, y2, x2, targetBitmapSize[ dCanvas::dHeight ] - y2,
189 0 );
190
191 this->mDrawBitmap( this->mBitmap,
192 0, this->mCamera[ dCanvas::dYPos ], w2, h1,
193 x2, 0, targetBitmapSize[ dCanvas::dWidth ] - x2, y2,
194 0 );
195
196 this->mDrawBitmap( this->mBitmap,
197 0, 0, w2, h2,
198 x2, y2, targetBitmapSize[ dCanvas::dWidth ] - x2, targetBitmapSize[ dCanvas::dHeight ] - y2,
199 0 );
200 }
201 }
202 }
203 else
204 {
205 this->mDrawBitmap( this->mBitmap,
206 this->mCamera[ dCanvas::dXPos ], this->mCamera[ dCanvas::dYPos ], this->mCamera[ dCanvas::dWidth ], this->mCamera[ dCanvas::dHeight ],
207 0, 0, targetBitmapSize[ dCanvas::dWidth ], targetBitmapSize[ dCanvas::dHeight ],
208 0 );
209 }
210
211 al_flip_display();
212 }
213
214 ALLEGRO_BITMAP *getBitmap()
215 {
216 return this->mBitmap;
217 }
218
219 void setZoom( float zoom )
220 {
221 this->mZoom = dMax( 1.0f, zoom );
222
223 this->mCamera[ dCanvas::dXPos ] = 0;
224 this->mCamera[ dCanvas::dYPos ] = 0;
225 this->mCamera[ dCanvas::dWidth ] = int( float( this->mBitmapSize[ dCanvas::dWidth ] ) / this->mZoom );
226 this->mCamera[ dCanvas::dHeight ] = int( float( this->mBitmapSize[ dCanvas::dHeight ] ) / this->mZoom );
227 }
228
229 void setWrap( bool wrap )
230 {
231 this->mWrap = wrap;
232 }
233
234 void doScroll( int dx, int dy )
235 {
236 if ( dx != 0 )
237 {
238 this->mCamera[ dCanvas::dXPos ] += dx;
239
240 if ( this->mWrap )
241 {
242 if ( this->mCamera[ dCanvas::dXPos ] < 0 )
243 {
244 this->mCamera[ dCanvas::dXPos ] += this->mBitmapSize[ dCanvas::dWidth ];
245 }
246
247 if ( this->mCamera[ dCanvas::dXPos ] >= this->mBitmapSize[ dCanvas::dWidth ] )
248 {
249 this->mCamera[ dCanvas::dXPos ] -= this->mBitmapSize[ dCanvas::dWidth ];
250 }
251 }
252 else
253 {
254 this->mCamera[ dCanvas::dXPos ] = dMax( 0, dMin( this->mCamera[ dCanvas::dXPos ], this->mBitmapSize[ dCanvas::dWidth ] - this->mCamera[ dCanvas::dWidth ] ) );
255 }
256 }
257
258 if ( dy != 0 )
259 {
260 this->mCamera[ dCanvas::dYPos ] += dy;
261
262 if ( this->mWrap )
263 {
264 if ( this->mCamera[ dCanvas::dYPos ] < 0 )
265 {
266 this->mCamera[ dCanvas::dYPos ] += this->mBitmapSize[ dCanvas::dHeight ];
267 }
268
269 if ( this->mCamera[ dCanvas::dYPos ] >= this->mBitmapSize[ dCanvas::dHeight ] )
270 {
271 this->mCamera[ dCanvas::dYPos ] -= this->mBitmapSize[ dCanvas::dHeight ];
272 }
273 }
274 else
275 {
276 this->mCamera[ dCanvas::dYPos ] = dMax( 0, dMin( this->mCamera[ dCanvas::dYPos ], this->mBitmapSize[ dCanvas::dHeight ] - this->mCamera[ dCanvas::dHeight ] ) );
277 }
278 }
279 }
280
281 void convertMouseCoordinates( ALLEGRO_DISPLAY *display, int &x, int &y )
282 {
283 x = ( x * this->mBitmapSize[ dCanvas::dWidth ] ) / al_get_display_width( display );
284 y = ( y * this->mBitmapSize[ dCanvas::dHeight ] ) / al_get_display_height( display );
285
286 if ( ( this->mZoom - 1.0f ) < 0.0000001f )
287 {
288 x += ( this->mBitmapSize[ dCanvas::dWidth ] - this->mCamera[ dCanvas::dXPos ] );
289 y += ( this->mBitmapSize[ dCanvas::dHeight ] - this->mCamera[ dCanvas::dYPos ] );
290 }
291 else
292 {
293 x = ( int( float( x ) / this->mZoom ) ) + this->mCamera[ dCanvas::dXPos ];
294 y = ( int( float( y ) / this->mZoom ) ) + this->mCamera[ dCanvas::dYPos ];
295 }
296
297 x %= this->mBitmapSize[ dCanvas::dWidth ];
298 y %= this->mBitmapSize[ dCanvas::dHeight ];
299 }
300
301 void setDrawScaledBitmapFunction( void (*drawfunc)( ALLEGRO_BITMAP *bitmap, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh, int flags ) )
302 {
303 this->mDrawBitmap = drawfunc;
304 }
305
306 int getWidth()
307 {
308 return this->mBitmapSize[ dCanvas::dWidth ];
309 }
310
311 int getHeight()
312 {
313 return this->mBitmapSize[ dCanvas::dHeight ];
314 }
315
316 private:
317 ALLEGRO_BITMAP *mBitmap;
318 bool mDelete;
319 int mBitmapSize[ 2 ];
320 int mCamera[ 4 ];
321 float mZoom;
322 bool mWrap;
323 void (*mDrawBitmap)( ALLEGRO_BITMAP *bitmap, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh, int flags );
324 };
325}
326
327#endif
There is also a function to convert mouse display coordinates to corresponding position of canvas. Example: void dGameView::draw( ALLEGRO_DISPLAY *display ) { this->mCanvas->beginDrawing(); // TODO: do all drawing here this->mCanvas->flipToDisplay( display ); } The advice I'm looking for is if there are any optimizations that I could do to speed things up. |
jmasterx
Member #11,410
October 2009
|
Any particular reason you don't use the graphics card to do your transformations? And this for the mouse: http://alleg.sourceforge.net/a5docs/refman/transformations.html#al_transform_coordinates Agui GUI API -> https://github.com/jmasterx/Agui |
DanielH
Member #934
January 2001
|
I was reading this article about resolution independence. It said that "using a stretched buffer" ... "is preferred if your game is using a lot of bitmaps." Still trying to wrap my head about the whole resolution independence idea. |
jmasterx
Member #11,410
October 2009
|
I wonder where that conclusion came from. If you use transformations, everything you draw is sent to the graphics card, then the graphics card multiplies the view matrix by your transformation matrix to figure out where the fragments will be in screen space. Using a stretched buffer I would fear would drive a game closer to being fill limited. Graphics cards have a limit to the number of pixels they can fill. So first you 'fill' your buffer, then you blit that, effectivly doing tripple buffering amd filling a lot more pixels. Agui GUI API -> https://github.com/jmasterx/Agui |
Thomas Fjellstrom
Member #476
June 2000
|
jmasterx said: Using a stretched buffer I would fear would drive a game closer to being fill limited. Graphics cards have a limit to the number of pixels they can fill. So first you 'fill' your buffer, then you blit that, effectivly doing tripple buffering amd filling a lot more pixels. Allegro 5 uses geometry and tex coords to stretch bitmaps to the display or textures (most bitmaps) afaik. So I don't think it's much different than using transforms. -- |
|