Had to change the #includes of dependend headers from "dir/header.h" to "../dir...
[supertux.git] / lib / video / 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 <cstdio>
22 #include <cstdlib>
23 #include <cstring>
24 #include <cerrno>
25
26 #include <unistd.h>
27
28 #include "SDL.h"
29 #include "SDL_image.h"
30
31 #ifndef WIN32
32 #include <sys/types.h>
33 #include <ctype.h>
34 #endif
35
36 #include "../video/screen.h"
37 #include "../app/globals.h"
38 #include "../video/drawing_context.h"
39 #include "../special/base.h"
40 #include "../math/vector.h"
41
42 using namespace SuperTux;
43
44 /* 'Stolen' from the SDL documentation.
45  * Set the pixel at (x, y) to the given value
46  * NOTE: The surface must be locked before calling this!
47  */
48 void SuperTux::putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
49 {
50   int bpp = surface->format->BytesPerPixel;
51   /* Here p is the address to the pixel we want to set */
52   Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
53
54   switch(bpp)
55     {
56     case 1:
57       *p = pixel;
58       break;
59
60     case 2:
61       *(Uint16 *)p = pixel;
62       break;
63
64     case 3:
65       if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
66         {
67           p[0] = (pixel >> 16) & 0xff;
68           p[1] = (pixel >> 8) & 0xff;
69           p[2] = pixel & 0xff;
70         }
71       else
72         {
73           p[0] = pixel & 0xff;
74           p[1] = (pixel >> 8) & 0xff;
75           p[2] = (pixel >> 16) & 0xff;
76         }
77       break;
78
79     case 4:
80       *(Uint32 *)p = pixel;
81       break;
82     }
83 }
84
85 /* Draw a single pixel on the screen. */
86 void SuperTux::drawpixel(int x, int y, Uint32 pixel)
87 {
88   /* Lock the screen for direct access to the pixels */
89   if ( SDL_MUSTLOCK(screen) )
90     {
91       if ( SDL_LockSurface(screen) < 0 )
92         {
93           fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());
94           return;
95         }
96     }
97
98   if(!(x < 0 || y < 0 || x > screen->w || y > screen->h))
99     putpixel(screen, x, y, pixel);
100
101   if ( SDL_MUSTLOCK(screen) )
102     {
103       SDL_UnlockSurface(screen);
104     }
105   /* Update just the part of the display that we've changed */
106   SDL_UpdateRect(screen, x, y, 1, 1);
107 }
108
109 /* --- FILL A RECT --- */
110
111 void SuperTux::fillrect(float x, float y, float w, float h, int r, int g, int b, int a)
112 {
113 if(w < 0)
114         {
115         x += w;
116         w = -w;
117         }
118 if(h < 0)
119         {
120         y += h;
121         h = -h;
122         }
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_POLYGON);
132       glVertex2f(x, y);
133       glVertex2f(x+w, y);
134       glVertex2f(x+w, y+h);
135       glVertex2f(x, y+h);
136       glEnd();
137       glDisable(GL_BLEND);
138     }
139   else
140     {
141 #endif
142       SDL_Rect src, rect;
143       SDL_Surface *temp = NULL;
144
145       rect.x = (int)x;
146       rect.y = (int)y;
147       rect.w = (int)w;
148       rect.h = (int)h;
149
150       if(a != 255)
151         {
152           temp = SDL_CreateRGBSurface(screen->flags, rect.w, rect.h, screen->format->BitsPerPixel,
153                                       screen->format->Rmask,
154                                       screen->format->Gmask,
155                                       screen->format->Bmask,
156                                       screen->format->Amask);
157
158
159           src.x = 0;
160           src.y = 0;
161           src.w = rect.w;
162           src.h = rect.h;
163
164           SDL_FillRect(temp, &src, SDL_MapRGB(screen->format, r, g, b));
165
166           SDL_SetAlpha(temp, SDL_SRCALPHA, a);
167
168           SDL_BlitSurface(temp,0,screen,&rect);
169
170           SDL_FreeSurface(temp);
171         }
172       else
173         SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, r, g, b));
174
175 #ifndef NOOPENGL
176
177     }
178 #endif
179 }
180
181 /* Needed for line calculations */
182 #define SGN(x) ((x)>0 ? 1 : ((x)==0 ? 0:(-1)))
183 #define ABS(x) ((x)>0 ? (x) : (-x))
184
185 void SuperTux::draw_line(float x1, float y1, float x2, float y2, int r, int g, int b, int a)
186 {
187 #ifndef NOOPENGL
188   if(use_gl)
189     {
190       glEnable(GL_BLEND);
191       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
192       glColor4ub(r, g, b,a);
193
194       glBegin(GL_LINES);
195       glVertex2f(x1, y1);
196       glVertex2f(x2, y2);
197       glEnd();
198       glDisable(GL_BLEND);
199     }
200   else
201     {
202 #endif
203       /* Basic unantialiased Bresenham line algorithm */
204       int lg_delta, sh_delta, cycle, lg_step, sh_step;
205       Uint32 color = SDL_MapRGBA(screen->format, r, g, b, a);
206
207       lg_delta = (int)(x2 - x1);
208       sh_delta = (int)(y2 - y1);
209       lg_step = SGN(lg_delta);
210       lg_delta = ABS(lg_delta);
211       sh_step = SGN(sh_delta);
212       sh_delta = ABS(sh_delta);
213       if (sh_delta < lg_delta)
214         {
215           cycle = lg_delta >> 1;
216           while (x1 != x2)
217             {
218               drawpixel((int)x1, (int)y1, color);
219               cycle += sh_delta;
220               if (cycle > lg_delta)
221                 {
222                   cycle -= lg_delta;
223                   y1 += sh_step;
224                 }
225               x1 += lg_step;
226             }
227           drawpixel((int)x1, (int)y1, color);
228         }
229       cycle = sh_delta >> 1;
230       while (y1 != y2)
231         {
232           drawpixel((int)x1, (int)y1, color);
233           cycle += lg_delta;
234           if (cycle > sh_delta)
235             {
236               cycle -= sh_delta;
237               x1 += lg_step;
238             }
239           y1 += sh_step;
240         }
241       drawpixel((int)x1, (int)y1, color);
242 #ifndef NOOPENGL
243
244     }
245 #endif
246 }
247
248 #define LOOP_DELAY 20.0
249
250 void SuperTux::fadeout(int fade_time)
251 {
252   float alpha_inc  = 256 / (fade_time / LOOP_DELAY);
253   float alpha = 256;
254
255   while(alpha > 0)
256     {
257     alpha -= alpha_inc;
258     fillrect(0, 0, screen->w, screen->h, 0,0,0, (int)alpha_inc);  // left side
259                                                    
260     DrawingContext context; // ugly...
261     context.do_drawing();
262
263     SDL_Delay(int(LOOP_DELAY));
264     }
265
266   fillrect(0, 0, screen->w, screen->h, 0, 0, 0, 255);
267   
268   DrawingContext context;
269   context.draw_text_center(white_text, "Loading...",
270       Vector(0, screen->h/2), LAYER_FOREGROUND1);
271   context.do_drawing();
272 }
273
274 void SuperTux::shrink_fade(const Vector& point, int fade_time)
275 {
276   float left_inc  = point.x / ((float)fade_time / LOOP_DELAY);
277   float right_inc = (screen->w - point.x) / ((float)fade_time / LOOP_DELAY);
278   float up_inc    = point.y / ((float)fade_time / LOOP_DELAY);
279   float down_inc  = (screen->h - point.y) / ((float)fade_time / LOOP_DELAY);
280                                                                                 
281   float left_cor = 0, right_cor = 0, up_cor = 0, down_cor = 0;
282                                                                                 
283   while(left_cor < point.x && right_cor < screen->w - point.x &&
284       up_cor < point.y && down_cor < screen->h - point.y)
285   {
286     left_cor  += left_inc;
287     right_cor += right_inc;
288     up_cor    += up_inc;
289     down_cor  += down_inc;
290                                                                                 
291     fillrect(0, 0, left_cor, screen->h, 0,0,0);  // left side
292     fillrect(screen->w - right_cor, 0, right_cor, screen->h, 0,0,0);  // right side
293     fillrect(0, 0, screen->w, up_cor, 0,0,0);  // up side
294     fillrect(0, screen->h - down_cor, screen->w, down_cor+1, 0,0,0);  // down side                                                                                
295     DrawingContext context; // ugly...
296     context.do_drawing();
297     
298     SDL_Delay(int(LOOP_DELAY));
299   }
300 }
301