Moved some declarations from drawing_requests.hpp to drawing_context.hpp to reduce...
[supertux.git] / src / video / gl / gl_lightmap.cpp
1 //  SuperTux
2 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3 //
4 //  This program is free software: you can redistribute it and/or modify
5 //  it under the terms of the GNU General Public License as published by
6 //  the Free Software Foundation, either version 3 of the License, or
7 //  (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17 #include "video/gl/gl_lightmap.hpp"
18
19 #include <SDL_image.h>
20 #include <algorithm>
21 #include <assert.h>
22 #include <functional>
23 #include <iomanip>
24 #include <iostream>
25 #include <math.h>
26 #include <physfs.h>
27 #include <sstream>
28
29 #include "supertux/gameconfig.hpp"
30 #include "supertux/globals.hpp"
31 #include "util/obstackpp.hpp"
32 #include "video/drawing_context.hpp"
33 #include "video/drawing_request.hpp"
34 #include "video/font.hpp"
35 #include "video/gl/gl_surface_data.hpp"
36 #include "video/gl/gl_renderer.hpp"
37 #include "video/gl/gl_texture.hpp"
38 #include "video/glutil.hpp"
39 #include "video/lightmap.hpp"
40 #include "video/renderer.hpp"
41 #include "video/surface.hpp"
42 #include "video/texture_manager.hpp"
43
44 inline int next_po2(int val)
45 {
46   int result = 1;
47   while(result < val)
48     result *= 2;
49
50   return result;
51 }
52
53 GLLightmap::GLLightmap() :
54   lightmap(),
55   lightmap_width(),
56   lightmap_height(),
57   lightmap_uv_right(),
58   lightmap_uv_bottom()
59 {
60   lightmap_width = SCREEN_WIDTH / LIGHTMAP_DIV;
61   lightmap_height = SCREEN_HEIGHT / LIGHTMAP_DIV;
62   unsigned int width = next_po2(lightmap_width);
63   unsigned int height = next_po2(lightmap_height);
64
65   lightmap.reset(new GLTexture(width, height));
66
67   lightmap_uv_right = static_cast<float>(lightmap_width) / static_cast<float>(width);
68   lightmap_uv_bottom = static_cast<float>(lightmap_height) / static_cast<float>(height);
69   texture_manager->register_texture(lightmap.get());
70 }
71
72 GLLightmap::~GLLightmap()
73 {
74 }
75
76 void
77 GLLightmap::start_draw(const Color &ambient_color)
78 {
79
80   glGetFloatv(GL_VIEWPORT, old_viewport); //save viewport
81   glViewport(old_viewport[0], old_viewport[3] - lightmap_height + old_viewport[1], lightmap_width, lightmap_height);
82   glMatrixMode(GL_PROJECTION);
83   glLoadIdentity();
84 #ifdef GL_VERSION_ES_CM_1_0
85   glOrthof(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0);
86 #else
87   glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0);
88 #endif
89   glMatrixMode(GL_MODELVIEW);
90   glLoadIdentity();
91
92   glClearColor( ambient_color.red, ambient_color.green, ambient_color.blue, 1 );
93   glClear(GL_COLOR_BUFFER_BIT);
94 }
95
96 void
97 GLLightmap::end_draw()
98 {
99   glDisable(GL_BLEND);
100   glBindTexture(GL_TEXTURE_2D, lightmap->get_handle());
101   glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, old_viewport[0], old_viewport[3]  - lightmap_height + old_viewport[1], lightmap_width, lightmap_height);
102
103   glViewport(old_viewport[0], old_viewport[1], old_viewport[2], old_viewport[3]);
104   glMatrixMode(GL_PROJECTION);
105   glLoadIdentity();
106 #ifdef GL_VERSION_ES_CM_1_0
107   glOrthof(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0);
108 #else
109   glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0);
110 #endif
111   glMatrixMode(GL_MODELVIEW);
112   glLoadIdentity();
113   glEnable(GL_BLEND);
114
115   glClearColor(0, 0, 0, 1 );
116   glClear(GL_COLOR_BUFFER_BIT);
117 }
118
119 void
120 GLLightmap::do_draw()
121 {
122   // multiple the lightmap with the framebuffer
123   glBlendFunc(GL_DST_COLOR, GL_ZERO);
124
125   glBindTexture(GL_TEXTURE_2D, lightmap->get_handle());
126
127   float vertices[] = {
128     0, 0,
129     float(SCREEN_WIDTH), 0,
130     float(SCREEN_WIDTH), float(SCREEN_HEIGHT),
131     0, float(SCREEN_HEIGHT)
132   };
133   glVertexPointer(2, GL_FLOAT, 0, vertices);
134
135   float uvs[] = {
136     0,                 lightmap_uv_bottom,
137     lightmap_uv_right, lightmap_uv_bottom,
138     lightmap_uv_right, 0,
139     0, 0
140   };
141   glTexCoordPointer(2, GL_FLOAT, 0, uvs);
142
143   glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
144
145   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
146 }
147
148 void
149 GLLightmap::draw_surface(const DrawingRequest& request)
150 {
151   const Surface* surface = (const Surface*) request.request_data;
152   boost::shared_ptr<GLTexture> gltexture = boost::dynamic_pointer_cast<GLTexture>(surface->get_texture());
153   GLSurfaceData *surface_data = reinterpret_cast<GLSurfaceData *>(surface->get_surface_data());
154
155   glBindTexture(GL_TEXTURE_2D, gltexture->get_handle());
156   intern_draw(request.pos.x, request.pos.y,
157               request.pos.x + surface->get_width(),
158               request.pos.y + surface->get_height(),
159               surface_data->get_uv_left(),
160               surface_data->get_uv_top(),
161               surface_data->get_uv_right(),
162               surface_data->get_uv_bottom(),
163               request.angle,
164               request.alpha,
165               request.color,
166               request.blend,
167               request.drawing_effect);
168 }
169
170 void
171 GLLightmap::draw_surface_part(const DrawingRequest& request)
172 {
173   const SurfacePartRequest* surfacepartrequest
174     = (SurfacePartRequest*) request.request_data;
175   const Surface* surface = surfacepartrequest->surface;
176   boost::shared_ptr<GLTexture> gltexture = boost::dynamic_pointer_cast<GLTexture>(surface->get_texture());
177   GLSurfaceData *surface_data = reinterpret_cast<GLSurfaceData *>(surface->get_surface_data());
178
179   float uv_width = surface_data->get_uv_right() - surface_data->get_uv_left();
180   float uv_height = surface_data->get_uv_bottom() - surface_data->get_uv_top();
181
182   float uv_left = surface_data->get_uv_left() + (uv_width * surfacepartrequest->source.x) / surface->get_width();
183   float uv_top = surface_data->get_uv_top() + (uv_height * surfacepartrequest->source.y) / surface->get_height();
184   float uv_right = surface_data->get_uv_left() + (uv_width * (surfacepartrequest->source.x + surfacepartrequest->size.x)) / surface->get_width();
185   float uv_bottom = surface_data->get_uv_top() + (uv_height * (surfacepartrequest->source.y + surfacepartrequest->size.y)) / surface->get_height();
186
187   glBindTexture(GL_TEXTURE_2D, gltexture->get_handle());
188   intern_draw(request.pos.x, request.pos.y,
189               request.pos.x + surfacepartrequest->size.x,
190               request.pos.y + surfacepartrequest->size.y,
191               uv_left,
192               uv_top,
193               uv_right,
194               uv_bottom,
195               0.0,
196               request.alpha,
197               Color(1.0, 1.0, 1.0),
198               Blend(),
199               request.drawing_effect);
200 }
201
202 void
203 GLLightmap::draw_gradient(const DrawingRequest& request)
204 {
205   const GradientRequest* gradientrequest
206     = (GradientRequest*) request.request_data;
207   const Color& top = gradientrequest->top;
208   const Color& bottom = gradientrequest->bottom;
209
210   glDisable(GL_TEXTURE_2D);
211   glDisable(GL_TEXTURE_COORD_ARRAY);
212   glEnable(GL_COLOR_ARRAY);
213
214   float vertices[] = {
215     0, 0,
216     float(SCREEN_WIDTH), 0,
217     float(SCREEN_WIDTH), float(SCREEN_HEIGHT),
218     0, float(SCREEN_HEIGHT)
219   };
220   glVertexPointer(2, GL_FLOAT, 0, vertices);
221
222   float colors[] = {
223     top.red, top.green, top.blue, top.alpha,
224     top.red, top.green, top.blue, top.alpha,
225     bottom.red, bottom.green, bottom.blue, bottom.alpha,
226     bottom.red, bottom.green, bottom.blue, bottom.alpha,
227   };
228   glColorPointer(4, GL_FLOAT, 0, colors);
229
230   glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
231
232   glDisable(GL_COLOR_ARRAY);
233   glEnable(GL_TEXTURE_COORD_ARRAY);
234
235   glEnable(GL_TEXTURE_2D);
236   glColor4f(1, 1, 1, 1);
237 }
238
239 void
240 GLLightmap::draw_filled_rect(const DrawingRequest& request)
241 {
242   const FillRectRequest* fillrectrequest
243     = (FillRectRequest*) request.request_data;
244
245   float x = request.pos.x;
246   float y = request.pos.y;
247   float w = fillrectrequest->size.x;
248   float h = fillrectrequest->size.y;
249
250   glDisable(GL_TEXTURE_2D);
251   glColor4f(fillrectrequest->color.red, fillrectrequest->color.green,
252             fillrectrequest->color.blue, fillrectrequest->color.alpha);
253   glDisable(GL_TEXTURE_COORD_ARRAY);
254
255   float vertices[] = {
256     x,   y,
257     x+w, y,
258     x+w, y+h,
259     x,   y+h
260   };
261   glVertexPointer(2, GL_FLOAT, 0, vertices);
262
263   glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
264
265   glEnable(GL_TEXTURE_COORD_ARRAY);
266   glEnable(GL_TEXTURE_2D);
267   glColor4f(1, 1, 1, 1);
268 }
269
270 void
271 GLLightmap::get_light(const DrawingRequest& request) const
272 {
273   const GetLightRequest* getlightrequest
274     = (GetLightRequest*) request.request_data;
275
276   float pixels[3];
277   for( int i = 0; i<3; i++)
278     pixels[i] = 0.0f; //set to black
279
280   float posX = request.pos.x * lightmap_width / SCREEN_WIDTH + old_viewport[0];
281   float posY = old_viewport[3] + old_viewport[1] - request.pos.y * lightmap_height / SCREEN_HEIGHT;
282   glReadPixels((GLint) posX, (GLint) posY , 1, 1, GL_RGB, GL_FLOAT, pixels);
283   *(getlightrequest->color_ptr) = Color( pixels[0], pixels[1], pixels[2]);
284 }
285
286 /* EOF */