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