first steps towards Map2String
[Lilanci.git] / gr.c
blobfcc7ee396e053513f9ba48f59a39ad5b99d0ddd5
1 #include "config.h"
2 #include "gr.h"
3 #include <string.h>
4 #include <stdlib.h>
5 #include <limits.h>
6 #include <stdio.h>
7 #include <sys/types.h>
8 #include <cairo.h>
9 #include <librsvg/rsvg.h>
10 #include <librsvg/rsvg-cairo.h>
12 #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();
13 #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();
15 #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();
17 unsigned int occupied=0;
19 typedef struct{
20 GLuint *surfaces;
21 unsigned int allocated;
22 }SurfaceList;
24 SurfaceList gsprite_surfaces;
25 int AddSurface(GLuint s);
26 void RemoveSurface(GLuint s);
27 void RemoveSID(int SID);
28 void FlushSpriteSurfaces();
29 int SetVideoMode(int width, int height);
30 SDL_Surface *gscreen;
32 typedef struct{
33 Sprite **sprites;
34 unsigned int allocated;
35 }SpriteList;
37 SpriteList gsprites;
38 int AddSprite(Sprite *s);
39 void RemoveSprite(Sprite *s);
41 typedef struct{
42 Sprite *sprite;
43 double x;
44 double y;
45 double xx;
46 double yy;
47 int z; //z
48 SDL_Color c;
49 }SpriteQueueItem;
51 typedef struct{
52 SpriteQueueItem *items;
53 unsigned int allocated;
54 unsigned int next_id;
55 }SpriteQueue;
56 SpriteQueue gsprite_queue;
57 SpriteQueue gsprite_queue_sorted;
58 void FlushSpriteQueue();
59 void RotateSurface(int SID, int rotation);
61 int ginvalidsprites;
63 GLuint load_svg (char *file, int width, int height, double *pdw, double *pdh);
65 int G2SX(double x);
66 int G2SY(double y);
68 int G2SX(double x){
69 return (x/(double)SCREEN_WIDTH)*GetConfig().screen_width;
71 int G2SY(double y){
72 return (y/(double)SCREEN_HEIGHT)*GetConfig().screen_height;
75 int SetVideoMode(int width, int height){
76 SDL_Rect **modes;
77 int ibest;
78 int bestdif;
79 int i;
80 Uint32 flags;
82 Config config=GetConfig();
84 SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
85 flags = SDL_OPENGL ;
86 if(config.fullscreen)
87 flags = flags |SDL_FULLSCREEN;
88 /* Get available fullscreen/hardware modes */
89 modes=SDL_ListModes(NULL, flags);
91 /* Check if there are any modes available */
92 if(modes == (SDL_Rect **)0){
93 printf("No modes available!\n");
94 exit(-1);
97 /* Check if our resolution is restricted */
98 if(modes == (SDL_Rect **)-1){
99 printf("All resolutions available.\n");
100 gscreen = SDL_SetVideoMode(config.screen_width, config.screen_height, 0, flags);
102 else{
103 /* Print valid modes */
104 printf("Available Modes\n");
105 bestdif = abs((modes[0]->w - config.screen_width) + (modes[0]->h - config.screen_height));
106 ibest = 0;
107 for(i=0;modes[i];++i){
108 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
109 if(bestdif > abs((modes[i]->w - config.screen_width) + (modes[i]->h - config.screen_height))){
110 bestdif = abs((modes[i]->w - config.screen_width) + (modes[i]->h - config.screen_height));
111 ibest = i;
114 printf("Using: %d x %d\n", modes[ibest]->w, modes[ibest]->h);
115 gscreen = SDL_SetVideoMode(modes[ibest]->w, modes[ibest]->h, 0, flags);
116 config.screen_height = modes[ibest]->h;
117 config.screen_width = modes[ibest]->w;
118 SetConfig(config);
120 return 0;
123 int AddSurface(GLuint s){ //returns -1 on error, SID if success
124 int i;
125 GLuint *tmp;
126 for(i=0;i<gsprite_surfaces.allocated;i++)
127 if( gsprite_surfaces.surfaces[i]==s ){
128 return i;
131 for(i=0;i<gsprite_surfaces.allocated;i++)
132 if( gsprite_surfaces.surfaces[i]==0 ){
133 gsprite_surfaces.surfaces[i]=s;
134 return i;
136 i=gsprite_surfaces.allocated;
137 tmp = (GLuint*) realloc(gsprite_surfaces.surfaces, sizeof(GLuint)*i*2); //if the allocated space is not wide enough, then allocate double space than previous
138 if(tmp==0)
139 return -1;
140 gsprite_surfaces.surfaces=tmp;
141 memset(&gsprite_surfaces.surfaces[i],0, sizeof(GLuint)*i); //zero newly allocated space
142 gsprite_surfaces.allocated=i*2;
143 gsprite_surfaces.surfaces[i]=s;
144 return i;
147 void RemoveSurface(GLuint s){
148 int i,iwannakillyoubitch;
150 iwannakillyoubitch=1;
151 for(i=0;i<gsprite_surfaces.allocated;i++){
152 if( gsprite_surfaces.surfaces[i]==s ){
153 gsprite_surfaces.surfaces[i]=0;
155 if( i>=gsprite_surfaces.allocated/2 && iwannakillyoubitch && gsprite_surfaces.surfaces[i]!=0 )
156 iwannakillyoubitch=0;
159 if(iwannakillyoubitch){
160 gsprite_surfaces.allocated /=2;
161 gsprite_surfaces.surfaces = (GLuint *)realloc(gsprite_surfaces.surfaces, sizeof(GLuint)*gsprite_surfaces.allocated);//TODO:check return value
165 void RemoveSID(int SID){
166 int i,iwannakillyoubitch;
168 iwannakillyoubitch=1;
169 for(i=0;i<gsprite_surfaces.allocated;i++){
170 if( i==SID ){
171 gsprite_surfaces.surfaces[i]=0;
173 if( i>=gsprite_surfaces.allocated/2 && iwannakillyoubitch && gsprite_surfaces.surfaces[i]!=0 )
174 iwannakillyoubitch=0;
177 if(iwannakillyoubitch){
178 gsprite_surfaces.allocated /=2;
179 gsprite_surfaces.surfaces = (GLuint *)realloc(gsprite_surfaces.surfaces, sizeof(GLuint)*gsprite_surfaces.allocated);//TODO:check return value
183 int AddSprite(Sprite *s){//returns 0 on error, Sprite ID on success
184 int i;
185 Sprite **tmp;
186 for(i=0;i<gsprites.allocated;i++)
187 if( gsprites.sprites[i]==s ){
188 return i;
191 for(i=0;i<gsprites.allocated;i++)
192 if( gsprites.sprites[i]==0 ){
193 gsprites.sprites[i]=s;
194 return i;
196 i=gsprites.allocated;
197 tmp=(Sprite **)realloc(gsprites.sprites, sizeof(Sprite *)*i*2); //if the allocated space is not wide enough, then allocate double space than previous
198 if(tmp==0)
199 return 0;
200 gsprites.sprites=tmp;
201 memset(&gsprites.sprites[i],0, sizeof(Sprite *)*i); //zero newly allocated space
202 gsprites.allocated=i*2;
203 gsprites.sprites[i]=s;
204 return i;
207 void RemoveSprite(Sprite *s){
208 int i,iwannakillyoubitch;
210 iwannakillyoubitch=1;
211 for(i=0;i<gsprites.allocated;i++){
212 if( gsprites.sprites[i]==s ){
213 gsprites.sprites[i]=0;
215 if( i>=gsprites.allocated/2 && iwannakillyoubitch && gsprites.sprites[i]!=0 )
216 iwannakillyoubitch=0;
219 if(iwannakillyoubitch){
220 gsprites.allocated /=2;
221 gsprites.sprites = (Sprite **) realloc(gsprites.sprites, sizeof(Sprite *)*gsprites.allocated);//TODO:check return value
225 int GrKill(){
226 Config config;
227 int i;
229 FlushSpriteQueue();
230 FlushSpriteSurfaces();
232 config=GetConfig();
233 free(gsprite_surfaces.surfaces);
234 gsprite_surfaces.surfaces=0;
237 for(i=0; i<gsprites.allocated; i++)
238 if(gsprites.sprites[i]){
239 free(gsprites.sprites[i]->fname);
240 free(gsprites.sprites[i]);
241 gsprites.sprites[i]=0;
244 gsprites.allocated = 0;
247 rsvg_term ();
248 SetVideoMode(config.screen_width, config.screen_height);
250 return 0;
253 int GrInit(){
254 Config config;
256 config=GetConfig();
257 rsvg_init();
258 gsprite_surfaces.surfaces = (GLuint*) calloc(2, sizeof(GLuint));
259 if( gsprite_surfaces.surfaces == 0 )
260 return 1;
262 gsprite_surfaces.allocated = 2;
263 memset(gsprite_surfaces.surfaces, 0, gsprite_surfaces.allocated * sizeof(GLuint));
265 gsprites.sprites = (Sprite**) calloc(2,sizeof(Sprite*));
266 if( gsprites.sprites == 0 )
267 return 2;
268 memset(gsprites.sprites, 0, gsprites.allocated * sizeof(Sprite*));
269 gsprites.allocated = 2;
270 ginvalidsprites=1;
272 gsprite_queue.allocated=2;
273 gsprite_queue.items=(SpriteQueueItem*) malloc(sizeof(SpriteQueueItem)*2);
274 gsprite_queue.next_id=0;
276 SetVideoMode(config.screen_width, config.screen_height);
278 glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
279 glClearDepth(1.0);
280 glDisable(GL_DEPTH_TEST);
281 //glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
282 glEnable(GL_BLEND);
283 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
284 //glEnable(GL_ALPHA_TEST);
285 //glAlphaFunc(GL_GREATER, 0);
286 SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
288 glViewport(0, 0, config.screen_width, config.screen_height);
289 glMatrixMode(GL_PROJECTION);
290 glLoadIdentity();
292 glOrtho(0.0f,config.screen_width, config.screen_height,0.0f,-1.0f,1.0f);
294 glMatrixMode(GL_MODELVIEW);
295 glLoadIdentity();
297 return 0;
300 void FlushSpriteSurfaces(){
301 int i;
303 for(i=0;i<gsprite_surfaces.allocated;i++){
304 if(gsprite_surfaces.surfaces[i]){
305 glDeleteTextures(1, &gsprite_surfaces.surfaces[i]);
306 gsprite_surfaces.surfaces[i]=0;
309 occupied =0;
312 int RegenerateSprites(){
313 int i,SID;
314 Config config;
315 Sprite *tmpsprite;
316 GLuint tmpsurface;
317 int xx,yy;
319 config=GetConfig();
322 FlushSpriteSurfaces();
324 SetVideoMode(config.screen_width, config.screen_height);
327 for(i=0;i<gsprites.allocated;i++)
328 if(gsprites.sprites[i]){
329 tmpsprite=gsprites.sprites[i];
330 xx = (tmpsprite->width/SCREEN_WIDTH)*config.screen_width;
331 yy = (tmpsprite->height/SCREEN_HEIGHT)*config.screen_height;
333 tmpsurface=load_svg(tmpsprite->fname, xx, yy, &tmpsprite->twidth, &tmpsprite->theight);
335 SID=AddSurface(tmpsurface);
336 if(SID==-1){
337 return 1;
339 RotateSurface(SID,tmpsprite->rotation);
343 ginvalidsprites=0;
344 return 0;
346 void InvalidateSprites(){
347 printf("Invalid\n");
348 ginvalidsprites=1;
351 void FlushSpriteQueue(){
352 int i;
354 for(i=0;i<gsprite_queue.allocated;i++){
355 gsprite_queue.items[i].sprite = 0;
357 if(gsprite_queue.next_id < gsprite_queue.allocated/2){
358 //TODO:dopsat zmenseni fronty
360 gsprite_queue.next_id = 0;
363 void SwapSpriteQueueItems(int aid, int bid){
364 SpriteQueueItem c;
365 memcpy(&c, &gsprite_queue_sorted.items[aid], sizeof(SpriteQueueItem));
366 memcpy(&gsprite_queue_sorted.items[aid], &gsprite_queue_sorted.items[bid], sizeof(SpriteQueueItem));
367 memcpy(&gsprite_queue_sorted.items[bid], &c, sizeof(SpriteQueueItem));
368 /*c.sprite = gsprite_queue_sorted.items[aid].sprite;
369 c.x = gsprite_queue_sorted.items[aid].x;
370 c.xx = gsprite_queue_sorted.items[aid].xx;
371 c.y = gsprite_queue_sorted.items[aid].y;
372 c.yy = gsprite_queue_sorted.items[aid].yy;
373 c.z = gsprite_queue_sorted.items[aid].z;
374 c.c = gsprite_queue_sorted.items[aid].c;
376 gsprite_queue_sorted.items[aid].sprite = gsprite_queue_sorted.items[bid].sprite ;
377 gsprite_queue_sorted.items[aid].x = gsprite_queue_sorted.items[bid].x ;
378 gsprite_queue_sorted.items[aid].xx = gsprite_queue_sorted.items[bid].xx ;
379 gsprite_queue_sorted.items[aid].y = gsprite_queue_sorted.items[bid].y ;
380 gsprite_queue_sorted.items[aid].yy = gsprite_queue_sorted.items[bid].yy ;
381 gsprite_queue_sorted.items[aid].z = gsprite_queue_sorted.items[bid].z ;
382 gsprite_queue_sorted.items[aid].c = gsprite_queue_sorted.items[bid].c ;
384 gsprite_queue_sorted.items[bid].sprite = c.sprite;
385 gsprite_queue_sorted.items[bid].x = c.x;
386 gsprite_queue_sorted.items[bid].xx = c.xx;
387 gsprite_queue_sorted.items[bid].y = c.y;
388 gsprite_queue_sorted.items[bid].yy = c.yy;
389 gsprite_queue_sorted.items[bid].z = c.z;
390 gsprite_queue_sorted.items[bid].c = c.c;*/
393 void YSortSpriteQueue(int from, int to){
394 int i;
395 int y1, y2;
396 int TheEnd = 0;
397 //TODO:validity check
398 while(!TheEnd){
399 TheEnd = 1;
400 for(i = from; i < to ; i++){
401 y1 = gsprite_queue_sorted.items[i].sprite->height * 0.5 + gsprite_queue_sorted.items[i].y;
402 y2 = gsprite_queue_sorted.items[i+1].sprite->height * 0.5 + gsprite_queue_sorted.items[i+1].y;
403 if(y1 > y2){
404 TheEnd = 0;
405 SwapSpriteQueueItems(i+1, i);
411 void ZSortSpriteQueue(){
412 int minz, lastminz, found;
413 int i;
414 int ysortfrom, ysortto;
415 lastminz = INT_MIN;
418 found = 1;
419 gsprite_queue_sorted.next_id= 0;
420 while(found){
421 found = 0;
422 minz = INT_MAX;
423 //we seek for smallest z bigger than z in last iteration
424 for(i=0; i<gsprite_queue.next_id; i++){
425 if( gsprite_queue.items[i].z < minz && gsprite_queue.items[i].z > lastminz){
426 found = 1;
427 minz = gsprite_queue.items[i].z;
430 if(!found)
431 break;
432 //now we copy all items on z==minz
433 ysortfrom = gsprite_queue_sorted.next_id;
434 for(i=0; i < gsprite_queue.next_id; i++){
435 if(gsprite_queue.items[i].z == minz){
436 memcpy(&gsprite_queue_sorted.items[gsprite_queue_sorted.next_id], &gsprite_queue.items[i], sizeof(SpriteQueueItem));
437 ysortto = gsprite_queue_sorted.next_id;
438 gsprite_queue_sorted.next_id++;
441 YSortSpriteQueue(ysortfrom, ysortto);
442 lastminz=minz;
447 int DrawSprites(){
448 int i;
449 SDL_Rect dest;
450 SDL_Rect src;
451 GLuint ds;
452 Sprite *dspr;
454 if(ginvalidsprites){
455 printf("invalid\n");
456 RegenerateSprites();
459 gsprite_queue_sorted.allocated = gsprite_queue.allocated;
460 gsprite_queue_sorted.next_id = 0;
461 gsprite_queue_sorted.items = malloc(sizeof(SpriteQueueItem)* gsprite_queue_sorted.allocated);
462 ZSortSpriteQueue();
464 // select modulate to mix texture with color for shading
465 glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
466 glEnable(GL_TEXTURE_2D);
468 for(i=0;i<gsprite_queue_sorted.next_id;i++)
469 if(gsprite_queue_sorted.items[i].sprite){
470 dspr = gsprite_queue_sorted.items[i].sprite;
471 ds = gsprite_surfaces.surfaces[dspr->SID];
472 dest.x = G2SX(gsprite_queue_sorted.items[i].x);
473 dest.y = G2SY(gsprite_queue_sorted.items[i].y);
474 dest.w = G2SX(gsprite_queue_sorted.items[i].xx);
475 dest.h = G2SX(gsprite_queue_sorted.items[i].yy);
476 src.x = 0;
477 src.y = 0;
478 src.w = G2SX(gsprite_queue_sorted.items[i].sprite->width);
479 src.h = G2SX(gsprite_queue_sorted.items[i].sprite->height);
482 glBindTexture(GL_TEXTURE_2D, ds);
483 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);
484 TTRECT(dest.x, dest.y, dest.w, dest.h, src.w, src.h, dspr->twidth, dspr->theight);
487 glDisable(GL_TEXTURE_2D);
489 gsprite_queue_sorted.allocated = 0;
490 gsprite_queue_sorted.next_id = 0;
491 free(gsprite_queue_sorted.items);
492 gsprite_queue_sorted.items = 0;
493 FlushSpriteQueue();
495 SDL_GL_SwapBuffers();
497 return 0;
500 int ClrScr(){
501 //SDL_FillRect(gscreen, 0, 0x0);
502 return 0;
505 Sprite* LoadSpriteSVG(char *fname, double width, double height){
506 Sprite *sprite;
507 GLuint surface;
508 int xx,yy;
509 Config conf=GetConfig();
511 xx = width*(double)conf.screen_width/SCREEN_WIDTH;
512 yy = height*(double)conf.screen_height/SCREEN_HEIGHT;
515 sprite = (Sprite*)malloc(sizeof(Sprite));
516 surface = load_svg(fname, xx, yy, &sprite->twidth, &sprite->theight);
517 sprite->fname = malloc(sizeof(char)*(strlen(fname)+2));
518 strcpy(sprite->fname, fname);
519 sprite->width = width;
520 sprite->height = height;
521 sprite->rotation = 0;
522 sprite->SID = AddSurface(surface);
523 AddSprite(sprite);
525 return sprite;
527 void DestroySprite(Sprite *sprite){
528 RemoveSprite(sprite);
529 free(sprite->fname);
530 sprite->fname=0;
531 glDeleteTextures(1, &gsprite_surfaces.surfaces[sprite->SID]);
532 RemoveSID(sprite->SID);
533 free(sprite);
536 Sprite* CopySprite(Sprite *old){
537 printf("CopySprite not Implemented\n");
539 return 0;
543 void RotateSurface(int SID, int rotation){
544 //int i,x,y;
545 //int size;
547 fprintf(stderr, "Rotation of sprites not implemented :(\n");
550 void RotateClockwise(Sprite *sprite){
551 RotateSurface(sprite->SID,1);
552 sprite->rotation=1;
555 void QueueDrawSprite(Sprite *sprite, double x, double y, int z){
556 SDL_Color white = {255, 255, 255, 255};
557 QueueDrawSpriteColorize(sprite, x, y, z, white);
560 void QueueDrawSpriteColorize(Sprite *sprite, double x, double y, int z, SDL_Color color){
561 SpriteQueueItem *item;
562 if(!sprite){
563 printf("NULL sprite*\n");
564 return;
566 if(gsprite_queue.next_id >=gsprite_queue.allocated){
567 item = (SpriteQueueItem *) realloc(gsprite_queue.items, sizeof(SpriteQueueItem)*gsprite_queue.allocated*2);
568 if(item == 0){
569 fprintf(stderr, "Can't allocate enough memory for sprite queue\n");
570 return;
572 gsprite_queue.allocated *= 2;
573 gsprite_queue.items = item;
576 item = &gsprite_queue.items[gsprite_queue.next_id];
577 item->sprite = sprite;
578 item->x = x;
579 item->xx = sprite->width;
580 item->y = y;
581 item->yy = sprite->height;
582 item->z = z;
583 item->c = color;
585 gsprite_queue.next_id ++;
588 void QueueDrawSpriteColorizeStretch(Sprite *sprite, double x, double y, double xx, double yy, int z, SDL_Color color){
589 SpriteQueueItem *item;
590 if(!sprite){
591 printf("NULL sprite*\n");
592 return;
594 if(gsprite_queue.next_id >=gsprite_queue.allocated){
595 item = (SpriteQueueItem *) realloc(gsprite_queue.items, sizeof(SpriteQueueItem)*gsprite_queue.allocated*2);
596 if(item == 0){
597 fprintf(stderr, "Can't allocate enough memory for sprite queue\n");
598 return;
600 gsprite_queue.allocated *= 2;
601 gsprite_queue.items = item;
604 item = &gsprite_queue.items[gsprite_queue.next_id];
605 item->sprite = sprite;
606 item->x = x;
607 item->xx = xx;
608 item->y = y;
609 item->yy = yy;
610 item->z = z;
611 item->c = color;
613 gsprite_queue.next_id ++;
617 unsigned int closestpoweroftwo(unsigned int i){
618 int p;
619 p=0;
620 while(i){
621 i=i>>1;
622 p++;
624 return 1<<(p-0);
628 //load_svg borrowed from cairo demo
630 /* load_svg: This is what you're probably interested in!
631 * -----------------------------------------------------
632 * If width and height are greater than 0, the image will
633 * be scaled to that size. wscale and hscale would be ignored.
635 * If width and height are less than 1, wscale and hscale will
636 * resize the width and the height to the specified scales.
638 * If width and height are less than 1, and wscale and hscale
639 * are either 0 or 1, then the image will be loaded at it's
640 * natural size.
642 * See main() for examples.
644 GLuint load_svg (char *file, int width, int height, double *pdw, double *pdh) {
645 RsvgDimensionData g_DimensionData;
646 RsvgHandle* rsvghandle;
647 GError* pError;
649 int bpp;
650 int btpp;
651 unsigned int rwidth;
652 unsigned int rheight;
653 unsigned int pw,ph; //power of two dimensions
654 double wscale,hscale;
655 Config config=GetConfig();
657 // Create the SVG cairo stuff.
658 rsvghandle = rsvg_handle_new_from_file(file, &pError);
660 rsvg_handle_get_dimensions( rsvghandle, &g_DimensionData);
661 rwidth = g_DimensionData.width;
662 rheight = g_DimensionData.height;
663 *pdw = closestpoweroftwo(width);
664 *pdh = closestpoweroftwo(height);
665 width = width>>config.texture_lod;
666 height = height>>config.texture_lod;
667 printf("w:%u h:%u\n",width, height);
669 /*Calculate final width and height of our surface based on the parameters passed */
670 if (width > 0) {
671 wscale=(float)width/(float)rwidth;
672 } else {
673 width=(int)(rwidth*wscale);
675 if (height > 0) {
676 hscale=(float)height/(float)rheight;
677 } else {
678 height=(int)(rheight*hscale);
682 if(hscale>wscale){
683 hscale=wscale;
684 }else{
685 wscale=hscale;
688 /* We will create a CAIRO_FORMAT_ARGB32 surface. We don't need to match
689 the screen SDL format, but we are interested in the alpha bit */
690 bpp=32; /*bits per pixel*/
691 btpp=4; /*bytes per pixel*/
693 /* scanline width */
694 int stride=width * btpp;
696 /* Allocate an image */
697 unsigned char *image=calloc(stride*height, 1);
699 /* Create the cairo surface with the adjusted width and height */
700 cairo_surface_t *cairo_surface;
701 cairo_surface = cairo_image_surface_create_for_data (image,
702 CAIRO_FORMAT_ARGB32,
703 width, height, stride);
705 cairo_t *cr=cairo_create(cairo_surface);
706 cairo_scale (cr, wscale, hscale);
708 /* Render SVG to our surface */
709 rsvg_handle_render_cairo(rsvghandle, cr);
710 rsvg_handle_free(rsvghandle);
712 /* Cleanup cairo */
713 cairo_surface_destroy (cairo_surface);
714 cairo_destroy (cr);
716 /*Destroy the svg_cairo structure */
718 /*Adjust the SDL surface mask to ARGB, matching the cairo surface created.*/
719 Uint32 rmask, gmask, bmask, amask;
721 rmask = 0x00ff0000;
722 gmask = 0x0000ff00;
723 bmask = 0x000000ff;
724 amask = 0xff000000;
726 /* Create the SDL surface using the pixel data stored. It will automatically be set to use alpha using these mask values */
727 SDL_Surface *sdl_surface=SDL_CreateRGBSurfaceFrom( (void *) image, width, height, bpp, stride, rmask, gmask, bmask, amask);
728 SDL_SetAlpha(sdl_surface, 0, 255);
729 rmask = 0x000000ff;
730 gmask = 0x0000ff00;
731 bmask = 0x00ff0000;
732 amask = 0xff000000;
733 pw = closestpoweroftwo(width);
734 ph = closestpoweroftwo(height);
735 SDL_Surface *sdl_rgba_surface=SDL_CreateRGBSurface( SDL_SWSURFACE, pw, ph, bpp, rmask, gmask, bmask, amask);
736 SDL_BlitSurface(sdl_surface, 0, sdl_rgba_surface, 0);
737 SDL_FreeSurface(sdl_surface);
738 cfree(image);
740 SDL_LockSurface(sdl_rgba_surface);
742 GLuint tid;
743 glGenTextures(1, &tid);
744 glBindTexture(GL_TEXTURE_2D, tid);
745 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // scale linearly when image bigger than texture
746 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // scale linearly when image smalled than texture
747 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pw, ph, 0, GL_RGBA, GL_UNSIGNED_BYTE, sdl_rgba_surface->pixels);
748 SDL_UnlockSurface(sdl_rgba_surface);
749 SDL_FreeSurface(sdl_rgba_surface);
750 occupied += pw*ph;
751 printf("Occupied: %u\n", occupied);
753 return tid;