9 #include <librsvg/rsvg.h>
10 #include <librsvg/rsvg-cairo.h>
14 #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();
15 #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();
17 #define TTRECT(x,y,w,h,sw,sh, tw, th) glBegin(GL_TRIANGLE_STRIP);glTexCoord2f(0.0,sh/th);glVertex2f(x, y+1*h);glTexCoord2f(0.0,0.0);glVertex2f(x, y);glTexCoord2f(sw/tw,sh/th);glVertex2f(x+1*w, y+1*h);glTexCoord2f(sw/tw,0.0);glVertex2f(x+1*w, y);glEnd();
19 unsigned int occupied
=0;
23 unsigned int allocated
;
26 SurfaceList gsprite_surfaces
;
27 int AddSurface(GLuint s
);
28 void RemoveSurface(GLuint s
);
29 void RemoveSID(int SID
);
30 void FlushSpriteSurfaces();
31 int SetVideoMode(int width
, int height
);
36 unsigned int allocated
;
40 int AddSprite(Sprite
*s
);
41 void RemoveSprite(Sprite
*s
);
54 SpriteQueueItem
*items
;
55 unsigned int allocated
;
58 SpriteQueue gsprite_queue
;
59 SpriteQueue gsprite_queue_sorted
;
60 void FlushSpriteQueue();
61 void RotateSurface(int SID
, int rotation
);
65 GLuint
load_svg (char *file
, int width
, int height
, double *pdw
, double *pdh
);
71 return (x
/(double)SCREEN_WIDTH
)*GetConfig().screen_width
;
74 return (y
/(double)SCREEN_HEIGHT
)*GetConfig().screen_height
;
77 return (x
*(double)SCREEN_WIDTH
)/(double)GetConfig().screen_width
;
80 return (y
*(double)SCREEN_HEIGHT
)/(double)GetConfig().screen_height
;
83 int SetVideoMode(int width
, int height
){
90 Config config
=GetConfig();
92 SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER
, 1 );
95 flags
= flags
|SDL_FULLSCREEN
;
96 /* Get available fullscreen/hardware modes */
97 modes
=SDL_ListModes(NULL
, flags
);
99 /* Check if there are any modes available */
100 if(modes
== (SDL_Rect
**)0){
101 printf("No modes available!\n");
105 /* Check if our resolution is restricted */
106 if(modes
== (SDL_Rect
**)-1){
107 printf("All resolutions available.\n");
108 gscreen
= SDL_SetVideoMode(config
.screen_width
, config
.screen_height
, 0, flags
);
111 /* Print valid modes */
112 printf("Available Modes\n");
113 bestdif
= abs((modes
[0]->w
- config
.screen_width
) + (modes
[0]->h
- config
.screen_height
));
115 for(i
=0;modes
[i
];++i
){
116 printf(" %d x %d\n", modes
[i
]->w
, modes
[i
]->h
);
117 if(bestdif
> abs((modes
[i
]->w
- config
.screen_width
) + (modes
[i
]->h
- config
.screen_height
))){
118 bestdif
= abs((modes
[i
]->w
- config
.screen_width
) + (modes
[i
]->h
- config
.screen_height
));
122 printf("Using: %d x %d\n", modes
[ibest
]->w
, modes
[ibest
]->h
);
123 gscreen
= SDL_SetVideoMode(modes
[ibest
]->w
, modes
[ibest
]->h
, 0, flags
);
124 config
.screen_height
= modes
[ibest
]->h
;
125 config
.screen_width
= modes
[ibest
]->w
;
131 int AddSurface(GLuint s
){ //returns -1 on error, SID if success
134 for(i
=0;i
<gsprite_surfaces
.allocated
;i
++)
135 if( gsprite_surfaces
.surfaces
[i
]==s
){
139 for(i
=0;i
<gsprite_surfaces
.allocated
;i
++)
140 if( gsprite_surfaces
.surfaces
[i
]==0 ){
141 gsprite_surfaces
.surfaces
[i
]=s
;
144 i
=gsprite_surfaces
.allocated
;
145 tmp
= (GLuint
*) realloc(gsprite_surfaces
.surfaces
, sizeof(GLuint
)*i
*2); //if the allocated space is not wide enough, then allocate double space than previous
148 gsprite_surfaces
.surfaces
=tmp
;
149 memset(&gsprite_surfaces
.surfaces
[i
],0, sizeof(GLuint
)*i
); //zero newly allocated space
150 gsprite_surfaces
.allocated
=i
*2;
151 gsprite_surfaces
.surfaces
[i
]=s
;
155 void RemoveSurface(GLuint s
){
156 int i
,iwannakillyoubitch
;
158 iwannakillyoubitch
=1;
159 for(i
=0;i
<gsprite_surfaces
.allocated
;i
++){
160 if( gsprite_surfaces
.surfaces
[i
]==s
){
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 void RemoveSID(int SID
){
174 int i
,iwannakillyoubitch
;
176 iwannakillyoubitch
=1;
177 for(i
=0;i
<gsprite_surfaces
.allocated
;i
++){
179 gsprite_surfaces
.surfaces
[i
]=0;
181 if( i
>=gsprite_surfaces
.allocated
/2 && iwannakillyoubitch
&& gsprite_surfaces
.surfaces
[i
]!=0 )
182 iwannakillyoubitch
=0;
185 if(iwannakillyoubitch
){
186 gsprite_surfaces
.allocated
/=2;
187 gsprite_surfaces
.surfaces
= (GLuint
*)realloc(gsprite_surfaces
.surfaces
, sizeof(GLuint
)*gsprite_surfaces
.allocated
);//TODO:check return value
191 int AddSprite(Sprite
*s
){//returns 0 on error, Sprite ID on success
194 for(i
=0;i
<gsprites
.allocated
;i
++)
195 if( gsprites
.sprites
[i
]==s
){
199 for(i
=0;i
<gsprites
.allocated
;i
++)
200 if( gsprites
.sprites
[i
]==0 ){
201 gsprites
.sprites
[i
]=s
;
204 i
=gsprites
.allocated
;
205 tmp
=(Sprite
**)realloc(gsprites
.sprites
, sizeof(Sprite
*)*i
*2); //if the allocated space is not wide enough, then allocate double space than previous
208 gsprites
.sprites
=tmp
;
209 memset(&gsprites
.sprites
[i
],0, sizeof(Sprite
*)*i
); //zero newly allocated space
210 gsprites
.allocated
=i
*2;
211 gsprites
.sprites
[i
]=s
;
215 void RemoveSprite(Sprite
*s
){
216 int i
,iwannakillyoubitch
;
218 iwannakillyoubitch
=1;
219 for(i
=0;i
<gsprites
.allocated
;i
++){
220 if( gsprites
.sprites
[i
]==s
){
221 gsprites
.sprites
[i
]=0;
223 if( i
>=gsprites
.allocated
/2 && iwannakillyoubitch
&& gsprites
.sprites
[i
]!=0 )
224 iwannakillyoubitch
=0;
227 if(iwannakillyoubitch
){
228 gsprites
.allocated
/=2;
229 gsprites
.sprites
= (Sprite
**) realloc(gsprites
.sprites
, sizeof(Sprite
*)*gsprites
.allocated
);//TODO:check return value
238 FlushSpriteSurfaces();
241 free(gsprite_surfaces
.surfaces
);
242 gsprite_surfaces
.surfaces
=0;
245 for(i
=0; i
<gsprites
.allocated
; i
++)
246 if(gsprites
.sprites
[i
]){
247 free(gsprites
.sprites
[i
]->fname
);
248 free(gsprites
.sprites
[i
]);
249 gsprites
.sprites
[i
]=0;
252 gsprites
.allocated
= 0;
256 SetVideoMode(config
.screen_width
, config
.screen_height
);
266 gsprite_surfaces
.surfaces
= (GLuint
*) calloc(2, sizeof(GLuint
));
267 if( gsprite_surfaces
.surfaces
== 0 )
270 gsprite_surfaces
.allocated
= 2;
271 memset(gsprite_surfaces
.surfaces
, 0, gsprite_surfaces
.allocated
* sizeof(GLuint
));
273 gsprites
.sprites
= (Sprite
**) calloc(2,sizeof(Sprite
*));
274 if( gsprites
.sprites
== 0 )
276 memset(gsprites
.sprites
, 0, gsprites
.allocated
* sizeof(Sprite
*));
277 gsprites
.allocated
= 2;
280 gsprite_queue
.allocated
=2;
281 gsprite_queue
.items
=(SpriteQueueItem
*) malloc(sizeof(SpriteQueueItem
)*2);
282 gsprite_queue
.next_id
=0;
284 SetVideoMode(config
.screen_width
, config
.screen_height
);
286 glClearColor(0.0f
, 0.0f
, 0.0f
, 0.5f
);
288 glDisable(GL_DEPTH_TEST
);
289 //glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
291 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
292 //glEnable(GL_ALPHA_TEST);
293 //glAlphaFunc(GL_GREATER, 0);
294 SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL
, 1);
296 glViewport(0, 0, config
.screen_width
, config
.screen_height
);
297 glMatrixMode(GL_PROJECTION
);
300 glOrtho(0.0f
,config
.screen_width
, config
.screen_height
,0.0f
,-1.0f
,1.0f
);
302 glMatrixMode(GL_MODELVIEW
);
308 void FlushSpriteSurfaces(){
311 for(i
=0;i
<gsprite_surfaces
.allocated
;i
++){
312 if(gsprite_surfaces
.surfaces
[i
]){
313 glDeleteTextures(1, &gsprite_surfaces
.surfaces
[i
]);
314 gsprite_surfaces
.surfaces
[i
]=0;
320 int RegenerateSprites(){
330 FlushSpriteSurfaces();
332 SetVideoMode(config
.screen_width
, config
.screen_height
);
335 for(i
=0;i
<gsprites
.allocated
;i
++)
336 if(gsprites
.sprites
[i
]){
337 tmpsprite
=gsprites
.sprites
[i
];
338 xx
= (tmpsprite
->width
/SCREEN_WIDTH
)*config
.screen_width
;
339 yy
= (tmpsprite
->height
/SCREEN_HEIGHT
)*config
.screen_height
;
341 tmpsurface
=load_svg(tmpsprite
->fname
, xx
, yy
, &tmpsprite
->twidth
, &tmpsprite
->theight
);
343 SID
=AddSurface(tmpsurface
);
347 RotateSurface(SID
,tmpsprite
->rotation
);
355 void InvalidateSprites(){
360 void FlushSpriteQueue(){
363 for(i
=0;i
<gsprite_queue
.allocated
;i
++){
364 gsprite_queue
.items
[i
].sprite
= 0;
366 if(gsprite_queue
.next_id
< gsprite_queue
.allocated
/2){
367 //TODO:dopsat zmenseni fronty
369 gsprite_queue
.next_id
= 0;
372 void SwapSpriteQueueItems(int aid
, int bid
){
374 memcpy(&c
, &gsprite_queue_sorted
.items
[aid
], sizeof(SpriteQueueItem
));
375 memcpy(&gsprite_queue_sorted
.items
[aid
], &gsprite_queue_sorted
.items
[bid
], sizeof(SpriteQueueItem
));
376 memcpy(&gsprite_queue_sorted
.items
[bid
], &c
, sizeof(SpriteQueueItem
));
379 void YSortSpriteQueue(int from
, int to
){
383 //TODO:validity check
386 for(i
= from
; i
< to
; i
++){
387 y1
= gsprite_queue_sorted
.items
[i
].sprite
->height
* 0.5 + gsprite_queue_sorted
.items
[i
].y
;
388 y2
= gsprite_queue_sorted
.items
[i
+1].sprite
->height
* 0.5 + gsprite_queue_sorted
.items
[i
+1].y
;
391 SwapSpriteQueueItems(i
+1, i
);
397 void ZSortSpriteQueue(){
398 int minz
, lastminz
, found
;
400 int ysortfrom
, ysortto
;
405 gsprite_queue_sorted
.next_id
= 0;
409 //we seek for smallest z bigger than z in last iteration
410 for(i
=0; i
<gsprite_queue
.next_id
; i
++){
411 if( gsprite_queue
.items
[i
].z
< minz
&& gsprite_queue
.items
[i
].z
> lastminz
){
413 minz
= gsprite_queue
.items
[i
].z
;
418 //now we copy all items on z==minz
419 ysortfrom
= gsprite_queue_sorted
.next_id
;
420 for(i
=0; i
< gsprite_queue
.next_id
; i
++){
421 if(gsprite_queue
.items
[i
].z
== minz
){
422 memcpy(&gsprite_queue_sorted
.items
[gsprite_queue_sorted
.next_id
], &gsprite_queue
.items
[i
], sizeof(SpriteQueueItem
));
423 ysortto
= gsprite_queue_sorted
.next_id
;
424 gsprite_queue_sorted
.next_id
++;
427 YSortSpriteQueue(ysortfrom
, ysortto
);
439 int LastLayer
, LayerI
;
446 gsprite_queue_sorted
.allocated
= gsprite_queue
.allocated
;
447 gsprite_queue_sorted
.next_id
= 0;
448 gsprite_queue_sorted
.items
= malloc(sizeof(SpriteQueueItem
)* gsprite_queue_sorted
.allocated
);
452 // select modulate to mix texture with color for shading
453 glTexEnvf( GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
454 glEnable(GL_TEXTURE_2D
);
457 for(i
=0;i
<gsprite_queue_sorted
.next_id
;i
++)
458 if (gsprite_queue_sorted
.items
[i
].sprite
){
459 for (LayerI
= LastLayer
; LayerI
< gsprite_queue_sorted
.items
[i
].z
; LayerI
++) {
460 glDisable(GL_TEXTURE_2D
);
461 DrawTextsOnLayer(LayerI
);
462 glEnable(GL_TEXTURE_2D
);
464 dspr
= gsprite_queue_sorted
.items
[i
].sprite
;
465 ds
= gsprite_surfaces
.surfaces
[dspr
->SID
];
466 dest
.x
= G2SX(gsprite_queue_sorted
.items
[i
].x
);
467 dest
.y
= G2SY(gsprite_queue_sorted
.items
[i
].y
);
468 dest
.w
= G2SX(gsprite_queue_sorted
.items
[i
].xx
);
469 dest
.h
= G2SX(gsprite_queue_sorted
.items
[i
].yy
);
472 src
.w
= G2SX(gsprite_queue_sorted
.items
[i
].sprite
->width
);
473 src
.h
= G2SX(gsprite_queue_sorted
.items
[i
].sprite
->height
);
476 glBindTexture(GL_TEXTURE_2D
, ds
);
477 glColor4ub(gsprite_queue_sorted
.items
[i
].c
.r
, gsprite_queue_sorted
.items
[i
].c
.g
, gsprite_queue_sorted
.items
[i
].c
.b
, gsprite_queue_sorted
.items
[i
].c
.unused
);
478 TTRECT(dest
.x
, dest
.y
, dest
.w
, dest
.h
, src
.w
, src
.h
, dspr
->twidth
, dspr
->theight
);
481 glDisable(GL_TEXTURE_2D
);
484 gsprite_queue_sorted
.allocated
= 0;
485 gsprite_queue_sorted
.next_id
= 0;
486 free(gsprite_queue_sorted
.items
);
487 gsprite_queue_sorted
.items
= 0;
490 SDL_GL_SwapBuffers();
496 //SDL_FillRect(gscreen, 0, 0x0);
500 Sprite
* LoadSpriteSVG(char *fname
, double width
, double height
){
504 Config conf
=GetConfig();
506 xx
= width
*(double)conf
.screen_width
/SCREEN_WIDTH
;
507 yy
= height
*(double)conf
.screen_height
/SCREEN_HEIGHT
;
510 sprite
= (Sprite
*)malloc(sizeof(Sprite
));
511 surface
= load_svg(fname
, xx
, yy
, &sprite
->twidth
, &sprite
->theight
);
512 sprite
->fname
= malloc(sizeof(char)*(strlen(fname
)+2));
513 strcpy(sprite
->fname
, fname
);
514 sprite
->width
= width
;
515 sprite
->height
= height
;
516 sprite
->rotation
= 0;
517 sprite
->SID
= AddSurface(surface
);
522 void DestroySprite(Sprite
*sprite
){
523 RemoveSprite(sprite
);
526 glDeleteTextures(1, &gsprite_surfaces
.surfaces
[sprite
->SID
]);
527 RemoveSID(sprite
->SID
);
531 Sprite
* CopySprite(Sprite
*old
){
532 printf("CopySprite not Implemented\n");
538 void RotateSurface(int SID
, int rotation
){
542 fprintf(stderr
, "Rotation of sprites not implemented :(\n");
545 void RotateClockwise(Sprite
*sprite
){
546 RotateSurface(sprite
->SID
,1);
550 void QueueDrawSprite(Sprite
*sprite
, double x
, double y
, int z
){
551 const SDL_Color white
= {255, 255, 255, 255};
552 QueueDrawSpriteColorize(sprite
, x
, y
, z
, white
);
555 void QueueDrawSpriteColorize(Sprite
*sprite
, double x
, double y
, int z
, SDL_Color color
){
556 SpriteQueueItem
*item
;
558 printf("NULL sprite*\n");
561 if(gsprite_queue
.next_id
>=gsprite_queue
.allocated
){
562 item
= (SpriteQueueItem
*) realloc(gsprite_queue
.items
, sizeof(SpriteQueueItem
)*gsprite_queue
.allocated
*2);
564 fprintf(stderr
, "Can't allocate enough memory for sprite queue\n");
567 gsprite_queue
.allocated
*= 2;
568 gsprite_queue
.items
= item
;
571 item
= &gsprite_queue
.items
[gsprite_queue
.next_id
];
572 item
->sprite
= sprite
;
574 item
->xx
= sprite
->width
;
576 item
->yy
= sprite
->height
;
580 gsprite_queue
.next_id
++;
583 void QueueDrawSpriteColorizeStretch(Sprite
*sprite
, double x
, double y
, double xx
, double yy
, int z
, SDL_Color color
){
584 SpriteQueueItem
*item
;
586 printf("NULL sprite*\n");
589 if(gsprite_queue
.next_id
>=gsprite_queue
.allocated
){
590 item
= (SpriteQueueItem
*) realloc(gsprite_queue
.items
, sizeof(SpriteQueueItem
)*gsprite_queue
.allocated
*2);
592 fprintf(stderr
, "Can't allocate enough memory for sprite queue\n");
595 gsprite_queue
.allocated
*= 2;
596 gsprite_queue
.items
= item
;
599 item
= &gsprite_queue
.items
[gsprite_queue
.next_id
];
600 item
->sprite
= sprite
;
608 gsprite_queue
.next_id
++;
612 unsigned int closestpoweroftwo(unsigned int i
){
623 //load_svg borrowed from cairo demo
625 /* load_svg: This is what you're probably interested in!
626 * -----------------------------------------------------
627 * If width and height are greater than 0, the image will
628 * be scaled to that size. wscale and hscale would be ignored.
630 * If width and height are less than 1, wscale and hscale will
631 * resize the width and the height to the specified scales.
633 * If width and height are less than 1, and wscale and hscale
634 * are either 0 or 1, then the image will be loaded at it's
637 * See main() for examples.
639 GLuint
load_svg (char *file
, int width
, int height
, double *pdw
, double *pdh
) {
640 RsvgDimensionData g_DimensionData
;
641 RsvgHandle
* rsvghandle
;
647 unsigned int rheight
;
648 unsigned int pw
,ph
; //power of two dimensions
649 double wscale
,hscale
;
650 Config config
=GetConfig();
652 // Create the SVG cairo stuff.
653 rsvghandle
= rsvg_handle_new_from_file(file
, &pError
);
655 rsvg_handle_get_dimensions( rsvghandle
, &g_DimensionData
);
656 rwidth
= g_DimensionData
.width
;
657 rheight
= g_DimensionData
.height
;
658 *pdw
= closestpoweroftwo(width
);
659 *pdh
= closestpoweroftwo(height
);
660 width
= width
>>config
.texture_lod
;
661 height
= height
>>config
.texture_lod
;
662 printf("w:%u h:%u\n",width
, height
);
664 /*Calculate final width and height of our surface based on the parameters passed */
666 wscale
=(float)width
/(float)rwidth
;
668 width
=(int)(rwidth
*wscale
);
671 hscale
=(float)height
/(float)rheight
;
673 height
=(int)(rheight
*hscale
);
683 /* We will create a CAIRO_FORMAT_ARGB32 surface. We don't need to match
684 the screen SDL format, but we are interested in the alpha bit */
685 bpp
=32; /*bits per pixel*/
686 btpp
=4; /*bytes per pixel*/
689 int stride
=width
* btpp
;
691 /* Allocate an image */
692 unsigned char *image
=calloc(stride
*height
, 1);
694 /* Create the cairo surface with the adjusted width and height */
695 cairo_surface_t
*cairo_surface
;
696 cairo_surface
= cairo_image_surface_create_for_data (image
,
698 width
, height
, stride
);
700 cairo_t
*cr
=cairo_create(cairo_surface
);
701 cairo_scale (cr
, wscale
, hscale
);
703 /* Render SVG to our surface */
704 rsvg_handle_render_cairo(rsvghandle
, cr
);
705 rsvg_handle_free(rsvghandle
);
708 cairo_surface_destroy (cairo_surface
);
711 /*Destroy the svg_cairo structure */
713 /*Adjust the SDL surface mask to ARGB, matching the cairo surface created.*/
714 Uint32 rmask
, gmask
, bmask
, amask
;
721 /* Create the SDL surface using the pixel data stored. It will automatically be set to use alpha using these mask values */
722 SDL_Surface
*sdl_surface
=SDL_CreateRGBSurfaceFrom( (void *) image
, width
, height
, bpp
, stride
, rmask
, gmask
, bmask
, amask
);
723 SDL_SetAlpha(sdl_surface
, 0, 255);
728 pw
= closestpoweroftwo(width
);
729 ph
= closestpoweroftwo(height
);
730 SDL_Surface
*sdl_rgba_surface
=SDL_CreateRGBSurface( SDL_SWSURFACE
, pw
, ph
, bpp
, rmask
, gmask
, bmask
, amask
);
731 SDL_BlitSurface(sdl_surface
, 0, sdl_rgba_surface
, 0);
732 SDL_FreeSurface(sdl_surface
);
735 SDL_LockSurface(sdl_rgba_surface
);
738 glGenTextures(1, &tid
);
739 glBindTexture(GL_TEXTURE_2D
, tid
);
740 glTexParameteri(GL_TEXTURE_2D
,GL_TEXTURE_MAG_FILTER
,GL_LINEAR
); // scale linearly when image bigger than texture
741 glTexParameteri(GL_TEXTURE_2D
,GL_TEXTURE_MIN_FILTER
,GL_LINEAR
); // scale linearly when image smalled than texture
742 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, pw
, ph
, 0, GL_RGBA
, GL_UNSIGNED_BYTE
, sdl_rgba_surface
->pixels
);
743 SDL_UnlockSurface(sdl_rgba_surface
);
744 SDL_FreeSurface(sdl_rgba_surface
);
746 printf("Occupied: %u\n", occupied
);