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