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