7 #define TRECT(x,y,w,h, tw, th) glBegin(GL_TRIANGLE_STRIP);glTexCoord2f(0.0,h/th);glVertex2f(x, y+1*h);glTexCoord2f(0.0,0.0);glVertex2f(x, y);glTexCoord2f(w/tw,h/th);glVertex2f(x+1*w, y+1*h);glTexCoord2f(w/tw,0.0);glVertex2f(x+1*w, y);glEnd();
8 #define RECT(x,y,w,h) glBegin(GL_TRIANGLE_STRIP);glVertex2f(x, y+1*h);glVertex2f(x, y);glVertex2f(x+1*w, y+1*h);glVertex2f(x+1*w, y);glEnd();
11 unsigned int occupied
=0;
15 unsigned int allocated
;
18 SurfaceList gsprite_surfaces
;
19 int AddSurface(GLuint s
);
20 void RemoveSurface(GLuint s
);
21 void RemoveSID(int SID
);
22 void FlushSpriteSurfaces();
23 int SetVideoMode(int width
, int height
);
28 unsigned int allocated
;
32 int AddSprite(Sprite
*s
);
33 void RemoveSprite(Sprite
*s
);
43 SpriteQueueItem
*items
;
44 unsigned int allocated
;
47 SpriteQueue gsprite_queue
;
48 SpriteQueue gsprite_queue_sorted
;
49 void FlushSpriteQueue();
50 void RotateSurface(int SID
, int rotation
);
54 GLuint
load_svg (char *file
, int width
, int height
, double *pdw
, double *pdh
);
60 return (x
/(double)SCREEN_WIDTH
)*GetConfig().screen_width
;
63 return (y
/(double)SCREEN_HEIGHT
)*GetConfig().screen_height
;
66 int SetVideoMode(int width
, int height
){
73 Config config
=GetConfig();
75 SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER
, 1 );
78 flags
= flags
|SDL_FULLSCREEN
;
79 /* Get available fullscreen/hardware modes */
80 modes
=SDL_ListModes(NULL
, flags
);
82 /* Check if there are any modes available */
83 if(modes
== (SDL_Rect
**)0){
84 printf("No modes available!\n");
88 /* Check if our resolution is restricted */
89 if(modes
== (SDL_Rect
**)-1){
90 printf("All resolutions available.\n");
91 gscreen
= SDL_SetVideoMode(config
.screen_width
, config
.screen_height
, 0, flags
);
94 /* Print valid modes */
95 printf("Available Modes\n");
96 bestdif
= abs((modes
[0]->w
- config
.screen_width
) + (modes
[0]->h
- config
.screen_height
));
98 for(i
=0;modes
[i
];++i
){
99 printf(" %d x %d\n", modes
[i
]->w
, modes
[i
]->h
);
100 if(bestdif
> abs((modes
[i
]->w
- config
.screen_width
) + (modes
[i
]->h
- config
.screen_height
))){
101 bestdif
= abs((modes
[i
]->w
- config
.screen_width
) + (modes
[i
]->h
- config
.screen_height
));
105 printf("Using: %d x %d\n", modes
[ibest
]->w
, modes
[ibest
]->h
);
106 gscreen
= SDL_SetVideoMode(modes
[ibest
]->w
, modes
[ibest
]->h
, 0, flags
);
107 config
.screen_height
= modes
[ibest
]->h
;
108 config
.screen_width
= modes
[ibest
]->w
;
113 int AddSurface(GLuint s
){ //returns -1 on error, SID if success
116 for(i
=0;i
<gsprite_surfaces
.allocated
;i
++)
117 if( gsprite_surfaces
.surfaces
[i
]==s
){
121 for(i
=0;i
<gsprite_surfaces
.allocated
;i
++)
122 if( gsprite_surfaces
.surfaces
[i
]==0 ){
123 gsprite_surfaces
.surfaces
[i
]=s
;
126 i
=gsprite_surfaces
.allocated
;
127 tmp
= (GLuint
*) realloc(gsprite_surfaces
.surfaces
, sizeof(GLuint
)*i
*2); //if the allocated space is not wide enough, then allocate double space than previous
130 gsprite_surfaces
.surfaces
=tmp
;
131 memset(&gsprite_surfaces
.surfaces
[i
],0, sizeof(GLuint
)*i
); //zero newly allocated space
132 gsprite_surfaces
.allocated
=i
*2;
133 gsprite_surfaces
.surfaces
[i
]=s
;
137 void RemoveSurface(GLuint s
){
138 int i
,iwannakillyoubitch
;
140 iwannakillyoubitch
=1;
141 for(i
=0;i
<gsprite_surfaces
.allocated
;i
++){
142 if( gsprite_surfaces
.surfaces
[i
]==s
){
143 gsprite_surfaces
.surfaces
[i
]=0;
145 if( i
>=gsprite_surfaces
.allocated
/2 && iwannakillyoubitch
&& gsprite_surfaces
.surfaces
[i
]!=0 )
146 iwannakillyoubitch
=0;
149 if(iwannakillyoubitch
){
150 gsprite_surfaces
.allocated
/=2;
151 gsprite_surfaces
.surfaces
= (GLuint
*)realloc(gsprite_surfaces
.surfaces
, sizeof(GLuint
)*gsprite_surfaces
.allocated
);//TODO:check return value
155 void RemoveSID(int SID
){
156 int i
,iwannakillyoubitch
;
158 iwannakillyoubitch
=1;
159 for(i
=0;i
<gsprite_surfaces
.allocated
;i
++){
161 gsprite_surfaces
.surfaces
[i
]=0;
163 if( i
>=gsprite_surfaces
.allocated
/2 && iwannakillyoubitch
&& gsprite_surfaces
.surfaces
[i
]!=0 )
164 iwannakillyoubitch
=0;
167 if(iwannakillyoubitch
){
168 gsprite_surfaces
.allocated
/=2;
169 gsprite_surfaces
.surfaces
= (GLuint
*)realloc(gsprite_surfaces
.surfaces
, sizeof(GLuint
)*gsprite_surfaces
.allocated
);//TODO:check return value
173 int AddSprite(Sprite
*s
){//returns 0 on error, Sprite ID on success
176 for(i
=0;i
<gsprites
.allocated
;i
++)
177 if( gsprites
.sprites
[i
]==s
){
181 for(i
=0;i
<gsprites
.allocated
;i
++)
182 if( gsprites
.sprites
[i
]==0 ){
183 gsprites
.sprites
[i
]=s
;
186 i
=gsprites
.allocated
;
187 tmp
=(Sprite
**)realloc(gsprites
.sprites
, sizeof(Sprite
*)*i
*2); //if the allocated space is not wide enough, then allocate double space than previous
190 gsprites
.sprites
=tmp
;
191 memset(&gsprites
.sprites
[i
],0, sizeof(Sprite
*)*i
); //zero newly allocated space
192 gsprites
.allocated
=i
*2;
193 gsprites
.sprites
[i
]=s
;
197 void RemoveSprite(Sprite
*s
){
198 int i
,iwannakillyoubitch
;
200 iwannakillyoubitch
=1;
201 for(i
=0;i
<gsprites
.allocated
;i
++){
202 if( gsprites
.sprites
[i
]==s
){
203 gsprites
.sprites
[i
]=0;
205 if( i
>=gsprites
.allocated
/2 && iwannakillyoubitch
&& gsprites
.sprites
[i
]!=0 )
206 iwannakillyoubitch
=0;
209 if(iwannakillyoubitch
){
210 gsprites
.allocated
/=2;
211 gsprites
.sprites
= (Sprite
**) realloc(gsprites
.sprites
, sizeof(Sprite
*)*gsprites
.allocated
);//TODO:check return value
220 FlushSpriteSurfaces();
223 free(gsprite_surfaces
.surfaces
);
224 gsprite_surfaces
.surfaces
=0;
227 for(i
=0; i
<gsprites
.allocated
; i
++)
228 if(gsprites
.sprites
[i
]){
229 free(gsprites
.sprites
[i
]->fname
);
230 free(gsprites
.sprites
[i
]);
231 gsprites
.sprites
[i
]=0;
234 gsprites
.allocated
= 0;
237 SetVideoMode(config
.screen_width
, config
.screen_height
);
246 gsprite_surfaces
.surfaces
= (GLuint
*) calloc(2, sizeof(GLuint
));
247 if( gsprite_surfaces
.surfaces
== 0 )
250 gsprite_surfaces
.allocated
= 2;
251 memset(gsprite_surfaces
.surfaces
, 0, gsprite_surfaces
.allocated
* sizeof(GLuint
));
253 gsprites
.sprites
= (Sprite
**) calloc(2,sizeof(Sprite
*));
254 if( gsprites
.sprites
== 0 )
256 memset(gsprites
.sprites
, 0, gsprites
.allocated
* sizeof(Sprite
*));
257 gsprites
.allocated
= 2;
260 gsprite_queue
.allocated
=2;
261 gsprite_queue
.items
=(SpriteQueueItem
*) malloc(sizeof(SpriteQueueItem
)*2);
262 gsprite_queue
.next_id
=0;
264 SetVideoMode(config
.screen_width
, config
.screen_height
);
266 glClearColor(0.0f
, 0.0f
, 0.0f
, 0.5f
);
268 glDisable(GL_DEPTH_TEST
);
269 //glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
271 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
272 //glEnable(GL_ALPHA_TEST);
273 //glAlphaFunc(GL_GREATER, 0);
274 SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL
, 1);
276 glViewport(0, 0, config
.screen_width
, config
.screen_height
);
277 glMatrixMode(GL_PROJECTION
);
280 glOrtho(0.0f
,config
.screen_width
, config
.screen_height
,0.0f
,-1.0f
,1.0f
);
282 glMatrixMode(GL_MODELVIEW
);
288 void FlushSpriteSurfaces(){
291 for(i
=0;i
<gsprite_surfaces
.allocated
;i
++){
292 if(gsprite_surfaces
.surfaces
[i
]){
293 glDeleteTextures(1, &gsprite_surfaces
.surfaces
[i
]);
294 gsprite_surfaces
.surfaces
[i
]=0;
300 int RegenerateSprites(){
310 FlushSpriteSurfaces();
312 SetVideoMode(config
.screen_width
, config
.screen_height
);
315 for(i
=0;i
<gsprites
.allocated
;i
++)
316 if(gsprites
.sprites
[i
]){
317 tmpsprite
=gsprites
.sprites
[i
];
318 xx
= (tmpsprite
->width
/SCREEN_WIDTH
)*config
.screen_width
;
319 yy
= (tmpsprite
->height
/SCREEN_HEIGHT
)*config
.screen_height
;
321 tmpsurface
=load_svg(tmpsprite
->fname
, xx
, yy
, &tmpsprite
->twidth
, &tmpsprite
->theight
);
323 SID
=AddSurface(tmpsurface
);
327 RotateSurface(SID
,tmpsprite
->rotation
);
334 void InvalidateSprites(){
339 void FlushSpriteQueue(){
342 for(i
=0;i
<gsprite_queue
.allocated
;i
++){
343 gsprite_queue
.items
[i
].sprite
= 0;
345 if(gsprite_queue
.next_id
< gsprite_queue
.allocated
/2){
346 //TODO:dopsat zmenseni fronty
348 gsprite_queue
.next_id
= 0;
351 void SwapSpriteQueueItems(int aid
, int bid
){
353 c
.sprite
= gsprite_queue_sorted
.items
[aid
].sprite
;
354 c
.x
= gsprite_queue_sorted
.items
[aid
].x
;
355 c
.y
= gsprite_queue_sorted
.items
[aid
].y
;
356 c
.z
= gsprite_queue_sorted
.items
[aid
].z
;
358 gsprite_queue_sorted
.items
[aid
].sprite
= gsprite_queue_sorted
.items
[bid
].sprite
;
359 gsprite_queue_sorted
.items
[aid
].x
= gsprite_queue_sorted
.items
[bid
].x
;
360 gsprite_queue_sorted
.items
[aid
].y
= gsprite_queue_sorted
.items
[bid
].y
;
361 gsprite_queue_sorted
.items
[aid
].z
= gsprite_queue_sorted
.items
[bid
].z
;
363 gsprite_queue_sorted
.items
[bid
].sprite
= c
.sprite
;
364 gsprite_queue_sorted
.items
[bid
].x
= c
.x
;
365 gsprite_queue_sorted
.items
[bid
].y
= c
.y
;
366 gsprite_queue_sorted
.items
[bid
].z
= c
.z
;
369 void YSortSpriteQueue(int from
, int to
){
373 //TODO:validity check
376 for(i
= from
; i
< to
; i
++){
377 y1
= gsprite_queue_sorted
.items
[i
].sprite
->height
* 0.5 + gsprite_queue_sorted
.items
[i
].y
;
378 y2
= gsprite_queue_sorted
.items
[i
+1].sprite
->height
* 0.5 + gsprite_queue_sorted
.items
[i
+1].y
;
381 SwapSpriteQueueItems(i
+1, i
);
387 void ZSortSpriteQueue(){
388 int minz
, lastminz
, found
;
390 int ysortfrom
, ysortto
;
395 gsprite_queue_sorted
.next_id
= 0;
399 //we seek for smallest z bigger than z in last iteration
400 for(i
=0; i
<gsprite_queue
.next_id
; i
++){
401 if( gsprite_queue
.items
[i
].z
< minz
&& gsprite_queue
.items
[i
].z
> lastminz
){
403 minz
= gsprite_queue
.items
[i
].z
;
408 //now we copy all items on z==minz
409 ysortfrom
= gsprite_queue_sorted
.next_id
;
410 for(i
=0; i
< gsprite_queue
.next_id
; i
++){
411 if(gsprite_queue
.items
[i
].z
== minz
){
412 memcpy(&gsprite_queue_sorted
.items
[gsprite_queue_sorted
.next_id
], &gsprite_queue
.items
[i
], sizeof(SpriteQueueItem
));
413 ysortto
= gsprite_queue_sorted
.next_id
;
414 gsprite_queue_sorted
.next_id
++;
417 YSortSpriteQueue(ysortfrom
, ysortto
);
435 gsprite_queue_sorted
.allocated
= gsprite_queue
.allocated
;
436 gsprite_queue_sorted
.next_id
= 0;
437 gsprite_queue_sorted
.items
= malloc(sizeof(SpriteQueueItem
)* gsprite_queue_sorted
.allocated
);
440 for(i
=0;i
<gsprite_queue_sorted
.next_id
;i
++)
441 if(gsprite_queue_sorted
.items
[i
].sprite
){
442 dspr
= gsprite_queue_sorted
.items
[i
].sprite
;
443 ds
= gsprite_surfaces
.surfaces
[dspr
->SID
];
444 dest
.x
= G2SX(gsprite_queue_sorted
.items
[i
].x
);
445 dest
.y
= G2SY(gsprite_queue_sorted
.items
[i
].y
);
446 dest
.w
= G2SX(gsprite_queue_sorted
.items
[i
].sprite
->width
);
447 dest
.h
= G2SX(gsprite_queue_sorted
.items
[i
].sprite
->height
);
450 src
.w
= G2SX(gsprite_queue_sorted
.items
[i
].sprite
->width
);
451 src
.h
= G2SX(gsprite_queue_sorted
.items
[i
].sprite
->height
);
452 glBindTexture(GL_TEXTURE_2D
, ds
);
453 glEnable(GL_TEXTURE_2D
);
454 TRECT(dest
.x
, dest
.y
, dest
.w
, dest
.h
, dspr
->twidth
, dspr
->theight
);
455 glDisable(GL_TEXTURE_2D
);
458 gsprite_queue_sorted
.allocated
= 0;
459 gsprite_queue_sorted
.next_id
= 0;
460 free(gsprite_queue_sorted
.items
);
461 gsprite_queue_sorted
.items
= 0;
464 SDL_GL_SwapBuffers();
470 //SDL_FillRect(gscreen, 0, 0x0);
473 Sprite
* LoadSpriteSVG(char *fname
, double width
, double height
){
477 Config conf
=GetConfig();
479 xx
= width
*(double)conf
.screen_width
/SCREEN_WIDTH
;
480 yy
= height
*(double)conf
.screen_height
/SCREEN_HEIGHT
;
483 sprite
= (Sprite
*)malloc(sizeof(Sprite
));
484 surface
= load_svg(fname
, xx
, yy
, &sprite
->twidth
, &sprite
->theight
);
485 sprite
->fname
= malloc(sizeof(char)*(strlen(fname
)+2));
486 strcpy(sprite
->fname
, fname
);
487 sprite
->width
= width
;
488 sprite
->height
= height
;
489 sprite
->rotation
= 0;
490 sprite
->SID
= AddSurface(surface
);
495 void DestroySprite(Sprite
*sprite
){
498 RemoveSprite(sprite
);
501 glDeleteTextures(1, &gsprite_surfaces
.surfaces
[sprite
->SID
]);
502 RemoveSID(sprite
->SID
);
506 Sprite
* CopySprite(Sprite
*old
){
507 printf("CopySprite not Implemented\n");
513 void RotateSurface(int SID
, int rotation
){
517 fprintf(stderr
, "Rotation of sprites not implemented :(\n");
520 void RotateClockwise(Sprite
*sprite
){
521 RotateSurface(sprite
->SID
,1);
525 void QueueDrawSprite(Sprite
*sprite
, double x
, double y
, int z
){
526 SpriteQueueItem
*item
;
528 printf("NULL sprite*\n");
531 if(gsprite_queue
.next_id
>=gsprite_queue
.allocated
){
532 item
= (SpriteQueueItem
*) realloc(gsprite_queue
.items
, sizeof(SpriteQueueItem
)*gsprite_queue
.allocated
*2);
534 fprintf(stderr
, "Can't allocate enough memory for sprite queue\n");
537 gsprite_queue
.allocated
*= 2;
538 gsprite_queue
.items
= item
;
541 item
= &gsprite_queue
.items
[gsprite_queue
.next_id
];
542 item
->sprite
= sprite
;
547 gsprite_queue
.next_id
++;
551 unsigned int closestpoweroftwo(unsigned int i
){
562 //load_svg borrowed from cairo demo
565 #include <sys/types.h>
568 #include <svg-cairo.h>
570 /* load_svg: This is what you're probably interested in!
571 * -----------------------------------------------------
572 * If width and height are greater than 0, the image will
573 * be scaled to that size. wscale and hscale would be ignored.
575 * If width and height are less than 1, wscale and hscale will
576 * resize the width and the height to the specified scales.
578 * If width and height are less than 1, and wscale and hscale
579 * are either 0 or 1, then the image will be loaded at it's
582 * See main() for examples.
584 GLuint
load_svg (char *file
, int width
, int height
, double *pdw
, double *pdh
) {
589 unsigned int rheight
;
590 unsigned int pw
,ph
; //power of two dimensions
591 double wscale
,hscale
;
592 Config config
=GetConfig();
594 // Create the SVG cairo stuff.
595 svg_cairo_create(&scr
);
596 svg_cairo_parse (scr
, file
);
598 svg_cairo_get_size (scr
, &rwidth
, &rheight
);
599 *pdw
= closestpoweroftwo(width
);
600 *pdh
= closestpoweroftwo(height
);
601 width
= width
>>config
.texture_lod
;
602 height
= height
>>config
.texture_lod
;
604 /*Calculate final width and height of our surface based on the parameters passed */
606 wscale
=(float)width
/(float)rwidth
;
608 width
=(int)(rwidth
*wscale
);
611 hscale
=(float)height
/(float)rheight
;
613 height
=(int)(rheight
*hscale
);
623 /* We will create a CAIRO_FORMAT_ARGB32 surface. We don't need to match
624 the screen SDL format, but we are interested in the alpha bit */
625 bpp
=32; /*bits per pixel*/
626 btpp
=4; /*bytes per pixel*/
629 int stride
=width
* btpp
;
631 /* Allocate an image */
632 unsigned char *image
=calloc(stride
*height
, 1);
634 /* Create the cairo surface with the adjusted width and height */
635 cairo_surface_t
*cairo_surface
;
636 cairo_surface
= cairo_image_surface_create_for_data (image
,
638 width
, height
, stride
);
640 cairo_t
*cr
=cairo_create(cairo_surface
);
641 cairo_scale (cr
, wscale
, hscale
);
643 /* Render SVG to our surface */
644 svg_cairo_render (scr
, cr
);
647 cairo_surface_destroy (cairo_surface
);
650 /*Destroy the svg_cairo structure */
651 svg_cairo_destroy (scr
);
653 /*Adjust the SDL surface mask to ARGB, matching the cairo surface created.*/
654 Uint32 rmask
, gmask
, bmask
, amask
;
661 /* Create the SDL surface using the pixel data stored. It will automatically be set to use alpha using these mask values */
662 SDL_Surface
*sdl_surface
=SDL_CreateRGBSurfaceFrom( (void *) image
, width
, height
, bpp
, stride
, rmask
, gmask
, bmask
, amask
);
663 SDL_SetAlpha(sdl_surface
, 0, 255);
668 pw
= closestpoweroftwo(width
);
669 ph
= closestpoweroftwo(height
);
670 SDL_Surface
*sdl_rgba_surface
=SDL_CreateRGBSurface( SDL_SWSURFACE
, pw
, ph
, bpp
, rmask
, gmask
, bmask
, amask
);
671 SDL_BlitSurface(sdl_surface
, 0, sdl_rgba_surface
, 0);
672 SDL_FreeSurface(sdl_surface
);
675 SDL_LockSurface(sdl_rgba_surface
);
678 glGenTextures(1, &tid
);
679 glBindTexture(GL_TEXTURE_2D
, tid
);
680 glTexParameteri(GL_TEXTURE_2D
,GL_TEXTURE_MAG_FILTER
,GL_LINEAR
); // scale linearly when image bigger than texture
681 glTexParameteri(GL_TEXTURE_2D
,GL_TEXTURE_MIN_FILTER
,GL_LINEAR
); // scale linearly when image smalled than texture
682 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, pw
, ph
, 0, GL_RGBA
, GL_UNSIGNED_BYTE
, sdl_rgba_surface
->pixels
);
683 SDL_UnlockSurface(sdl_rgba_surface
);
684 SDL_FreeSurface(sdl_rgba_surface
);
686 printf("Occupied: %u\n", occupied
);