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_system.hpp"
34 DrawingContext::DrawingContext(VideoSystem& video_system_) :
35 video_system(video_system_),
43 ambient_color(1.0f, 1.0f, 1.0f, 1.0f),
47 screenshot_requested(false)
49 requests = &drawing_requests;
53 DrawingContext::~DrawingContext()
55 clear_drawing_requests(lightmap_requests);
56 clear_drawing_requests(drawing_requests);
58 obstack_free(&obst, NULL);
62 DrawingContext::clear_drawing_requests(DrawingRequests& requests_)
64 for(auto& request : requests_)
66 if (request->request_data)
68 request->request_data->~DrawingRequestData();
70 request->~DrawingRequest();
76 DrawingContext::draw_surface(SurfacePtr surface, const Vector& position,
77 float angle, const Color& color, const Blend& blend,
82 DrawingRequest* request = new(obst) DrawingRequest();
84 request->target = target;
85 request->type = SURFACE;
86 request->pos = transform.apply(position);
88 if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT
89 || request->pos.x + surface->get_width() < 0
90 || request->pos.y + surface->get_height() < 0)
93 request->layer = layer;
94 request->drawing_effect = transform.drawing_effect;
95 request->alpha = transform.alpha;
96 request->angle = angle;
97 request->color = color;
98 request->blend = blend;
100 SurfaceRequest* surfacerequest = new(obst) SurfaceRequest();
101 surfacerequest->surface = surface.get();
102 request->request_data = surfacerequest;
104 requests->push_back(request);
108 DrawingContext::draw_surface(SurfacePtr surface, const Vector& position,
111 draw_surface(surface, position, 0.0f, Color(1.0f, 1.0f, 1.0f), Blend(), layer);
115 DrawingContext::draw_surface_part(SurfacePtr surface,
116 const Rectf& srcrect, const Rectf& dstrect,
119 assert(surface != 0);
121 DrawingRequest* request = new(obst) DrawingRequest();
123 request->target = target;
124 request->type = SURFACE_PART;
125 request->pos = transform.apply(dstrect.p1);
126 request->layer = layer;
127 request->drawing_effect = transform.drawing_effect;
128 request->alpha = transform.alpha;
130 SurfacePartRequest* surfacepartrequest = new(obst) SurfacePartRequest();
131 surfacepartrequest->srcrect = srcrect;
132 surfacepartrequest->dstsize = dstrect.get_size();
133 surfacepartrequest->surface = surface.get();
135 request->request_data = surfacepartrequest;
137 requests->push_back(request);
141 DrawingContext::draw_text(FontPtr font, const std::string& text,
142 const Vector& position, FontAlignment alignment, int layer, Color color)
144 DrawingRequest* request = new(obst) DrawingRequest();
146 request->target = target;
147 request->type = TEXT;
148 request->pos = transform.apply(position);
149 request->layer = layer;
150 request->drawing_effect = transform.drawing_effect;
151 request->alpha = transform.alpha;
152 request->color = color;
154 TextRequest* textrequest = new(obst) TextRequest();
155 textrequest->font = font.get();
156 textrequest->text = text;
157 textrequest->alignment = alignment;
158 request->request_data = textrequest;
160 requests->push_back(request);
164 DrawingContext::draw_center_text(FontPtr font, const std::string& text,
165 const Vector& position, int layer, Color color)
167 draw_text(font, text, Vector(position.x + SCREEN_WIDTH/2, position.y),
168 ALIGN_CENTER, layer, color);
172 DrawingContext::draw_gradient(const Color& top, const Color& bottom, int layer)
174 DrawingRequest* request = new(obst) DrawingRequest();
176 request->target = target;
177 request->type = GRADIENT;
178 request->pos = Vector(0,0);
179 request->layer = layer;
181 request->drawing_effect = transform.drawing_effect;
182 request->alpha = transform.alpha;
184 GradientRequest* gradientrequest = new(obst) GradientRequest();
185 gradientrequest->top = top;
186 gradientrequest->bottom = bottom;
187 request->request_data = gradientrequest;
189 requests->push_back(request);
193 DrawingContext::draw_filled_rect(const Vector& topleft, const Vector& size,
194 const Color& color, int layer)
196 DrawingRequest* request = new(obst) DrawingRequest();
198 request->target = target;
199 request->type = FILLRECT;
200 request->pos = transform.apply(topleft);
201 request->layer = layer;
203 request->drawing_effect = transform.drawing_effect;
204 request->alpha = transform.alpha;
206 FillRectRequest* fillrectrequest = new(obst) FillRectRequest();
207 fillrectrequest->size = size;
208 fillrectrequest->color = color;
209 fillrectrequest->color.alpha = color.alpha * transform.alpha;
210 fillrectrequest->radius = 0.0f;
211 request->request_data = fillrectrequest;
213 requests->push_back(request);
217 DrawingContext::draw_filled_rect(const Rectf& rect, const Color& color,
220 draw_filled_rect(rect, color, 0.0f, layer);
224 DrawingContext::draw_filled_rect(const Rectf& rect, const Color& color, float radius, int layer)
226 DrawingRequest* request = new(obst) DrawingRequest();
228 request->target = target;
229 request->type = FILLRECT;
230 request->pos = transform.apply(rect.p1);
231 request->layer = layer;
233 request->drawing_effect = transform.drawing_effect;
234 request->alpha = transform.alpha;
236 FillRectRequest* fillrectrequest = new(obst) FillRectRequest;
237 fillrectrequest->size = Vector(rect.get_width(), rect.get_height());
238 fillrectrequest->color = color;
239 fillrectrequest->color.alpha = color.alpha * transform.alpha;
240 fillrectrequest->radius = radius;
241 request->request_data = fillrectrequest;
243 requests->push_back(request);
247 DrawingContext::draw_inverse_ellipse(const Vector& pos, const Vector& size, const Color& color, int layer)
249 DrawingRequest* request = new(obst) DrawingRequest();
251 request->target = target;
252 request->type = INVERSEELLIPSE;
253 request->pos = transform.apply(pos);
254 request->layer = layer;
256 request->drawing_effect = transform.drawing_effect;
257 request->alpha = transform.alpha;
259 InverseEllipseRequest* ellipse = new(obst)InverseEllipseRequest;
261 ellipse->color = color;
262 ellipse->color.alpha = color.alpha * transform.alpha;
263 ellipse->size = size;
264 request->request_data = ellipse;
266 requests->push_back(request);
270 DrawingContext::get_cliprect() const
272 return Rectf(get_translation().x, get_translation().y,
273 get_translation().x + SCREEN_WIDTH,
274 get_translation().y + SCREEN_HEIGHT);
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 ||
315 ambient_color.green != 1.0f ||
316 ambient_color.blue != 1.0f );
318 // PART1: create lightmap
320 Lightmap& lightmap = video_system.get_lightmap();
322 lightmap.start_draw(ambient_color);
323 handle_drawing_requests(lightmap_requests);
326 DrawingRequest* request = new(obst) DrawingRequest();
327 request->target = NORMAL;
328 request->type = DRAW_LIGHTMAP;
329 request->layer = LAYER_HUD - 1;
330 drawing_requests.push_back(request);
333 Renderer& renderer = video_system.get_renderer();
334 renderer.start_draw();
335 handle_drawing_requests(drawing_requests);
338 clear_drawing_requests(lightmap_requests);
339 clear_drawing_requests(drawing_requests);
341 obstack_free(&obst, NULL);
344 // if a screenshot was requested, take one
345 if (screenshot_requested) {
346 renderer.do_take_screenshot();
347 screenshot_requested = false;
353 class RequestPtrCompare
356 bool operator()(const DrawingRequest* r1, const DrawingRequest* r2) const
363 DrawingContext::handle_drawing_requests(DrawingRequests& requests_)
365 std::stable_sort(requests_.begin(), requests_.end(), RequestPtrCompare());
367 Renderer& renderer = video_system.get_renderer();
368 Lightmap& lightmap = video_system.get_lightmap();
370 DrawingRequests::const_iterator i;
371 for(i = requests_.begin(); i != requests_.end(); ++i) {
372 const DrawingRequest& request = **i;
374 switch(request.target) {
376 switch(request.type) {
378 renderer.draw_surface(request);
381 renderer.draw_surface_part(request);
384 renderer.draw_gradient(request);
388 const TextRequest* textrequest = static_cast<TextRequest*>(request.request_data);
389 textrequest->font->draw(&renderer, textrequest->text, request.pos,
390 textrequest->alignment, request.drawing_effect, request.color, request.alpha);
394 renderer.draw_filled_rect(request);
397 renderer.draw_inverse_ellipse(request);
403 lightmap.get_light(request);
408 switch(request.type) {
410 lightmap.draw_surface(request);
413 lightmap.draw_surface_part(request);
416 lightmap.draw_gradient(request);
420 const TextRequest* textrequest = static_cast<TextRequest*>(request.request_data);
421 textrequest->font->draw(&renderer, textrequest->text, request.pos,
422 textrequest->alignment, request.drawing_effect, request.color, request.alpha);
426 lightmap.draw_filled_rect(request);
429 assert(!"InverseEllipse doesn't make sense on the lightmap");
435 lightmap.get_light(request);
444 DrawingContext::push_transform()
446 transformstack.push_back(transform);
450 DrawingContext::pop_transform()
452 assert(!transformstack.empty());
454 transform = transformstack.back();
455 transformstack.pop_back();
459 DrawingContext::set_drawing_effect(DrawingEffect effect)
461 transform.drawing_effect = effect;
465 DrawingContext::get_drawing_effect() const
467 return transform.drawing_effect;
471 DrawingContext::set_alpha(float alpha)
473 transform.alpha = alpha;
477 DrawingContext::get_alpha() const
479 return transform.alpha;
483 DrawingContext::push_target()
485 target_stack.push_back(target);
489 DrawingContext::pop_target()
491 set_target(target_stack.back());
492 target_stack.pop_back();
496 DrawingContext::set_target(Target target_)
498 this->target = target_;
499 if(target_ == LIGHTMAP) {
500 requests = &lightmap_requests;
502 assert(target_ == NORMAL);
503 requests = &drawing_requests;
508 DrawingContext::set_ambient_color( Color new_color )
510 ambient_color = new_color;
514 DrawingContext::take_screenshot()
516 screenshot_requested = true;