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 "supertux/gameconfig.hpp"
23 #include "supertux/globals.hpp"
24 #include "util/obstackpp.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 DrawingContext::DrawingContext() :
43 ambient_color(1.0f, 1.0f, 1.0f, 1.0f),
47 screenshot_requested(false)
49 requests = &drawing_requests;
53 DrawingContext::~DrawingContext()
58 obstack_free(&obst, NULL);
62 DrawingContext::init_renderer()
67 renderer = VideoSystem::new_renderer();
68 lightmap = VideoSystem::new_lightmap();
72 DrawingContext::draw_surface(SurfacePtr surface, const Vector& position,
73 float angle, const Color& color, const Blend& blend,
78 DrawingRequest* request = new(obst) DrawingRequest();
80 request->target = target;
81 request->type = SURFACE;
82 request->pos = transform.apply(position);
84 if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT
85 || request->pos.x + surface->get_width() < 0
86 || request->pos.y + surface->get_height() < 0)
89 request->layer = layer;
90 request->drawing_effect = transform.drawing_effect;
91 request->alpha = transform.alpha;
92 request->angle = angle;
93 request->color = color;
94 request->blend = blend;
96 request->request_data = surface.get();
98 requests->push_back(request);
102 DrawingContext::draw_surface(SurfacePtr surface, const Vector& position,
105 draw_surface(surface, position, 0.0f, Color(1.0f, 1.0f, 1.0f), Blend(), layer);
109 DrawingContext::draw_surface_part(SurfacePtr surface, const Vector& source,
110 const Vector& size, const Vector& dest, int layer)
112 assert(surface != 0);
114 DrawingRequest* request = new(obst) DrawingRequest();
116 request->target = target;
117 request->type = SURFACE_PART;
118 request->pos = transform.apply(dest);
119 request->layer = layer;
120 request->drawing_effect = transform.drawing_effect;
121 request->alpha = transform.alpha;
123 SurfacePartRequest* surfacepartrequest = new(obst) SurfacePartRequest();
124 surfacepartrequest->size = size;
125 surfacepartrequest->source = source;
126 surfacepartrequest->surface = surface.get();
128 // clip on screen borders
129 if(request->pos.x < 0) {
130 surfacepartrequest->size.x += request->pos.x;
131 if(surfacepartrequest->size.x <= 0)
133 surfacepartrequest->source.x -= request->pos.x;
136 if(request->pos.y < 0) {
137 surfacepartrequest->size.y += request->pos.y;
138 if(surfacepartrequest->size.y <= 0)
140 surfacepartrequest->source.y -= request->pos.y;
143 request->request_data = surfacepartrequest;
145 requests->push_back(request);
149 DrawingContext::draw_text(FontPtr font, const std::string& text,
150 const Vector& position, FontAlignment alignment, int layer, Color color)
152 DrawingRequest* request = new(obst) DrawingRequest();
154 request->target = target;
155 request->type = TEXT;
156 request->pos = transform.apply(position);
157 request->layer = layer;
158 request->drawing_effect = transform.drawing_effect;
159 request->alpha = transform.alpha;
160 request->color = color;
162 TextRequest* textrequest = new(obst) TextRequest();
163 textrequest->font = font.get();
164 textrequest->text = text;
165 textrequest->alignment = alignment;
166 request->request_data = textrequest;
168 requests->push_back(request);
172 DrawingContext::draw_center_text(FontPtr font, const std::string& text,
173 const Vector& position, int layer, Color color)
175 draw_text(font, text, Vector(position.x + SCREEN_WIDTH/2, position.y),
176 ALIGN_CENTER, layer, color);
180 DrawingContext::draw_gradient(const Color& top, const Color& bottom, int layer)
182 DrawingRequest* request = new(obst) DrawingRequest();
184 request->target = target;
185 request->type = GRADIENT;
186 request->pos = Vector(0,0);
187 request->layer = layer;
189 request->drawing_effect = transform.drawing_effect;
190 request->alpha = transform.alpha;
192 GradientRequest* gradientrequest = new(obst) GradientRequest();
193 gradientrequest->top = top;
194 gradientrequest->bottom = bottom;
195 request->request_data = gradientrequest;
197 requests->push_back(request);
201 DrawingContext::draw_filled_rect(const Vector& topleft, const Vector& size,
202 const Color& color, int layer)
204 DrawingRequest* request = new(obst) DrawingRequest();
206 request->target = target;
207 request->type = FILLRECT;
208 request->pos = transform.apply(topleft);
209 request->layer = layer;
211 request->drawing_effect = transform.drawing_effect;
212 request->alpha = transform.alpha;
214 FillRectRequest* fillrectrequest = new(obst) FillRectRequest();
215 fillrectrequest->size = size;
216 fillrectrequest->color = color;
217 fillrectrequest->color.alpha = color.alpha * transform.alpha;
218 fillrectrequest->radius = 0.0f;
219 request->request_data = fillrectrequest;
221 requests->push_back(request);
225 DrawingContext::draw_filled_rect(const Rectf& rect, const Color& color,
228 draw_filled_rect(rect, color, 0.0f, layer);
232 DrawingContext::draw_filled_rect(const Rectf& rect, const Color& color, float radius, int layer)
234 DrawingRequest* request = new(obst) DrawingRequest();
236 request->target = target;
237 request->type = FILLRECT;
238 request->pos = transform.apply(rect.p1);
239 request->layer = layer;
241 request->drawing_effect = transform.drawing_effect;
242 request->alpha = transform.alpha;
244 FillRectRequest* fillrectrequest = new(obst) FillRectRequest;
245 fillrectrequest->size = Vector(rect.get_width(), rect.get_height());
246 fillrectrequest->color = color;
247 fillrectrequest->color.alpha = color.alpha * transform.alpha;
248 fillrectrequest->radius = radius;
249 request->request_data = fillrectrequest;
251 requests->push_back(request);
255 DrawingContext::draw_inverse_ellipse(const Vector& pos, const Vector& size, const Color& color, int layer)
257 DrawingRequest* request = new(obst) DrawingRequest();
259 request->target = target;
260 request->type = INVERSEELLIPSE;
261 request->pos = transform.apply(pos);
262 request->layer = layer;
264 request->drawing_effect = transform.drawing_effect;
265 request->alpha = transform.alpha;
267 InverseEllipseRequest* ellipse = new(obst)InverseEllipseRequest;
269 ellipse->color = color;
270 ellipse->color.alpha = color.alpha * transform.alpha;
271 ellipse->size = size;
272 request->request_data = ellipse;
274 requests->push_back(request);
278 DrawingContext::get_light(const Vector& position, Color* color)
280 if( ambient_color.red == 1.0f && ambient_color.green == 1.0f
281 && ambient_color.blue == 1.0f ) {
282 *color = Color( 1.0f, 1.0f, 1.0f);
286 DrawingRequest* request = new(obst) DrawingRequest();
287 request->target = target;
288 request->type = GETLIGHT;
289 request->pos = transform.apply(position);
291 //There is no light offscreen.
292 if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT
293 || request->pos.x < 0 || request->pos.y < 0){
294 *color = Color( 0, 0, 0);
298 request->layer = LAYER_GUI; //make sure all get_light requests are handled last.
299 GetLightRequest* getlightrequest = new(obst) GetLightRequest();
300 getlightrequest->color_ptr = color;
301 request->request_data = getlightrequest;
302 lightmap_requests.push_back(request);
306 DrawingContext::do_drawing()
308 assert(transformstack.empty());
309 assert(target_stack.empty());
310 transformstack.clear();
311 target_stack.clear();
313 //Use Lightmap if ambient color is not white.
314 bool use_lightmap = ( ambient_color.red != 1.0f || ambient_color.green != 1.0f ||
315 ambient_color.blue != 1.0f );
317 // PART1: create lightmap
319 lightmap->start_draw(ambient_color);
320 handle_drawing_requests(lightmap_requests);
321 lightmap->end_draw();
323 DrawingRequest* request = new(obst) DrawingRequest();
324 request->target = NORMAL;
325 request->type = DRAW_LIGHTMAP;
326 request->layer = LAYER_HUD - 1;
327 drawing_requests.push_back(request);
329 lightmap_requests.clear();
331 handle_drawing_requests(drawing_requests);
332 drawing_requests.clear();
333 obstack_free(&obst, NULL);
336 // if a screenshot was requested, take one
337 if (screenshot_requested) {
338 renderer->do_take_screenshot();
339 screenshot_requested = false;
345 class RequestPtrCompare
348 bool operator()(const DrawingRequest* r1, const DrawingRequest* r2) const
355 DrawingContext::handle_drawing_requests(DrawingRequests& requests)
357 std::stable_sort(requests.begin(), requests.end(), RequestPtrCompare());
359 DrawingRequests::const_iterator i;
360 for(i = requests.begin(); i != requests.end(); ++i) {
361 const DrawingRequest& request = **i;
363 switch(request.target) {
365 switch(request.type) {
367 renderer->draw_surface(request);
370 renderer->draw_surface_part(request);
373 renderer->draw_gradient(request);
377 const TextRequest* textrequest = (TextRequest*) request.request_data;
378 textrequest->font->draw(renderer, textrequest->text, request.pos,
379 textrequest->alignment, request.drawing_effect, request.color, request.alpha);
383 renderer->draw_filled_rect(request);
386 renderer->draw_inverse_ellipse(request);
392 lightmap->get_light(request);
397 switch(request.type) {
399 lightmap->draw_surface(request);
402 lightmap->draw_surface_part(request);
405 lightmap->draw_gradient(request);
409 const TextRequest* textrequest = (TextRequest*) request.request_data;
410 textrequest->font->draw(renderer, textrequest->text, request.pos,
411 textrequest->alignment, request.drawing_effect, request.color, request.alpha);
415 lightmap->draw_filled_rect(request);
418 assert(!"InverseEllipse doesn't make sense on the lightmap");
424 lightmap->get_light(request);
433 DrawingContext::push_transform()
435 transformstack.push_back(transform);
439 DrawingContext::pop_transform()
441 assert(!transformstack.empty());
443 transform = transformstack.back();
444 transformstack.pop_back();
448 DrawingContext::set_drawing_effect(DrawingEffect effect)
450 transform.drawing_effect = effect;
454 DrawingContext::get_drawing_effect() const
456 return transform.drawing_effect;
460 DrawingContext::set_alpha(float alpha)
462 transform.alpha = alpha;
466 DrawingContext::get_alpha() const
468 return transform.alpha;
472 DrawingContext::push_target()
474 target_stack.push_back(target);
478 DrawingContext::pop_target()
480 set_target(target_stack.back());
481 target_stack.pop_back();
485 DrawingContext::set_target(Target target)
487 this->target = target;
488 if(target == LIGHTMAP) {
489 requests = &lightmap_requests;
491 assert(target == NORMAL);
492 requests = &drawing_requests;
497 DrawingContext::set_ambient_color( Color new_color )
499 ambient_color = new_color;
503 DrawingContext::take_screenshot()
505 screenshot_requested = true;