]>
Dogcows Code - chaz/yoink/blob - src/Moof/Texture.cc
2 /*******************************************************************************
4 Copyright (c) 2009, Charles McGarvey
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
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.
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.
27 *******************************************************************************/
29 #include <cstring> // memcpy
31 #include <boost/bind.hpp>
34 #include <SDL/SDL_image.h>
36 #include "Dispatch.hh"
38 #include "Exception.hh"
49 * The texture implementation just contains all the information about the image
50 * which is worth having in memory. The image data itself is not worth keeping
51 * in memory if the texture has been loaded to GL, but the name of the resource
52 * is retained so that it can be reloaded if necessary. The implementation is a
53 * mippleton so that multiple texture objects can share the same internal
54 * objects and avoid having duplicate textures loaded to GL.
57 class Texture::Impl
: public Library
<Impl
>
61 * Delete the texture (if it is loaded) from GL.
68 if (mObject
== gObject
)
73 glDeleteTextures(1, &mObject
);
79 * If the GL context was recreated, we need to reload the texture. This may
80 * involve reading it from disk again, but hopefully the OS was smart enough
81 * to cache it if the client has plenty of RAM.
84 void contextRecreated()
86 mObject
= gObject
= 0;
91 * This is a helper method used by some of the texture loading code. It
92 * returns the first power of two which is greater than the input value.
95 static int powerOfTwo(int input
)
107 static void flipSurface(SDL_Surface
* image
)
109 unsigned char* pixels
= (Uint8
*)(image
->pixels
);
111 unsigned pitch
= image
->pitch
;
112 unsigned char line
[pitch
];
115 int yEnd
= image
->h
- 1;
117 if (SDL_MUSTLOCK(image
)) SDL_LockSurface(image
);
118 while (yBegin
< yEnd
)
120 memcpy(line
, pixels
+ pitch
* yBegin
, pitch
);
121 memcpy(pixels
+ pitch
* yBegin
, pixels
+ pitch
* yEnd
, pitch
);
122 memcpy(pixels
+ pitch
* yEnd
, line
, pitch
);
126 if (SDL_MUSTLOCK(image
)) SDL_UnlockSurface(image
);
132 * Construction is initialization.
135 explicit Impl(const std::string
& name
) :
141 mMinFilter(GL_NEAREST
),
142 mMagFilter(GL_NEAREST
),
147 // make sure the engine is initialized
148 Engine
& engine
= Engine::getInstance();
149 VideoP video
= engine
.getVideo();
150 ASSERT(video
&& "cannot load textures without a current video context");
152 // we want to know when the GL context is recreated
153 mDispatchHandler
= engine
.addHandler("video.newcontext",
154 boost::bind(&Impl::contextRecreated
, this));
163 SDL_FreeSurface(mContext
);
171 * Adapted from some public domain code. This stuff is common enough that
172 * it really should be included in SDL_image... We need this because images
173 * loaded with SDL_image aren't exactly GL-ready right out of the box. This
174 * method makes them ready.
177 static SDL_Surface
* prepareImageForGL(SDL_Surface
* surface
)
179 int w
= powerOfTwo(surface
->w
);
180 int h
= powerOfTwo(surface
->h
);
182 // 2. OpenGL textures make more sense within the coordinate system when
183 // they are "upside down," so let's flip it.
185 flipSurface(surface
);
187 // 1. OpenGL images must (generally) have dimensions of a power-of-two.
188 // If this one doesn't, we can at least be more friendly by expanding
189 // the dimensions so that they are, though there will be some empty
190 // space within the range of normal texture coordinates. It's better if
191 // textures are the right size to begin with.
193 SDL_Surface
* image
= SDL_CreateRGBSurface
198 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
216 Uint32 savedFlags
= surface
->flags
&(SDL_SRCALPHA
|SDL_RLEACCELOK
);
217 Uint8 savedAlpha
= surface
->format
->alpha
;
218 if (savedFlags
& SDL_SRCALPHA
)
220 SDL_SetAlpha(surface
, 0, 0);
223 SDL_Rect srcArea
, destArea
;
224 srcArea
.x
= 0; destArea
.x
= 0;
225 srcArea
.y
= 0; destArea
.y
= h
- surface
->h
;
226 srcArea
.w
= surface
->w
;
227 srcArea
.h
= surface
->h
;
228 SDL_BlitSurface(surface
, &srcArea
, image
, &destArea
);
230 if (savedFlags
& SDL_SRCALPHA
)
232 SDL_SetAlpha(surface
, savedFlags
, savedAlpha
);
239 * Use SDL_image to load images from file. A surface with the image data is
241 * @return Image data.
246 SDL_Surface
* surface
;
248 surface
= IMG_Load(Texture::getPath(getName()).c_str());
252 logWarning("texture not found: %s", getName().c_str());
253 throw Exception(ErrorCode::FILE_NOT_FOUND
, getName());
256 SDL_Surface
* temp
= prepareImageForGL(surface
);
257 SDL_FreeSurface(surface
);
261 throw Exception(ErrorCode::UNKNOWN_IMAGE_FORMAT
, getName());
264 if (temp
->format
->BytesPerPixel
== 3)
268 else if (temp
->format
->BytesPerPixel
== 4)
274 SDL_FreeSurface(temp
);
275 throw Exception(ErrorCode::UNKNOWN_IMAGE_FORMAT
, getName());
286 * Upload the image to GL so that it will be accessible by a much more
287 * manageable handle and hopefully reside in video memory.
298 if (!mContext
) loadFromFile();
300 glGenTextures(1, &mObject
);
301 glBindTexture(GL_TEXTURE_2D
, mObject
);
320 SDL_FreeSurface(mContext
);
326 * Sets some texture properties such as the filters and external coordinate
332 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, mMinFilter
);
333 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, mMagFilter
);
334 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, mWrapS
);
335 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, mWrapT
);
338 inline void setMinFilter(GLuint filter
)
342 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, mMinFilter
);
345 inline void setMagFilter(GLuint filter
)
349 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, mMagFilter
);
352 inline void setWrapS(GLuint wrap
)
356 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, mWrapS
);
359 inline void setWrapT(GLuint wrap
)
363 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, mWrapT
);
373 if (mObject
!= gObject
)
375 glBindTexture(GL_TEXTURE_2D
, mObject
);
381 SDL_Surface
* mContext
;
382 unsigned mWidth
; ///< Horizontal dimension of the image.
383 unsigned mHeight
; ///< Vertical dimension.
385 GLuint mMode
; ///< GL_RGB or GL_RGBA.
386 GLuint mMinFilter
; ///< Minifcation filter.
387 GLuint mMagFilter
; ///< Magnification filter.
388 GLuint mWrapS
; ///< Wrapping behavior horizontally.
389 GLuint mWrapT
; ///< Wrapping behavior vertically.
391 GLuint mObject
; ///< GL texture handle.
392 static GLuint gObject
; ///< Global GL texture handle.
394 Dispatch::Handler mDispatchHandler
;
397 GLuint
Texture::Impl::gObject
= 0;
400 Texture::Texture(const std::string
& name
) :
402 mImpl(Texture::Impl::getInstance(name
)) {}
406 * Bind the GL texture for mapping, etc.
409 void Texture::bind() const
417 * Get the texture object, for the curious.
420 GLuint
Texture::getObject() const
423 return mImpl
->mObject
;
427 void Texture::resetBind()
429 glBindTexture(GL_TEXTURE_2D
, 0);
434 unsigned Texture::getWidth() const
437 return mImpl
->mWidth
;
440 unsigned Texture::getHeight() const
443 return mImpl
->mHeight
;
447 void Texture::setMinFilter(GLuint filter
)
450 mImpl
->setMinFilter(filter
);
453 void Texture::setMagFilter(GLuint filter
)
456 mImpl
->setMagFilter(filter
);
459 void Texture::setWrapS(GLuint wrap
)
462 mImpl
->setWrapS(wrap
);
465 void Texture::setWrapT(GLuint wrap
)
468 mImpl
->setWrapT(wrap
);
472 std::string
Texture::getPath(const std::string
& name
)
474 std::string path
= Resource::getPath("textures/" + name
+ ".png");
481 /** vim: set ts=4 sw=4 tw=80: *************************************************/
This page took 0.05502 seconds and 4 git commands to generate.