1 /*
2     XorGramana Copyright 2009 James W. Morris, james@jwm-art.net
3 
4     This file is part of XorGramana.
5 
6     XorGramana is free software: you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation, either version 3 of the License, or
9     (at your option) any later version.
10 
11     XorGramana is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with XorGramana.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 #include "gfx.h"
20 #include "input.h"
21 
22 #include <stdlib.h>
23 #include <stdarg.h>
24 
25 SDL_Surface* screen=0;
26 struct gfx_mode kermode;
27 struct gfx_win* scr_win=0;
28 struct gfx_win* main_win=0;
29 struct gfx_win* cur_win=0;
30 
gfx_start()31 void gfx_start()
32 {
33     int i,n;
34     int rx,by;
35     int mc=0;
36     SDL_Rect **modes;
37     if(SDL_Init(SDL_INIT_VIDEO)<0){
38         fprintf(stderr,"Couldn't initialize SDL: %s\n",SDL_GetError());
39         exit(-1);
40     }
41     SDL_WM_SetCaption("XorGramana",0);
42     kermode.def=kermode.last=kermode.mode=-1;
43     kermode.m=0;
44     kermode.modes=0;
45     modes=SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_HWSURFACE);
46     if(!modes){
47         fprintf(stderr,"No modes available!\n");
48         SDL_Quit();
49         exit(-1);
50     }
51     if(modes == (SDL_Rect **)-1){
52       fprintf(stderr,"All resolutions available.\n");
53       fprintf(stderr,"Dont't know what to do!!!!\n Probably will crash!\n");
54       /* now what? how do we know what they are? */
55     }
56     else{
57         mc=0;
58         for(i=0;modes[i];++i){
59             #ifdef GFX_DEBUG
60             printf("Checking mode: %d x %d ... ",
61                 modes[i]->w,
62                 modes[i]->h);
63             #endif
64             if(modes[i]->w<GFX_MIN_WIDTH
65              ||modes[i]->h<GFX_MIN_HEIGHT)
66             {
67                 modes[i]=0;
68                 #ifdef GFX_DEBUG
69                 printf("Too small.\n");
70                 #endif
71             }
72             else{
73                 #ifdef GFX_DEBUG
74                 printf("Ok.\n");
75                 #endif
76                 mc++;
77             }
78         }
79     }
80     #ifdef GFX_DEBUG
81     printf("%d gfx modes found\n",mc);
82     #endif
83     if(!(kermode.modes=malloc(sizeof(SDL_Rect*)*mc))){
84         fprintf(stderr,"Failed to allocate for gfx modes dit dit dit...");
85         SDL_Quit();
86         exit(-1);
87     }
88     if(mc==0){
89         fprintf(stderr,
90             "%d x %d video mode or larger not found.\n",
91             GFX_MIN_WIDTH,GFX_MIN_HEIGHT);
92         fprintf(stderr,"Sorry, this is a minimum requirement.\n");
93         SDL_Quit();
94         exit(-1);
95     }
96     #ifdef GFX_LARGEST_RES
97     kermode.mode=kermode.last=0;
98     #else
99     kermode.mode=kermode.last=mc-1;
100     #endif
101     mc=0;
102     n=i;
103     for(i=0;i<n;i++)
104         if(modes[i]){
105             kermode.modes[mc]=modes[i];
106             mc++;
107         }
108     kermode.m=kermode.modes[kermode.mode];
109     screen=SDL_SetVideoMode(kermode.m->w,kermode.m->h,0,
110         SDL_HWSURFACE|SDL_HWPALETTE|SDL_DOUBLEBUF);
111     if(!screen){
112         fprintf(stderr,
113             "Couldn't set %d x %d hardware surface video mode: %s\n",
114             kermode.m->w,kermode.m->h,SDL_GetError());
115         SDL_Quit();
116         exit(-1);
117     }
118     scr_win=gfx_new_win(GFX_CENTER_X|GFX_CENTER_Y,0,0,0,0,ICON_WIDTH,ICON_HEIGHT);
119     rx=scr_win->win_w-ICON_WIDTH;
120     by=scr_win->win_h-ICON_HEIGHT;
121     main_win=gfx_new_win(GFX_CENTER_X|GFX_CENTER_Y,0,0,rx,by,ICON_WIDTH,ICON_HEIGHT);
122 }
123 
gfx_end()124 void gfx_end()
125 {
126     free(scr_win);
127     free(main_win);
128     scr_win=0;
129     SDL_Quit();
130 }
131 
scr_win_border()132 void scr_win_border()
133 {
134     gfx_set_win(scr_win);
135     gfx_win_half_size();
136     gfx_box(0,0,scr_win->blk_count_x-1,scr_win->blk_count_y-1,FALSE);
137 }
138 
gfx_inc_mode()139 void gfx_inc_mode()
140 {
141 }
142 
gfx_dec_mode()143 void gfx_dec_mode()
144 {
145 }
146 
draw_image(SDL_Surface * image,int x,int y)147 void draw_image(SDL_Surface *image, int x, int y)
148 {
149     SDL_Rect dest;
150     dest.x=x;
151     dest.y=y;
152     dest.w=image->w;
153     dest.h=image->h;
154     SDL_BlitSurface(image, NULL, screen, &dest);
155 }
156 
gfx_win_draw_image(SDL_Surface * image,int blk_x,int blk_y)157 void gfx_win_draw_image(SDL_Surface *image, int blk_x, int blk_y)
158 {
159     SDL_Rect dest;
160     dest.x=cur_win->blk_tlx+blk_x*image->w;
161     dest.y=cur_win->blk_tly+blk_y*image->h;
162     dest.w=image->w;
163     dest.h=image->h;
164     SDL_BlitSurface(image, NULL, screen, &dest);
165 }
166 
overlay_image(SDL_Surface * image,SDL_Surface * overlay,int x,int y)167 void overlay_image(SDL_Surface* image, SDL_Surface *overlay, int x, int y)
168 {
169     SDL_Rect dest;
170     dest.x=x;
171     dest.y=y;
172     dest.w=image->w;
173     dest.h=image->h;
174     SDL_BlitSurface(overlay, NULL, image, &dest);
175 }
176 
getpixel(SDL_Surface * surface,int x,int y)177 Uint32 getpixel(SDL_Surface *surface, int x, int y)
178 {
179     int bpp=surface->format->BytesPerPixel;
180     /* Here p is the address to the pixel we want to retrieve */
181     Uint8* p=(Uint8*)surface->pixels+y*surface->pitch+x*bpp;
182     switch(bpp){
183         case 1: return *p;
184         case 2: return *(Uint16 *)p;
185         case 3:
186             if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
187                 return p[0] << 16 | p[1] << 8 | p[2];
188             else
189                 return p[0] | p[1] << 8 | p[2] << 16;
190         case 4: return *(Uint32 *)p;
191         default:
192             return 0;
193     }
194 }
195 
putpixel(SDL_Surface * surface,int x,int y,Uint32 pixel)196 void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
197 {
198     int bpp=surface->format->BytesPerPixel;
199     /* Here p is the address to the pixel we want to set */
200     Uint8* p=(Uint8*)surface->pixels+y*surface->pitch+x*bpp;
201     switch(bpp){
202         case 1: *p = pixel;             break;
203         case 2: *(Uint16 *)p = pixel;   break;
204         case 3:
205             if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
206                 p[0] = (pixel >> 16) & 0xff;
207                 p[1] = (pixel >> 8) & 0xff;
208                 p[2] = pixel & 0xff;
209             }
210             else{
211                 p[0] = pixel & 0xff;
212                 p[1] = (pixel >> 8) & 0xff;
213                 p[2] = (pixel >> 16) & 0xff;
214             }
215             break;
216         case 4: *(Uint32 *)p = pixel;   break;
217     }
218 }
219 
220 struct gfx_win*
gfx_new_win(int flags,int tlx,int tly,int brx,int bry,int blk_width,int blk_height)221 gfx_new_win(int flags,
222             int tlx, int tly,int brx, int bry,
223             int blk_width,int blk_height)
224 {
225     struct gfx_win* win=0;
226     int tmptlx,tmptly,tmpbrx,tmpbry;
227     int offx=0;
228     int offy=0;
229     int tmp;
230     if(tlx==0&&tly==0&&brx==0&&bry==0){
231         brx=screen->w;
232         bry=screen->h;
233     }
234     if(blk_width<2||blk_height<2)
235         return 0;
236     tmptlx=((tlx>=0?tlx:0)<screen->w?tlx:screen->w);
237     tmptly=((tly>=0?tly:0)<screen->h?tly:screen->h);
238     tmpbrx=((brx>=0?brx:0)<screen->w?brx:screen->w);
239     tmpbry=((bry>=0?bry:0)<screen->h?bry:screen->h);
240     if(tmptlx>=tmpbrx||tmptly>=tmpbry)
241         return 0;
242     if(!(win=malloc(sizeof(struct gfx_win))))
243         return 0;
244     win->win_w=tmpbrx-tmptlx;
245     win->win_h=tmpbry-tmptly;
246     if(flags&GFX_CENTER_X)
247         offx=(screen->w - win->win_w)/2;
248     else if(flags&GFX_ALIGN_R)
249         offx=screen->w - win->win_w;
250     if(flags&GFX_CENTER_Y)
251         offy=(screen->h - win->win_h)/2;
252     else if(flags&GFX_ALIGN_B)
253         offy=screen->h - win->win_h;
254     win->win_tlx=offx+tmptlx;
255     win->win_tly=offy+tmptly;
256     win->win_brx=offx+tmpbrx;
257     win->win_bry=offy+tmpbry;
258     if(flags&GFX_BLK_ALIGN_X){
259         win->win_tlx=(win->win_tlx/blk_width)*blk_width;
260         win->win_brx=(win->win_brx/blk_width)*blk_width;
261         win->win_w=win->win_brx-win->win_tlx;
262     }
263     if(flags&GFX_BLK_ALIGN_Y){
264         win->win_tly=(win->win_tly/blk_height)*blk_height;
265         win->win_bry=(win->win_bry/blk_height)*blk_height;
266         win->win_h=win->win_bry-win->win_tly;
267     }
268     win->win_cx=0;
269     win->win_cy=0;
270 
271     /* calc block printing area */
272     win->icon_width=blk_width;
273     win->icon_height=blk_height;
274     win->blk_count_x=win->win_w/blk_width;
275     win->blk_count_y=win->win_h/blk_height;
276     offx=0;
277     offy=0;
278 
279     /* do the number of blocks fit exactly? */
280     tmp=win->blk_count_x * blk_width;
281     if(tmp<win->win_w)
282         offx=(win->win_w-tmp)/2;
283     tmp=win->blk_count_y * blk_height;
284     if(tmp<win->win_h)
285         offy=(win->win_h-tmp)/2;
286     win->blk_tlx=win->win_tlx+offx;
287     win->blk_brx=win->win_brx-offx;
288     win->blk_tly=win->win_tly+offy;
289     win->blk_bry=win->win_bry-offy;
290     win->blk_cx=0;
291     win->blk_cy=0;
292     win->icons=icons;
293     win->half_size=0;
294     return win;
295 }
296 
gfx_set_win(struct gfx_win * win)297 void gfx_set_win(struct gfx_win* win)
298 {
299     cur_win=win;
300 }
301 
gfx_win_half_size()302 void gfx_win_half_size()
303 {
304     if(!cur_win){
305         fprintf(stderr,"gfx_win_half_size: cur_win == NULL!\n");
306         return;
307     }
308     if(cur_win->half_size)
309         return;
310     cur_win->half_size=1;
311     cur_win->icons=hs_icons;
312     cur_win->icon_width/=2;
313     cur_win->icon_height/=2;
314     cur_win->blk_cx*=2;
315     cur_win->blk_cy*=2;
316     cur_win->blk_count_x*=2;
317     cur_win->blk_count_y*=2;
318 }
319 
gfx_win_full_size()320 void gfx_win_full_size()
321 {
322     if(!cur_win){
323         fprintf(stderr,"gfx_win_full_size: cur_win == NULL!\n");
324         return;
325     }
326     if(!cur_win->half_size)
327         return;
328     cur_win->half_size=0;
329     cur_win->icons=icons;
330     cur_win->icon_width*=2;
331     cur_win->icon_height*=2;
332     cur_win->blk_cx/=2;
333     cur_win->blk_cy/=2;
334     cur_win->blk_count_x/=2;
335     cur_win->blk_count_y/=2;
336 }
337 
gfx_mv_cur(su_t blk_x,su_t blk_y)338 su_t gfx_mv_cur(su_t blk_x, su_t blk_y)
339 {
340     int x,y;
341     if(!cur_win){
342         fprintf(stderr,"gfx_mv_cur: cur_win == NULL!\n");
343         return 0;
344     }
345     if(blk_x>cur_win->blk_count_x||blk_x<0
346      ||blk_y>cur_win->blk_count_y||blk_y<0)
347     {
348         fprintf(stderr,
349             "gfx_mv_cur: loc %d,%d outside range 0,0 - %d,%d\n",
350             (int)blk_x, (int)blk_y,
351             (int)cur_win->blk_count_x,(int)cur_win->blk_count_y);
352         return 0;
353     }
354     x=cur_win->blk_tlx+blk_x*cur_win->icon_width;
355     y=cur_win->blk_tly+blk_y*cur_win->icon_height;
356     cur_win->blk_cx=blk_x;
357     cur_win->blk_cy=blk_y;
358     cur_win->win_cx=x;
359     cur_win->win_cy=y;
360     return 1;
361 }
362 
gfx_inc_cursor(bool line)363 void gfx_inc_cursor(bool line)
364 {
365     if(!line){
366         cur_win->blk_cx++;
367         if(cur_win->blk_cx==cur_win->blk_count_x)
368             line=TRUE;
369     }
370     if(line){
371         cur_win->blk_cx=0;
372         cur_win->blk_cy++;
373         if(cur_win->blk_cy==cur_win->blk_count_y)
374             cur_win->blk_cx=cur_win->blk_cy=0;
375     }
376     gfx_mv_cur(cur_win->blk_cx,cur_win->blk_cy);
377 }
378 
gfx_printf(const char * format,...)379 int gfx_printf(const char* format, ...)
380 {
381     va_list ap;
382     int ret=0;
383     int n=0;
384     int i;
385     char buf[MAX_PRINTLEN];
386     SDL_Surface* icon;
387     if(!cur_win){
388         fprintf(stderr,"gfx_printf: cur_win == NULL!\n");
389         return 0;
390     }
391     va_start(ap, format);
392     ret=vsnprintf(buf,MAX_PRINTLEN-1,format,ap);
393     va_end(ap);
394     while(buf[n]&&n<MAX_PRINTLEN){
395         if(buf[n]=='\n'){
396             n++;
397             gfx_inc_cursor(TRUE);
398             continue;
399         }
400         i=char_to_icon(buf[n]);
401         icon=(cur_win->half_size?hs_icons[i]:icons[i]);
402         draw_image(icon,cur_win->win_cx,cur_win->win_cy);
403         gfx_inc_cursor(FALSE);
404         n++;
405     }
406     return n;
407 }
408 
delay(unsigned int flimit)409 void delay(unsigned int flimit)
410 {
411     unsigned int ticks=SDL_GetTicks();
412     if (flimit<ticks)
413         return;
414     if (flimit>ticks+TICK_COUNT)
415         SDL_Delay(TICK_COUNT);
416     else
417         SDL_Delay(flimit-ticks);
418 }
419 
gfx_message(const char * format,...)420 void gfx_message(const char* format, ...)
421 {
422     va_list ap;
423     int x,y;
424     int n=0;
425     bool half_size=cur_win->half_size;
426     char buf[MAX_PRINTLEN];
427     if(!cur_win){
428         fprintf(stderr,"gfx_message: cur_win == NULL!\n");
429         return;
430     }
431     va_start(ap, format);
432     n=vsnprintf(buf,MAX_PRINTLEN-1,format,ap);
433     va_end(ap);
434     if(!half_size)
435         gfx_win_half_size();
436     x=(cur_win->blk_count_x-strlen(buf))/2;
437     y=cur_win->blk_count_y/2+2;
438     gfx_box(x-1,y-1,x+n,y+1,TRUE);
439     set_space_icon(SPC_OPAQUE);
440     gfx_mv_cur(x,y);
441     gfx_printf(buf);
442     if(!half_size)
443         gfx_win_full_size();
444     SDL_Flip(screen);
445     wait_till_pressed();
446 }
447 
gfx_box(int tlx,int tly,int brx,int bry,bool solid)448 void gfx_box(int tlx, int tly, int brx, int bry, bool solid)
449 {
450     int x,y;
451     for(x=tlx;x<=brx;x++){
452         gfx_win_draw_image(hs_icons[ICON_LINE_T],x, tly);
453         gfx_win_draw_image(hs_icons[ICON_LINE_B],x, bry);
454     }
455     for(y=tly;y<=bry;y++){
456         gfx_win_draw_image(hs_icons[ICON_LINE_L],tlx,y);
457         gfx_win_draw_image(hs_icons[ICON_LINE_R],brx,y);
458     }
459     gfx_win_draw_image(hs_icons[ICON_LINE_TL],tlx,tly);
460     gfx_win_draw_image(hs_icons[ICON_LINE_TR],brx,tly);
461     gfx_win_draw_image(hs_icons[ICON_LINE_BL],tlx,bry);
462     gfx_win_draw_image(hs_icons[ICON_LINE_BR],brx,bry);
463     if(solid){
464         for(y=tly+1;y<bry;y++)
465             for(x=tlx+1;x<brx;x++)
466                 gfx_win_draw_image(hs_icons[ICON_SPACE_OPAQUE],x,y);
467     }
468 }
469