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>
28 #include "drawing_context.hpp"
29 #include "surface.hpp"
32 #include "gameconfig.hpp"
34 #include "texture.hpp"
35 #include "texture_manager.hpp"
37 #define LIGHTMAP_DIV 4
39 static inline int next_po2(int val)
48 DrawingContext::DrawingContext()
50 screen = SDL_GetVideoSurface();
52 lightmap_width = screen->w / LIGHTMAP_DIV;
53 lightmap_height = screen->h / LIGHTMAP_DIV;
54 unsigned int width = next_po2(lightmap_width);
55 unsigned int height = next_po2(lightmap_height);
57 lightmap = new Texture(width, height, GL_RGB);
59 lightmap_uv_right = static_cast<float>(lightmap_width) / static_cast<float>(width);
60 lightmap_uv_bottom = static_cast<float>(lightmap_height) / static_cast<float>(height);
61 texture_manager->register_texture(lightmap);
63 requests = &drawing_requests;
66 DrawingContext::~DrawingContext()
68 texture_manager->remove_texture(lightmap);
73 DrawingContext::draw_surface(const Surface* surface, const Vector& position, float angle,
78 DrawingRequest request;
80 request.type = SURFACE;
81 request.pos = transform.apply(position);
83 if(request.pos.x >= SCREEN_WIDTH || request.pos.y >= SCREEN_HEIGHT
84 || request.pos.x + surface->get_width() < 0
85 || request.pos.y + surface->get_height() < 0)
88 request.layer = layer;
89 request.drawing_effect = transform.drawing_effect;
90 request.alpha = transform.alpha;
91 request.angle = angle;
92 request.request_data = const_cast<Surface*> (surface);
94 requests->push_back(request);
98 DrawingContext::draw_surface(const Surface* surface, const Vector& position,
101 draw_surface(surface, position, 0.0f, layer);
105 DrawingContext::draw_surface_part(const Surface* surface, const Vector& source,
106 const Vector& size, const Vector& dest, int layer)
108 assert(surface != 0);
110 DrawingRequest request;
112 request.type = SURFACE_PART;
113 request.pos = transform.apply(dest);
114 request.layer = layer;
115 request.drawing_effect = transform.drawing_effect;
116 request.alpha = transform.alpha;
118 SurfacePartRequest* surfacepartrequest = new SurfacePartRequest();
119 surfacepartrequest->size = size;
120 surfacepartrequest->source = source;
121 surfacepartrequest->surface = surface;
123 // clip on screen borders
124 if(request.pos.x < 0) {
125 surfacepartrequest->size.x += request.pos.x;
126 if(surfacepartrequest->size.x <= 0)
128 surfacepartrequest->source.x -= request.pos.x;
131 if(request.pos.y < 0) {
132 surfacepartrequest->size.y += request.pos.y;
133 if(surfacepartrequest->size.y <= 0)
135 surfacepartrequest->source.y -= request.pos.y;
138 request.request_data = surfacepartrequest;
140 requests->push_back(request);
144 DrawingContext::draw_text(const Font* font, const std::string& text,
145 const Vector& position, FontAlignment alignment, int layer)
147 DrawingRequest request;
150 request.pos = transform.apply(position);
151 request.layer = layer;
152 request.drawing_effect = transform.drawing_effect;
153 request.alpha = transform.alpha;
155 TextRequest* textrequest = new TextRequest;
156 textrequest->font = font;
157 textrequest->text = text;
158 textrequest->alignment = alignment;
159 request.request_data = textrequest;
161 requests->push_back(request);
165 DrawingContext::draw_center_text(const Font* font, const std::string& text,
166 const Vector& position, int layer)
168 draw_text(font, text, Vector(position.x + SCREEN_WIDTH/2, position.y),
169 CENTER_ALLIGN, layer);
173 DrawingContext::draw_gradient(const Color& top, const Color& bottom, int layer)
175 DrawingRequest request;
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 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;
198 request.type = FILLRECT;
199 request.pos = transform.apply(topleft);
200 request.layer = layer;
202 request.drawing_effect = transform.drawing_effect;
203 request.alpha = transform.alpha;
205 FillRectRequest* fillrectrequest = new FillRectRequest;
206 fillrectrequest->size = size;
207 fillrectrequest->color = color;
208 fillrectrequest->color.alpha = color.alpha * transform.alpha;
209 request.request_data = fillrectrequest;
211 requests->push_back(request);
215 DrawingContext::draw_filled_rect(const Rect& rect, const Color& color,
218 DrawingRequest request;
220 request.type = FILLRECT;
221 request.pos = transform.apply(rect.p1);
222 request.layer = layer;
224 request.drawing_effect = transform.drawing_effect;
225 request.alpha = transform.alpha;
227 FillRectRequest* fillrectrequest = new FillRectRequest;
228 fillrectrequest->size = Vector(rect.get_width(), rect.get_height());
229 fillrectrequest->color = color;
230 fillrectrequest->color.alpha = color.alpha * transform.alpha;
231 request.request_data = fillrectrequest;
233 requests->push_back(request);
237 DrawingContext::draw_surface_part(DrawingRequest& request)
239 SurfacePartRequest* surfacepartrequest
240 = (SurfacePartRequest*) request.request_data;
242 surfacepartrequest->surface->draw_part(
243 surfacepartrequest->source.x, surfacepartrequest->source.y,
244 request.pos.x, request.pos.y,
245 surfacepartrequest->size.x, surfacepartrequest->size.y,
246 request.alpha, request.drawing_effect);
248 delete surfacepartrequest;
252 DrawingContext::draw_gradient(DrawingRequest& request)
254 GradientRequest* gradientrequest = (GradientRequest*) request.request_data;
255 const Color& top = gradientrequest->top;
256 const Color& bottom = gradientrequest->bottom;
258 glDisable(GL_TEXTURE_2D);
260 glColor4f(top.red, top.green, top.blue, top.alpha);
262 glVertex2f(SCREEN_WIDTH, 0);
263 glColor4f(bottom.red, bottom.green, bottom.blue, bottom.alpha);
264 glVertex2f(SCREEN_WIDTH, SCREEN_HEIGHT);
265 glVertex2f(0, SCREEN_HEIGHT);
267 glEnable(GL_TEXTURE_2D);
269 delete gradientrequest;
273 DrawingContext::draw_text(DrawingRequest& request)
275 TextRequest* textrequest = (TextRequest*) request.request_data;
277 textrequest->font->draw(textrequest->text, request.pos,
278 textrequest->alignment, request.drawing_effect, request.alpha);
284 DrawingContext::draw_filled_rect(DrawingRequest& request)
286 FillRectRequest* fillrectrequest = (FillRectRequest*) request.request_data;
288 float x = request.pos.x;
289 float y = request.pos.y;
290 float w = fillrectrequest->size.x;
291 float h = fillrectrequest->size.y;
293 glDisable(GL_TEXTURE_2D);
294 glColor4f(fillrectrequest->color.red, fillrectrequest->color.green,
295 fillrectrequest->color.blue, fillrectrequest->color.alpha);
300 glVertex2f(x+w, y+h);
303 glEnable(GL_TEXTURE_2D);
305 delete fillrectrequest;
309 DrawingContext::do_drawing()
312 assert(transformstack.empty());
313 assert(target_stack.empty());
315 transformstack.clear();
316 target_stack.clear();
318 bool use_lightmap = lightmap_requests.size() != 0;
320 // PART1: create lightmap
322 glViewport(0, screen->h - lightmap_height, lightmap_width, lightmap_height);
323 glMatrixMode(GL_PROJECTION);
325 glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0);
326 glMatrixMode(GL_MODELVIEW);
329 // FIXME: Add ambient light support here
330 glClearColor(0.5, 0.5, 0.5, 1);
331 glClear(GL_COLOR_BUFFER_BIT);
332 handle_drawing_requests(lightmap_requests);
333 lightmap_requests.clear();
336 glBindTexture(GL_TEXTURE_2D, lightmap->get_handle());
337 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, screen->h - lightmap_height, lightmap_width, lightmap_height);
339 glViewport(0, 0, screen->w, screen->h);
340 glMatrixMode(GL_PROJECTION);
342 glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0);
343 glMatrixMode(GL_MODELVIEW);
348 //glClear(GL_COLOR_BUFFER_BIT);
349 handle_drawing_requests(drawing_requests);
350 drawing_requests.clear();
353 // multiple the lightmap with the framebuffer
354 glBlendFunc(GL_DST_COLOR, GL_ZERO);
356 glBindTexture(GL_TEXTURE_2D, lightmap->get_handle());
359 glTexCoord2f(0, lightmap_uv_bottom);
362 glTexCoord2f(lightmap_uv_right, lightmap_uv_bottom);
363 glVertex2f(SCREEN_WIDTH, 0);
365 glTexCoord2f(lightmap_uv_right, 0);
366 glVertex2f(SCREEN_WIDTH, SCREEN_HEIGHT);
369 glVertex2f(0, SCREEN_HEIGHT);
373 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
376 assert_gl("drawing");
378 SDL_GL_SwapBuffers();
382 DrawingContext::handle_drawing_requests(DrawingRequests& requests)
384 std::stable_sort(requests.begin(), requests.end());
386 for(DrawingRequests::iterator i = requests.begin();
387 i != requests.end(); ++i) {
391 const Surface* surface = (const Surface*) i->request_data;
392 if (i->angle == 0.0f)
393 surface->draw(i->pos.x, i->pos.y, i->alpha, i->drawing_effect);
395 surface->draw(i->pos.x, i->pos.y, i->alpha, i->angle, i->drawing_effect);
399 draw_surface_part(*i);
408 draw_filled_rect(*i);
415 DrawingContext::push_transform()
417 transformstack.push_back(transform);
421 DrawingContext::pop_transform()
423 assert(!transformstack.empty());
425 transform = transformstack.back();
426 transformstack.pop_back();
430 DrawingContext::set_drawing_effect(DrawingEffect effect)
432 transform.drawing_effect = effect;
436 DrawingContext::get_drawing_effect() const
438 return transform.drawing_effect;
442 DrawingContext::set_alpha(float alpha)
444 transform.alpha = alpha;
448 DrawingContext::get_alpha() const
450 return transform.alpha;
454 DrawingContext::push_target()
456 target_stack.push_back(target);
460 DrawingContext::pop_target()
462 set_target(target_stack.back());
463 target_stack.pop_back();
467 DrawingContext::set_target(Target target)
469 this->target = target;
470 if(target == LIGHTMAP)
471 requests = &lightmap_requests;
473 requests = &drawing_requests;