Added an alpha parameter for transformation and got rid of ugly alpha draw_font(...
[supertux.git] / lib / video / drawing_context.cpp
1 //  $Id$
2 //
3 //  SuperTux -  A Jump'n Run
4 //  Copyright (C) 2004 Matthias Braun <matze@braunis.de
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 #include <algorithm>
20 #include <cassert>
21 #include <iostream>
22
23 #include "../video/drawing_context.h"
24 #include "../video/surface.h"
25 #include "../app/globals.h"
26 #include "../video/font.h"
27
28 using namespace SuperTux;
29
30 DrawingContext::DrawingContext()
31 {
32 transform.draw_effect = NONE_EFFECT;
33 transform.zoom = 1;
34 transform.alpha = 255;
35 }
36
37 DrawingContext::~DrawingContext()
38 {
39 }
40
41 void
42 DrawingContext::draw_surface(const Surface* surface, const Vector& position,
43     int layer, Uint32 drawing_effect)
44 {
45   assert(surface != 0);
46   
47   DrawingRequest request;
48
49   request.type = SURFACE;
50   request.layer = layer;
51   request.request_data = const_cast<Surface*> (surface);
52   request.pos = transform.apply(position);
53   request.drawing_effect = drawing_effect;
54   request.drawing_effect = transform.draw_effect | drawing_effect;
55   request.zoom = transform.zoom;
56   request.alpha = transform.alpha;
57
58   drawingrequests.push_back(request);
59 }
60
61 void
62 DrawingContext::draw_surface_part(const Surface* surface, const Vector& source,
63     const Vector& size, const Vector& dest, int layer, Uint32 drawing_effect)
64 {
65   assert(surface != 0);
66
67   DrawingRequest request;
68
69   request.type = SURFACE_PART;
70   request.layer = layer;
71   request.pos = transform.apply(dest);
72   request.drawing_effect = drawing_effect;
73   request.alpha = transform.alpha;
74   
75   SurfacePartRequest* surfacepartrequest = new SurfacePartRequest();
76   surfacepartrequest->size = size;
77   surfacepartrequest->source = source;
78   surfacepartrequest->surface = surface;
79   request.request_data = surfacepartrequest;
80
81   drawingrequests.push_back(request);
82 }
83
84 void
85 DrawingContext::draw_text(Font* font, const std::string& text,
86     const Vector& position, int allignment, int layer,
87     Uint32 drawing_effect)
88 {
89   DrawingRequest request;
90
91   request.type = TEXT;
92   request.layer = layer;
93   request.pos = transform.apply(position);
94   request.drawing_effect = drawing_effect;
95   request.alpha = transform.alpha;
96
97   TextRequest* textrequest = new TextRequest;
98   textrequest->font = font;
99   textrequest->text = text;
100   textrequest->allignment = allignment;
101   request.request_data = textrequest;
102
103   drawingrequests.push_back(request);
104 }
105
106 void
107 DrawingContext::draw_gradient(Color top, Color bottom, int layer)
108 {
109   DrawingRequest request;
110
111   request.type = GRADIENT;
112   request.layer = layer;
113   request.pos = Vector(0,0);
114
115   GradientRequest* gradientrequest = new GradientRequest;
116   gradientrequest->top = top;
117   gradientrequest->bottom = bottom;
118   request.request_data = gradientrequest;
119
120   drawingrequests.push_back(request);
121 }
122
123 void
124 DrawingContext::draw_filled_rect(const Vector& topleft, const Vector& size,
125         Color color, int layer)
126 {
127   DrawingRequest request;
128
129   request.type = FILLRECT;
130   request.layer = layer;
131   request.pos = transform.apply(topleft);
132
133   FillRectRequest* fillrectrequest = new FillRectRequest;
134   fillrectrequest->size = size;
135   fillrectrequest->color = color;
136   request.request_data = fillrectrequest;
137
138   drawingrequests.push_back(request);
139 }
140
141 void
142 DrawingContext::draw_surface_part(DrawingRequest& request)
143 {
144   SurfacePartRequest* surfacepartrequest
145     = (SurfacePartRequest*) request.request_data;
146
147   surfacepartrequest->surface->impl->draw_part(
148       surfacepartrequest->source.x, surfacepartrequest->source.y,
149       request.pos.x, request.pos.y,
150       surfacepartrequest->size.x, surfacepartrequest->size.y, request.alpha,
151       request.drawing_effect);
152
153   delete surfacepartrequest;
154 }
155
156 void
157 DrawingContext::draw_gradient(DrawingRequest& request)
158 {
159   GradientRequest* gradientrequest = (GradientRequest*) request.request_data;
160   const Color& top = gradientrequest->top;
161   const Color& bottom = gradientrequest->bottom;
162   
163 #ifndef NOOPENGL
164   if(use_gl)
165     {
166       glBegin(GL_QUADS);
167       glColor3ub(top.red, top.green, top.blue);
168       glVertex2f(0, 0);
169       glVertex2f(screen->w, 0);
170       glColor3ub(bottom.red, bottom.green, bottom.blue);
171       glVertex2f(screen->w, screen->h);
172       glVertex2f(0, screen->h);
173       glEnd();
174     }
175   else
176   {
177 #endif
178     if(&top == &bottom)
179       {
180       fillrect(0, 0, screen->w, screen->h, top.red, top.green, top.blue);
181       }
182     else
183       {
184       float redstep = (float(bottom.red)-float(top.red)) / float(screen->h);
185       float greenstep = (float(bottom.green)-float(top.green)) / float(screen->h);
186       float bluestep = (float(bottom.blue) - float(top.blue)) / float(screen->h);
187
188       for(float y = 0; y < screen->h; y += 2)
189         fillrect(0, (int)y, screen->w, 2,
190             int(float(top.red) + redstep * y),
191             int(float(top.green) + greenstep * y),
192             int(float(top.blue) + bluestep * y), 255);
193       }
194 #ifndef NOOPENGL
195
196     }
197 #endif
198
199   delete gradientrequest;
200 }
201
202 void
203 DrawingContext::draw_text(DrawingRequest& request)
204 {
205   TextRequest* textrequest = (TextRequest*) request.request_data;
206
207   textrequest->font->draw(textrequest->text, request.pos, textrequest->allignment, request.drawing_effect, request.alpha);
208
209   delete textrequest;
210 }
211
212 void
213 DrawingContext::draw_filled_rect(DrawingRequest& request)
214 {
215   FillRectRequest* fillrectrequest = (FillRectRequest*) request.request_data;
216
217   float x = request.pos.x;
218   float y = request.pos.y;
219   float w = fillrectrequest->size.x;
220   float h = fillrectrequest->size.y;
221
222 #ifndef NOOPENGL
223   if(use_gl)
224     {
225       glEnable(GL_BLEND);
226       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
227       glColor4ub(fillrectrequest->color.red, fillrectrequest->color.green,
228           fillrectrequest->color.blue, fillrectrequest->color.alpha);
229
230       glBegin(GL_POLYGON);
231       glVertex2f(x, y);
232       glVertex2f(x+w, y);
233       glVertex2f(x+w, y+h);
234       glVertex2f(x, y+h);
235       glEnd();
236       glDisable(GL_BLEND);
237     }
238   else
239     {
240 #endif
241       SDL_Rect src, rect;
242       SDL_Surface *temp = NULL;
243                                                                                 
244       rect.x = (int)x;
245       rect.y = (int)y;
246       rect.w = (int)w;
247       rect.h = (int)h;
248                                                                                 
249       if(fillrectrequest->color.alpha != 255)
250         {
251           temp = SDL_CreateRGBSurface(screen->flags, rect.w, rect.h, screen->format->BitsPerPixel,
252                                       screen->format->Rmask,
253                                       screen->format->Gmask,
254                                       screen->format->Bmask,
255                                       screen->format->Amask);
256                                                                                 
257                                                                                 
258           src.x = 0;
259           src.y = 0;
260           src.w = rect.w;
261           src.h = rect.h;
262                                                                                 
263           SDL_FillRect(temp, &src, SDL_MapRGB(screen->format, 
264                 fillrectrequest->color.red, fillrectrequest->color.green,
265                 fillrectrequest->color.blue));
266                                                                                 
267           SDL_SetAlpha(temp, SDL_SRCALPHA, fillrectrequest->color.alpha);
268                                                                                 
269           SDL_BlitSurface(temp,0,screen,&rect);
270                                                                                 
271           SDL_FreeSurface(temp);
272         }
273       else
274         SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, 
275               fillrectrequest->color.red, fillrectrequest->color.green,
276               fillrectrequest->color.blue));
277                                                                                 
278 #ifndef NOOPENGL
279                                                                                 
280     }
281 #endif
282
283   delete fillrectrequest;
284 }
285
286 void
287 DrawingContext::do_drawing()
288 {
289   std::stable_sort(drawingrequests.begin(), drawingrequests.end());
290
291   for(DrawingRequests::iterator i = drawingrequests.begin();
292       i != drawingrequests.end(); ++i) {
293     switch(i->type) {
294       case SURFACE:
295       {
296         const Surface* surface = (const Surface*) i->request_data;
297
298         if(i->zoom != 1.0)
299           surface->impl->draw_stretched(i->pos.x * i->zoom, i->pos.y * i->zoom,
300                          (int)(surface->w * i->zoom), (int)(surface->h * i->zoom),
301                          i->alpha, i->drawing_effect);
302         else
303           surface->impl->draw(i->pos.x, i->pos.y, i->alpha, i->drawing_effect);
304         break;
305       }
306       case SURFACE_PART:
307         draw_surface_part(*i);
308         break;
309       case GRADIENT:
310         draw_gradient(*i);
311         break;
312       case TEXT:
313         draw_text(*i);
314         break;
315       case FILLRECT:
316         draw_filled_rect(*i);
317         break;
318     }
319   }
320
321   // update screen
322   if(use_gl)
323     SDL_GL_SwapBuffers();
324   else
325     SDL_Flip(screen);
326
327   drawingrequests.clear();
328 }
329
330 void
331 DrawingContext::push_transform()
332 {
333   transformstack.push_back(transform);
334 }
335
336 void
337 DrawingContext::pop_transform()
338 {
339   assert(!transformstack.empty());
340
341   transform = transformstack.back();
342   transformstack.pop_back();
343 }
344
345 void
346 DrawingContext::set_drawing_effect(int effect)
347 {
348   transform.draw_effect = effect;
349 }
350
351 void
352 DrawingContext::set_zooming(float zoom)
353 {
354   transform.zoom = zoom;
355 }
356
357 void
358 DrawingContext::set_alpha(int alpha)
359 {
360   transform.alpha = alpha;
361 }