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 "gl_renderer.hpp"
33 #include "gl_lightmap.hpp"
34 #include "sdl_renderer.hpp"
35 #include "sdl_lightmap.hpp"
36 #include "surface.hpp"
38 #include "gameconfig.hpp"
39 #include "texture.hpp"
40 #include "texture_manager.hpp"
41 #include "obstack/obstackpp.hpp"
42 #define LIGHTMAP_DIV 5
44 static inline int next_po2(int val)
53 DrawingContext::DrawingContext() :
54 renderer(0), lightmap(0), ambient_color(1.0f, 1.0f, 1.0f, 1.0f), target(NORMAL), screenshot_requested(false)
56 requests = &drawing_requests;
60 DrawingContext::~DrawingContext()
65 obstack_free(&obst, NULL);
69 DrawingContext::init_renderer()
77 if(config->video == "opengl")
79 renderer = new GL::Renderer();
80 lightmap = new GL::Lightmap();
85 renderer = new SDL::Renderer();
86 lightmap = new SDL::Lightmap();
91 DrawingContext::draw_surface(const Surface* surface, const Vector& position,
92 float angle, const Color& color, const Blend& blend,
97 DrawingRequest* request = new(obst) DrawingRequest();
99 request->target = target;
100 request->type = SURFACE;
101 request->pos = transform.apply(position);
103 if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT
104 || request->pos.x + surface->get_width() < 0
105 || request->pos.y + surface->get_height() < 0)
108 request->layer = layer;
109 request->drawing_effect = transform.drawing_effect;
110 request->alpha = transform.alpha;
111 request->angle = angle;
112 request->color = color;
113 request->blend = blend;
115 request->request_data = const_cast<Surface*> (surface);
117 requests->push_back(request);
121 DrawingContext::draw_surface(const Surface* surface, const Vector& position,
124 draw_surface(surface, position, 0.0f, Color(1.0f, 1.0f, 1.0f), Blend(), layer);
128 DrawingContext::draw_surface_part(const Surface* surface, const Vector& source,
129 const Vector& size, const Vector& dest, int layer)
131 assert(surface != 0);
133 DrawingRequest* request = new(obst) DrawingRequest();
135 request->target = target;
136 request->type = SURFACE_PART;
137 request->pos = transform.apply(dest);
138 request->layer = layer;
139 request->drawing_effect = transform.drawing_effect;
140 request->alpha = transform.alpha;
142 SurfacePartRequest* surfacepartrequest = new(obst) SurfacePartRequest();
143 surfacepartrequest->size = size;
144 surfacepartrequest->source = source;
145 surfacepartrequest->surface = surface;
147 // clip on screen borders
148 if(request->pos.x < 0) {
149 surfacepartrequest->size.x += request->pos.x;
150 if(surfacepartrequest->size.x <= 0)
152 surfacepartrequest->source.x -= request->pos.x;
155 if(request->pos.y < 0) {
156 surfacepartrequest->size.y += request->pos.y;
157 if(surfacepartrequest->size.y <= 0)
159 surfacepartrequest->source.y -= request->pos.y;
162 request->request_data = surfacepartrequest;
164 requests->push_back(request);
168 DrawingContext::draw_text(const Font* font, const std::string& text,
169 const Vector& position, FontAlignment alignment, int layer)
171 DrawingRequest* request = new(obst) DrawingRequest();
173 request->target = target;
174 request->type = TEXT;
175 request->pos = transform.apply(position);
176 request->layer = layer;
177 request->drawing_effect = transform.drawing_effect;
178 request->alpha = transform.alpha;
180 TextRequest* textrequest = new(obst) TextRequest();
181 textrequest->font = font;
182 textrequest->text = text;
183 textrequest->alignment = alignment;
184 request->request_data = textrequest;
186 requests->push_back(request);
190 DrawingContext::draw_center_text(const Font* font, const std::string& text,
191 const Vector& position, int layer)
193 draw_text(font, text, Vector(position.x + SCREEN_WIDTH/2, position.y),
194 ALIGN_CENTER, layer);
198 DrawingContext::draw_gradient(const Color& top, const Color& bottom, int layer)
200 DrawingRequest* request = new(obst) DrawingRequest();
202 request->target = target;
203 request->type = GRADIENT;
204 request->pos = Vector(0,0);
205 request->layer = layer;
207 request->drawing_effect = transform.drawing_effect;
208 request->alpha = transform.alpha;
210 GradientRequest* gradientrequest = new(obst) GradientRequest();
211 gradientrequest->top = top;
212 gradientrequest->bottom = bottom;
213 request->request_data = gradientrequest;
215 requests->push_back(request);
219 DrawingContext::draw_filled_rect(const Vector& topleft, const Vector& size,
220 const Color& color, int layer)
222 DrawingRequest* request = new(obst) DrawingRequest();
224 request->target = target;
225 request->type = FILLRECT;
226 request->pos = transform.apply(topleft);
227 request->layer = layer;
229 request->drawing_effect = transform.drawing_effect;
230 request->alpha = transform.alpha;
232 FillRectRequest* fillrectrequest = new(obst) FillRectRequest();
233 fillrectrequest->size = size;
234 fillrectrequest->color = color;
235 fillrectrequest->color.alpha = color.alpha * transform.alpha;
236 request->request_data = fillrectrequest;
238 requests->push_back(request);
242 DrawingContext::draw_filled_rect(const Rect& rect, const Color& color,
245 DrawingRequest* request = new(obst) DrawingRequest();
247 request->target = target;
248 request->type = FILLRECT;
249 request->pos = transform.apply(rect.p1);
250 request->layer = layer;
252 request->drawing_effect = transform.drawing_effect;
253 request->alpha = transform.alpha;
255 FillRectRequest* fillrectrequest = new(obst) FillRectRequest;
256 fillrectrequest->size = Vector(rect.get_width(), rect.get_height());
257 fillrectrequest->color = color;
258 fillrectrequest->color.alpha = color.alpha * transform.alpha;
259 request->request_data = fillrectrequest;
261 requests->push_back(request);
265 DrawingContext::get_light(const Vector& position, Color* color)
267 if( ambient_color.red == 1.0f && ambient_color.green == 1.0f
268 && ambient_color.blue == 1.0f ) {
269 *color = Color( 1.0f, 1.0f, 1.0f);
273 DrawingRequest* request = new(obst) DrawingRequest();
274 request->target = target;
275 request->type = GETLIGHT;
276 request->pos = transform.apply(position);
278 //There is no light offscreen.
279 if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT
280 || request->pos.x < 0 || request->pos.y < 0){
281 *color = Color( 0, 0, 0);
285 request->layer = LAYER_GUI; //make sure all get_light requests are handled last.
286 GetLightRequest* getlightrequest = new(obst) GetLightRequest();
287 getlightrequest->color_ptr = color;
288 request->request_data = getlightrequest;
289 lightmap_requests.push_back(request);
293 DrawingContext::do_drawing()
296 assert(transformstack.empty());
297 assert(target_stack.empty());
299 transformstack.clear();
300 target_stack.clear();
302 //Use Lightmap if ambient color is not white.
303 bool use_lightmap = ( ambient_color.red != 1.0f || ambient_color.green != 1.0f ||
304 ambient_color.blue != 1.0f );
306 // PART1: create lightmap
308 lightmap->start_draw(ambient_color);
309 handle_drawing_requests(lightmap_requests);
310 lightmap->end_draw();
313 handle_drawing_requests(drawing_requests);
317 obstack_free(&obst, NULL);
320 // if a screenshot was requested, take one
321 if (screenshot_requested) {
322 renderer->do_take_screenshot();
323 screenshot_requested = false;
329 class RequestPtrCompare
330 : public std::binary_function<const DrawingRequest*,
331 const DrawingRequest*,
335 bool operator()(const DrawingRequest* r1, const DrawingRequest* r2) const
342 DrawingContext::handle_drawing_requests(DrawingRequests& requests)
344 std::stable_sort(requests.begin(), requests.end(), RequestPtrCompare());
346 DrawingRequests::const_iterator i;
347 for(i = requests.begin(); i != requests.end(); ++i) {
348 const DrawingRequest& request = **i;
350 switch(request.target) {
352 switch(request.type) {
354 renderer->draw_surface(request);
357 renderer->draw_surface_part(request);
360 renderer->draw_gradient(request);
363 renderer->draw_text(request);
366 renderer->draw_filled_rect(request);
369 lightmap->get_light(request);
374 switch(request.type) {
376 lightmap->draw_surface(request);
379 lightmap->draw_surface_part(request);
382 lightmap->draw_gradient(request);
385 lightmap->draw_text(request);
388 lightmap->draw_filled_rect(request);
391 lightmap->get_light(request);
401 DrawingContext::push_transform()
403 transformstack.push_back(transform);
407 DrawingContext::pop_transform()
409 assert(!transformstack.empty());
411 transform = transformstack.back();
412 transformstack.pop_back();
416 DrawingContext::set_drawing_effect(DrawingEffect effect)
418 transform.drawing_effect = effect;
422 DrawingContext::get_drawing_effect() const
424 return transform.drawing_effect;
428 DrawingContext::set_alpha(float alpha)
430 transform.alpha = alpha;
434 DrawingContext::get_alpha() const
436 return transform.alpha;
440 DrawingContext::push_target()
442 target_stack.push_back(target);
446 DrawingContext::pop_target()
448 set_target(target_stack.back());
449 target_stack.pop_back();
453 DrawingContext::set_target(Target target)
455 this->target = target;
456 if(target == LIGHTMAP) {
457 requests = &lightmap_requests;
459 assert(target == NORMAL);
460 requests = &drawing_requests;
465 DrawingContext::set_ambient_color( Color new_color )
467 ambient_color = new_color;
471 DrawingContext::take_screenshot()
473 screenshot_requested = true;