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/>.
17 #include "video/drawing_context.hpp"
22 #include "math/sizef.hpp"
23 #include "supertux/gameconfig.hpp"
24 #include "supertux/globals.hpp"
25 #include "util/obstackpp.hpp"
26 #include "video/drawing_request.hpp"
27 #include "video/lightmap.hpp"
28 #include "video/renderer.hpp"
29 #include "video/surface.hpp"
30 #include "video/texture.hpp"
31 #include "video/texture_manager.hpp"
32 #include "video/video_systems.hpp"
34 DrawingContext::DrawingContext(Renderer& renderer, Lightmap& lightmap) :
44 ambient_color(1.0f, 1.0f, 1.0f, 1.0f),
48 screenshot_requested(false)
50 requests = &drawing_requests;
54 DrawingContext::~DrawingContext()
56 obstack_free(&obst, NULL);
60 DrawingContext::draw_surface(SurfacePtr surface, const Vector& position,
61 float angle, const Color& color, const Blend& blend,
66 DrawingRequest* request = new(obst) DrawingRequest();
68 request->target = target;
69 request->type = SURFACE;
70 request->pos = transform.apply(position);
72 if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT
73 || request->pos.x + surface->get_width() < 0
74 || request->pos.y + surface->get_height() < 0)
77 request->layer = layer;
78 request->drawing_effect = transform.drawing_effect;
79 request->alpha = transform.alpha;
80 request->angle = angle;
81 request->color = color;
82 request->blend = blend;
84 request->request_data = surface.get();
86 requests->push_back(request);
90 DrawingContext::draw_surface(SurfacePtr surface, const Vector& position,
93 draw_surface(surface, position, 0.0f, Color(1.0f, 1.0f, 1.0f), Blend(), layer);
97 DrawingContext::draw_surface_part(SurfacePtr surface, const Vector& source,
98 const Vector& size, const Vector& dest, int layer)
100 assert(surface != 0);
102 DrawingRequest* request = new(obst) DrawingRequest();
104 request->target = target;
105 request->type = SURFACE_PART;
106 request->pos = transform.apply(dest);
107 request->layer = layer;
108 request->drawing_effect = transform.drawing_effect;
109 request->alpha = transform.alpha;
111 SurfacePartRequest* surfacepartrequest = new(obst) SurfacePartRequest();
112 surfacepartrequest->size = size;
113 surfacepartrequest->source = source;
114 surfacepartrequest->surface = surface.get();
116 // clip on screen borders
117 if(request->pos.x < 0) {
118 surfacepartrequest->size.x += request->pos.x;
119 if(surfacepartrequest->size.x <= 0)
121 surfacepartrequest->source.x -= request->pos.x;
124 if(request->pos.y < 0) {
125 surfacepartrequest->size.y += request->pos.y;
126 if(surfacepartrequest->size.y <= 0)
128 surfacepartrequest->source.y -= request->pos.y;
131 request->request_data = surfacepartrequest;
133 requests->push_back(request);
137 DrawingContext::draw_text(FontPtr font, const std::string& text,
138 const Vector& position, FontAlignment alignment, int layer, Color color)
140 DrawingRequest* request = new(obst) DrawingRequest();
142 request->target = target;
143 request->type = TEXT;
144 request->pos = transform.apply(position);
145 request->layer = layer;
146 request->drawing_effect = transform.drawing_effect;
147 request->alpha = transform.alpha;
148 request->color = color;
150 TextRequest* textrequest = new(obst) TextRequest();
151 textrequest->font = font.get();
152 textrequest->text = text;
153 textrequest->alignment = alignment;
154 request->request_data = textrequest;
156 requests->push_back(request);
160 DrawingContext::draw_center_text(FontPtr font, const std::string& text,
161 const Vector& position, int layer, Color color)
163 draw_text(font, text, Vector(position.x + SCREEN_WIDTH/2, position.y),
164 ALIGN_CENTER, layer, color);
168 DrawingContext::draw_gradient(const Color& top, const Color& bottom, int layer)
170 DrawingRequest* request = new(obst) DrawingRequest();
172 request->target = target;
173 request->type = GRADIENT;
174 request->pos = Vector(0,0);
175 request->layer = layer;
177 request->drawing_effect = transform.drawing_effect;
178 request->alpha = transform.alpha;
180 GradientRequest* gradientrequest = new(obst) GradientRequest();
181 gradientrequest->top = top;
182 gradientrequest->bottom = bottom;
183 request->request_data = gradientrequest;
185 requests->push_back(request);
189 DrawingContext::draw_filled_rect(const Vector& topleft, const Vector& size,
190 const Color& color, int layer)
192 DrawingRequest* request = new(obst) DrawingRequest();
194 request->target = target;
195 request->type = FILLRECT;
196 request->pos = transform.apply(topleft);
197 request->layer = layer;
199 request->drawing_effect = transform.drawing_effect;
200 request->alpha = transform.alpha;
202 FillRectRequest* fillrectrequest = new(obst) FillRectRequest();
203 fillrectrequest->size = size;
204 fillrectrequest->color = color;
205 fillrectrequest->color.alpha = color.alpha * transform.alpha;
206 fillrectrequest->radius = 0.0f;
207 request->request_data = fillrectrequest;
209 requests->push_back(request);
213 DrawingContext::draw_filled_rect(const Rectf& rect, const Color& color,
216 draw_filled_rect(rect, color, 0.0f, layer);
220 DrawingContext::draw_filled_rect(const Rectf& rect, const Color& color, float radius, int layer)
222 DrawingRequest* request = new(obst) DrawingRequest();
224 request->target = target;
225 request->type = FILLRECT;
226 request->pos = transform.apply(rect.p1);
227 request->layer = layer;
229 request->drawing_effect = transform.drawing_effect;
230 request->alpha = transform.alpha;
232 FillRectRequest* fillrectrequest = new(obst) FillRectRequest;
233 fillrectrequest->size = Vector(rect.get_width(), rect.get_height());
234 fillrectrequest->color = color;
235 fillrectrequest->color.alpha = color.alpha * transform.alpha;
236 fillrectrequest->radius = radius;
237 request->request_data = fillrectrequest;
239 requests->push_back(request);
243 DrawingContext::draw_inverse_ellipse(const Vector& pos, const Vector& size, const Color& color, int layer)
245 DrawingRequest* request = new(obst) DrawingRequest();
247 request->target = target;
248 request->type = INVERSEELLIPSE;
249 request->pos = transform.apply(pos);
250 request->layer = layer;
252 request->drawing_effect = transform.drawing_effect;
253 request->alpha = transform.alpha;
255 InverseEllipseRequest* ellipse = new(obst)InverseEllipseRequest;
257 ellipse->color = color;
258 ellipse->color.alpha = color.alpha * transform.alpha;
259 ellipse->size = size;
260 request->request_data = ellipse;
262 requests->push_back(request);
266 DrawingContext::get_cliprect() const
268 return Rectf(get_translation().x, get_translation().y,
269 get_translation().x + SCREEN_WIDTH,
270 get_translation().y + SCREEN_HEIGHT);
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()
304 assert(transformstack.empty());
305 assert(target_stack.empty());
306 transformstack.clear();
307 target_stack.clear();
309 //Use Lightmap if ambient color is not white.
310 bool use_lightmap = ( ambient_color.red != 1.0f || ambient_color.green != 1.0f ||
311 ambient_color.blue != 1.0f );
313 // PART1: create lightmap
315 lightmap.start_draw(ambient_color);
316 handle_drawing_requests(lightmap_requests);
319 DrawingRequest* request = new(obst) DrawingRequest();
320 request->target = NORMAL;
321 request->type = DRAW_LIGHTMAP;
322 request->layer = LAYER_HUD - 1;
323 drawing_requests.push_back(request);
325 lightmap_requests.clear();
327 handle_drawing_requests(drawing_requests);
328 drawing_requests.clear();
329 obstack_free(&obst, NULL);
332 // if a screenshot was requested, take one
333 if (screenshot_requested) {
334 renderer.do_take_screenshot();
335 screenshot_requested = false;
341 class RequestPtrCompare
344 bool operator()(const DrawingRequest* r1, const DrawingRequest* r2) const
351 DrawingContext::handle_drawing_requests(DrawingRequests& requests)
353 std::stable_sort(requests.begin(), requests.end(), RequestPtrCompare());
355 DrawingRequests::const_iterator i;
356 for(i = requests.begin(); i != requests.end(); ++i) {
357 const DrawingRequest& request = **i;
359 switch(request.target) {
361 switch(request.type) {
363 renderer.draw_surface(request);
366 renderer.draw_surface_part(request);
369 renderer.draw_gradient(request);
373 const TextRequest* textrequest = (TextRequest*) request.request_data;
374 textrequest->font->draw(&renderer, textrequest->text, request.pos,
375 textrequest->alignment, request.drawing_effect, request.color, request.alpha);
379 renderer.draw_filled_rect(request);
382 renderer.draw_inverse_ellipse(request);
388 lightmap.get_light(request);
393 switch(request.type) {
395 lightmap.draw_surface(request);
398 lightmap.draw_surface_part(request);
401 lightmap.draw_gradient(request);
405 const TextRequest* textrequest = (TextRequest*) request.request_data;
406 textrequest->font->draw(&renderer, textrequest->text, request.pos,
407 textrequest->alignment, request.drawing_effect, request.color, request.alpha);
411 lightmap.draw_filled_rect(request);
414 assert(!"InverseEllipse doesn't make sense on the lightmap");
420 lightmap.get_light(request);
429 DrawingContext::push_transform()
431 transformstack.push_back(transform);
435 DrawingContext::pop_transform()
437 assert(!transformstack.empty());
439 transform = transformstack.back();
440 transformstack.pop_back();
444 DrawingContext::set_drawing_effect(DrawingEffect effect)
446 transform.drawing_effect = effect;
450 DrawingContext::get_drawing_effect() const
452 return transform.drawing_effect;
456 DrawingContext::set_alpha(float alpha)
458 transform.alpha = alpha;
462 DrawingContext::get_alpha() const
464 return transform.alpha;
468 DrawingContext::push_target()
470 target_stack.push_back(target);
474 DrawingContext::pop_target()
476 set_target(target_stack.back());
477 target_stack.pop_back();
481 DrawingContext::set_target(Target target)
483 this->target = target;
484 if(target == LIGHTMAP) {
485 requests = &lightmap_requests;
487 assert(target == NORMAL);
488 requests = &drawing_requests;
493 DrawingContext::set_ambient_color( Color new_color )
495 ambient_color = new_color;
499 DrawingContext::take_screenshot()
501 screenshot_requested = true;