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