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"
42 #include "math/vector.hpp"
43 #include "math/rect.hpp"
45 #include <unison/video/Renderers.hpp>
47 /*static inline int next_po2(int val)
56 DrawingContext::DrawingContext()
57 /*renderer(0), lightmap(0), ambient_color(1.0f, 1.0f, 1.0f, 1.0f), target(NORMAL), screenshot_requested(false)*/
59 ambient_color = Color(1.0f, 1.0f, 1.0f, 1.0f);
61 screenshot_requested = false;
62 draw_target = &normal_list;
63 /*requests = &drawing_requests;
64 obstack_init(&obst);*/
67 DrawingContext::~DrawingContext()
72 obstack_free(&obst, NULL);*/
76 DrawingContext::init_renderer()
78 Unison::Video::Renderers::get().set_renderer(config->video);
79 Unison::Video::Window::get().set_logical_size(Unison::Video::Area(SCREEN_WIDTH, SCREEN_HEIGHT));
80 Unison::Video::Window::get().open(Unison::Video::Area(config->screenwidth, config->screenheight), config->use_fullscreen);
81 lightmap = Unison::Video::Surface(Unison::Video::Area(SCREEN_WIDTH, SCREEN_HEIGHT));
85 renderer = new_renderer();
86 lightmap = new_lightmap();*/
90 DrawingContext::draw_surface(const Surface* surface, const Vector& position,
91 float angle, const Color& color, const Blend& blend,
96 Unison::Video::RenderOptions options;
97 options.color = color.to_unison_color();
98 options.alpha = (unsigned char) transform.alpha * 0xff;
99 options.blend = blend.to_unison_blend();
100 options.h_flip = surface->get_flipx() != (transform.drawing_effect == HORIZONTAL_FLIP);
101 options.v_flip = (transform.drawing_effect == VERTICAL_FLIP);
103 Vector transformed = transform.apply(position);
104 Unison::Video::Point dst_pos((int) transformed.x, (int) transformed.y);
106 (*draw_target)[layer].blit_section(surface->get_texture(), dst_pos, options);
108 /*DrawingRequest* request = new(obst) DrawingRequest();
110 request->target = target;
111 request->type = SURFACE;
112 request->pos = transform.apply(position);
114 if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT
115 || request->pos.x + surface->get_width() < 0
116 || request->pos.y + surface->get_height() < 0)
119 request->layer = layer;
120 request->drawing_effect = transform.drawing_effect;
121 request->alpha = transform.alpha;
122 request->angle = angle;
123 request->color = color;
124 request->blend = blend;
126 request->request_data = const_cast<Surface*> (surface);
128 requests->push_back(request);*/
132 DrawingContext::draw_surface(const Surface* surface, const Vector& position,
135 draw_surface(surface, position, 0.0f, Color(1.0f, 1.0f, 1.0f), Blend(), layer);
139 DrawingContext::draw_surface_part(const Surface* surface, const Vector& source,
140 const Vector& size, const Vector& dest, int layer)
142 assert(surface != 0);
144 Unison::Video::TextureSection texture = surface->get_texture();
145 texture.clip_rect.pos.x += (int) source.x;
146 texture.clip_rect.pos.y += (int) source.y;
147 texture.clip_rect.size.x += (unsigned int) size.x;
148 texture.clip_rect.size.y += (unsigned int) size.y;
150 Unison::Video::RenderOptions options;
151 options.alpha = (unsigned char) transform.alpha * 0xff;
152 options.h_flip = surface->get_flipx() != (transform.drawing_effect == HORIZONTAL_FLIP);
153 options.v_flip = (transform.drawing_effect == VERTICAL_FLIP);
155 Vector transformed = transform.apply(dest);
156 Unison::Video::Point dst_pos((int) transformed.x, (int) transformed.y);
158 (*draw_target)[layer].blit_section(texture, dst_pos, options);
160 /*DrawingRequest* request = new(obst) DrawingRequest();
162 request->target = target;
163 request->type = SURFACE_PART;
164 request->pos = transform.apply(dest);
165 request->layer = layer;
166 request->drawing_effect = transform.drawing_effect;
167 request->alpha = transform.alpha;
169 SurfacePartRequest* surfacepartrequest = new(obst) SurfacePartRequest();
170 surfacepartrequest->size = size;
171 surfacepartrequest->source = source;
172 surfacepartrequest->surface = surface;
174 // clip on screen borders
175 if(request->pos.x < 0) {
176 surfacepartrequest->size.x += request->pos.x;
177 if(surfacepartrequest->size.x <= 0)
179 surfacepartrequest->source.x -= request->pos.x;
182 if(request->pos.y < 0) {
183 surfacepartrequest->size.y += request->pos.y;
184 if(surfacepartrequest->size.y <= 0)
186 surfacepartrequest->source.y -= request->pos.y;
189 request->request_data = surfacepartrequest;
191 requests->push_back(request);*/
195 DrawingContext::draw_text(const Font* font, const std::string& text,
196 const Vector& position, FontAlignment alignment, int layer)
198 font->draw((*draw_target)[layer], text, transform.apply(position),
199 alignment, transform.drawing_effect, transform.alpha);
201 /*DrawingRequest* request = new(obst) DrawingRequest();
203 request->target = target;
204 request->type = TEXT;
205 request->pos = transform.apply(position);
206 request->layer = layer;
207 request->drawing_effect = transform.drawing_effect;
208 request->alpha = transform.alpha;
210 TextRequest* textrequest = new(obst) TextRequest();
211 textrequest->font = font;
212 textrequest->text = text;
213 textrequest->alignment = alignment;
214 request->request_data = textrequest;
216 requests->push_back(request);*/
220 DrawingContext::draw_center_text(const Font* font, const std::string& text,
221 const Vector& position, int layer)
223 draw_text(font, text, Vector(position.x + SCREEN_WIDTH/2, position.y),
224 ALIGN_CENTER, layer);
229 class GradientRequest : public Unison::Video::DisplayList::Request
232 GradientRequest(const Color &top, const Color &bottom) :
238 void do_request(Unison::Video::Blittable *dst) const
240 for(int y = 0;y < SCREEN_HEIGHT;++y)
242 Unison::Video::Color color;
243 color.red = (Uint8)((((float)(top.red-bottom.red)/(0-SCREEN_HEIGHT)) * y + top.red) * 255);
244 color.green = (Uint8)((((float)(top.green-bottom.green)/(0-SCREEN_HEIGHT)) * y + top.green) * 255);
245 color.green = (Uint8)((((float)(top.blue-bottom.blue)/(0-SCREEN_HEIGHT)) * y + top.blue) * 255);
246 color.alpha = (Uint8)((((float)(top.alpha-bottom.alpha)/(0-SCREEN_HEIGHT)) * y + top.alpha) * 255);
247 dst->fill(color, Unison::Video::Rect(0, y, SCREEN_WIDTH, 1));
257 DrawingContext::draw_gradient(const Color& top, const Color& bottom, int layer)
259 (*draw_target)[layer].add_request(new GradientRequest(top, bottom));
261 /*DrawingRequest* request = new(obst) DrawingRequest();
263 request->target = target;
264 request->type = GRADIENT;
265 request->pos = Vector(0,0);
266 request->layer = layer;
268 request->drawing_effect = transform.drawing_effect;
269 request->alpha = transform.alpha;
271 GradientRequest* gradientrequest = new(obst) GradientRequest();
272 gradientrequest->top = top;
273 gradientrequest->bottom = bottom;
274 request->request_data = gradientrequest;
276 requests->push_back(request);*/
280 DrawingContext::draw_filled_rect(const Vector& topleft, const Vector& size,
281 const Color& color, int layer)
283 Vector transformed = transform.apply(topleft);
285 Unison::Video::Rect rect;
286 rect.pos = Unison::Video::Point((int) transformed.x, (int) transformed.y);
287 rect.size.x = (unsigned int) size.x;
288 rect.size.y = (unsigned int) size.y;
290 (*draw_target)[layer].fill_blend(color.to_unison_color(), rect);
292 /*DrawingRequest* request = new(obst) DrawingRequest();
294 request->target = target;
295 request->type = FILLRECT;
296 request->pos = transform.apply(topleft);
297 request->layer = layer;
299 request->drawing_effect = transform.drawing_effect;
300 request->alpha = transform.alpha;
302 FillRectRequest* fillrectrequest = new(obst) FillRectRequest();
303 fillrectrequest->size = size;
304 fillrectrequest->color = color;
305 fillrectrequest->color.alpha = color.alpha * transform.alpha;
306 request->request_data = fillrectrequest;
308 requests->push_back(request);*/
312 DrawingContext::draw_filled_rect(const Rect& rect, const Color& color,
315 Vector transformed = transform.apply(rect.p1);
317 Unison::Video::Rect unison_rect;
318 unison_rect.pos.x = (int) transformed.x;
319 unison_rect.pos.y = (int) transformed.y;
320 unison_rect.size.x = (unsigned int) rect.get_width();
321 unison_rect.size.y = (unsigned int) rect.get_height();
323 (*draw_target)[layer].fill_blend(color.to_unison_color(), unison_rect);
325 /*DrawingRequest* request = new(obst) DrawingRequest();
327 request->target = target;
328 request->type = FILLRECT;
329 request->pos = transform.apply(rect.p1);
330 request->layer = layer;
332 request->drawing_effect = transform.drawing_effect;
333 request->alpha = transform.alpha;
335 FillRectRequest* fillrectrequest = new(obst) FillRectRequest;
336 fillrectrequest->size = Vector(rect.get_width(), rect.get_height());
337 fillrectrequest->color = color;
338 fillrectrequest->color.alpha = color.alpha * transform.alpha;
339 request->request_data = fillrectrequest;
341 requests->push_back(request);*/
345 DrawingContext::get_light(const Vector& position, Color* color)
347 if( ambient_color.red == 1.0f && ambient_color.green == 1.0f
348 && ambient_color.blue == 1.0f ) {
349 *color = Color( 1.0f, 1.0f, 1.0f);
353 /*DrawingRequest* request = new(obst) DrawingRequest();
354 request->target = target;
355 request->type = GETLIGHT;
356 request->pos = transform.apply(position);*/
358 //There is no light offscreen.
359 if(position.x >= SCREEN_WIDTH || position.y >= SCREEN_HEIGHT
360 || position.x < 0 || position.y < 0){
361 *color = Color( 0, 0, 0);
365 Vector transformed = transform.apply(position);
366 Unison::Video::Point pos((int) transformed.x, (int) transformed.y);
367 get_light_requests.push_back(std::make_pair(pos, color));
369 /*request->layer = LAYER_GUI; //make sure all get_light requests are handled last.
370 GetLightRequest* getlightrequest = new(obst) GetLightRequest();
371 getlightrequest->color_ptr = color;
372 request->request_data = getlightrequest;
373 lightmap_requests.push_back(request);*/
377 DrawingContext::do_drawing()
380 assert(transformstack.empty());
381 assert(target_stack.empty());
383 transformstack.clear();
384 target_stack.clear();
386 //Use Lightmap if ambient color is not white.
387 bool use_lightmap = ( ambient_color.red != 1.0f || ambient_color.green != 1.0f ||
388 ambient_color.blue != 1.0f );
390 // PART1: create lightmap
392 lightmap.fill(ambient_color.to_unison_color());
393 lightmap.draw(lightmap_list);
394 //lightmap->start_draw(ambient_color);
395 //handle_drawing_requests(lightmap_requests);
396 //lightmap->end_draw();
399 Unison::Video::Window::get().draw(normal_list);
401 //handle_drawing_requests(drawing_requests);
403 Unison::Video::Window::get().blit(lightmap, Unison::Video::Point(), Unison::Video::Rect(), Unison::Video::BLEND_MOD);
404 //lightmap->do_draw();
406 //obstack_free(&obst, NULL);
407 //obstack_init(&obst);
409 // if a screenshot was requested, take one
410 if (screenshot_requested) {
411 // FIXME renderer->do_take_screenshot();
412 screenshot_requested = false;
416 Unison::Video::Window::get().flip();
419 lightmap_list.clear();
422 /*class RequestPtrCompare
423 : public std::binary_function<const DrawingRequest*,
424 std::vector<std::pair<Unison::Video::Point, Color *> > get_light_requests;
425 const DrawingRequest*,
429 bool operator()(const DrawingRequest* r1, const DrawingRequest* r2) const
436 DrawingContext::handle_drawing_requests(DrawingRequests& requests)
438 std::stable_sort(requests.begin(), requests.end(), RequestPtrCompare());
440 DrawingRequests::const_iterator i;
441 for(i = requests.begin(); i != requests.end(); ++i) {
442 const DrawingRequest& request = **i;
444 switch(request.target) {
446 switch(request.type) {
448 renderer->draw_surface(request);
451 renderer->draw_surface_part(request);
454 renderer->draw_gradient(request);
458 const TextRequest* textrequest = (TextRequest*) request.request_data;
459 textrequest->font->draw(renderer, textrequest->text, request.pos,
460 textrequest->alignment, request.drawing_effect, request.alpha);
464 renderer->draw_filled_rect(request);
467 lightmap->get_light(request);
472 switch(request.type) {
474 lightmap->draw_surface(request);
477 lightmap->draw_surface_part(request);
480 lightmap->draw_gradient(request);
484 const TextRequest* textrequest = (TextRequest*) request.request_data;
485 textrequest->font->draw(renderer, textrequest->text, request.pos,
486 textrequest->alignment, request.drawing_effect, request.alpha);
490 lightmap->draw_filled_rect(request);
493 lightmap->get_light(request);
503 DrawingContext::push_transform()
505 transformstack.push_back(transform);
509 DrawingContext::pop_transform()
511 assert(!transformstack.empty());
513 transform = transformstack.back();
514 transformstack.pop_back();
518 DrawingContext::set_drawing_effect(DrawingEffect effect)
520 transform.drawing_effect = effect;
524 DrawingContext::get_drawing_effect() const
526 return transform.drawing_effect;
530 DrawingContext::set_alpha(float alpha)
532 transform.alpha = alpha;
536 DrawingContext::get_alpha() const
538 return transform.alpha;
542 DrawingContext::push_target()
544 target_stack.push_back(target);
548 DrawingContext::pop_target()
550 set_target(target_stack.back());
551 target_stack.pop_back();
555 DrawingContext::set_target(Target target)
557 this->target = target;
558 if(target == LIGHTMAP) {
559 draw_target = &lightmap_list;
561 assert(target == NORMAL);
562 draw_target = &normal_list;
567 DrawingContext::set_ambient_color( Color new_color )
569 ambient_color = new_color;
573 DrawingContext::take_screenshot()
575 screenshot_requested = true;