inline void VL_glGenerateMipmap(GLenum target) { if (glGenerateMipmapOES) glGenerateMipmapOES(target); else VL_TRAP(); }
Texture::Texture(const TextureData &data) { glGenTextures(1, &_textureID); glBindTexture(GL_TEXTURE_2D, _textureID); if (_textureID) { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, data.getFormat(), data.getWidth(), data.getHeight(), 0, data.getFormat(), GL_UNSIGNED_BYTE, data.getImageData().get()); #ifndef USE_GL_ES2 glGenerateMipmapOES(GL_TEXTURE_2D); #else glGenerateMipmap(GL_TEXTURE_2D); #endif } }
/* ================= gl_texture_create ================= */ erbool gl_texture_create (image_t *image, int flags, int *gltex, int *texw, int *texh) { int max, sw, sh, mip; GLuint tex; if (NULL == image || NULL == gltex || NULL == texw || NULL == texh) { sys_printf("bad args (image=%p, flags=%i, gltex=%p, texw=%p, texh=%p)\n", image, flags, gltex, texw, texh); return false; } if (flags & GL_TEX_FL_TEX3D) { max = gl_texture3d_size_max; } else if (flags & GL_TEX_FL_CUBEMAP) { max = gl_texture_cube_map_size_max; } else { max = gl_max_texture_size; } if (GL_TEX_FL_NOPICMIP) { sw = CLAMP(image->width, 1, max); sh = CLAMP(image->height, 1, max); } else { sw = CLAMP(image->width >> gl_picmip->i, 1, max); sh = CLAMP(image->height >> gl_picmip->i, 1, max); } if (!ext_gl_arb_texture_non_power_of_two || !gl_arb_texture_non_power_of_two->i) { sw = ceil_pwrov2(sw); sh = ceil_pwrov2(sh); } sw = CLAMP(sw, GL_MIN_TEXTURE_DIMENSION, max); sh = CLAMP(sh, GL_MIN_TEXTURE_DIMENSION, max); if (flags & GL_TEX_FL_NOSCALE) { *texw = sw; *texh = sh; if (!image_resize(image, sw, sh)) return false; } else { *texw = image->width; *texh = image->height; if (!image_scale(image, sw, sh)) return false; } glGenTextures(1, &tex); GLERROR(); eglBindTexture(GL_TEXTURE_2D, tex); GLERROR(); *gltex = tex; if (NULL != image->teximage2d) { image->teximage2d(image); } else { if (ext_gl_sgis_generate_mipmap && gl_sgis_generate_mipmap->i) { #ifdef ENGINE_OS_IPHONE glGenerateMipmapOES(GL_TEXTURE_2D); #else glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); #endif GLERROR(); GL_IMAGE_DATA2D(0, image); GLERROR(); } else { GL_IMAGE_DATA2D(0, image); GLERROR(); for (mip = 1; image->width > 1 || image->height > 1 ; mip++) { int status; if (0 > (status = image_mipmap(image))) { sys_printf("mipmap failed\n"); goto error; } else if (status > 0) { break; } GL_IMAGE_DATA2D(mip, image); GLERROR(); } } } if (flags & GL_TEX_FL_NOFILTER) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); GLERROR(); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); GLERROR(); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_trilinear->i ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR_MIPMAP_NEAREST); GLERROR(); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); GLERROR(); } if (!(flags & GL_TEX_FL_NOANISO) && ext_gl_ext_texture_filter_anisotropic && gl_ext_texture_filter_anisotropic->i) { GLfloat ani = CLAMP(gl_anisotropy_level->f, 1, gl_anisotropy_max); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, ani); GLERROR(); } if (!(flags & GL_TEX_FL_NOLOD) && ext_gl_ext_texture_lod_bias && gl_ext_texture_lod_bias->i) { GLfloat lod = CLAMP(gl_lod_bias->f, 0, gl_lod_bias_max); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS_EXT, lod); GLERROR(); } return true; error: glDeleteTextures(1, &tex); GLERROR(); return false; }
//----------------------------------------------------------------------------- // Very fast texture-to-texture blitter and hardware bi/trilinear scaling implementation using FBO // Destination texture must be 2D // Source texture must be 2D // Supports compressed formats as both source and destination format, it will use the hardware DXT compressor // if available. // @author W.J. van der Laan void GLESTextureBuffer::blitFromTexture(GLESTextureBuffer *src, const Image::Box &srcBox, const Image::Box &dstBox) { if(Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_FBO) == false) { // the following code depends on FBO support, it crashes if FBO is not supported. // TODO - write PBUFFER version of this function or a version that doesn't require FBO return; // for now - do nothing. } // std::cerr << "GLESTextureBuffer::blitFromTexture " << // src->mTextureID << ":" << srcBox.left << "," << srcBox.top << "," << srcBox.right << "," << srcBox.bottom << " " << // mTextureID << ":" << dstBox.left << "," << dstBox.top << "," << dstBox.right << "," << dstBox.bottom << std::endl; // Store reference to FBO manager GLESFBOManager *fboMan = static_cast<GLESFBOManager *>(GLESRTTManager::getSingletonPtr()); // Save and clear GL state for rendering glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); RenderSystem* rsys = Root::getSingleton().getRenderSystem(); rsys->_disableTextureUnitsFrom(0); // Disable alpha, depth and scissor testing, disable blending, // disable culling, disble lighting, disable fog and reset foreground // colour. glDisable(GL_ALPHA_TEST); glDisable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); glDisable(GL_BLEND); glDisable(GL_CULL_FACE); glDisable(GL_LIGHTING); glDisable(GL_FOG); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); GL_CHECK_ERROR; // Save and reset matrices glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_TEXTURE); glPushMatrix(); glLoadIdentity(); GL_CHECK_ERROR; // Set up source texture glBindTexture(src->mTarget, src->mTextureID); GL_CHECK_ERROR; // Set filtering modes depending on the dimensions and source if(srcBox.getWidth()==dstBox.getWidth() && srcBox.getHeight()==dstBox.getHeight() && srcBox.getDepth()==dstBox.getDepth()) { // Dimensions match -- use nearest filtering (fastest and pixel correct) glTexParameteri(src->mTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); GL_CHECK_ERROR; glTexParameteri(src->mTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); GL_CHECK_ERROR; } else { // Dimensions don't match -- use bi or trilinear filtering depending on the // source texture. if(src->mUsage & TU_AUTOMIPMAP) { // Automatic mipmaps, we can safely use trilinear filter which // brings greatly imporoved quality for minimisation. glTexParameteri(src->mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); GL_CHECK_ERROR; glTexParameteri(src->mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); GL_CHECK_ERROR; } else { // Manual mipmaps, stay safe with bilinear filtering so that no // intermipmap leakage occurs. glTexParameteri(src->mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); GL_CHECK_ERROR; glTexParameteri(src->mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); GL_CHECK_ERROR; } } // Clamp to edge (fastest) glTexParameteri(src->mTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); GL_CHECK_ERROR; glTexParameteri(src->mTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); GL_CHECK_ERROR; // Store old binding so it can be restored later GLint oldfb; glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &oldfb); GL_CHECK_ERROR; // Set up temporary FBO glBindFramebufferOES(GL_FRAMEBUFFER_OES, fboMan->getTemporaryFBO()); GL_CHECK_ERROR; GLuint tempTex = 0; if(!fboMan->checkFormat(mFormat)) { // If target format not directly supported, create intermediate texture GLenum tempFormat = GLESPixelUtil::getClosestGLInternalFormat(fboMan->getSupportedAlternative(mFormat)); glGenTextures(1, &tempTex); GL_CHECK_ERROR; glBindTexture(GL_TEXTURE_2D, tempTex); GL_CHECK_ERROR; // Allocate temporary texture of the size of the destination area glTexImage2D(GL_TEXTURE_2D, 0, tempFormat, GLESPixelUtil::optionalPO2(dstBox.getWidth()), GLESPixelUtil::optionalPO2(dstBox.getHeight()), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); GL_CHECK_ERROR; glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tempTex, 0); GL_CHECK_ERROR; // Set viewport to size of destination slice glViewport(0, 0, dstBox.getWidth(), dstBox.getHeight()); GL_CHECK_ERROR; } else { // We are going to bind directly, so set viewport to size and position of destination slice glViewport(dstBox.left, dstBox.top, dstBox.getWidth(), dstBox.getHeight()); GL_CHECK_ERROR; } // Process each destination slice for(size_t slice=dstBox.front; slice<dstBox.back; ++slice) { if(!tempTex) { /// Bind directly bindToFramebuffer(GL_COLOR_ATTACHMENT0_OES, slice); } if(tempTex) { // Copy temporary texture glBindTexture(mTarget, mTextureID); GL_CHECK_ERROR; switch(mTarget) { case GL_TEXTURE_2D: #if OGRE_PLATFORM == OGRE_PLATFORM_ANDROID case GL_TEXTURE_CUBE_MAP_OES: #endif glCopyTexSubImage2D(mFaceTarget, mLevel, dstBox.left, dstBox.top, 0, 0, dstBox.getWidth(), dstBox.getHeight()); GL_CHECK_ERROR; break; } } } // Finish up if(!tempTex) { // Generate mipmaps if(mUsage & TU_AUTOMIPMAP) { glBindTexture(mTarget, mTextureID); GL_CHECK_ERROR; glGenerateMipmapOES(mTarget); GL_CHECK_ERROR; } } // Reset source texture to sane state glBindTexture(src->mTarget, src->mTextureID); GL_CHECK_ERROR; // Detach texture from temporary framebuffer glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, 0); GL_CHECK_ERROR; // Restore old framebuffer glBindFramebufferOES(GL_FRAMEBUFFER_OES, oldfb); GL_CHECK_ERROR; // Restore matrix stacks and render state glMatrixMode(GL_TEXTURE); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); GL_CHECK_ERROR; glDeleteTextures(1, &tempTex); GL_CHECK_ERROR; }
void glGenerateMipmapOESLogged(GLenum target) { printf("glGenerateMipmapOES(%s)\n", GLEnumName(target)); glGenerateMipmapOES(target); }
void RETextureInternal::update(GLuint identifier, const REUByte * pixelsData, const REImagePixelFormat pixelsFormat, const REUInt32 width, const REUInt32 height, RETextureFilterType filterType) { GLenum textureType = 0; switch (pixelsFormat) { case REImagePixelFormatR8G8B8: textureType = GL_RGB; break; case REImagePixelFormatR8G8B8A8: textureType = GL_RGBA; break; case REImagePixelFormatLuminance8Alpha8: textureType = GL_LUMINANCE_ALPHA; break; case REImagePixelFormatAlpha8: textureType = GL_ALPHA; break; default: return; break; } glBindTexture(GL_TEXTURE_2D, identifier); #if defined(IS_OPENGL_MIPMAPS) /* MIPMAPS */ const REBOOL isGenerateMipmaps = RETextureInternal::isMipmaped(filterType); if (isGenerateMipmaps) { #if defined(HAVE_FUNCTION_GLUBUILD2DMIPMAPS) gluBuild2DMipmaps(GL_TEXTURE_2D, textureType, width, height, textureType, GL_UNSIGNED_BYTE, pixelsData); #else #if defined(HAVE_FUNCTION_GLTEXIMAGE2D) glTexImage2D(GL_TEXTURE_2D, 0, textureType, width, height, 0, textureType, GL_UNSIGNED_BYTE, pixelsData); #endif #if defined(HAVE_FUNCTION_GLGENERATEMIPMAPOES) glGenerateMipmapOES(GL_TEXTURE_2D); #endif #endif } else { #if defined(HAVE_FUNCTION_GLTEXIMAGE2D) glTexImage2D(GL_TEXTURE_2D, 0, textureType, width, height, 0, textureType, GL_UNSIGNED_BYTE, pixelsData); #endif } /* MIPMAPS */ #else /* NO MIPMAPS */ #if defined(HAVE_FUNCTION_GLTEXIMAGE2D) glTexImage2D(GL_TEXTURE_2D, 0, textureType, width, height, 0, textureType, GL_UNSIGNED_BYTE, pixelsData); #endif /* HAVE_FUNCTION_GLTEXIMAGE2D */ /* NO MIPMAPS */ #endif }
void GLTexture_setImage(void * selfPtr, GLint mipmapLevel, GLsizei width, GLsizei height, unsigned int bytesPerRow, void * bitmapData) { GLTexture * self = selfPtr; if (self->textureName == 0) { glGenTextures(1, &self->textureName); } self->pixelWidth = width; self->pixelHeight = height; glBindTexture(GL_TEXTURE_2D, self->textureName); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, self->wrapS); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, self->wrapT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, self->magFilter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, self->minFilter); #if defined(GL_EXT_texture_filter_anisotropic) && GL_EXT_texture_filter_anisotropic if (self->anisotropicFilter) { GLfloat maxAnisotropy; glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, maxAnisotropy); } #endif if (bytesPerRow % 4 == 0) { glPixelStorei(GL_UNPACK_ALIGNMENT, 4); } else if (bytesPerRow % 2 == 0) { glPixelStorei(GL_UNPACK_ALIGNMENT, 2); } else { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); } #if !TARGET_OPENGL_ES if (self->autoMipmap) { switch (GLGraphics_getOpenGLAPIVersion()) { case GL_API_VERSION_DESKTOP_1: case GL_API_VERSION_DESKTOP_2: case GL_API_VERSION_DESKTOP_3: glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); break; default: break; } } #endif glTexImage2D(GL_TEXTURE_2D, mipmapLevel, self->bitmapDataFormat, width, height, 0, self->bitmapDataFormat, self->bitmapDataType, bitmapData); #if TARGET_OPENGL_ES if (self->autoMipmap) { switch (GLGraphics_getOpenGLAPIVersion()) { case GL_API_VERSION_ES1: glGenerateMipmapOES(GL_TEXTURE_2D); break; case GL_API_VERSION_ES2: glGenerateMipmap(GL_TEXTURE_2D); break; default: break; } } #endif }
bool cfxSampler::apply(cfxParam* param) { // lookup source for the matching surface; if (surface == NULL) { surface = effect->getSurfaceByName(source); // only go through this if the surface is newly initialized // this will update the textureId // bind the texture and initialize the sampler states // generate mipmaps if needed if (surface) { surface->addReferencingParam(param); const std::string surfaceSource = surface->getInitFrom(); //cfxPrint("Found surface init from %p %s\n", surface, surfaceSource.c_str()); // get the texture object from the surface that is its source, or if that can't be found // just try using texture 1 as the default which is definitely not the solution but may // be interesting until this feature is fully supported // the mechanism to pair a texture with a surface for use by a parameter is in place. // the support for loading textures, as would probably be done by the surface is out // of the scope of this library. this is something that needs to exist // in a lower layer that can do resource management. this is something that // needs to exist in a layer that allows this other aspect of resource management. // this uses a static map (which has its own set of disadvantages) from surface to lookup // texture ids from images that were loaded elsewhere and pushed into cfx textureId = cfxSurface::getTexIdByImageId(surfaceSource); if (textureId > 0) { //cfxPrint("Set sampler state\n"); // this works on the currently bound texture object // not important which texture unit is used, we just need to use one to // allow cgSetSamplerState() to work properly. cfxPrint("going to bind %d\n", textureId); glBindTexture(GL_TEXTURE_2D, textureId); // apply the state settings std::vector<cfxGlSamplerSetting*>::iterator settingIter = settingArray.begin(); while (settingIter != settingArray.end()) { (*settingIter)->apply(param); settingIter++; } // calling this before generate mipmaps is better cause then the call // to generate mipmaps already has the space set up for it to use cgSetSamplerState(param->getParameter()); if (generateMipmaps) { #ifdef SN_TARGET_PS3 glGenerateMipmapOES(GL_TEXTURE_2D); #endif } } else { cfxPrint("Texture not found for surface: %s\n", surfaceSource.c_str()); return false; } } } return true; }