GLuint NvCreateTextureFromDDSEx(const char* filename, NvBool flipVertical, NvBool useMipmaps, int* width, int* height, NvBool* alpha, NvBool *isCubeMap) { // Clear the GL error before this function, since at the end of this // function, we test the error and report it. We do not want to report // an error that happened at some random time before. If we want to // catch those, we need more general/comprehensive handling. But having // this function print a GL error for something that happened in other // random code is confusing, especially to non-rail developers. // Some other code, like NVBitfont, prints error messages at the top of // the function and print a message that implies that the error was there // at the time of call. That may make sense as an optional setting down // the road glGetError(); GLuint tex = 0; NVHHDDSImage *img = NVHHDDSLoad(filename, flipVertical ? 1 : 0); if (img) { if(isCubeMap) { *isCubeMap = img->cubemap ? NV_TRUE:NV_FALSE; } if (width) *width = img->width; if (height) *height = img->height; if (alpha) *alpha = img->alpha ? NV_TRUE : NV_FALSE; glGenTextures(1, &tex); if (!img->cubemap) { glBindTexture(GL_TEXTURE_2D, tex); LoadTextureFromDDSData(GL_TEXTURE_2D, 0, img, useMipmaps); } else { int baseLevel = 0; glBindTexture(GL_TEXTURE_CUBE_MAP, tex); LoadTextureFromDDSData(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, baseLevel, img, useMipmaps); baseLevel += img->numMipmaps ? img->numMipmaps : 1; LoadTextureFromDDSData(GL_TEXTURE_CUBE_MAP_POSITIVE_X, baseLevel, img, useMipmaps); baseLevel += img->numMipmaps ? img->numMipmaps : 1; LoadTextureFromDDSData(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, baseLevel, img, useMipmaps); baseLevel += img->numMipmaps ? img->numMipmaps : 1; LoadTextureFromDDSData(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, baseLevel, img, useMipmaps); baseLevel += img->numMipmaps ? img->numMipmaps : 1; LoadTextureFromDDSData(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, baseLevel, img, useMipmaps); baseLevel += img->numMipmaps ? img->numMipmaps : 1; LoadTextureFromDDSData(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, baseLevel, img, useMipmaps); baseLevel += img->numMipmaps ? img->numMipmaps : 1; } GLint err = glGetError(); if (err) NVLogError("NvCreateTextureFromDDSEx error", ""); NVHHDDSFree(img); } return tex; }
bool createNormalMapGL(GLuint &textureID, const unsigned int index, const GLenum textureUnit, const GLfloat heightScale, const char *filename) { //Temporary variables for loading pixel data unsigned char* pHeightPixels, *pNormalPixels; unsigned int uiFormat, uiType, uiWidth, uiHeight; NVHHDDSImage *img = NVHHDDSLoad(filename, (NvS32)1); if(!img) { DEBUG("ERROR createNormalMapGL: problem loading height map texture."); return false; } pHeightPixels = (unsigned char*)(img->data[0]); uiWidth = (unsigned int) (img->width); uiHeight = (unsigned int) (img->height); uiFormat = (unsigned int) (img->format); uiType = (unsigned int) (img->componentFormat); unsigned int uiFormatWidth = 4U; pNormalPixels = new unsigned char[uiWidth * uiHeight * uiFormatWidth]; for(unsigned int j = 0U; j < uiHeight; j++) for(unsigned int i = 0U; i < uiWidth; i++) { unsigned int iCenterIdx = uiFormatWidth * (j * uiWidth + i); unsigned int iLeftIdx = uiFormatWidth * ((i > 0U) ? ( j * uiWidth + (i - 1U)) : ( j * uiWidth + (uiWidth - 1U))); unsigned int iRightIdx = uiFormatWidth * ((i < uiWidth - 1U) ? ( j * uiWidth + (i + 1U)) : ( j * uiWidth + 0U )); unsigned int iUpIdx = uiFormatWidth * ((j > 0U) ? ((j - 1U) * uiWidth + i ) : ((uiHeight - 1U) * uiWidth + i )); unsigned int iDownIdx = uiFormatWidth * ((j < uiHeight - 1U) ? ((j + 1U) * uiWidth + i ) : ( 0U * uiWidth + i )); GLfloat fDx, fDy, fDz; //Compute gradients fDx = (GLfloat)(pHeightPixels[iRightIdx]); //[ 0, 255] fDy = (GLfloat)(pHeightPixels[iUpIdx]); //[ 0, 255] fDx -= (GLfloat)(pHeightPixels[iLeftIdx]); //[-255, 255] fDy -= (GLfloat)(pHeightPixels[iDownIdx]); //[-255, 255] fDx /= 255.0F; //[ -1, 1] fDy /= 255.0F; //[ -1, 1] //Scale them fDx *= heightScale; //[ -H, H] fDy *= heightScale; //[ -H, H] //Putting them in vectors (1, 0, fDx) and (0, 1, fDy) and //doing a cross product results in (-fDx, -fDy, 1) //BUT, for some reason, fDx needs to be turned into its //negative again for normal mapping to work, so we will only //turn fDy into its negative fDy *= -1; //[ -H, H] //We normalize the vector GLfloat fDet = (GLfloat)(sqrt(fDx * fDx + fDy * fDy + 1.0)); fDx /= fDet; fDy /= fDet; //[ -1, 1] //Now, we have to fit them into unsigned chars. We map them from //[-1, 1] to [0, 255] fDx += 1.0F; fDy += 1.0F; //[ 0, 2] fDx *= 128.0F; fDy *= 128.0F; //[ 0, 255] //The z component of the vector is just 1 //(not scaled, but normalized) fDz = (GLfloat)1.0F / fDet; //[ 0, 1] fDz *= 255.0F; pNormalPixels[iCenterIdx + 0U] = (unsigned char)fDx; pNormalPixels[iCenterIdx + 1U] = (unsigned char)fDy; pNormalPixels[iCenterIdx + 2U] = (unsigned char)fDz; pNormalPixels[iCenterIdx + 3U] = pHeightPixels[iCenterIdx]; } NVHHDDSFree(img); glGenTextures(1, &(textureID)); glActiveTexture(textureUnit); glBindTexture(GL_TEXTURE_2D, textureID); glTexImage2D(GL_TEXTURE_2D, (GLint)0, (GLint)uiFormat, (GLsizei)uiWidth, (GLsizei)uiHeight, (GLint)0, (GLenum)uiFormat, (GLenum)uiType, (const GLvoid*)pNormalPixels); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); delete [] pNormalPixels; return true; }