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