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 static inline int next_po2(int val)
42 DrawingContext::DrawingContext() :
52 ambient_color(1.0f, 1.0f, 1.0f, 1.0f),
56 screenshot_requested(false)
58 requests = &drawing_requests;
62 DrawingContext::~DrawingContext()
67 obstack_free(&obst, NULL);
71 DrawingContext::init_renderer()
76 renderer = VideoSystem::new_renderer();
77 lightmap = VideoSystem::new_lightmap();
81 DrawingContext::draw_surface(const Surface* surface, const Vector& position,
82 float angle, const Color& color, const Blend& blend,
87 DrawingRequest* request = new(obst) DrawingRequest();
89 request->target = target;
90 request->type = SURFACE;
91 request->pos = transform.apply(position);
93 if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT
94 || request->pos.x + surface->get_width() < 0
95 || request->pos.y + surface->get_height() < 0)
98 request->layer = layer;
99 request->drawing_effect = transform.drawing_effect;
100 request->alpha = transform.alpha;
101 request->angle = angle;
102 request->color = color;
103 request->blend = blend;
105 request->request_data = const_cast<Surface*> (surface);
107 requests->push_back(request);
111 DrawingContext::draw_surface(const Surface* surface, const Vector& position,
114 draw_surface(surface, position, 0.0f, Color(1.0f, 1.0f, 1.0f), Blend(), layer);
118 DrawingContext::draw_surface_part(const Surface* surface, const Vector& source,
119 const Vector& size, const Vector& dest, int layer)
121 assert(surface != 0);
123 DrawingRequest* request = new(obst) DrawingRequest();
125 request->target = target;
126 request->type = SURFACE_PART;
127 request->pos = transform.apply(dest);
128 request->layer = layer;
129 request->drawing_effect = transform.drawing_effect;
130 request->alpha = transform.alpha;
132 SurfacePartRequest* surfacepartrequest = new(obst) SurfacePartRequest();
133 surfacepartrequest->size = size;
134 surfacepartrequest->source = source;
135 surfacepartrequest->surface = surface;
137 // clip on screen borders
138 if(request->pos.x < 0) {
139 surfacepartrequest->size.x += request->pos.x;
140 if(surfacepartrequest->size.x <= 0)
142 surfacepartrequest->source.x -= request->pos.x;
145 if(request->pos.y < 0) {
146 surfacepartrequest->size.y += request->pos.y;
147 if(surfacepartrequest->size.y <= 0)
149 surfacepartrequest->source.y -= request->pos.y;
152 request->request_data = surfacepartrequest;
154 requests->push_back(request);
158 DrawingContext::draw_text(const Font* font, const std::string& text,
159 const Vector& position, FontAlignment alignment, int layer, Color color)
161 DrawingRequest* request = new(obst) DrawingRequest();
163 request->target = target;
164 request->type = TEXT;
165 request->pos = transform.apply(position);
166 request->layer = layer;
167 request->drawing_effect = transform.drawing_effect;
168 request->alpha = transform.alpha;
169 request->color = color;
171 TextRequest* textrequest = new(obst) TextRequest();
172 textrequest->font = font;
173 textrequest->text = text;
174 textrequest->alignment = alignment;
175 request->request_data = textrequest;
177 requests->push_back(request);
181 DrawingContext::draw_center_text(const Font* font, const std::string& text,
182 const Vector& position, int layer, Color color)
184 draw_text(font, text, Vector(position.x + SCREEN_WIDTH/2, position.y),
185 ALIGN_CENTER, layer, color);
189 DrawingContext::draw_gradient(const Color& top, const Color& bottom, int layer)
191 DrawingRequest* request = new(obst) DrawingRequest();
193 request->target = target;
194 request->type = GRADIENT;
195 request->pos = Vector(0,0);
196 request->layer = layer;
198 request->drawing_effect = transform.drawing_effect;
199 request->alpha = transform.alpha;
201 GradientRequest* gradientrequest = new(obst) GradientRequest();
202 gradientrequest->top = top;
203 gradientrequest->bottom = bottom;
204 request->request_data = gradientrequest;
206 requests->push_back(request);
210 DrawingContext::draw_filled_rect(const Vector& topleft, const Vector& size,
211 const Color& color, int layer)
213 DrawingRequest* request = new(obst) DrawingRequest();
215 request->target = target;
216 request->type = FILLRECT;
217 request->pos = transform.apply(topleft);
218 request->layer = layer;
220 request->drawing_effect = transform.drawing_effect;
221 request->alpha = transform.alpha;
223 FillRectRequest* fillrectrequest = new(obst) FillRectRequest();
224 fillrectrequest->size = size;
225 fillrectrequest->color = color;
226 fillrectrequest->color.alpha = color.alpha * transform.alpha;
227 fillrectrequest->radius = 0.0f;
228 request->request_data = fillrectrequest;
230 requests->push_back(request);
234 DrawingContext::draw_filled_rect(const Rectf& rect, const Color& color,
237 draw_filled_rect(rect, color, 0.0f, layer);
241 DrawingContext::draw_filled_rect(const Rectf& rect, const Color& color, float radius, int layer)
243 DrawingRequest* request = new(obst) DrawingRequest();
245 request->target = target;
246 request->type = FILLRECT;
247 request->pos = transform.apply(rect.p1);
248 request->layer = layer;
250 request->drawing_effect = transform.drawing_effect;
251 request->alpha = transform.alpha;
253 FillRectRequest* fillrectrequest = new(obst) FillRectRequest;
254 fillrectrequest->size = Vector(rect.get_width(), rect.get_height());
255 fillrectrequest->color = color;
256 fillrectrequest->color.alpha = color.alpha * transform.alpha;
257 fillrectrequest->radius = radius;
258 request->request_data = fillrectrequest;
260 requests->push_back(request);
264 DrawingContext::draw_inverse_ellipse(const Vector& pos, const Vector& size, const Color& color, int layer)
266 DrawingRequest* request = new(obst) DrawingRequest();
268 request->target = target;
269 request->type = INVERSEELLIPSE;
270 request->pos = transform.apply(pos);
271 request->layer = layer;
273 request->drawing_effect = transform.drawing_effect;
274 request->alpha = transform.alpha;
276 InverseEllipseRequest* ellipse = new(obst)InverseEllipseRequest;
278 ellipse->color = color;
279 ellipse->color.alpha = color.alpha * transform.alpha;
280 ellipse->size = size;
281 request->request_data = ellipse;
283 requests->push_back(request);
287 DrawingContext::get_light(const Vector& position, Color* color)
289 if( ambient_color.red == 1.0f && ambient_color.green == 1.0f
290 && ambient_color.blue == 1.0f ) {
291 *color = Color( 1.0f, 1.0f, 1.0f);
295 DrawingRequest* request = new(obst) DrawingRequest();
296 request->target = target;
297 request->type = GETLIGHT;
298 request->pos = transform.apply(position);
300 //There is no light offscreen.
301 if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT
302 || request->pos.x < 0 || request->pos.y < 0){
303 *color = Color( 0, 0, 0);
307 request->layer = LAYER_GUI; //make sure all get_light requests are handled last.
308 GetLightRequest* getlightrequest = new(obst) GetLightRequest();
309 getlightrequest->color_ptr = color;
310 request->request_data = getlightrequest;
311 lightmap_requests.push_back(request);
315 DrawingContext::do_drawing()
317 assert(transformstack.empty());
318 assert(target_stack.empty());
319 transformstack.clear();
320 target_stack.clear();
322 //Use Lightmap if ambient color is not white.
323 bool use_lightmap = ( ambient_color.red != 1.0f || ambient_color.green != 1.0f ||
324 ambient_color.blue != 1.0f );
326 // PART1: create lightmap
328 lightmap->start_draw(ambient_color);
329 handle_drawing_requests(lightmap_requests);
330 lightmap->end_draw();
332 DrawingRequest* request = new(obst) DrawingRequest();
333 request->target = NORMAL;
334 request->type = DRAW_LIGHTMAP;
335 request->layer = LAYER_HUD - 1;
336 drawing_requests.push_back(request);
338 lightmap_requests.clear();
340 handle_drawing_requests(drawing_requests);
341 drawing_requests.clear();
342 obstack_free(&obst, NULL);
345 // if a screenshot was requested, take one
346 if (screenshot_requested) {
347 renderer->do_take_screenshot();
348 screenshot_requested = false;
354 class RequestPtrCompare
357 bool operator()(const DrawingRequest* r1, const DrawingRequest* r2) const
364 DrawingContext::handle_drawing_requests(DrawingRequests& requests)
366 std::stable_sort(requests.begin(), requests.end(), RequestPtrCompare());
368 DrawingRequests::const_iterator i;
369 for(i = requests.begin(); i != requests.end(); ++i) {
370 const DrawingRequest& request = **i;
372 switch(request.target) {
374 switch(request.type) {
376 renderer->draw_surface(request);
379 renderer->draw_surface_part(request);
382 renderer->draw_gradient(request);
386 const TextRequest* textrequest = (TextRequest*) request.request_data;
387 textrequest->font->draw(renderer, textrequest->text, request.pos,
388 textrequest->alignment, request.drawing_effect, request.color, request.alpha);
392 renderer->draw_filled_rect(request);
395 renderer->draw_inverse_ellipse(request);
401 lightmap->get_light(request);
406 switch(request.type) {
408 lightmap->draw_surface(request);
411 lightmap->draw_surface_part(request);
414 lightmap->draw_gradient(request);
418 const TextRequest* textrequest = (TextRequest*) request.request_data;
419 textrequest->font->draw(renderer, textrequest->text, request.pos,
420 textrequest->alignment, request.drawing_effect, request.color, request.alpha);
424 lightmap->draw_filled_rect(request);
427 assert(!"InverseEllipse doesn't make sense on the lightmap");
433 lightmap->get_light(request);
442 DrawingContext::push_transform()
444 transformstack.push_back(transform);
448 DrawingContext::pop_transform()
450 assert(!transformstack.empty());
452 transform = transformstack.back();
453 transformstack.pop_back();
457 DrawingContext::set_drawing_effect(DrawingEffect effect)
459 transform.drawing_effect = effect;
463 DrawingContext::get_drawing_effect() const
465 return transform.drawing_effect;
469 DrawingContext::set_alpha(float alpha)
471 transform.alpha = alpha;
475 DrawingContext::get_alpha() const
477 return transform.alpha;
481 DrawingContext::push_target()
483 target_stack.push_back(target);
487 DrawingContext::pop_target()
489 set_target(target_stack.back());
490 target_stack.pop_back();
494 DrawingContext::set_target(Target target)
496 this->target = target;
497 if(target == LIGHTMAP) {
498 requests = &lightmap_requests;
500 assert(target == NORMAL);
501 requests = &drawing_requests;
506 DrawingContext::set_ambient_color( Color new_color )
508 ambient_color = new_color;
512 DrawingContext::take_screenshot()
514 screenshot_requested = true;