- replaced #ifdef LINUX with #ifndef WIN32, should be easier to handle for other...
[supertux.git] / src / screen.cpp
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 - March 15, 2004
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 #ifndef WIN32
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 /* --- CLEAR SCREEN --- */
38
39 void clearscreen(int r, int g, int b)
40 {
41 #ifndef NOOPENGL
42   if(use_gl)
43     {
44       glClearColor(r/256, g/256, b/256, 1.0);
45       glClear(GL_COLOR_BUFFER_BIT);
46     }
47   else
48   {
49 #endif
50
51     SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, r, g, b));
52 #ifndef NOOPENGL
53
54     }
55 #endif
56 }
57
58 /* 'Stolen' from the SDL documentation.
59  * Set the pixel at (x, y) to the given value
60  * NOTE: The surface must be locked before calling this!
61  */
62 void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
63 {
64   int bpp = surface->format->BytesPerPixel;
65   /* Here p is the address to the pixel we want to set */
66   Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
67
68   switch(bpp)
69     {
70     case 1:
71       *p = pixel;
72       break;
73
74     case 2:
75       *(Uint16 *)p = pixel;
76       break;
77
78     case 3:
79       if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
80         {
81           p[0] = (pixel >> 16) & 0xff;
82           p[1] = (pixel >> 8) & 0xff;
83           p[2] = pixel & 0xff;
84         }
85       else
86         {
87           p[0] = pixel & 0xff;
88           p[1] = (pixel >> 8) & 0xff;
89           p[2] = (pixel >> 16) & 0xff;
90         }
91       break;
92
93     case 4:
94       *(Uint32 *)p = pixel;
95       break;
96     }
97 }
98
99 /* Draw a single pixel on the screen. */
100 void drawpixel(int x, int y, Uint32 pixel)
101 {
102   /* Lock the screen for direct access to the pixels */
103   if ( SDL_MUSTLOCK(screen) )
104     {
105       if ( SDL_LockSurface(screen) < 0 )
106         {
107           fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());
108           return;
109         }
110     }
111
112   if(!(x < 0 || y < 0 || x > screen->w || y > screen->h))
113     putpixel(screen, x, y, pixel);
114
115   if ( SDL_MUSTLOCK(screen) )
116     {
117       SDL_UnlockSurface(screen);
118     }
119   /* Update just the part of the display that we've changed */
120   SDL_UpdateRect(screen, x, y, 1, 1);
121 }
122
123 void drawline(int x1, int y1, int x2, int y2, int r, int g, int b, int a)
124 {
125 #ifndef NOOPENGL
126   if(use_gl)
127     {
128       glEnable(GL_BLEND);
129       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
130       glColor4ub(r, g, b,a);
131
132       glBegin(GL_LINES);
133       glVertex2f(x1, y1);
134       glVertex2f(x2, y2);
135       glEnd();
136       glDisable(GL_BLEND);
137     }
138   else
139     {
140 #endif
141
142       /* Basic unantialiased Bresenham line algorithm */
143       int lg_delta, sh_delta, cycle, lg_step, sh_step;
144       Uint32 color = SDL_MapRGBA(screen->format, r, g, b, a);
145
146       lg_delta = x2 - x1;
147       sh_delta = y2 - y1;
148       lg_step = SGN(lg_delta);
149       lg_delta = ABS(lg_delta);
150       sh_step = SGN(sh_delta);
151       sh_delta = ABS(sh_delta);
152       if (sh_delta < lg_delta)
153         {
154           cycle = lg_delta >> 1;
155           while (x1 != x2)
156             {
157               drawpixel(x1, y1, color);
158               cycle += sh_delta;
159               if (cycle > lg_delta)
160                 {
161                   cycle -= lg_delta;
162                   y1 += sh_step;
163                 }
164               x1 += lg_step;
165             }
166           drawpixel(x1, y1, color);
167         }
168       cycle = sh_delta >> 1;
169       while (y1 != y2)
170         {
171           drawpixel(x1, y1, color);
172           cycle += lg_delta;
173           if (cycle > sh_delta)
174             {
175               cycle -= sh_delta;
176               x1 += lg_step;
177             }
178           y1 += sh_step;
179         }
180       drawpixel(x1, y1, color);
181 #ifndef NOOPENGL
182
183     }
184 #endif
185 }
186
187 /* --- FILL A RECT --- */
188
189 void fillrect(float x, float y, float w, float h, int r, int g, int b, int a)
190 {
191 if(w < 0)
192         {
193         x += w;
194         w = -w;
195         }
196 if(h < 0)
197         {
198         y += h;
199         h = -h;
200         }
201
202 #ifndef NOOPENGL
203   if(use_gl)
204     {
205       glEnable(GL_BLEND);
206       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
207       glColor4ub(r, g, b,a);
208
209       glBegin(GL_POLYGON);
210       glVertex2f(x, y);
211       glVertex2f(x+w, y);
212       glVertex2f(x+w, y+h);
213       glVertex2f(x, y+h);
214       glEnd();
215       glDisable(GL_BLEND);
216     }
217   else
218     {
219 #endif
220       SDL_Rect src, rect;
221       SDL_Surface *temp = NULL;
222
223       rect.x = (int)x;
224       rect.y = (int)y;
225       rect.w = (int)w;
226       rect.h = (int)h;
227
228       if(a != 255)
229         {
230           temp = SDL_CreateRGBSurface(screen->flags, rect.w, rect.h, screen->format->BitsPerPixel,
231                                       screen->format->Rmask,
232                                       screen->format->Gmask,
233                                       screen->format->Bmask,
234                                       screen->format->Amask);
235
236
237           src.x = 0;
238           src.y = 0;
239           src.w = rect.w;
240           src.h = rect.h;
241
242           SDL_FillRect(temp, &src, SDL_MapRGB(screen->format, r, g, b));
243
244           SDL_SetAlpha(temp, SDL_SRCALPHA, a);
245
246           SDL_BlitSurface(temp,0,screen,&rect);
247
248           SDL_FreeSurface(temp);
249         }
250       else
251         SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, r, g, b));
252
253 #ifndef NOOPENGL
254
255     }
256 #endif
257 }
258
259
260 /* --- UPDATE SCREEN --- */
261
262 void updatescreen(void)
263 {
264   if(use_gl)  /*clearscreen(0,0,0);*/
265     SDL_GL_SwapBuffers();
266   else
267     SDL_UpdateRect(screen, 0, 0, screen->w, screen->h);
268 }
269
270 void flipscreen(void)
271 {
272   if(use_gl)
273     SDL_GL_SwapBuffers();
274   else
275     SDL_Flip(screen);
276 }
277
278 void update_rect(SDL_Surface *scr, Sint32 x, Sint32 y, Sint32 w, Sint32 h)
279 {
280   if(!use_gl)
281     SDL_UpdateRect(scr, x, y, w, h);
282 }
283