]> Dogcows Code - chaz/yoink/blob - src/texture.cc
new classes; yajl library
[chaz/yoink] / src / texture.cc
1
2 /*******************************************************************************
3
4 Copyright (c) 2009, Charles McGarvey
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9
10 * Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27 *******************************************************************************/
28
29 #include <stdexcept>
30 #include <cstdlib>
31
32 #include <boost/bind.hpp>
33
34 #include <SDL/SDL.h>
35 #include <SDL/SDL_image.h>
36
37 #include "dispatcher.hh"
38 #include "opengl.hh"
39
40 #include "texture.hh"
41
42
43 namespace dc {
44
45
46 class texture_impl
47 {
48 void unloadFromGL()
49 {
50 if (object)
51 {
52 glDeleteTextures(1, &object);
53 object = 0;
54 }
55 }
56
57 void contextRecreated(const notification& note)
58 {
59 unloadFromGL();
60 uploadToGL();
61 }
62
63 public:
64 texture_impl(const std::string& filePath, bool keepInMemory)
65 : object(0), imageData(0), imagePath(filePath), keepData(keepInMemory)
66 {
67 dispatcher::instance().addHandler("video.context_recreated",
68 boost::bind(&texture_impl::contextRecreated, this, _1),
69 this);
70 }
71
72 ~texture_impl()
73 {
74 dispatcher::instance().removeHandler(this);
75
76 if (imageData)
77 {
78 SDL_FreeSurface(imageData);
79 }
80 unloadFromGL();
81 }
82
83
84 static int powerOfTwo(int input)
85 {
86 int value = 1;
87
88 while (value < input)
89 {
90 value <<= 1;
91 }
92 return value;
93 }
94
95 // Adapted from some public domain code. This code is common enough that it
96 // really should be included in SDL_image...
97 static SDL_Surface* prepareImageForGL(SDL_Surface* surface)
98 {
99 /* Use the surface width and height expanded to powers of 2 */
100 int w = powerOfTwo(surface->w);
101 int h = powerOfTwo(surface->h);
102
103 SDL_Surface* image = SDL_CreateRGBSurface
104 (
105 SDL_SWSURFACE,
106 w, h,
107 32,
108 #if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
109 0x000000FF,
110 0x0000FF00,
111 0x00FF0000,
112 0xFF000000
113 #else
114 0xFF000000,
115 0x00FF0000,
116 0x0000FF00,
117 0x000000FF
118 #endif
119 );
120
121 if (!image)
122 {
123 return 0;
124 }
125
126 // Save the alpha blending attributes.
127 Uint32 savedFlags = surface->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
128 Uint8 savedAlpha = surface->format->alpha;
129 if (savedFlags & SDL_SRCALPHA)
130 {
131 SDL_SetAlpha(surface, 0, 0);
132 }
133
134 SDL_Rect srcArea, destArea;
135 /* Copy the surface into the GL texture image */
136 srcArea.x = 0; destArea.x = 0;
137 /* Copy it in at the bottom, because we're going to flip
138 this image upside-down in a moment
139 */
140 srcArea.y = 0; destArea.y = h - surface->h;
141 srcArea.w = surface->w;
142 srcArea.h = surface->h;
143 SDL_BlitSurface(surface, &srcArea, image, &destArea);
144
145 /* Restore the alpha blending attributes */
146 if (savedFlags & SDL_SRCALPHA)
147 {
148 SDL_SetAlpha(surface, savedFlags, savedAlpha);
149 }
150
151 /* Turn the image upside-down, because OpenGL textures
152 start at the bottom-left, instead of the top-left
153 */
154 Uint8 line[image->pitch];
155
156 /* These two make the following more readable */
157 Uint8 *pixels = static_cast<Uint8*>(image->pixels);
158 Uint16 pitch = image->pitch;
159 int ybegin = 0;
160 int yend = image->h - 1;
161
162 // TODO: consider if this lock is legal/appropriate
163 if (SDL_MUSTLOCK(image)) { SDL_LockSurface(image); }
164 while (ybegin < yend)
165 {
166 memcpy(line, pixels + pitch*ybegin, pitch);
167 memcpy(pixels + pitch*ybegin, pixels + pitch*yend, pitch);
168 memcpy(pixels + pitch*yend, line, pitch);
169 ybegin++;
170 yend--;
171 }
172 if (SDL_MUSTLOCK(image)) { SDL_UnlockSurface(image); }
173
174 return image;
175 }
176
177
178 void loadImageData()
179 {
180 SDL_Surface* surface;
181
182 surface = IMG_Load(imagePath.c_str());
183
184 if (!surface)
185 {
186 throw std::runtime_error("could not load image data from file");
187 }
188
189 imageData = prepareImageForGL(surface);
190 SDL_FreeSurface(surface);
191
192 if (!imageData)
193 {
194 throw std::runtime_error("error in preparing image data for GL");
195 }
196
197 if (imageData->format->BytesPerPixel == 3)
198 {
199 mode = GL_RGB;
200 }
201 else if (imageData->format->BytesPerPixel == 4)
202 {
203 mode = GL_RGBA;
204 }
205 else
206 {
207 SDL_FreeSurface(imageData);
208 throw std::runtime_error("image must be 24 or 32 bpp");
209 }
210
211 width = imageData->w;
212 height = imageData->h;
213 }
214
215
216 void uploadToGL()
217 {
218 if (object)
219 {
220 // Already loaded.
221 return;
222 }
223
224 if (!imageData)
225 {
226 loadImageData();
227 }
228
229 glGenTextures(1, &object);
230
231 glBindTexture(GL_TEXTURE_2D, object);
232
233 glTexImage2D
234 (
235 GL_TEXTURE_2D,
236 0,
237 mode,
238 imageData->w,
239 imageData->h,
240 0,
241 mode,
242 GL_UNSIGNED_BYTE,
243 imageData->pixels
244 );
245
246 // These default filters can be changed later...
247 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
248 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
249
250 if (!keepData)
251 {
252 SDL_FreeSurface(imageData);
253 imageData = 0;
254 }
255 }
256
257
258 unsigned width;
259 unsigned height;
260 int mode;
261 GLuint object;
262
263 std::string imagePath;
264 bool keepData;
265 SDL_Surface* imageData;
266 };
267
268
269 texture::texture(const std::string& filePath, bool keepInMemory)
270 : impl(new texture_impl(filePath, keepInMemory)) {}
271
272
273 const std::string& texture::filePath()
274 {
275 return impl->imagePath;
276 }
277
278
279 void texture::bind()
280 {
281 glBindTexture(GL_TEXTURE_2D, object());
282 }
283
284 GLuint texture::object()
285 {
286 if (!impl->object)
287 {
288 impl->uploadToGL();
289 }
290
291 return impl->object;
292 }
293
294
295 unsigned texture::width()
296 {
297 return impl->width;
298 }
299
300 unsigned texture::height()
301 {
302 return impl->height;
303 }
304
305
306
307 } // namespace dc
308
This page took 0.041995 seconds and 4 git commands to generate.