Added support for non power of two textures on newer graphics cards.
This commit is contained in:
parent
a8d9356d97
commit
29b04dbb7e
|
@ -85,6 +85,13 @@ using namespace std;
|
|||
#endif // PNG_SUPPORT
|
||||
|
||||
|
||||
// All rows are padded to a size that's a multiple of 4 bytes
|
||||
static int pad(int n)
|
||||
{
|
||||
return (n + 3) & ~0x3;
|
||||
}
|
||||
|
||||
|
||||
static int formatComponents(int fmt)
|
||||
{
|
||||
switch (fmt)
|
||||
|
@ -131,7 +138,7 @@ static int calcMipLevelSize(int fmt, int w, int h, int mip)
|
|||
// 4x4 blocks, 16 bytes per block
|
||||
return ((w + 3) / 4) * ((h + 3) / 4) * 16;
|
||||
default:
|
||||
return h * w * formatComponents(fmt);
|
||||
return h * pad(w * formatComponents(fmt));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,6 +153,8 @@ Image::Image(int fmt, int w, int h, int mips) :
|
|||
components = formatComponents(fmt);
|
||||
assert(components != 0);
|
||||
|
||||
pitch = pad(w * components);
|
||||
|
||||
size = 0;
|
||||
for (int i = 0; i < mipLevels; i++)
|
||||
size += calcMipLevelSize(fmt, w, h, i);
|
||||
|
@ -172,6 +181,12 @@ int Image::getHeight() const
|
|||
}
|
||||
|
||||
|
||||
int Image::getPitch() const
|
||||
{
|
||||
return pitch;
|
||||
}
|
||||
|
||||
|
||||
int Image::getMipLevelCount() const
|
||||
{
|
||||
return mipLevels;
|
||||
|
@ -213,7 +228,7 @@ unsigned char* Image::getPixelRow(int mip, int row)
|
|||
if (isCompressed())
|
||||
return NULL;
|
||||
|
||||
return getMipLevel(mip) + row * w * components;
|
||||
return getMipLevel(mip) + row * pitch;
|
||||
}
|
||||
|
||||
|
||||
|
@ -292,6 +307,7 @@ Image* Image::computeNormalMap(float scale, bool wrap) const
|
|||
return NULL;
|
||||
|
||||
unsigned char* nmPixels = normalMap->getPixels();
|
||||
int nmPitch = normalMap->getPitch();
|
||||
|
||||
// Compute normals using differences between adjacent texels.
|
||||
for (int i = 0; i < height; i++)
|
||||
|
@ -327,9 +343,9 @@ Image* Image::computeNormalMap(float scale, bool wrap) const
|
|||
}
|
||||
}
|
||||
|
||||
int h00 = (int) pixels[(i0 * width + j0) * components];
|
||||
int h10 = (int) pixels[(i0 * width + j1) * components];
|
||||
int h01 = (int) pixels[(i1 * width + j0) * components];
|
||||
int h00 = (int) pixels[i0 * pitch + j0 * components];
|
||||
int h10 = (int) pixels[i0 * pitch + j1 * components];
|
||||
int h01 = (int) pixels[i1 * pitch + j0 * components];
|
||||
|
||||
float dx = (float) (h10 - h00) * (1.0f / 255.0f) * scale;
|
||||
float dy = (float) (h01 - h00) * (1.0f / 255.0f) * scale;
|
||||
|
@ -337,7 +353,7 @@ Image* Image::computeNormalMap(float scale, bool wrap) const
|
|||
float mag = (float) sqrt(dx * dx + dy * dy + 1.0f);
|
||||
float rmag = 1.0f / mag;
|
||||
|
||||
int n = (i * width + j) * 4;
|
||||
int n = i * nmPitch + j * 4;
|
||||
nmPixels[n] = (unsigned char) (128 + 127 * dx * rmag);
|
||||
nmPixels[n + 1] = (unsigned char) (128 + 127 * dy * rmag);
|
||||
nmPixels[n + 2] = (unsigned char) (128 + 127 * rmag);
|
||||
|
|
|
@ -27,6 +27,7 @@ class Image
|
|||
|
||||
int getWidth() const;
|
||||
int getHeight() const;
|
||||
int getPitch() const;
|
||||
int getMipLevelCount() const;
|
||||
int getFormat() const;
|
||||
int getComponents() const;
|
||||
|
@ -50,6 +51,7 @@ class Image
|
|||
private:
|
||||
int width;
|
||||
int height;
|
||||
int pitch;
|
||||
int mipLevels;
|
||||
int components;
|
||||
int format;
|
||||
|
|
|
@ -101,6 +101,7 @@ struct TextureCaps
|
|||
bool autoMipMapSupported;
|
||||
bool maxLevelSupported;
|
||||
GLint maxTextureSize;
|
||||
bool nonPow2Supported;
|
||||
};
|
||||
|
||||
static TextureCaps texCaps;
|
||||
|
@ -147,6 +148,7 @@ static const TextureCaps& GetTextureCaps()
|
|||
texCaps.autoMipMapSupported = ExtensionSupported("GL_SGIS_generate_mipmap");
|
||||
texCaps.maxLevelSupported = testMaxLevel();
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texCaps.maxTextureSize);
|
||||
texCaps.nonPow2Supported = ExtensionSupported("GL_ARB_texture_non_power_of_two");
|
||||
}
|
||||
|
||||
return texCaps;
|
||||
|
@ -404,7 +406,7 @@ ImageTexture::ImageTexture(Image& img,
|
|||
Texture(img.getWidth(), img.getHeight()),
|
||||
glName(0)
|
||||
{
|
||||
glGenTextures(1, (GLuint*)&glName);
|
||||
glGenTextures(1, (GLuint*) &glName);
|
||||
glBindTexture(GL_TEXTURE_2D, glName);
|
||||
|
||||
bool mipmap = mipMapMode == DefaultMipMaps;
|
||||
|
@ -417,7 +419,7 @@ ImageTexture::ImageTexture(Image& img,
|
|||
precomputedMipMaps = true;
|
||||
|
||||
// We can't automatically generate mipmaps for compressed textures.
|
||||
// If a precomputed mipmap set isn't provided, turn of mipmapping entirely.
|
||||
// If a precomputed mipmap set isn't provided, turn off mipmapping entirely.
|
||||
if (!precomputedMipMaps && img.isCompressed())
|
||||
mipmap = false;
|
||||
|
||||
|
@ -426,7 +428,7 @@ ImageTexture::ImageTexture(Image& img,
|
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, texAddress);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
|
||||
mipMapMode == NoMipMaps ? GL_LINEAR : GL_LINEAR_MIPMAP_LINEAR);
|
||||
|
||||
if (mipMapMode == AutoMipMaps)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
|
||||
|
@ -445,6 +447,7 @@ ImageTexture::ImageTexture(Image& img,
|
|||
}
|
||||
else
|
||||
{
|
||||
clog << "gluBuild2DMipmaps\n";
|
||||
gluBuild2DMipmaps(GL_TEXTURE_2D,
|
||||
internalFormat,
|
||||
getWidth(), getHeight(),
|
||||
|
@ -513,7 +516,7 @@ TiledTexture::TiledTexture(Image& img,
|
|||
|
||||
alpha = img.hasAlpha();
|
||||
|
||||
bool mipmap = mipMapMode == DefaultMipMaps;
|
||||
bool mipmap = mipMapMode != NoMipMaps;
|
||||
bool precomputedMipMaps = false;
|
||||
|
||||
// Require a complete set of mipmaps
|
||||
|
@ -745,8 +748,9 @@ CubeMap::CubeMap(Image* faces[]) :
|
|||
glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MIN_FILTER,
|
||||
mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
|
||||
// mipMapMode == NoMipMaps ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
|
||||
|
||||
int internalFormat = getInternalFormat(format);
|
||||
|
||||
|
@ -955,6 +959,7 @@ static Texture* CreateTextureFromImage(Image& img,
|
|||
Texture::AddressMode addressMode,
|
||||
Texture::MipMapMode mipMode)
|
||||
{
|
||||
#if 0
|
||||
// Require texture dimensions to be powers of two. Even though the
|
||||
// OpenGL driver will automatically rescale textures with non-power of
|
||||
// two sizes, some quality loss may result. The power of two requirement
|
||||
|
@ -966,23 +971,34 @@ static Texture* CreateTextureFromImage(Image& img,
|
|||
clog << "Texture has non-power of two dimensions.\n";
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
// If non power of two textures are supported switch mipmap generation to
|
||||
// automatic. gluBuildMipMaps may rescale the texture to a power of two
|
||||
// on some drivers even when the hardware supports non power of two textures,
|
||||
// whereas auto mipmap generation will properly deal with the dimensions.
|
||||
if (GetTextureCaps().nonPow2Supported)
|
||||
{
|
||||
if (mipMode == Texture::DefaultMipMaps)
|
||||
mipMode = Texture::AutoMipMaps;
|
||||
}
|
||||
|
||||
bool splittingAllowed = true;
|
||||
Texture* tex = NULL;
|
||||
|
||||
int maxDim = GetTextureCaps().maxTextureSize;
|
||||
//int maxDim = 256;
|
||||
if ((img.getWidth() > maxDim || img.getHeight() > maxDim) &&
|
||||
splittingAllowed)
|
||||
{
|
||||
// The texture is too large; we need to split it.
|
||||
int uSplit = max(1, img.getWidth() / maxDim);
|
||||
int vSplit = max(1, img.getHeight() / maxDim);
|
||||
|
||||
clog << "Creating tiled texture. Width=" << img.getWidth() << ", max=" << maxDim << "\n";
|
||||
tex = new TiledTexture(img, uSplit, vSplit, mipMode);
|
||||
}
|
||||
else
|
||||
{
|
||||
clog << "Creating ordinary texture: " << img.getWidth() << "x" << img.getHeight() << "\n";
|
||||
// The image is small enough to fit in a single texture; or, splitting
|
||||
// was disallowed so we'll scale the large image down to fit in
|
||||
// an ordinary texture.
|
||||
|
|
Loading…
Reference in a new issue