Mercurial > fife-parpg
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 } |