I allways noticed that in the SDL mode, the gradient was sometimes different than...
[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(screen->w, 0);
76       glColor3ub(bot_clr.red, bot_clr.green, bot_clr.blue);
77       glVertex2f(screen->w, screen->h);
78       glVertex2f(0, screen->h);
79       glEnd();
80     }
81   else
82   {
83 #endif
84
85 //void fillrect(float x, float y, float w, float h, int r, int g, int b, int a)
86
87     for(float y = 0; y < screen->h; y += 2)
88       fillrect(0, (int)y, screen->w, 2,
89        (int)(((float)(top_clr.red-bot_clr.red)/(0-screen->h)) * y + top_clr.red),
90        (int)(((float)(top_clr.green-bot_clr.green)/(0-screen->h)) * y + top_clr.green),
91        (int)(((float)(top_clr.blue-bot_clr.blue)/(0-screen->h)) * y + top_clr.blue),
92        255);
93 /* calculates the color for each line, based in the generic equation for functions: y = mx + b */
94
95 #ifndef NOOPENGL
96
97     }
98 #endif
99 }
100
101 /* --- FADE IN --- */
102
103 /** Fades the given surface into a black one. If fade_out is true, it will fade out, else
104 it will fade in */
105
106 void fade(Surface *surface, int seconds, bool fade_out);
107
108 void fade(const std::string& surface, int seconds, bool fade_out)
109 {
110 Surface* sur = new Surface(datadir + surface, IGNORE_ALPHA);
111 fade(sur, seconds, fade_out);
112 delete sur;
113 }
114
115 void fade(Surface *surface, int seconds, bool fade_out)
116 {
117 float alpha;
118 if (fade_out)
119   alpha = 0;
120 else
121   alpha = 255;
122
123   int cur_time, old_time;
124   cur_time = SDL_GetTicks();
125
126   while(alpha >= 0 && alpha < 256)
127     {
128     surface->draw(0,0,(int)alpha);
129     flipscreen();
130
131     old_time = cur_time;
132     cur_time = SDL_GetTicks();
133
134     /* Calculate the next alpha value */
135     float calc = (float) ((cur_time - old_time) / seconds);
136     if(fade_out)
137       alpha += 255 * calc;
138     else
139       alpha -= 255 * calc;
140     }
141 }
142
143 /* 'Stolen' from the SDL documentation.
144  * Set the pixel at (x, y) to the given value
145  * NOTE: The surface must be locked before calling this!
146  */
147 void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
148 {
149   int bpp = surface->format->BytesPerPixel;
150   /* Here p is the address to the pixel we want to set */
151   Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
152
153   switch(bpp)
154     {
155     case 1:
156       *p = pixel;
157       break;
158
159     case 2:
160       *(Uint16 *)p = pixel;
161       break;
162
163     case 3:
164       if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
165         {
166           p[0] = (pixel >> 16) & 0xff;
167           p[1] = (pixel >> 8) & 0xff;
168           p[2] = pixel & 0xff;
169         }
170       else
171         {
172           p[0] = pixel & 0xff;
173           p[1] = (pixel >> 8) & 0xff;
174           p[2] = (pixel >> 16) & 0xff;
175         }
176       break;
177
178     case 4:
179       *(Uint32 *)p = pixel;
180       break;
181     }
182 }
183
184 /* Draw a single pixel on the screen. */
185 void drawpixel(int x, int y, Uint32 pixel)
186 {
187   /* Lock the screen for direct access to the pixels */
188   if ( SDL_MUSTLOCK(screen) )
189     {
190       if ( SDL_LockSurface(screen) < 0 )
191         {
192           fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());
193           return;
194         }
195     }
196
197   if(!(x < 0 || y < 0 || x > screen->w || y > screen->h))
198     putpixel(screen, x, y, pixel);
199
200   if ( SDL_MUSTLOCK(screen) )
201     {
202       SDL_UnlockSurface(screen);
203     }
204   /* Update just the part of the display that we've changed */
205   SDL_UpdateRect(screen, x, y, 1, 1);
206 }
207
208 void drawline(int x1, int y1, int x2, int y2, int r, int g, int b, int a)
209 {
210 #ifndef NOOPENGL
211   if(use_gl)
212     {
213       glEnable(GL_BLEND);
214       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
215       glColor4ub(r, g, b,a);
216
217       glBegin(GL_LINES);
218       glVertex2f(x1, y1);
219       glVertex2f(x2, y2);
220       glEnd();
221       glDisable(GL_BLEND);
222     }
223   else
224     {
225 #endif
226
227       /* Basic unantialiased Bresenham line algorithm */
228       int lg_delta, sh_delta, cycle, lg_step, sh_step;
229       Uint32 color = SDL_MapRGBA(screen->format, r, g, b, a);
230
231       lg_delta = x2 - x1;
232       sh_delta = y2 - y1;
233       lg_step = SGN(lg_delta);
234       lg_delta = ABS(lg_delta);
235       sh_step = SGN(sh_delta);
236       sh_delta = ABS(sh_delta);
237       if (sh_delta < lg_delta)
238         {
239           cycle = lg_delta >> 1;
240           while (x1 != x2)
241             {
242               drawpixel(x1, y1, color);
243               cycle += sh_delta;
244               if (cycle > lg_delta)
245                 {
246                   cycle -= lg_delta;
247                   y1 += sh_step;
248                 }
249               x1 += lg_step;
250             }
251           drawpixel(x1, y1, color);
252         }
253       cycle = sh_delta >> 1;
254       while (y1 != y2)
255         {
256           drawpixel(x1, y1, color);
257           cycle += lg_delta;
258           if (cycle > sh_delta)
259             {
260               cycle -= sh_delta;
261               x1 += lg_step;
262             }
263           y1 += sh_step;
264         }
265       drawpixel(x1, y1, color);
266 #ifndef NOOPENGL
267
268     }
269 #endif
270 }
271
272 /* --- FILL A RECT --- */
273
274 void fillrect(float x, float y, float w, float h, int r, int g, int b, int a)
275 {
276 if(w < 0)
277         {
278         x += w;
279         w = -w;
280         }
281 if(h < 0)
282         {
283         y += h;
284         h = -h;
285         }
286
287 #ifndef NOOPENGL
288   if(use_gl)
289     {
290       glEnable(GL_BLEND);
291       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
292       glColor4ub(r, g, b,a);
293
294       glBegin(GL_POLYGON);
295       glVertex2f(x, y);
296       glVertex2f(x+w, y);
297       glVertex2f(x+w, y+h);
298       glVertex2f(x, y+h);
299       glEnd();
300       glDisable(GL_BLEND);
301     }
302   else
303     {
304 #endif
305       SDL_Rect src, rect;
306       SDL_Surface *temp = NULL;
307
308       rect.x = (int)x;
309       rect.y = (int)y;
310       rect.w = (int)w;
311       rect.h = (int)h;
312
313       if(a != 255)
314         {
315           temp = SDL_CreateRGBSurface(screen->flags, rect.w, rect.h, screen->format->BitsPerPixel,
316                                       screen->format->Rmask,
317                                       screen->format->Gmask,
318                                       screen->format->Bmask,
319                                       screen->format->Amask);
320
321
322           src.x = 0;
323           src.y = 0;
324           src.w = rect.w;
325           src.h = rect.h;
326
327           SDL_FillRect(temp, &src, SDL_MapRGB(screen->format, r, g, b));
328
329           SDL_SetAlpha(temp, SDL_SRCALPHA, a);
330
331           SDL_BlitSurface(temp,0,screen,&rect);
332
333           SDL_FreeSurface(temp);
334         }
335       else
336         SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, r, g, b));
337
338 #ifndef NOOPENGL
339
340     }
341 #endif
342 }
343
344
345 /* --- UPDATE SCREEN --- */
346
347 void updatescreen(void)
348 {
349   if(use_gl)  /*clearscreen(0,0,0);*/
350     SDL_GL_SwapBuffers();
351   else
352     SDL_UpdateRect(screen, 0, 0, screen->w, screen->h);
353 }
354
355 void flipscreen(void)
356 {
357   if(use_gl)
358     SDL_GL_SwapBuffers();
359   else
360     SDL_Flip(screen);
361 }
362
363 void fadeout()
364 {
365   clearscreen(0, 0, 0);
366   white_text->draw_align("Loading...", screen->w/2, screen->h/2, A_HMIDDLE, A_TOP);
367   flipscreen();
368 }
369
370 void update_rect(SDL_Surface *scr, Sint32 x, Sint32 y, Sint32 w, Sint32 h)
371 {
372   if(!use_gl)
373     SDL_UpdateRect(scr, x, y, w, h);
374 }
375