comparison engine/core/video/opengl/glimage.cpp @ 0:4a0efb7baf70

* Datasets becomes the new trunk and retires after that :-)
author mvbarracuda@33b003aa-7bff-0310-803a-e67f0ece8222
date Sun, 29 Jun 2008 18:44:17 +0000
parents
children 90005975cdbb
comparison
equal deleted inserted replaced
-1:000000000000 0:4a0efb7baf70
1 /***************************************************************************
2 * Copyright (C) 2005-2008 by the FIFE team *
3 * http://www.fifengine.de *
4 * This file is part of FIFE. *
5 * *
6 * FIFE is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
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. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the *
18 * Free Software Foundation, Inc., *
19 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
20 ***************************************************************************/
21
22 // Standard C++ library includes
23 #include <cassert>
24
25 // 3rd party library includes
26
27 // FIFE includes
28 // These includes are split up in two parts, separated by one empty line
29 // First block: files included from the FIFE root src directory
30 // Second block: files included from the same folder
31 #include "util/structures/rect.h"
32 #include "video/sdl/sdlimage.h"
33 #include "video/renderbackend.h"
34
35 #include "glimage.h"
36
37 namespace FIFE {
38 GLImage::GLImage(SDL_Surface* surface):
39 Image(surface) {
40 m_sdlimage = new SDLImage(surface);
41 resetGlimage();
42 }
43
44 GLImage::GLImage(const uint8_t* data, unsigned int width, unsigned int height):
45 Image(data, width, height) {
46 resetGlimage();
47 }
48
49 GLImage::~GLImage() {
50 // remove surface so that deletion happens correctly (by base class destructor)
51 m_sdlimage->detachSurface();
52 delete m_sdlimage;
53 cleanup();
54 }
55
56 void GLImage::resetGlimage() {
57 m_last_col_fill_ratio = 0;
58 m_last_row_fill_ratio = 0;
59 m_textureids = NULL;
60 m_rows = 0;
61 m_cols = 0;
62 m_last_col_width = 0;
63 m_last_row_height = 0;
64 m_chunk_size = RenderBackend::instance()->getChunkingSize();
65 }
66
67 void GLImage::cleanup() {
68 for (unsigned int i = 0; i < m_rows*m_cols; ++i) {
69 glDeleteTextures(1, &m_textureids[i]);
70 }
71 delete[] m_textureids;
72 m_textureids = NULL;
73 resetGlimage();
74 }
75
76 void GLImage::render(const Rect& rect, SDL_Surface* screen, unsigned char alpha) {
77 if (!m_textureids) {
78 generateTextureChunks();
79 }
80
81 if (rect.right() < 0 || rect.x > static_cast<int>(screen->w) || rect.bottom() < 0 || rect.y > static_cast<int>(screen->h)) {
82 return;
83 }
84
85 if (0 == alpha) {
86 return;
87 }
88
89 // used to calculate the fill ratio for given chunk
90 float col_fill_ratio;
91 float row_fill_ratio;
92
93 // the amount of "zooming" for the image
94 float scale_x = static_cast<float>(rect.w) / static_cast<float>(m_surface->w);
95 float scale_y = static_cast<float>(rect.h) / static_cast<float>(m_surface->h);
96
97 // rectangle used for drawing
98 Rect target;
99 // zooming causes scaling sometimes to round pixels incorrectly. Instead of
100 // recalculating it all, store the values from previous round and calculate
101 // new x & y
102 Rect prev;
103
104 /// setting transparency for the whole primitive:
105 glColor4ub( 255, 255, 255, alpha );
106
107 glEnable(GL_TEXTURE_2D);
108 for (unsigned int i = 0; i < m_cols; ++i) {
109 if (i == m_cols-1) {
110 col_fill_ratio = m_last_col_fill_ratio;
111 target.w = static_cast<int>(round(scale_y*m_last_col_width*m_last_col_fill_ratio));
112 } else {
113 col_fill_ratio = 1.0;
114 target.w = static_cast<int>(round(scale_y*m_chunk_size));
115 }
116 if (i > 0) {
117 target.x = prev.x + prev.w;
118 } else {
119 target.x = rect.x;
120 }
121
122 for (unsigned int j = 0; j < m_rows; ++j) {
123 if (j == m_rows-1) {
124 row_fill_ratio = m_last_row_fill_ratio;
125 target.h = static_cast<int>(round(scale_y*m_last_row_height*m_last_row_fill_ratio));
126 } else {
127 row_fill_ratio = 1.0;
128 target.h = static_cast<int>(round(scale_y*m_chunk_size));
129 }
130 if (j > 0) {
131 target.y = prev.y + prev.h;
132 } else {
133 target.y = rect.y;
134 }
135 prev = target;
136
137 glBindTexture(GL_TEXTURE_2D, m_textureids[j*m_cols + i]);
138 glBegin(GL_QUADS);
139 glTexCoord2f(0.0f, 0.0f);
140 glVertex2i(target.x, target.y);
141
142 glTexCoord2f(0.0f, row_fill_ratio);
143 glVertex2i(target.x, target.y + target.h);
144
145 glTexCoord2f(col_fill_ratio, row_fill_ratio);
146 glVertex2i(target.x + target.w, target.y + target.h);
147
148 glTexCoord2f(col_fill_ratio, 0.0f);
149 glVertex2i(target.x + target.w, target.y);
150 glEnd();
151 }
152 }
153 glDisable(GL_TEXTURE_2D);
154 }
155
156 void GLImage::generateTextureChunks() {
157 const unsigned int width = m_surface->w;
158 const unsigned int height = m_surface->h;
159 uint8_t* data = static_cast<uint8_t*>(m_surface->pixels);
160 int pitch = m_surface->pitch;
161
162 m_last_col_width = 1;
163 m_cols = static_cast<int>(width/m_chunk_size);
164 if (width%m_chunk_size) {
165 ++m_cols;
166 while(m_last_col_width < width%m_chunk_size) {
167 m_last_col_width <<= 1;
168 }
169 } else {
170 m_last_col_width = m_chunk_size;
171 }
172
173 m_last_row_height = 1;
174 m_rows = static_cast<int>(height/m_chunk_size);
175 if (height%m_chunk_size) {
176 ++m_rows;
177 while(m_last_row_height < height%m_chunk_size) {
178 m_last_row_height <<= 1;
179 }
180 } else {
181 m_last_row_height = m_chunk_size;
182 }
183
184 m_textureids = new GLuint[m_rows*m_cols];
185 memset(m_textureids, 0x00, m_rows*m_cols*sizeof(GLuint));
186
187 if(width%m_chunk_size) {
188 m_last_col_fill_ratio = static_cast<float>(width%m_chunk_size) / static_cast<float>(m_last_col_width);
189 m_last_row_fill_ratio = static_cast<float>(height%m_chunk_size) / static_cast<float>(m_last_row_height);
190 }
191 else { // (width%m_chunk_size) / m_last_col_width == 0 == m_chunk_size (mod m_chunk_size)
192 m_last_col_fill_ratio = 1.0f;
193 m_last_row_fill_ratio = 1.0f;
194 }
195
196 unsigned int chunk_width;
197 unsigned int chunk_height;
198 unsigned int data_chunk_height;
199 unsigned int data_chunk_width;
200
201 for (unsigned int i = 0; i < m_cols; ++i) {
202 for (unsigned int j = 0; j < m_rows; ++j) {
203 if (i==m_cols-1) {
204 chunk_width = m_last_col_width;
205 data_chunk_width = width%m_chunk_size;
206 if(data_chunk_width == 0) { // 0 == m_chunk_size (mod m_chunk_size)
207 data_chunk_width = m_chunk_size;
208 }
209 } else {
210 chunk_width = m_chunk_size;
211 data_chunk_width = m_chunk_size;
212 }
213 if (j==m_rows-1) {
214 chunk_height = m_last_row_height;
215 data_chunk_height = height%m_chunk_size;
216 if(data_chunk_height == 0) { // 0 = m_chunk_size (mod m_chunk_size)
217 data_chunk_height = m_chunk_size;
218 }
219 } else {
220 chunk_height = m_chunk_size;
221 data_chunk_height = m_chunk_size;
222 }
223
224 uint32_t* oglbuffer = new uint32_t[chunk_width * chunk_height];
225 memset(oglbuffer, 0x00, chunk_width*chunk_height*4);
226
227 for (unsigned int y = 0; y < data_chunk_height; ++y) {
228 for (unsigned int x = 0; x < data_chunk_width; ++x) {
229 unsigned int pos = (y + j*m_chunk_size)*pitch + (x + i*m_chunk_size) * 4;
230
231 // FIXME
232 // The following code might not be endianness correct
233
234 uint8_t r = data[pos + 0];
235 uint8_t g = data[pos + 1];
236 uint8_t b = data[pos + 2];
237 uint8_t a = data[pos + 3];
238
239 oglbuffer[(y*chunk_width) + x] = (r << 24) | (g << 16) | (b << 8) | a;
240 }
241 }
242
243 // get texture id from opengl
244 glGenTextures(1, &m_textureids[j*m_cols + i]);
245 // set focus on that texture
246 glBindTexture(GL_TEXTURE_2D, m_textureids[j*m_cols + i]);
247 // set filters for texture
248 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
249 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
250 // transfer data from sdl buffer
251 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, chunk_width, chunk_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, static_cast<GLvoid*>(oglbuffer));
252
253 delete[] oglbuffer;
254 }
255 }
256 }
257
258 void GLImage::saveImage(const std::string& filename) {
259 const unsigned int swidth = getWidth();
260 const unsigned int sheight = getHeight();
261 Uint32 rmask, gmask, bmask, amask;
262 SDL_Surface *surface = NULL;
263 uint8_t *pixels;
264
265 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
266 rmask = 0xff000000; gmask = 0x00ff0000; bmask = 0x0000ff00; amask = 0x000000ff;
267 #else
268 rmask = 0x000000ff; gmask = 0x0000ff00; bmask = 0x00ff0000; amask = 0xff000000;
269 #endif
270
271 surface = SDL_CreateRGBSurface(SDL_SWSURFACE, swidth,
272 sheight, 24,
273 rmask, gmask, bmask, 0);
274
275 if(surface == NULL) {
276 return;
277 }
278
279 SDL_LockSurface(surface);
280 pixels = new uint8_t[swidth * sheight * 3];
281 glReadPixels(0, 0, swidth, sheight, GL_RGB, GL_UNSIGNED_BYTE, reinterpret_cast<GLvoid*>(pixels));
282
283 uint8_t *imagepixels = reinterpret_cast<uint8_t*>(surface->pixels);
284 // Copy the "reversed_image" memory to the "image" memory
285 for (int y = (sheight - 1); y >= 0; --y) {
286 uint8_t *rowbegin = pixels + y * swidth * 3;
287 uint8_t *rowend = rowbegin + swidth * 3;
288
289 std::copy(rowbegin, rowend, imagepixels);
290
291 // Advance a row in the output surface.
292 imagepixels += surface->pitch;
293 }
294
295 SDL_UnlockSurface(surface);
296 saveAsPng(filename, *surface);
297 SDL_FreeSurface(surface);
298 delete [] pixels;
299
300
301 }
302
303 void GLImage::setClipArea(const Rect& cliparea, bool clear) {
304 glScissor(cliparea.x, getHeight() - cliparea.y - cliparea.h, cliparea.w, cliparea.h);
305 if (clear) {
306 glClear(GL_COLOR_BUFFER_BIT);
307 }
308 }
309
310 bool GLImage::putPixel(int x, int y, int r, int g, int b) {
311 cleanup();
312 return m_sdlimage->putPixel(x, y, r, g, b);
313 }
314
315 void GLImage::drawLine(const Point& p1, const Point& p2, int r, int g, int b) {
316 cleanup();
317 m_sdlimage->drawLine(p1, p2, r, g, b);
318 }
319
320 void GLImage::drawQuad(const Point& p1, const Point& p2, const Point& p3, const Point& p4, int r, int g, int b) {
321 cleanup();
322 m_sdlimage->drawQuad(p1, p2, p3, p4, r, g, b);
323 }
324 }