4 // Copyright (C) 2006 Matthias Braun <matze@braunis.de>
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 #include "drawing_context.hpp"
23 #include "drawing_request.hpp"
24 #include "video_systems.hpp"
25 #include "renderer.hpp"
26 #include "lightmap.hpp"
27 #include "surface.hpp"
29 #include "gameconfig.hpp"
30 #include "texture.hpp"
31 #include "texture_manager.hpp"
32 #include "obstack/obstackpp.hpp"
34 static inline int next_po2(int val)
43 DrawingContext::DrawingContext() :
44 renderer(0), lightmap(0), ambient_color(1.0f, 1.0f, 1.0f, 1.0f), target(NORMAL), screenshot_requested(false)
46 requests = &drawing_requests;
50 DrawingContext::~DrawingContext()
55 obstack_free(&obst, NULL);
59 DrawingContext::init_renderer()
64 renderer = new_renderer();
65 lightmap = new_lightmap();
69 DrawingContext::draw_surface(const Surface* surface, const Vector& position,
70 float angle, const Color& color, const Blend& blend,
75 DrawingRequest* request = new(obst) DrawingRequest();
77 request->target = target;
78 request->type = SURFACE;
79 request->pos = transform.apply(position);
81 if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT
82 || request->pos.x + surface->get_width() < 0
83 || request->pos.y + surface->get_height() < 0)
86 request->layer = layer;
87 request->drawing_effect = transform.drawing_effect;
88 request->alpha = transform.alpha;
89 request->angle = angle;
90 request->color = color;
91 request->blend = blend;
93 request->request_data = const_cast<Surface*> (surface);
95 requests->push_back(request);
99 DrawingContext::draw_surface(const Surface* surface, const Vector& position,
102 draw_surface(surface, position, 0.0f, Color(1.0f, 1.0f, 1.0f), Blend(), layer);
106 DrawingContext::draw_surface_part(const Surface* surface, const Vector& source,
107 const Vector& size, const Vector& dest, int layer)
109 assert(surface != 0);
111 DrawingRequest* request = new(obst) DrawingRequest();
113 request->target = target;
114 request->type = SURFACE_PART;
115 request->pos = transform.apply(dest);
116 request->layer = layer;
117 request->drawing_effect = transform.drawing_effect;
118 request->alpha = transform.alpha;
120 SurfacePartRequest* surfacepartrequest = new(obst) SurfacePartRequest();
121 surfacepartrequest->size = size;
122 surfacepartrequest->source = source;
123 surfacepartrequest->surface = surface;
125 // clip on screen borders
126 if(request->pos.x < 0) {
127 surfacepartrequest->size.x += request->pos.x;
128 if(surfacepartrequest->size.x <= 0)
130 surfacepartrequest->source.x -= request->pos.x;
133 if(request->pos.y < 0) {
134 surfacepartrequest->size.y += request->pos.y;
135 if(surfacepartrequest->size.y <= 0)
137 surfacepartrequest->source.y -= request->pos.y;
140 request->request_data = surfacepartrequest;
142 requests->push_back(request);
146 DrawingContext::draw_text(const Font* font, const std::string& text,
147 const Vector& position, FontAlignment alignment, int layer, Color color)
149 DrawingRequest* request = new(obst) DrawingRequest();
151 request->target = target;
152 request->type = TEXT;
153 request->pos = transform.apply(position);
154 request->layer = layer;
155 request->drawing_effect = transform.drawing_effect;
156 request->alpha = transform.alpha;
157 request->color = color;
159 TextRequest* textrequest = new(obst) TextRequest();
160 textrequest->font = font;
161 textrequest->text = text;
162 textrequest->alignment = alignment;
163 request->request_data = textrequest;
165 requests->push_back(request);
169 DrawingContext::draw_center_text(const Font* font, const std::string& text,
170 const Vector& position, int layer, Color color)
172 draw_text(font, text, Vector(position.x + SCREEN_WIDTH/2, position.y),
173 ALIGN_CENTER, layer, color);
177 DrawingContext::draw_gradient(const Color& top, const Color& bottom, int layer)
179 DrawingRequest* request = new(obst) DrawingRequest();
181 request->target = target;
182 request->type = GRADIENT;
183 request->pos = Vector(0,0);
184 request->layer = layer;
186 request->drawing_effect = transform.drawing_effect;
187 request->alpha = transform.alpha;
189 GradientRequest* gradientrequest = new(obst) GradientRequest();
190 gradientrequest->top = top;
191 gradientrequest->bottom = bottom;
192 request->request_data = gradientrequest;
194 requests->push_back(request);
198 DrawingContext::draw_filled_rect(const Vector& topleft, const Vector& size,
199 const Color& color, int layer)
201 DrawingRequest* request = new(obst) DrawingRequest();
203 request->target = target;
204 request->type = FILLRECT;
205 request->pos = transform.apply(topleft);
206 request->layer = layer;
208 request->drawing_effect = transform.drawing_effect;
209 request->alpha = transform.alpha;
211 FillRectRequest* fillrectrequest = new(obst) FillRectRequest();
212 fillrectrequest->size = size;
213 fillrectrequest->color = color;
214 fillrectrequest->color.alpha = color.alpha * transform.alpha;
215 fillrectrequest->radius = 0.0f;
216 request->request_data = fillrectrequest;
218 requests->push_back(request);
222 DrawingContext::draw_filled_rect(const Rect& rect, const Color& color,
225 draw_filled_rect(rect, color, 0.0f, layer);
229 DrawingContext::draw_filled_rect(const Rect& rect, const Color& color, float radius, int layer)
231 DrawingRequest* request = new(obst) DrawingRequest();
233 request->target = target;
234 request->type = FILLRECT;
235 request->pos = transform.apply(rect.p1);
236 request->layer = layer;
238 request->drawing_effect = transform.drawing_effect;
239 request->alpha = transform.alpha;
241 FillRectRequest* fillrectrequest = new(obst) FillRectRequest;
242 fillrectrequest->size = Vector(rect.get_width(), rect.get_height());
243 fillrectrequest->color = color;
244 fillrectrequest->color.alpha = color.alpha * transform.alpha;
245 fillrectrequest->radius = radius;
246 request->request_data = fillrectrequest;
248 requests->push_back(request);
252 DrawingContext::draw_inverse_ellipse(const Vector& pos, const Vector& size, const Color& color, int layer)
254 DrawingRequest* request = new(obst) DrawingRequest();
256 request->target = target;
257 request->type = INVERSEELLIPSE;
258 request->pos = transform.apply(pos);
259 request->layer = layer;
261 request->drawing_effect = transform.drawing_effect;
262 request->alpha = transform.alpha;
264 InverseEllipseRequest* ellipse = new(obst)InverseEllipseRequest;
266 ellipse->color = color;
267 ellipse->color.alpha = color.alpha * transform.alpha;
268 ellipse->size = size;
269 request->request_data = ellipse;
271 requests->push_back(request);
275 DrawingContext::get_light(const Vector& position, Color* color)
277 if( ambient_color.red == 1.0f && ambient_color.green == 1.0f
278 && ambient_color.blue == 1.0f ) {
279 *color = Color( 1.0f, 1.0f, 1.0f);
283 DrawingRequest* request = new(obst) DrawingRequest();
284 request->target = target;
285 request->type = GETLIGHT;
286 request->pos = transform.apply(position);
288 //There is no light offscreen.
289 if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT
290 || request->pos.x < 0 || request->pos.y < 0){
291 *color = Color( 0, 0, 0);
295 request->layer = LAYER_GUI; //make sure all get_light requests are handled last.
296 GetLightRequest* getlightrequest = new(obst) GetLightRequest();
297 getlightrequest->color_ptr = color;
298 request->request_data = getlightrequest;
299 lightmap_requests.push_back(request);
303 DrawingContext::do_drawing()
306 assert(transformstack.empty());
307 assert(target_stack.empty());
309 transformstack.clear();
310 target_stack.clear();
312 //Use Lightmap if ambient color is not white.
313 bool use_lightmap = ( ambient_color.red != 1.0f || ambient_color.green != 1.0f ||
314 ambient_color.blue != 1.0f );
316 // PART1: create lightmap
318 lightmap->start_draw(ambient_color);
319 handle_drawing_requests(lightmap_requests);
320 lightmap->end_draw();
322 DrawingRequest* request = new(obst) DrawingRequest();
323 request->target = NORMAL;
324 request->type = DRAW_LIGHTMAP;
325 request->layer = LAYER_HUD - 1;
326 drawing_requests.push_back(request);
328 lightmap_requests.clear();
330 handle_drawing_requests(drawing_requests);
331 drawing_requests.clear();
332 obstack_free(&obst, NULL);
335 // if a screenshot was requested, take one
336 if (screenshot_requested) {
337 renderer->do_take_screenshot();
338 screenshot_requested = false;
344 class RequestPtrCompare
345 : public std::binary_function<const DrawingRequest*,
346 const DrawingRequest*,
350 bool operator()(const DrawingRequest* r1, const DrawingRequest* r2) const
357 DrawingContext::handle_drawing_requests(DrawingRequests& requests)
359 std::stable_sort(requests.begin(), requests.end(), RequestPtrCompare());
361 DrawingRequests::const_iterator i;
362 for(i = requests.begin(); i != requests.end(); ++i) {
363 const DrawingRequest& request = **i;
365 switch(request.target) {
367 switch(request.type) {
369 renderer->draw_surface(request);
372 renderer->draw_surface_part(request);
375 renderer->draw_gradient(request);
379 const TextRequest* textrequest = (TextRequest*) request.request_data;
380 textrequest->font->draw(renderer, textrequest->text, request.pos,
381 textrequest->alignment, request.drawing_effect, request.color, request.alpha);
385 renderer->draw_filled_rect(request);
388 renderer->draw_inverse_ellipse(request);
394 lightmap->get_light(request);
399 switch(request.type) {
401 lightmap->draw_surface(request);
404 lightmap->draw_surface_part(request);
407 lightmap->draw_gradient(request);
411 const TextRequest* textrequest = (TextRequest*) request.request_data;
412 textrequest->font->draw(renderer, textrequest->text, request.pos,
413 textrequest->alignment, request.drawing_effect, request.color, request.alpha);
417 lightmap->draw_filled_rect(request);
420 assert(!"InverseEllipse doesn't make sense on the lightmap");
426 lightmap->get_light(request);
435 DrawingContext::push_transform()
437 transformstack.push_back(transform);
441 DrawingContext::pop_transform()
443 assert(!transformstack.empty());
445 transform = transformstack.back();
446 transformstack.pop_back();
450 DrawingContext::set_drawing_effect(DrawingEffect effect)
452 transform.drawing_effect = effect;
456 DrawingContext::get_drawing_effect() const
458 return transform.drawing_effect;
462 DrawingContext::set_alpha(float alpha)
464 transform.alpha = alpha;
468 DrawingContext::get_alpha() const
470 return transform.alpha;
474 DrawingContext::push_target()
476 target_stack.push_back(target);
480 DrawingContext::pop_target()
482 set_target(target_stack.back());
483 target_stack.pop_back();
487 DrawingContext::set_target(Target target)
489 this->target = target;
490 if(target == LIGHTMAP) {
491 requests = &lightmap_requests;
493 assert(target == NORMAL);
494 requests = &drawing_requests;
499 DrawingContext::set_ambient_color( Color new_color )
501 ambient_color = new_color;
505 DrawingContext::take_screenshot()
507 screenshot_requested = true;