]> Dogcows Code - chaz/yoink/blob - src/Moof/Texture.cc
22d3f15e92cab597259673d86c08cd2f4692d292
[chaz/yoink] / src / Moof / 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 <cstdio> // FILE
30 #include <cstring> // strncmp
31
32 #include <boost/bind.hpp>
33
34 #include "Dispatch.hh"
35 #include "Engine.hh"
36 #include "Exception.hh"
37 #include "Image.hh"
38 #include "Library.hh"
39 #include "Log.hh"
40 #include "OpenGL.hh"
41 #include "Texture.hh"
42
43
44 namespace Mf {
45
46
47 /**
48 * The texture implementation just contains all the information about the image
49 * which is worth having in memory. The image data itself is not worth keeping
50 * in memory if the texture has been loaded to GL, but the name of the resource
51 * is retained so that it can be reloaded if necessary. The implementation is a
52 * library so that multiple texture objects can share the same internal objects
53 * and avoid having duplicate textures loaded to GL.
54 */
55
56 class Texture::Impl : public Library<Impl>
57 {
58
59 /**
60 * Delete the texture (if it is loaded) from GL.
61 */
62
63 void unloadFromGL()
64 {
65 if (mObject)
66 {
67 if (mObject == gObject)
68 {
69 gObject = 0;
70 }
71
72 glDeleteTextures(1, &mObject);
73 mObject = 0;
74 }
75 }
76
77 /**
78 * If the GL context was recreated, we need to reload the texture. This may
79 * involve reading it from disk again, but hopefully the OS was smart enough
80 * to cache it if the client has plenty of RAM.
81 */
82
83 void contextRecreated()
84 {
85 mObject = gObject = 0;
86 uploadToGL();
87 }
88
89 /**
90 * This is a helper method used by some of the texture loading code. It
91 * returns the first power of two which is greater than the input value.
92 */
93
94 static int powerOfTwo(int input)
95 {
96 int value = 1;
97
98 while (value < input)
99 {
100 value <<= 1;
101 }
102 return value;
103 }
104
105 public:
106
107 /**
108 * Construction is initialization.
109 */
110
111 explicit Impl(const std::string& name) :
112 Library<Impl>(name),
113 //mContext(0),
114 mImage(Texture::getPath(getName())),
115 mWidth(0),
116 mHeight(0),
117 mMode(0),
118 mMinFilter(GL_NEAREST),
119 mMagFilter(GL_NEAREST),
120 mWrapS(GL_CLAMP),
121 mWrapT(GL_CLAMP),
122 mObject(0)
123 {
124 // make sure the engine is initialized
125 Engine& engine = Engine::getInstance();
126 VideoP video = engine.getVideo();
127 ASSERT(video && "cannot load textures without a current video context");
128
129 // we want to know when the GL context is recreated
130 mDispatchHandler = engine.addHandler("video.newcontext",
131 boost::bind(&Impl::contextRecreated, this));
132
133 loadFromFile();
134 }
135
136 ~Impl()
137 {
138 unloadFromGL();
139 }
140
141
142 /**
143 * Adapted from some public domain code. This stuff is common enough that
144 * it really should be included in SDL_image... We need this because images
145 * loaded with SDL_image aren't exactly GL-ready right out of the box. This
146 * method makes them ready.
147 */
148
149 /*
150 static SDL_Surface* prepareImageForGL(SDL_Surface* surface)
151 {
152 int w = powerOfTwo(surface->w);
153 int h = powerOfTwo(surface->h);
154
155 // 2. OpenGL textures make more sense within the coordinate system when
156 // they are "upside down," so let's flip it.
157
158 flipSurface(surface);
159
160 // 1. OpenGL images must (generally) have dimensions of a power-of-two.
161 // If this one doesn't, we can at least be more friendly by expanding
162 // the dimensions so that they are, though there will be some empty
163 // space within the range of normal texture coordinates. It's better if
164 // textures are the right size to begin with.
165
166 SDL_Surface* image = SDL_CreateRGBSurface
167 (
168 SDL_SWSURFACE,
169 w, h,
170 32,
171 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
172 0x000000FF,
173 0x0000FF00,
174 0x00FF0000,
175 0xFF000000
176 #else
177 0xFF000000,
178 0x00FF0000,
179 0x0000FF00,
180 0x000000FF
181 #endif
182 );
183
184 if (!image)
185 {
186 return 0;
187 }
188
189 Uint32 savedFlags = surface->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
190 Uint8 savedAlpha = surface->format->alpha;
191 if (savedFlags & SDL_SRCALPHA)
192 {
193 SDL_SetAlpha(surface, 0, 0);
194 }
195
196 SDL_Rect srcArea, destArea;
197 srcArea.x = 0; destArea.x = 0;
198 srcArea.y = 0; destArea.y = h - surface->h;
199 srcArea.w = surface->w;
200 srcArea.h = surface->h;
201 SDL_BlitSurface(surface, &srcArea, image, &destArea);
202
203 if (savedFlags & SDL_SRCALPHA)
204 {
205 SDL_SetAlpha(surface, savedFlags, savedAlpha);
206 }
207
208 return image;
209 }
210 */
211
212 /**
213 * Use SDL_image to load images from file. A surface with the image data is
214 * returned.
215 * @return Image data.
216 */
217
218 void loadFromFile()
219 {
220 if (!mImage.isValid())
221 {
222 logWarning << "texture not found: " << getName() << std::endl;
223 throw Exception(ErrorCode::RESOURCE_NOT_FOUND, getName());
224 }
225
226 mImage.flip();
227
228 mWidth = mImage.getWidth();
229 mHeight = mImage.getHeight();
230 mMode = mImage.getColorMode();
231 }
232
233
234 /**
235 * Upload the image to GL so that it will be accessible by a much more
236 * manageable handle and hopefully reside in video memory.
237 */
238
239 void uploadToGL()
240 {
241 if (mObject)
242 {
243 // already loaded
244 return;
245 }
246
247 //if (!mContext) loadFromFile();
248
249 glGenTextures(1, &mObject);
250 glBindTexture(GL_TEXTURE_2D, mObject);
251
252 glTexImage2D
253 //gluBuild2DMipmaps
254 (
255 GL_TEXTURE_2D,
256 0,
257 mMode,
258 //3,
259 mWidth,
260 mHeight,
261 0,
262 mMode,
263 GL_UNSIGNED_BYTE,
264 mImage.getPixels()
265 );
266
267 setProperties();
268
269 //SDL_FreeSurface(mContext);
270 //mContext = 0;
271 }
272
273
274 /**
275 * Sets some texture properties such as the filters and external coordinate
276 * behavior.
277 */
278
279 void setProperties()
280 {
281 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mMinFilter);
282 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mMagFilter);
283 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mWrapS);
284 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mWrapT);
285 }
286
287 inline void setMinFilter(GLuint filter)
288 {
289 bind();
290 mMinFilter = filter;
291 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mMinFilter);
292 }
293
294 inline void setMagFilter(GLuint filter)
295 {
296 bind();
297 mMagFilter = filter;
298 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mMagFilter);
299 }
300
301 inline void setWrapS(GLuint wrap)
302 {
303 bind();
304 mWrapS = wrap;
305 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mWrapS);
306 }
307
308 inline void setWrapT(GLuint wrap)
309 {
310 bind();
311 mWrapT = wrap;
312 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mWrapT);
313 }
314
315
316 inline void bind()
317 {
318 if (mObject == 0)
319 {
320 uploadToGL();
321 }
322 if (mObject != gObject)
323 {
324 glBindTexture(GL_TEXTURE_2D, mObject);
325 gObject = mObject;
326 }
327 }
328
329
330 Image mImage;
331 unsigned mWidth; ///< Horizontal dimension of the image.
332 unsigned mHeight; ///< Vertical dimension.
333
334 GLuint mMode; ///< GL_RGB or GL_RGBA.
335 GLuint mMinFilter; ///< Minifcation filter.
336 GLuint mMagFilter; ///< Magnification filter.
337 GLuint mWrapS; ///< Wrapping behavior horizontally.
338 GLuint mWrapT; ///< Wrapping behavior vertically.
339
340 GLuint mObject; ///< GL texture handle.
341 static GLuint gObject; ///< Global GL texture handle.
342
343 Dispatch::Handler mDispatchHandler;
344 };
345
346 GLuint Texture::Impl::gObject = 0;
347
348
349 Texture::Texture(const std::string& name) :
350 // pass through
351 mImpl(Texture::Impl::getInstance(name)) {}
352
353
354 /**
355 * Bind the GL texture for mapping, etc.
356 */
357
358 void Texture::bind() const
359 {
360 // pass through
361 mImpl->bind();
362 }
363
364
365 /**
366 * Get the texture object, for the curious.
367 */
368
369 GLuint Texture::getObject() const
370 {
371 // pass through
372 return mImpl->mObject;
373 }
374
375
376 void Texture::resetBind()
377 {
378 glBindTexture(GL_TEXTURE_2D, 0);
379 Impl::gObject = 0;
380 }
381
382
383 unsigned Texture::getWidth() const
384 {
385 // pass through
386 return mImpl->mWidth;
387 }
388
389 unsigned Texture::getHeight() const
390 {
391 // pass through
392 return mImpl->mHeight;
393 }
394
395
396 void Texture::setMinFilter(GLuint filter)
397 {
398 // pass through
399 mImpl->setMinFilter(filter);
400 }
401
402 void Texture::setMagFilter(GLuint filter)
403 {
404 // pass through
405 mImpl->setMagFilter(filter);
406 }
407
408 void Texture::setWrapS(GLuint wrap)
409 {
410 // pass through
411 mImpl->setWrapS(wrap);
412 }
413
414 void Texture::setWrapT(GLuint wrap)
415 {
416 // pass through
417 mImpl->setWrapT(wrap);
418 }
419
420
421 std::string Texture::getPath(const std::string& name)
422 {
423 std::string path = Resource::getPath("textures/" + name + ".png");
424 return path;
425 }
426
427
428 } // namespace Mf
429
430 /** vim: set ts=4 sw=4 tw=80: *************************************************/
431
This page took 0.046519 seconds and 3 git commands to generate.