- replaced d_type with a stat() call (the former doesn't work with reiserfs)
[supertux.git] / src / screen.c
1 /*
2   screen.c
3   
4   Super Tux - Screen Functions
5   
6   by Bill Kendrick
7   bill@newbreedsoftware.com
8   http://www.newbreedsoftware.com/supertux/
9   
10   April 11, 2000 - April 22, 2000
11 */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <errno.h>
17 #include <unistd.h>
18 #include <SDL.h>
19 #include <SDL_image.h>
20
21 #ifdef LINUX
22 #include <pwd.h>
23 #include <sys/types.h>
24 #include <ctype.h>
25 #endif
26
27 #include "defines.h"
28 #include "globals.h"
29 #include "screen.h"
30 #include "setup.h"
31 #include "type.h"
32
33 /* Needed for line calculations */
34 #define SGN(x) ((x)>0 ? 1 : ((x)==0 ? 0:(-1)))
35 #define ABS(x) ((x)>0 ? (x) : (-x))
36
37 /* --- LOAD AND DISPLAY AN IMAGE --- */
38
39 void load_and_display_image(char * file)
40 {
41   SDL_Surface * img;
42
43   img = load_image(file, IGNORE_ALPHA);
44   SDL_BlitSurface(img, NULL, screen, NULL);
45   SDL_FreeSurface(img);
46 }
47
48
49 /* --- CLEAR SCREEN --- */
50
51 void clearscreen(int r, int g, int b)
52 {
53 #ifndef NOOPENGL
54   if(use_gl)
55     {
56       glClearColor(r/256, g/256, b/256, 1.0);
57       glClear(GL_COLOR_BUFFER_BIT);
58     }
59   else
60 #endif
61
62     SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, r, g, b));
63
64 }
65
66 /* 'Stolen' from the SDL documentation.
67  * Set the pixel at (x, y) to the given value
68  * NOTE: The surface must be locked before calling this!
69  */
70 void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
71 {
72   int bpp = surface->format->BytesPerPixel;
73   /* Here p is the address to the pixel we want to set */
74   Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
75
76   switch(bpp)
77     {
78     case 1:
79       *p = pixel;
80       break;
81
82     case 2:
83       *(Uint16 *)p = pixel;
84       break;
85
86     case 3:
87       if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
88         {
89           p[0] = (pixel >> 16) & 0xff;
90           p[1] = (pixel >> 8) & 0xff;
91           p[2] = pixel & 0xff;
92         }
93       else
94         {
95           p[0] = pixel & 0xff;
96           p[1] = (pixel >> 8) & 0xff;
97           p[2] = (pixel >> 16) & 0xff;
98         }
99       break;
100
101     case 4:
102       *(Uint32 *)p = pixel;
103       break;
104     }
105 }
106
107 void drawpixel(int x, int y, Uint32 pixel)
108 {
109   /* Lock the screen for direct access to the pixels */
110   if ( SDL_MUSTLOCK(screen) )
111     {
112       if ( SDL_LockSurface(screen) < 0 )
113         {
114           fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());
115           return;
116         }
117     }
118
119   if(!(x < 0 || y < 0 || x > screen->w || y > screen->h))
120     putpixel(screen, x, y, pixel);
121
122   if ( SDL_MUSTLOCK(screen) )
123     {
124       SDL_UnlockSurface(screen);
125     }
126   /* Update just the part of the display that we've changed */
127   SDL_UpdateRect(screen, x, y, 1, 1);
128 }
129
130 void drawline(int x1, int y1, int x2, int y2, int r, int g, int b, int a)
131 {
132 #ifndef NOOPENGL
133   if(use_gl)
134     {
135       glEnable(GL_BLEND);
136       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
137       glColor4ub(r, g, b,a);
138
139       glBegin(GL_LINES);
140       glVertex2f(x1, y1);
141       glVertex2f(x2, y2);
142       glEnd();
143       glDisable(GL_BLEND);
144     }
145   else
146     {
147 #endif
148
149       /* Basic unantialiased Bresenham line algorithm */
150       int lg_delta, sh_delta, cycle, lg_step, sh_step;
151       Uint32 color = SDL_MapRGBA(screen->format, r, g, b, a);
152
153       lg_delta = x2 - x1;
154       sh_delta = y2 - y1;
155       lg_step = SGN(lg_delta);
156       lg_delta = ABS(lg_delta);
157       sh_step = SGN(sh_delta);
158       sh_delta = ABS(sh_delta);
159       if (sh_delta < lg_delta)
160         {
161           cycle = lg_delta >> 1;
162           while (x1 != x2)
163             {
164               drawpixel(x1, y1, color);
165               cycle += sh_delta;
166               if (cycle > lg_delta)
167                 {
168                   cycle -= lg_delta;
169                   y1 += sh_step;
170                 }
171               x1 += lg_step;
172             }
173           drawpixel(x1, y1, color);
174         }
175       cycle = sh_delta >> 1;
176       while (y1 != y2)
177         {
178           drawpixel(x1, y1, color);
179           cycle += lg_delta;
180           if (cycle > sh_delta)
181             {
182               cycle -= sh_delta;
183               x1 += lg_step;
184             }
185           y1 += sh_step;
186         }
187       drawpixel(x1, y1, color);
188     }
189 }
190
191 /* --- FILL A RECT --- */
192
193 void fillrect(float x, float y, float w, float h, int r, int g, int b, int a)
194 {
195 #ifndef NOOPENGL
196   if(use_gl)
197     {
198       glEnable(GL_BLEND);
199       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
200       glColor4ub(r, g, b,a);
201
202       glBegin(GL_POLYGON);
203       glVertex2f(x, y);
204       glVertex2f(x+w, y);
205       glVertex2f(x+w, y+h);
206       glVertex2f(x, y+h);
207       glEnd();
208       glDisable(GL_BLEND);
209     }
210   else
211     {
212 #endif
213       SDL_Rect src, rect;
214       SDL_Surface *temp = NULL;
215
216       rect.x = (int)x;
217       rect.y = (int)y;
218       rect.w = (int)w;
219       rect.h = (int)h;
220
221       if(a != 255)
222         {
223           temp = SDL_CreateRGBSurface(screen->flags, rect.w, rect.h, screen->format->BitsPerPixel,
224                                       screen->format->Rmask,
225                                       screen->format->Gmask,
226                                       screen->format->Bmask,
227                                       screen->format->Amask);
228
229
230           src.x = 0;
231           src.y = 0;
232           src.w = rect.w;
233           src.h = rect.h;
234
235           SDL_FillRect(temp, &src, SDL_MapRGB(screen->format, r, g, b));
236
237           SDL_SetAlpha(temp, SDL_SRCALPHA, a);
238
239           SDL_BlitSurface(temp,0,screen,&rect);
240
241           SDL_FreeSurface(temp);
242         }
243       else
244         SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, r, g, b));
245
246 #ifndef NOOPENGL
247
248     }
249 #endif
250 }
251
252
253 /* --- UPDATE SCREEN --- */
254
255 void updatescreen(void)
256 {
257   if(use_gl)  /*clearscreen(0,0,0);*/
258     SDL_GL_SwapBuffers();
259   else
260     SDL_UpdateRect(screen, 0, 0, screen->w, screen->h);
261 }
262
263 void flipscreen(void)
264 {
265   if(use_gl)
266     SDL_GL_SwapBuffers();
267   else
268     SDL_Flip(screen);
269 }
270
271 /* --- LOAD AN IMAGE --- */
272
273 SDL_Surface * load_image(char * file, int use_alpha)
274 {
275   /*
276   if(!faccessible(file))
277   {
278   if(!faccessible(st_dir,
279   */
280
281   SDL_Surface * temp, * surf;
282
283   temp = IMG_Load(file);
284
285   if (temp == NULL)
286     st_abort("Can't load", file);
287
288   surf = SDL_DisplayFormatAlpha(temp);
289
290   if (surf == NULL)
291     st_abort("Can't covert to display format", file);
292
293   if (use_alpha == IGNORE_ALPHA)
294     SDL_SetAlpha(surf, 0, 0);
295
296   SDL_FreeSurface(temp);
297
298   return(surf);
299 }
300
301 void update_rect(SDL_Surface *scr, Sint32 x, Sint32 y, Sint32 w, Sint32 h)
302 {
303   if(!use_gl)
304     SDL_UpdateRect(scr, x, y, w, h);
305 }
306
307
308 /* --- ERASE TEXT: --- */
309
310 void erasetext(char * text, int x, int y, texture_type * ptexture, int update, int shadowsize)
311 {
312   SDL_Rect dest;
313
314
315   dest.x = x;
316   dest.y = y;
317   dest.w = strlen(text) * 16 + shadowsize;
318   dest.h = 17;
319
320   if (dest.w > screen->w)
321     dest.w = screen->w;
322
323   texture_draw_part(ptexture,dest.x,dest.y,dest.x,dest.y,dest.w,dest.h,update);
324
325   if (update == UPDATE)
326     update_rect(screen, dest.x, dest.y, dest.w, dest.h);
327 }
328
329
330 /* --- ERASE CENTERED TEXT: --- */
331
332 void erasecenteredtext(char * text, int y, texture_type * ptexture, int update, int shadowsize)
333 {
334   erasetext(text, screen->w / 2 - (strlen(text) * 8), y, ptexture, update, shadowsize);
335 }