Improved the CREDITS a little bit:
[supertux.git] / src / screen.cpp
1 //  $Id$
2 //
3 //  SuperTux -  A Jump'n Run
4 //  Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 2
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program 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 this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19
20 #include <iostream>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <SDL.h>
27 #include <SDL_image.h>
28
29 #ifndef WIN32
30 #include <sys/types.h>
31 #include <ctype.h>
32 #endif
33
34 #include "defines.h"
35 #include "globals.h"
36 #include "screen.h"
37 #include "setup.h"
38 #include "type.h"
39
40 /* Needed for line calculations */
41 #define SGN(x) ((x)>0 ? 1 : ((x)==0 ? 0:(-1)))
42 #define ABS(x) ((x)>0 ? (x) : (-x))
43
44 /* --- CLEAR SCREEN --- */
45
46 void clearscreen(int r, int g, int b)
47 {
48 #ifndef NOOPENGL
49   if(use_gl)
50     {
51       glClearColor(r/256, g/256, b/256, 1.0);
52       glClear(GL_COLOR_BUFFER_BIT);
53     }
54   else
55   {
56 #endif
57
58     SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, r, g, b));
59 #ifndef NOOPENGL
60
61     }
62 #endif
63 }
64
65 /* --- DRAWS A VERTICAL GRADIENT --- */
66
67 void drawgradient(Color top_clr, Color bot_clr)
68 {
69 #ifndef NOOPENGL
70   if(use_gl)
71     {
72       glBegin(GL_QUADS);
73       glColor3ub(top_clr.red, top_clr.green, top_clr.blue);
74       glVertex2f(0, 0);
75       glVertex2f(640, 0);
76       glColor3ub(bot_clr.red, bot_clr.green, bot_clr.blue);
77       glVertex2f(640, 480);
78       glVertex2f(0, 480);
79       glEnd();
80     }
81   else
82   {
83 #endif
84
85     for(float y = 0; y < 480; y += 2)
86       fillrect(0, (int)y, 640, 2,
87                      (int)(((float)(top_clr.red-bot_clr.red)/(0-480)) * y + top_clr.red),
88                      (int)(((float)(top_clr.green-bot_clr.green)/(0-480)) * y + top_clr.green),
89                      (int)(((float)(top_clr.blue-bot_clr.blue)/(0-480)) * y + top_clr.blue), 255);
90 /* calculates the color for each line, based in the generic equation for functions: y = mx + b */
91
92 #ifndef NOOPENGL
93
94     }
95 #endif
96 }
97
98 /* 'Stolen' from the SDL documentation.
99  * Set the pixel at (x, y) to the given value
100  * NOTE: The surface must be locked before calling this!
101  */
102 void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
103 {
104   int bpp = surface->format->BytesPerPixel;
105   /* Here p is the address to the pixel we want to set */
106   Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
107
108   switch(bpp)
109     {
110     case 1:
111       *p = pixel;
112       break;
113
114     case 2:
115       *(Uint16 *)p = pixel;
116       break;
117
118     case 3:
119       if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
120         {
121           p[0] = (pixel >> 16) & 0xff;
122           p[1] = (pixel >> 8) & 0xff;
123           p[2] = pixel & 0xff;
124         }
125       else
126         {
127           p[0] = pixel & 0xff;
128           p[1] = (pixel >> 8) & 0xff;
129           p[2] = (pixel >> 16) & 0xff;
130         }
131       break;
132
133     case 4:
134       *(Uint32 *)p = pixel;
135       break;
136     }
137 }
138
139 /* Draw a single pixel on the screen. */
140 void drawpixel(int x, int y, Uint32 pixel)
141 {
142   /* Lock the screen for direct access to the pixels */
143   if ( SDL_MUSTLOCK(screen) )
144     {
145       if ( SDL_LockSurface(screen) < 0 )
146         {
147           fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());
148           return;
149         }
150     }
151
152   if(!(x < 0 || y < 0 || x > screen->w || y > screen->h))
153     putpixel(screen, x, y, pixel);
154
155   if ( SDL_MUSTLOCK(screen) )
156     {
157       SDL_UnlockSurface(screen);
158     }
159   /* Update just the part of the display that we've changed */
160   SDL_UpdateRect(screen, x, y, 1, 1);
161 }
162
163 void drawline(int x1, int y1, int x2, int y2, int r, int g, int b, int a)
164 {
165 #ifndef NOOPENGL
166   if(use_gl)
167     {
168       glEnable(GL_BLEND);
169       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
170       glColor4ub(r, g, b,a);
171
172       glBegin(GL_LINES);
173       glVertex2f(x1, y1);
174       glVertex2f(x2, y2);
175       glEnd();
176       glDisable(GL_BLEND);
177     }
178   else
179     {
180 #endif
181
182       /* Basic unantialiased Bresenham line algorithm */
183       int lg_delta, sh_delta, cycle, lg_step, sh_step;
184       Uint32 color = SDL_MapRGBA(screen->format, r, g, b, a);
185
186       lg_delta = x2 - x1;
187       sh_delta = y2 - y1;
188       lg_step = SGN(lg_delta);
189       lg_delta = ABS(lg_delta);
190       sh_step = SGN(sh_delta);
191       sh_delta = ABS(sh_delta);
192       if (sh_delta < lg_delta)
193         {
194           cycle = lg_delta >> 1;
195           while (x1 != x2)
196             {
197               drawpixel(x1, y1, color);
198               cycle += sh_delta;
199               if (cycle > lg_delta)
200                 {
201                   cycle -= lg_delta;
202                   y1 += sh_step;
203                 }
204               x1 += lg_step;
205             }
206           drawpixel(x1, y1, color);
207         }
208       cycle = sh_delta >> 1;
209       while (y1 != y2)
210         {
211           drawpixel(x1, y1, color);
212           cycle += lg_delta;
213           if (cycle > sh_delta)
214             {
215               cycle -= sh_delta;
216               x1 += lg_step;
217             }
218           y1 += sh_step;
219         }
220       drawpixel(x1, y1, color);
221 #ifndef NOOPENGL
222
223     }
224 #endif
225 }
226
227 /* --- FILL A RECT --- */
228
229 void fillrect(float x, float y, float w, float h, int r, int g, int b, int a)
230 {
231 if(w < 0)
232         {
233         x += w;
234         w = -w;
235         }
236 if(h < 0)
237         {
238         y += h;
239         h = -h;
240         }
241
242 #ifndef NOOPENGL
243   if(use_gl)
244     {
245       glEnable(GL_BLEND);
246       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
247       glColor4ub(r, g, b,a);
248
249       glBegin(GL_POLYGON);
250       glVertex2f(x, y);
251       glVertex2f(x+w, y);
252       glVertex2f(x+w, y+h);
253       glVertex2f(x, y+h);
254       glEnd();
255       glDisable(GL_BLEND);
256     }
257   else
258     {
259 #endif
260       SDL_Rect src, rect;
261       SDL_Surface *temp = NULL;
262
263       rect.x = (int)x;
264       rect.y = (int)y;
265       rect.w = (int)w;
266       rect.h = (int)h;
267
268       if(a != 255)
269         {
270           temp = SDL_CreateRGBSurface(screen->flags, rect.w, rect.h, screen->format->BitsPerPixel,
271                                       screen->format->Rmask,
272                                       screen->format->Gmask,
273                                       screen->format->Bmask,
274                                       screen->format->Amask);
275
276
277           src.x = 0;
278           src.y = 0;
279           src.w = rect.w;
280           src.h = rect.h;
281
282           SDL_FillRect(temp, &src, SDL_MapRGB(screen->format, r, g, b));
283
284           SDL_SetAlpha(temp, SDL_SRCALPHA, a);
285
286           SDL_BlitSurface(temp,0,screen,&rect);
287
288           SDL_FreeSurface(temp);
289         }
290       else
291         SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, r, g, b));
292
293 #ifndef NOOPENGL
294
295     }
296 #endif
297 }
298
299
300 /* --- UPDATE SCREEN --- */
301
302 void updatescreen(void)
303 {
304   if(use_gl)  /*clearscreen(0,0,0);*/
305     SDL_GL_SwapBuffers();
306   else
307     SDL_UpdateRect(screen, 0, 0, screen->w, screen->h);
308 }
309
310 void flipscreen(void)
311 {
312   if(use_gl)
313     SDL_GL_SwapBuffers();
314   else
315     SDL_Flip(screen);
316 }
317
318 void fadeout()
319 {
320   clearscreen(0, 0, 0);
321   white_text->draw_align("Loading...", screen->w/2, screen->h/2, A_HMIDDLE, A_TOP);
322   flipscreen();
323 }
324
325 void update_rect(SDL_Surface *scr, Sint32 x, Sint32 y, Sint32 w, Sint32 h)
326 {
327   if(!use_gl)
328     SDL_UpdateRect(scr, x, y, w, h);
329 }
330