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.
25 #include <SDL_image.h>
30 #include "drawing_context.hpp"
31 #include "drawing_request.hpp"
32 #include "video_systems.hpp"
33 #include "renderer.hpp"
34 #include "lightmap.hpp"
35 #include "surface.hpp"
37 #include "gameconfig.hpp"
38 #include "texture.hpp"
39 #include "texture_manager.hpp"
40 #include "obstack/obstackpp.hpp"
41 #define LIGHTMAP_DIV 5
43 static inline int next_po2(int val)
52 DrawingContext::DrawingContext() :
53 renderer(0), lightmap(0), ambient_color(1.0f, 1.0f, 1.0f, 1.0f), target(NORMAL), screenshot_requested(false)
55 requests = &drawing_requests;
59 DrawingContext::~DrawingContext()
64 obstack_free(&obst, NULL);
68 DrawingContext::init_renderer()
73 renderer = new_renderer();
74 lightmap = new_lightmap();
78 DrawingContext::draw_surface(const Surface* surface, const Vector& position,
79 float angle, const Color& color, const Blend& blend,
84 DrawingRequest* request = new(obst) DrawingRequest();
86 request->target = target;
87 request->type = SURFACE;
88 request->pos = transform.apply(position);
90 if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT
91 || request->pos.x + surface->get_width() < 0
92 || request->pos.y + surface->get_height() < 0)
95 request->layer = layer;
96 request->drawing_effect = transform.drawing_effect;
97 request->alpha = transform.alpha;
98 request->angle = angle;
99 request->color = color;
100 request->blend = blend;
102 request->request_data = const_cast<Surface*> (surface);
104 requests->push_back(request);
108 DrawingContext::draw_surface(const Surface* 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(const Surface* surface, const Vector& source,
116 const Vector& size, const Vector& dest, int layer)
118 assert(surface != 0);
120 DrawingRequest* request = new(obst) DrawingRequest();
122 request->target = target;
123 request->type = SURFACE_PART;
124 request->pos = transform.apply(dest);
125 request->layer = layer;
126 request->drawing_effect = transform.drawing_effect;
127 request->alpha = transform.alpha;
129 SurfacePartRequest* surfacepartrequest = new(obst) SurfacePartRequest();
130 surfacepartrequest->size = size;
131 surfacepartrequest->source = source;
132 surfacepartrequest->surface = surface;
134 // clip on screen borders
135 if(request->pos.x < 0) {
136 surfacepartrequest->size.x += request->pos.x;
137 if(surfacepartrequest->size.x <= 0)
139 surfacepartrequest->source.x -= request->pos.x;
142 if(request->pos.y < 0) {
143 surfacepartrequest->size.y += request->pos.y;
144 if(surfacepartrequest->size.y <= 0)
146 surfacepartrequest->source.y -= request->pos.y;
149 request->request_data = surfacepartrequest;
151 requests->push_back(request);
155 DrawingContext::draw_text(const Font* font, const std::string& text,
156 const Vector& position, FontAlignment alignment, int layer)
158 DrawingRequest* request = new(obst) DrawingRequest();
160 request->target = target;
161 request->type = TEXT;
162 request->pos = transform.apply(position);
163 request->layer = layer;
164 request->drawing_effect = transform.drawing_effect;
165 request->alpha = transform.alpha;
167 TextRequest* textrequest = new(obst) TextRequest();
168 textrequest->font = font;
169 textrequest->text = text;
170 textrequest->alignment = alignment;
171 request->request_data = textrequest;
173 requests->push_back(request);
177 DrawingContext::draw_center_text(const Font* font, const std::string& text,
178 const Vector& position, int layer)
180 draw_text(font, text, Vector(position.x + SCREEN_WIDTH/2, position.y),
181 ALIGN_CENTER, layer);
185 DrawingContext::draw_gradient(const Color& top, const Color& bottom, int layer)
187 DrawingRequest* request = new(obst) DrawingRequest();
189 request->target = target;
190 request->type = GRADIENT;
191 request->pos = Vector(0,0);
192 request->layer = layer;
194 request->drawing_effect = transform.drawing_effect;
195 request->alpha = transform.alpha;
197 GradientRequest* gradientrequest = new(obst) GradientRequest();
198 gradientrequest->top = top;
199 gradientrequest->bottom = bottom;
200 request->request_data = gradientrequest;
202 requests->push_back(request);
206 DrawingContext::draw_filled_rect(const Vector& topleft, const Vector& size,
207 const Color& color, int layer)
209 DrawingRequest* request = new(obst) DrawingRequest();
211 request->target = target;
212 request->type = FILLRECT;
213 request->pos = transform.apply(topleft);
214 request->layer = layer;
216 request->drawing_effect = transform.drawing_effect;
217 request->alpha = transform.alpha;
219 FillRectRequest* fillrectrequest = new(obst) FillRectRequest();
220 fillrectrequest->size = size;
221 fillrectrequest->color = color;
222 fillrectrequest->color.alpha = color.alpha * transform.alpha;
223 request->request_data = fillrectrequest;
225 requests->push_back(request);
229 DrawingContext::draw_filled_rect(const Rect& rect, const Color& color,
232 DrawingRequest* request = new(obst) DrawingRequest();
234 request->target = target;
235 request->type = FILLRECT;
236 request->pos = transform.apply(rect.p1);
237 request->layer = layer;
239 request->drawing_effect = transform.drawing_effect;
240 request->alpha = transform.alpha;
242 FillRectRequest* fillrectrequest = new(obst) FillRectRequest;
243 fillrectrequest->size = Vector(rect.get_width(), rect.get_height());
244 fillrectrequest->color = color;
245 fillrectrequest->color.alpha = color.alpha * transform.alpha;
246 request->request_data = fillrectrequest;
248 requests->push_back(request);
252 DrawingContext::get_light(const Vector& position, Color* color)
254 if( ambient_color.red == 1.0f && ambient_color.green == 1.0f
255 && ambient_color.blue == 1.0f ) {
256 *color = Color( 1.0f, 1.0f, 1.0f);
260 DrawingRequest* request = new(obst) DrawingRequest();
261 request->target = target;
262 request->type = GETLIGHT;
263 request->pos = transform.apply(position);
265 //There is no light offscreen.
266 if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT
267 || request->pos.x < 0 || request->pos.y < 0){
268 *color = Color( 0, 0, 0);
272 request->layer = LAYER_GUI; //make sure all get_light requests are handled last.
273 GetLightRequest* getlightrequest = new(obst) GetLightRequest();
274 getlightrequest->color_ptr = color;
275 request->request_data = getlightrequest;
276 lightmap_requests.push_back(request);
280 DrawingContext::do_drawing()
283 assert(transformstack.empty());
284 assert(target_stack.empty());
286 transformstack.clear();
287 target_stack.clear();
289 //Use Lightmap if ambient color is not white.
290 bool use_lightmap = ( ambient_color.red != 1.0f || ambient_color.green != 1.0f ||
291 ambient_color.blue != 1.0f );
293 // PART1: create lightmap
295 lightmap->start_draw(ambient_color);
296 handle_drawing_requests(lightmap_requests);
297 lightmap->end_draw();
300 handle_drawing_requests(drawing_requests);
304 obstack_free(&obst, NULL);
307 // if a screenshot was requested, take one
308 if (screenshot_requested) {
309 renderer->do_take_screenshot();
310 screenshot_requested = false;
316 class RequestPtrCompare
317 : public std::binary_function<const DrawingRequest*,
318 const DrawingRequest*,
322 bool operator()(const DrawingRequest* r1, const DrawingRequest* r2) const
329 DrawingContext::handle_drawing_requests(DrawingRequests& requests)
331 std::stable_sort(requests.begin(), requests.end(), RequestPtrCompare());
333 DrawingRequests::const_iterator i;
334 for(i = requests.begin(); i != requests.end(); ++i) {
335 const DrawingRequest& request = **i;
337 switch(request.target) {
339 switch(request.type) {
341 renderer->draw_surface(request);
344 renderer->draw_surface_part(request);
347 renderer->draw_gradient(request);
350 renderer->draw_text(request);
353 renderer->draw_filled_rect(request);
356 lightmap->get_light(request);
361 switch(request.type) {
363 lightmap->draw_surface(request);
366 lightmap->draw_surface_part(request);
369 lightmap->draw_gradient(request);
372 lightmap->draw_text(request);
375 lightmap->draw_filled_rect(request);
378 lightmap->get_light(request);
388 DrawingContext::push_transform()
390 transformstack.push_back(transform);
394 DrawingContext::pop_transform()
396 assert(!transformstack.empty());
398 transform = transformstack.back();
399 transformstack.pop_back();
403 DrawingContext::set_drawing_effect(DrawingEffect effect)
405 transform.drawing_effect = effect;
409 DrawingContext::get_drawing_effect() const
411 return transform.drawing_effect;
415 DrawingContext::set_alpha(float alpha)
417 transform.alpha = alpha;
421 DrawingContext::get_alpha() const
423 return transform.alpha;
427 DrawingContext::push_target()
429 target_stack.push_back(target);
433 DrawingContext::pop_target()
435 set_target(target_stack.back());
436 target_stack.pop_back();
440 DrawingContext::set_target(Target target)
442 this->target = target;
443 if(target == LIGHTMAP) {
444 requests = &lightmap_requests;
446 assert(target == NORMAL);
447 requests = &drawing_requests;
452 DrawingContext::set_ambient_color( Color new_color )
454 ambient_color = new_color;
458 DrawingContext::take_screenshot()
460 screenshot_requested = true;