comparison engine/core/video/opengl/glimage.cpp @ 620:853d25234671

* Moved the GLEnable and GLDisable structures from opengl_gui_graphics.cpp to fife_opengl.h as they may prove to be useful elsewhere. * Fixed the color mask definitions in fife_stdint.h * Added the nextPow2() function to calculate the nearest (greater) power of 2 * Removed a bunch of re-definitions of RGB masks * Modified GLImage to only generate one "texture chunk". I hope this makes better use of memory and speeds things up a hair * Made use of the GLEnable structure when clearing the screen
author prock@33b003aa-7bff-0310-803a-e67f0ece8222
date Thu, 30 Sep 2010 21:24:55 +0000
parents 739d8a43d771
children 92290efadab7
comparison
equal deleted inserted replaced
619:f648bfbae5fe 620:853d25234671
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * 19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
20 ***************************************************************************/ 20 ***************************************************************************/
21 21
22 // Standard C++ library includes 22 // Standard C++ library includes
23 #include <cassert> 23 #include <cassert>
24 24 #include <iostream>
25 // 3rd party library includes 25 // 3rd party library includes
26 26
27 // FIFE includes 27 // FIFE includes
28 // These includes are split up in two parts, separated by one empty line 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 29 // First block: files included from the FIFE root src directory
36 36
37 namespace FIFE { 37 namespace FIFE {
38 GLImage::GLImage(SDL_Surface* surface): 38 GLImage::GLImage(SDL_Surface* surface):
39 Image(surface) { 39 Image(surface) {
40 m_sdlimage = new SDLImage(surface); 40 m_sdlimage = new SDLImage(surface);
41
42 m_textureids = NULL;
43
41 resetGlimage(); 44 resetGlimage();
42 } 45 }
43 46
44 GLImage::GLImage(const uint8_t* data, unsigned int width, unsigned int height): 47 GLImage::GLImage(const uint8_t* data, unsigned int width, unsigned int height):
45 Image(data, width, height) { 48 Image(data, width, height) {
49
50 m_textureids = NULL;
51
46 resetGlimage(); 52 resetGlimage();
47 } 53 }
48 54
49 GLImage::~GLImage() { 55 GLImage::~GLImage() {
50 // remove surface so that deletion happens correctly (by base class destructor) 56 // remove surface so that deletion happens correctly (by base class destructor)
51 m_sdlimage->detachSurface(); 57 m_sdlimage->detachSurface();
52 delete m_sdlimage; 58 delete m_sdlimage;
59
53 cleanup(); 60 cleanup();
54 } 61 }
55 62
56 void GLImage::resetGlimage() { 63 void GLImage::resetGlimage() {
57 m_last_col_fill_ratio = 0; 64 cleanup();
58 m_last_row_fill_ratio = 0; 65
59 m_textureids = NULL; 66 m_chunk_size = 0;
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 m_colorkey = RenderBackend::instance()->getColorKey(); 67 m_colorkey = RenderBackend::instance()->getColorKey();
66 } 68 }
67 69
68 void GLImage::cleanup() { 70 void GLImage::cleanup() {
69 for (unsigned int i = 0; i < m_rows*m_cols; ++i) { 71 if (m_textureids) {
70 glDeleteTextures(1, &m_textureids[i]); 72 glDeleteTextures(1, &m_textureids[0]);
71 } 73
72 delete[] m_textureids; 74 delete[] m_textureids;
73 m_textureids = NULL; 75 m_textureids = NULL;
74 resetGlimage(); 76 }
77
78 m_col_tex_coord = 0;
79 m_row_tex_coord = 0;
75 } 80 }
76 81
77 void GLImage::render(const Rect& rect, SDL_Surface* screen, unsigned char alpha) { 82 void GLImage::render(const Rect& rect, SDL_Surface* screen, unsigned char alpha) {
78 if (!m_textureids) { 83 if (!m_textureids) {
79 generateTextureChunks(); 84 generateGLTexture();
80 } 85 }
81 86
87 //not on the screen. dont render
82 if (rect.right() < 0 || rect.x > static_cast<int>(screen->w) || rect.bottom() < 0 || rect.y > static_cast<int>(screen->h)) { 88 if (rect.right() < 0 || rect.x > static_cast<int>(screen->w) || rect.bottom() < 0 || rect.y > static_cast<int>(screen->h)) {
83 return; 89 return;
84 } 90 }
85 91
92 //completely transparent so dont bother rendering
86 if (0 == alpha) { 93 if (0 == alpha) {
87 return; 94 return;
88 } 95 }
89
90 // used to calculate the fill ratio for given chunk
91 float col_fill_ratio;
92 float row_fill_ratio;
93 96
94 // the amount of "zooming" for the image 97 // the amount of "zooming" for the image
95 float scale_x = static_cast<float>(rect.w) / static_cast<float>(m_surface->w); 98 float scale_x = static_cast<float>(rect.w) / static_cast<float>(m_surface->w);
96 float scale_y = static_cast<float>(rect.h) / static_cast<float>(m_surface->h); 99 float scale_y = static_cast<float>(rect.h) / static_cast<float>(m_surface->h);
97 100
98 // rectangle used for drawing 101 // apply the scale to the width and height of the image
99 Rect target; 102 uint16_t w = static_cast<int>(round(scale_x*m_surface->w));
100 // zooming causes scaling sometimes to round pixels incorrectly. Instead of 103 uint16_t h = static_cast<int>(round(scale_y*m_surface->h));
101 // recalculating it all, store the values from previous round and calculate
102 // new x & y
103 Rect prev;
104 104
105 /// setting transparency for the whole primitive: 105 /// setting transparency for the whole primitive:
106 glColor4ub( 255, 255, 255, alpha ); 106 glColor4ub( 255, 255, 255, alpha );
107 107
108 glEnable(GL_TEXTURE_2D); 108 GLEnable flag(GL_TEXTURE_2D);
109 for (unsigned int i = 0; i < m_cols; ++i) { 109 glBindTexture(GL_TEXTURE_2D, m_textureids[0]);
110 if (i == m_cols-1) { 110
111 col_fill_ratio = m_last_col_fill_ratio; 111 glBegin(GL_QUADS);
112 target.w = static_cast<int>(round(scale_x*m_last_col_width*m_last_col_fill_ratio)); 112 glTexCoord2f(0.0f, 0.0f);
113 } else { 113 glVertex2i(rect.x, rect.y);
114 col_fill_ratio = 1.0; 114
115 target.w = static_cast<int>(round(scale_x*m_chunk_size)); 115 glTexCoord2f(0.0f, m_row_tex_coord);
116 } 116 glVertex2i(rect.x, rect.y + h);
117 if (i > 0) { 117
118 target.x = prev.x + prev.w; 118 glTexCoord2f(m_col_tex_coord, m_row_tex_coord);
119 } else { 119 glVertex2i(rect.x + w, rect.y + h);
120 target.x = rect.x; 120
121 } 121 glTexCoord2f(m_col_tex_coord, 0.0f);
122 122 glVertex2i(rect.x + w, rect.y);
123 for (unsigned int j = 0; j < m_rows; ++j) { 123 glEnd();
124 if (j == m_rows-1) { 124
125 row_fill_ratio = m_last_row_fill_ratio; 125 }
126 target.h = static_cast<int>(round(scale_y*m_last_row_height*m_last_row_fill_ratio)); 126
127 } else { 127 void GLImage::generateGLTexture() {
128 row_fill_ratio = 1.0;
129 target.h = static_cast<int>(round(scale_y*m_chunk_size));
130 }
131 if (j > 0) {
132 target.y = prev.y + prev.h;
133 } else {
134 target.y = rect.y;
135 }
136 prev = target;
137
138 glBindTexture(GL_TEXTURE_2D, m_textureids[j*m_cols + i]);
139 glBegin(GL_QUADS);
140 glTexCoord2f(0.0f, 0.0f);
141 glVertex2i(target.x, target.y);
142
143 glTexCoord2f(0.0f, row_fill_ratio);
144 glVertex2i(target.x, target.y + target.h);
145
146 glTexCoord2f(col_fill_ratio, row_fill_ratio);
147 glVertex2i(target.x + target.w, target.y + target.h);
148
149 glTexCoord2f(col_fill_ratio, 0.0f);
150 glVertex2i(target.x + target.w, target.y);
151 glEnd();
152 }
153 }
154 glDisable(GL_TEXTURE_2D);
155 }
156
157 void GLImage::generateTextureChunks() {
158 const unsigned int width = m_surface->w; 128 const unsigned int width = m_surface->w;
159 const unsigned int height = m_surface->h; 129 const unsigned int height = m_surface->h;
130
131 uint32_t size;
132
133 if (width > height){
134 size = width;
135 }
136 else {
137 size = height;
138 }
139
140 //calculate the nearest larger power of 2
141 m_chunk_size = nextPow2(size);
142
143 // used to calculate the fill ratio for given chunk
144 m_col_tex_coord = static_cast<float>(m_surface->w%m_chunk_size) / static_cast<float>(m_chunk_size);
145 m_row_tex_coord = static_cast<float>(m_surface->h%m_chunk_size) / static_cast<float>(m_chunk_size);
146
147 if (m_col_tex_coord == 0.0f){
148 m_col_tex_coord = 1.0f;
149 }
150
151 if (m_row_tex_coord == 0.0f){
152 m_row_tex_coord = 1.0f;
153 }
154
160 uint8_t* data = static_cast<uint8_t*>(m_surface->pixels); 155 uint8_t* data = static_cast<uint8_t*>(m_surface->pixels);
161 int pitch = m_surface->pitch; 156 int pitch = m_surface->pitch;
162 157
163 m_last_col_width = 1; 158
164 m_cols = static_cast<int>(width/m_chunk_size); 159 assert(!m_textureids);
165 if (width%m_chunk_size) { 160
166 ++m_cols; 161 m_textureids = new GLuint[1];
167 while(m_last_col_width < width%m_chunk_size) { 162 memset(m_textureids, 0x00, 1*sizeof(GLuint));
168 m_last_col_width <<= 1; 163
169 } 164
170 } else { 165 uint32_t* oglbuffer = new uint32_t[m_chunk_size * m_chunk_size];
171 m_last_col_width = m_chunk_size; 166 memset(oglbuffer, 0x00, m_chunk_size*m_chunk_size*sizeof(uint32_t));
172 } 167
173 168 for (unsigned int y = 0; y < height; ++y) {
174 m_last_row_height = 1; 169 for (unsigned int x = 0; x < width; ++x) {
175 m_rows = static_cast<int>(height/m_chunk_size); 170 unsigned int pos = (y * pitch) + (x * 4);
176 if (height%m_chunk_size) { 171
177 ++m_rows; 172 uint8_t r = data[pos + 3];
178 while(m_last_row_height < height%m_chunk_size) { 173 uint8_t g = data[pos + 2];
179 m_last_row_height <<= 1; 174 uint8_t b = data[pos + 1];
180 } 175 uint8_t a = data[pos + 0];
181 } else { 176
182 m_last_row_height = m_chunk_size; 177 if (RenderBackend::instance()->isColorKeyEnabled()) {
183 } 178 // only set alpha to zero if colorkey feature is enabled
184 179 if (r == m_colorkey.r && g == m_colorkey.g && b == m_colorkey.b) {
185 m_textureids = new GLuint[m_rows*m_cols]; 180 a = 0;
186 memset(m_textureids, 0x00, m_rows*m_cols*sizeof(GLuint));
187
188 if(width%m_chunk_size) {
189 m_last_col_fill_ratio = static_cast<float>(width%m_chunk_size) / static_cast<float>(m_last_col_width);
190 } else { // (width%m_chunk_size) / m_last_col_width == 0 == m_chunk_size (mod m_chunk_size)
191 m_last_col_fill_ratio = 1.0f;
192 }
193
194 if (height%m_chunk_size) {
195 m_last_row_fill_ratio = static_cast<float>(height%m_chunk_size) / static_cast<float>(m_last_row_height);
196 } else {
197 m_last_row_fill_ratio = 1.0f;
198 }
199
200 unsigned int chunk_width;
201 unsigned int chunk_height;
202 unsigned int data_chunk_height;
203 unsigned int data_chunk_width;
204
205 for (unsigned int i = 0; i < m_cols; ++i) {
206 for (unsigned int j = 0; j < m_rows; ++j) {
207 if (i==m_cols-1) {
208 chunk_width = m_last_col_width;
209 data_chunk_width = width%m_chunk_size;
210 if(data_chunk_width == 0) { // 0 == m_chunk_size (mod m_chunk_size)
211 data_chunk_width = m_chunk_size;
212 }
213 } else {
214 chunk_width = m_chunk_size;
215 data_chunk_width = m_chunk_size;
216 }
217 if (j==m_rows-1) {
218 chunk_height = m_last_row_height;
219 data_chunk_height = height%m_chunk_size;
220 if(data_chunk_height == 0) { // 0 = m_chunk_size (mod m_chunk_size)
221 data_chunk_height = m_chunk_size;
222 }
223 } else {
224 chunk_height = m_chunk_size;
225 data_chunk_height = m_chunk_size;
226 }
227
228 uint32_t* oglbuffer = new uint32_t[chunk_width * chunk_height];
229 memset(oglbuffer, 0x00, chunk_width*chunk_height*4);
230
231 for (unsigned int y = 0; y < data_chunk_height; ++y) {
232 for (unsigned int x = 0; x < data_chunk_width; ++x) {
233 unsigned int pos = (y + j*m_chunk_size)*pitch + (x + i*m_chunk_size) * 4;
234
235 uint8_t r = data[pos + 3];
236 uint8_t g = data[pos + 2];
237 uint8_t b = data[pos + 1];
238 uint8_t a = data[pos + 0];
239
240 if (RenderBackend::instance()->isColorKeyEnabled()) {
241 // only set alpha to zero if colorkey feature is enabled
242 if (r == m_colorkey.r && g == m_colorkey.g && b == m_colorkey.b) {
243 a = 0;
244 }
245 }
246
247 oglbuffer[(y*chunk_width) + x] = r | (g << 8) | (b << 16) | (a<<24);
248 } 181 }
249 } 182 }
250 183
251 // get texture id from opengl 184 oglbuffer[(y*m_chunk_size) + x] = r | (g << 8) | (b << 16) | (a<<24);
252 glGenTextures(1, &m_textureids[j*m_cols + i]);
253 // set focus on that texture
254 glBindTexture(GL_TEXTURE_2D, m_textureids[j*m_cols + i]);
255 // set filters for texture
256 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
257 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
258 // transfer data from sdl buffer
259 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, chunk_width, chunk_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, static_cast<GLvoid*>(oglbuffer));
260
261 delete[] oglbuffer;
262 } 185 }
263 } 186 }
187
188 // get texture id from opengl
189 glGenTextures(1, &m_textureids[0]);
190 // set focus on that texture
191 glBindTexture(GL_TEXTURE_2D, m_textureids[0]);
192 // set filters for texture
193 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
194 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
195 // transfer data from sdl buffer
196 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_chunk_size, m_chunk_size, 0, GL_RGBA, GL_UNSIGNED_BYTE, static_cast<GLvoid*>(oglbuffer));
197
198 delete[] oglbuffer;
264 } 199 }
265 200
266 void GLImage::saveImage(const std::string& filename) { 201 void GLImage::saveImage(const std::string& filename) {
267 const unsigned int swidth = getWidth(); 202 const unsigned int swidth = getWidth();
268 const unsigned int sheight = getHeight(); 203 const unsigned int sheight = getHeight();
269 Uint32 rmask, gmask, bmask, amask;
270 SDL_Surface *surface = NULL; 204 SDL_Surface *surface = NULL;
271 uint8_t *pixels; 205 uint8_t *pixels;
272 206
273 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
274 rmask = 0xff000000; gmask = 0x00ff0000; bmask = 0x0000ff00; amask = 0x000000ff;
275 #else
276 rmask = 0x000000ff; gmask = 0x0000ff00; bmask = 0x00ff0000; amask = 0xff000000;
277 #endif
278
279 surface = SDL_CreateRGBSurface(SDL_SWSURFACE, swidth, 207 surface = SDL_CreateRGBSurface(SDL_SWSURFACE, swidth,
280 sheight, 24, 208 sheight, 24,
281 rmask, gmask, bmask, 0); 209 RMASK,GMASK,BMASK, NULLMASK);
282 210
283 if(surface == NULL) { 211 if(surface == NULL) {
284 return; 212 return;
285 } 213 }
286 214
302 230
303 SDL_UnlockSurface(surface); 231 SDL_UnlockSurface(surface);
304 saveAsPng(filename, *surface); 232 saveAsPng(filename, *surface);
305 SDL_FreeSurface(surface); 233 SDL_FreeSurface(surface);
306 delete [] pixels; 234 delete [] pixels;
307
308
309 } 235 }
310 236
311 void GLImage::setClipArea(const Rect& cliparea, bool clear) { 237 void GLImage::setClipArea(const Rect& cliparea, bool clear) {
312 glScissor(cliparea.x, getHeight() - cliparea.y - cliparea.h, cliparea.w, cliparea.h); 238 glScissor(cliparea.x, getHeight() - cliparea.y - cliparea.h, cliparea.w, cliparea.h);
239
313 if (clear) { 240 if (clear) {
314 glClear(GL_COLOR_BUFFER_BIT); 241 glClear(GL_COLOR_BUFFER_BIT);
315 } 242 }
316 } 243 }
317 244