2 // Copyright (C) 2006 Matthias Braun <matze@braunis.de>
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "video/drawing_context.hpp"
22 #include "obstack/obstackpp.hpp"
23 #include "supertux/gameconfig.hpp"
24 #include "supertux/main.hpp"
25 #include "video/drawing_request.hpp"
26 #include "video/lightmap.hpp"
27 #include "video/renderer.hpp"
28 #include "video/surface.hpp"
29 #include "video/texture.hpp"
30 #include "video/texture_manager.hpp"
31 #include "video/video_systems.hpp"
33 static inline int next_po2(int val)
42 DrawingContext::DrawingContext() :
43 renderer(0), lightmap(0), ambient_color(1.0f, 1.0f, 1.0f, 1.0f), target(NORMAL), screenshot_requested(false)
45 requests = &drawing_requests;
49 DrawingContext::~DrawingContext()
54 obstack_free(&obst, NULL);
58 DrawingContext::init_renderer()
63 renderer = new_renderer();
64 lightmap = new_lightmap();
68 DrawingContext::draw_surface(const Surface* surface, const Vector& position,
69 float angle, const Color& color, const Blend& blend,
74 DrawingRequest* request = new(obst) DrawingRequest();
76 request->target = target;
77 request->type = SURFACE;
78 request->pos = transform.apply(position);
80 if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT
81 || request->pos.x + surface->get_width() < 0
82 || request->pos.y + surface->get_height() < 0)
85 request->layer = layer;
86 request->drawing_effect = transform.drawing_effect;
87 request->alpha = transform.alpha;
88 request->angle = angle;
89 request->color = color;
90 request->blend = blend;
92 request->request_data = const_cast<Surface*> (surface);
94 requests->push_back(request);
98 DrawingContext::draw_surface(const Surface* surface, const Vector& position,
101 draw_surface(surface, position, 0.0f, Color(1.0f, 1.0f, 1.0f), Blend(), layer);
105 DrawingContext::draw_surface_part(const Surface* surface, const Vector& source,
106 const Vector& size, const Vector& dest, int layer)
108 assert(surface != 0);
110 DrawingRequest* request = new(obst) DrawingRequest();
112 request->target = target;
113 request->type = SURFACE_PART;
114 request->pos = transform.apply(dest);
115 request->layer = layer;
116 request->drawing_effect = transform.drawing_effect;
117 request->alpha = transform.alpha;
119 SurfacePartRequest* surfacepartrequest = new(obst) SurfacePartRequest();
120 surfacepartrequest->size = size;
121 surfacepartrequest->source = source;
122 surfacepartrequest->surface = surface;
124 // clip on screen borders
125 if(request->pos.x < 0) {
126 surfacepartrequest->size.x += request->pos.x;
127 if(surfacepartrequest->size.x <= 0)
129 surfacepartrequest->source.x -= request->pos.x;
132 if(request->pos.y < 0) {
133 surfacepartrequest->size.y += request->pos.y;
134 if(surfacepartrequest->size.y <= 0)
136 surfacepartrequest->source.y -= request->pos.y;
139 request->request_data = surfacepartrequest;
141 requests->push_back(request);
145 DrawingContext::draw_text(const Font* font, const std::string& text,
146 const Vector& position, FontAlignment alignment, int layer, Color color)
148 DrawingRequest* request = new(obst) DrawingRequest();
150 request->target = target;
151 request->type = TEXT;
152 request->pos = transform.apply(position);
153 request->layer = layer;
154 request->drawing_effect = transform.drawing_effect;
155 request->alpha = transform.alpha;
156 request->color = color;
158 TextRequest* textrequest = new(obst) TextRequest();
159 textrequest->font = font;
160 textrequest->text = text;
161 textrequest->alignment = alignment;
162 request->request_data = textrequest;
164 requests->push_back(request);
168 DrawingContext::draw_center_text(const Font* font, const std::string& text,
169 const Vector& position, int layer, Color color)
171 draw_text(font, text, Vector(position.x + SCREEN_WIDTH/2, position.y),
172 ALIGN_CENTER, layer, color);
176 DrawingContext::draw_gradient(const Color& top, const Color& bottom, int layer)
178 DrawingRequest* request = new(obst) DrawingRequest();
180 request->target = target;
181 request->type = GRADIENT;
182 request->pos = Vector(0,0);
183 request->layer = layer;
185 request->drawing_effect = transform.drawing_effect;
186 request->alpha = transform.alpha;
188 GradientRequest* gradientrequest = new(obst) GradientRequest();
189 gradientrequest->top = top;
190 gradientrequest->bottom = bottom;
191 request->request_data = gradientrequest;
193 requests->push_back(request);
197 DrawingContext::draw_filled_rect(const Vector& topleft, const Vector& size,
198 const Color& color, int layer)
200 DrawingRequest* request = new(obst) DrawingRequest();
202 request->target = target;
203 request->type = FILLRECT;
204 request->pos = transform.apply(topleft);
205 request->layer = layer;
207 request->drawing_effect = transform.drawing_effect;
208 request->alpha = transform.alpha;
210 FillRectRequest* fillrectrequest = new(obst) FillRectRequest();
211 fillrectrequest->size = size;
212 fillrectrequest->color = color;
213 fillrectrequest->color.alpha = color.alpha * transform.alpha;
214 fillrectrequest->radius = 0.0f;
215 request->request_data = fillrectrequest;
217 requests->push_back(request);
221 DrawingContext::draw_filled_rect(const Rect& rect, const Color& color,
224 draw_filled_rect(rect, color, 0.0f, layer);
228 DrawingContext::draw_filled_rect(const Rect& rect, const Color& color, float radius, int layer)
230 DrawingRequest* request = new(obst) DrawingRequest();
232 request->target = target;
233 request->type = FILLRECT;
234 request->pos = transform.apply(rect.p1);
235 request->layer = layer;
237 request->drawing_effect = transform.drawing_effect;
238 request->alpha = transform.alpha;
240 FillRectRequest* fillrectrequest = new(obst) FillRectRequest;
241 fillrectrequest->size = Vector(rect.get_width(), rect.get_height());
242 fillrectrequest->color = color;
243 fillrectrequest->color.alpha = color.alpha * transform.alpha;
244 fillrectrequest->radius = radius;
245 request->request_data = fillrectrequest;
247 requests->push_back(request);
251 DrawingContext::draw_inverse_ellipse(const Vector& pos, const Vector& size, const Color& color, int layer)
253 DrawingRequest* request = new(obst) DrawingRequest();
255 request->target = target;
256 request->type = INVERSEELLIPSE;
257 request->pos = transform.apply(pos);
258 request->layer = layer;
260 request->drawing_effect = transform.drawing_effect;
261 request->alpha = transform.alpha;
263 InverseEllipseRequest* ellipse = new(obst)InverseEllipseRequest;
265 ellipse->color = color;
266 ellipse->color.alpha = color.alpha * transform.alpha;
267 ellipse->size = size;
268 request->request_data = ellipse;
270 requests->push_back(request);
274 DrawingContext::get_light(const Vector& position, Color* color)
276 if( ambient_color.red == 1.0f && ambient_color.green == 1.0f
277 && ambient_color.blue == 1.0f ) {
278 *color = Color( 1.0f, 1.0f, 1.0f);
282 DrawingRequest* request = new(obst) DrawingRequest();
283 request->target = target;
284 request->type = GETLIGHT;
285 request->pos = transform.apply(position);
287 //There is no light offscreen.
288 if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT
289 || request->pos.x < 0 || request->pos.y < 0){
290 *color = Color( 0, 0, 0);
294 request->layer = LAYER_GUI; //make sure all get_light requests are handled last.
295 GetLightRequest* getlightrequest = new(obst) GetLightRequest();
296 getlightrequest->color_ptr = color;
297 request->request_data = getlightrequest;
298 lightmap_requests.push_back(request);
302 DrawingContext::do_drawing()
305 assert(transformstack.empty());
306 assert(target_stack.empty());
308 transformstack.clear();
309 target_stack.clear();
311 //Use Lightmap if ambient color is not white.
312 bool use_lightmap = ( ambient_color.red != 1.0f || ambient_color.green != 1.0f ||
313 ambient_color.blue != 1.0f );
315 // PART1: create lightmap
317 lightmap->start_draw(ambient_color);
318 handle_drawing_requests(lightmap_requests);
319 lightmap->end_draw();
321 DrawingRequest* request = new(obst) DrawingRequest();
322 request->target = NORMAL;
323 request->type = DRAW_LIGHTMAP;
324 request->layer = LAYER_HUD - 1;
325 drawing_requests.push_back(request);
327 lightmap_requests.clear();
329 handle_drawing_requests(drawing_requests);
330 drawing_requests.clear();
331 obstack_free(&obst, NULL);
334 // if a screenshot was requested, take one
335 if (screenshot_requested) {
336 renderer->do_take_screenshot();
337 screenshot_requested = false;
343 class RequestPtrCompare
344 : public std::binary_function<const DrawingRequest*,
345 const DrawingRequest*,
349 bool operator()(const DrawingRequest* r1, const DrawingRequest* r2) const
356 DrawingContext::handle_drawing_requests(DrawingRequests& requests)
358 std::stable_sort(requests.begin(), requests.end(), RequestPtrCompare());
360 DrawingRequests::const_iterator i;
361 for(i = requests.begin(); i != requests.end(); ++i) {
362 const DrawingRequest& request = **i;
364 switch(request.target) {
366 switch(request.type) {
368 renderer->draw_surface(request);
371 renderer->draw_surface_part(request);
374 renderer->draw_gradient(request);
378 const TextRequest* textrequest = (TextRequest*) request.request_data;
379 textrequest->font->draw(renderer, textrequest->text, request.pos,
380 textrequest->alignment, request.drawing_effect, request.color, request.alpha);
384 renderer->draw_filled_rect(request);
387 renderer->draw_inverse_ellipse(request);
393 lightmap->get_light(request);
398 switch(request.type) {
400 lightmap->draw_surface(request);
403 lightmap->draw_surface_part(request);
406 lightmap->draw_gradient(request);
410 const TextRequest* textrequest = (TextRequest*) request.request_data;
411 textrequest->font->draw(renderer, textrequest->text, request.pos,
412 textrequest->alignment, request.drawing_effect, request.color, request.alpha);
416 lightmap->draw_filled_rect(request);
419 assert(!"InverseEllipse doesn't make sense on the lightmap");
425 lightmap->get_light(request);
434 DrawingContext::push_transform()
436 transformstack.push_back(transform);
440 DrawingContext::pop_transform()
442 assert(!transformstack.empty());
444 transform = transformstack.back();
445 transformstack.pop_back();
449 DrawingContext::set_drawing_effect(DrawingEffect effect)
451 transform.drawing_effect = effect;
455 DrawingContext::get_drawing_effect() const
457 return transform.drawing_effect;
461 DrawingContext::set_alpha(float alpha)
463 transform.alpha = alpha;
467 DrawingContext::get_alpha() const
469 return transform.alpha;
473 DrawingContext::push_target()
475 target_stack.push_back(target);
479 DrawingContext::pop_target()
481 set_target(target_stack.back());
482 target_stack.pop_back();
486 DrawingContext::set_target(Target target)
488 this->target = target;
489 if(target == LIGHTMAP) {
490 requests = &lightmap_requests;
492 assert(target == NORMAL);
493 requests = &drawing_requests;
498 DrawingContext::set_ambient_color( Color new_color )
500 ambient_color = new_color;
504 DrawingContext::take_screenshot()
506 screenshot_requested = true;