void QOpenGLTextureHelper::qt_CompressedTextureImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits) { GLint oldTexture; glGetIntegerv(bindingTarget, &oldTexture); glBindTexture(target, texture); glCompressedTexImage1D(target, level, internalFormat, width, border, imageSize, bits); glBindTexture(target, oldTexture); }
void Texture1D::init(int w, TextureInternalFormat tf, TextureFormat f, PixelType t, const Parameters ¶ms, const Buffer::Parameters &s, const Buffer &pixels) { Texture::init(tf, params); this->w = w; pixels.bind(GL_PIXEL_UNPACK_BUFFER); if (isCompressed() && s.compressedSize() > 0) { glCompressedTexImage1D(textureTarget, 0, getTextureInternalFormat(internalFormat), w, 0, s.compressedSize(), pixels.data(0)); } else { s.set(); glTexImage1D(textureTarget, 0, getTextureInternalFormat(internalFormat), w, 0, getTextureFormat(f), getPixelType(t), pixels.data(0)); s.unset(); } pixels.unbind(GL_PIXEL_UNPACK_BUFFER); generateMipMap(); if (FrameBuffer::getError() != 0) { throw exception(); } }
JNIEXPORT void JNICALL Java_org_lwjgl_opengl_GL13_nglCompressedTexImage1DBO(JNIEnv *env, jclass clazz, jint target, jint level, jint internalformat, jint width, jint border, jint imageSize, jlong data_buffer_offset, jlong function_pointer) { const GLvoid *data_address = (const GLvoid *)(intptr_t)offsetToPointer(data_buffer_offset); glCompressedTexImage1DPROC glCompressedTexImage1D = (glCompressedTexImage1DPROC)((intptr_t)function_pointer); glCompressedTexImage1D(target, level, internalformat, width, border, imageSize, data_address); }
void GLTextureBuffer::upload(const PixelData &data, const PixelVolume &dest) { if((mUsage & TU_RENDERTARGET) != 0) BS_EXCEPT(NotImplementedException, "Writing to render texture from CPU not supported."); if ((mUsage & TU_DEPTHSTENCIL) != 0) BS_EXCEPT(NotImplementedException, "Writing to depth stencil texture from CPU not supported."); glBindTexture( mTarget, mTextureID ); if(PixelUtil::isCompressed(data.getFormat())) { if(data.getFormat() != mFormat || !data.isConsecutive()) BS_EXCEPT(InvalidParametersException, "Compressed images must be consecutive, in the source format"); GLenum format = GLPixelUtil::getClosestGLInternalFormat(mFormat); switch(mTarget) { case GL_TEXTURE_1D: if (dest.left == 0) { glCompressedTexImage1D(GL_TEXTURE_1D, mLevel, format, dest.getWidth(), 0, data.getConsecutiveSize(), data.getData()); } else { glCompressedTexSubImage1D(GL_TEXTURE_1D, mLevel, dest.left, dest.getWidth(), format, data.getConsecutiveSize(), data.getData()); } break; case GL_TEXTURE_2D: case GL_TEXTURE_CUBE_MAP: if (dest.left == 0 && dest.top == 0) { glCompressedTexImage2D(mFaceTarget, mLevel, format, dest.getWidth(), dest.getHeight(), 0, data.getConsecutiveSize(), data.getData()); } else { glCompressedTexSubImage2D(mFaceTarget, mLevel, dest.left, dest.top, dest.getWidth(), dest.getHeight(), format, data.getConsecutiveSize(), data.getData()); } break; case GL_TEXTURE_3D: if (dest.left == 0 && dest.top == 0 && dest.front == 0) { glCompressedTexImage3D(GL_TEXTURE_3D, mLevel, format, dest.getWidth(), dest.getHeight(), dest.getDepth(), 0, data.getConsecutiveSize(), data.getData()); } else { glCompressedTexSubImage3D(GL_TEXTURE_3D, mLevel, dest.left, dest.top, dest.front, dest.getWidth(), dest.getHeight(), dest.getDepth(), format, data.getConsecutiveSize(), data.getData()); } break; } } else { if(data.getWidth() != data.getRowPitch()) glPixelStorei(GL_UNPACK_ROW_LENGTH, data.getRowPitch()); if(data.getHeight()*data.getWidth() != data.getSlicePitch()) glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, (data.getSlicePitch()/data.getWidth())); if(data.getLeft() > 0 || data.getTop() > 0 || data.getFront() > 0) glPixelStorei(GL_UNPACK_SKIP_PIXELS, data.getLeft() + data.getRowPitch() * data.getTop() + data.getSlicePitch() * data.getFront()); if((data.getWidth()*PixelUtil::getNumElemBytes(data.getFormat())) & 3) glPixelStorei(GL_UNPACK_ALIGNMENT, 1); switch(mTarget) { case GL_TEXTURE_1D: glTexSubImage1D(GL_TEXTURE_1D, mLevel, dest.left, dest.getWidth(), GLPixelUtil::getGLOriginFormat(data.getFormat()), GLPixelUtil::getGLOriginDataType(data.getFormat()), data.getData()); break; case GL_TEXTURE_2D: case GL_TEXTURE_CUBE_MAP: glTexSubImage2D(mFaceTarget, mLevel, dest.left, dest.top, dest.getWidth(), dest.getHeight(), GLPixelUtil::getGLOriginFormat(data.getFormat()), GLPixelUtil::getGLOriginDataType(data.getFormat()), data.getData()); break; case GL_TEXTURE_3D: glTexSubImage3D( GL_TEXTURE_3D, mLevel, dest.left, dest.top, dest.front, dest.getWidth(), dest.getHeight(), dest.getDepth(), GLPixelUtil::getGLOriginFormat(data.getFormat()), GLPixelUtil::getGLOriginDataType(data.getFormat()), data.getData()); break; } } // Restore defaults glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0); glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_Texture); }
/* * @~English * @brief Load a GL texture object from a ktxStream. * * This function will unpack compressed GL_ETC1_RGB8_OES and GL_ETC2_* format * textures in software when the format is not supported by the GL context, * provided the library has been compiled with SUPPORT_SOFTWARE_ETC_UNPACK * defined as 1. * * It will also convert textures with legacy formats to their modern equivalents * when the format is not supported by the GL context, provided that the library * has been compiled with SUPPORT_LEGACY_FORMAT_CONVERSION defined as 1. * * @param [in] stream pointer to the ktxStream from which to load. * @param [in,out] pTexture name of the GL texture to load. If NULL or if * <tt>*pTexture == 0</tt> the function will generate * a texture name. The function binds either the * generated name or the name given in @p *pTexture * to the texture target returned in @p *pTarget, * before loading the texture data. If @p pTexture * is not NULL and a name was generated, the generated * name will be returned in *pTexture. * @param [out] pTarget @p *pTarget is set to the texture target used. The * target is chosen based on the file contents. * @param [out] pDimensions If @p pDimensions is not NULL, the width, height and * depth of the texture's base level are returned in the * fields of the KTX_dimensions structure to which it points. * @param [out] pIsMipmapped * If @p pIsMipmapped is not NULL, @p *pIsMipmapped is set * to GL_TRUE if the KTX texture is mipmapped, GL_FALSE * otherwise. * @param [out] pGlerror @p *pGlerror is set to the value returned by * glGetError when this function returns the error * KTX_GL_ERROR. glerror can be NULL. * @param [in,out] pKvdLen If not NULL, @p *pKvdLen is set to the number of bytes * of key-value data pointed at by @p *ppKvd. Must not be * NULL, if @p ppKvd is not NULL. * @param [in,out] ppKvd If not NULL, @p *ppKvd is set to the point to a block of * memory containing key-value data read from the file. * The application is responsible for freeing the memory. * * * @return KTX_SUCCESS on success, other KTX_* enum values on error. * * @exception KTX_INVALID_VALUE @p target is @c NULL or the size of a mip * level is greater than the size of the * preceding level. * @exception KTX_INVALID_OPERATION @p ppKvd is not NULL but pKvdLen is NULL. * @exception KTX_UNEXPECTED_END_OF_FILE the file does not contain the * expected amount of data. * @exception KTX_OUT_OF_MEMORY Sufficient memory could not be allocated to store * the requested key-value data. * @exception KTX_GL_ERROR A GL error was raised by glBindTexture, * glGenTextures or gl*TexImage*. The GL error * will be returned in @p *glerror, if glerror * is not @c NULL. */ static KTX_error_code ktxLoadTextureS(struct ktxStream* stream, GLuint* pTexture, GLenum* pTarget, KTX_dimensions* pDimensions, GLboolean* pIsMipmapped, GLenum* pGlerror, unsigned int* pKvdLen, unsigned char** ppKvd) { GLint previousUnpackAlignment; KTX_header header; KTX_texinfo texinfo; void* data = NULL; khronos_uint32_t dataSize = 0; GLuint texname; int texnameUser; khronos_uint32_t faceLodSize; khronos_uint32_t faceLodSizeRounded; khronos_uint32_t level; khronos_uint32_t face; GLenum glFormat, glInternalFormat; KTX_error_code errorCode = KTX_SUCCESS; GLenum errorTmp; if (pGlerror) *pGlerror = GL_NO_ERROR; if (ppKvd) { *ppKvd = NULL; } if (!stream || !stream->read || !stream->skip) { return KTX_INVALID_VALUE; } if (!pTarget) { return KTX_INVALID_VALUE; } if (!stream->read(&header, KTX_HEADER_SIZE, stream->src)) { return KTX_UNEXPECTED_END_OF_FILE; } errorCode = _ktxCheckHeader(&header, &texinfo); if (errorCode != KTX_SUCCESS) { return errorCode; } if (ppKvd) { if (pKvdLen == NULL) return KTX_INVALID_OPERATION; *pKvdLen = header.bytesOfKeyValueData; if (*pKvdLen) { *ppKvd = (unsigned char*)malloc(*pKvdLen); if (*ppKvd == NULL) return KTX_OUT_OF_MEMORY; if (!stream->read(*ppKvd, *pKvdLen, stream->src)) { free(*ppKvd); *ppKvd = NULL; return KTX_UNEXPECTED_END_OF_FILE; } } } else { /* skip key/value metadata */ if (!stream->skip((long)header.bytesOfKeyValueData, stream->src)) { return KTX_UNEXPECTED_END_OF_FILE; } } if (contextProfile == 0) discoverContextCapabilities(); /* KTX files require an unpack alignment of 4 */ glGetIntegerv(GL_UNPACK_ALIGNMENT, &previousUnpackAlignment); if (previousUnpackAlignment != KTX_GL_UNPACK_ALIGNMENT) { glPixelStorei(GL_UNPACK_ALIGNMENT, KTX_GL_UNPACK_ALIGNMENT); } texnameUser = pTexture && *pTexture; if (texnameUser) { texname = *pTexture; } else { glGenTextures(1, &texname); } glBindTexture(texinfo.glTarget, texname); // Prefer glGenerateMipmaps over GL_GENERATE_MIPMAP if (texinfo.generateMipmaps && (glGenerateMipmap == NULL)) { glTexParameteri(texinfo.glTarget, GL_GENERATE_MIPMAP, GL_TRUE); } if (texinfo.glTarget == GL_TEXTURE_CUBE_MAP) { texinfo.glTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X; } glInternalFormat = header.glInternalFormat; glFormat = header.glFormat; if (!texinfo.compressed) { #if SUPPORT_LEGACY_FORMAT_CONVERSION // If sized legacy formats are supported there is no need to convert. // If only unsized formats are supported, there is no point in converting // as the modern formats aren't supported either. if (sizedFormats == _NON_LEGACY_FORMATS && supportsSwizzle) { convertFormat(texinfo.glTarget, &glFormat, &glInternalFormat); errorTmp = glGetError(); } else if (sizedFormats == _NO_SIZED_FORMATS) glInternalFormat = header.glBaseInternalFormat; #else // When no sized formats are supported, or legacy sized formats are not // supported, must change internal format. if (sizedFormats == _NO_SIZED_FORMATS || (!(sizedFormats & _LEGACY_FORMATS) && (header.glBaseInternalFormat == GL_ALPHA || header.glBaseInternalFormat == GL_LUMINANCE || header.glBaseInternalFormat == GL_LUMINANCE_ALPHA || header.glBaseInternalFormat == GL_INTENSITY))) { glInternalFormat = header.glBaseInternalFormat; } #endif } for (level = 0; level < header.numberOfMipmapLevels; ++level) { GLsizei pixelWidth = MAX(1, header.pixelWidth >> level); GLsizei pixelHeight = MAX(1, header.pixelHeight >> level); GLsizei pixelDepth = MAX(1, header.pixelDepth >> level); if (!stream->read(&faceLodSize, sizeof(khronos_uint32_t), stream->src)) { errorCode = KTX_UNEXPECTED_END_OF_FILE; goto cleanup; } if (header.endianness == KTX_ENDIAN_REF_REV) { _ktxSwapEndian32(&faceLodSize, 1); } faceLodSizeRounded = (faceLodSize + 3) & ~(khronos_uint32_t)3; if (!data) { /* allocate memory sufficient for the first level */ data = malloc(faceLodSizeRounded); if (!data) { errorCode = KTX_OUT_OF_MEMORY; goto cleanup; } dataSize = faceLodSizeRounded; } else if (dataSize < faceLodSizeRounded) { /* subsequent levels cannot be larger than the first level */ errorCode = KTX_INVALID_VALUE; goto cleanup; } for (face = 0; face < header.numberOfFaces; ++face) { if (!stream->read(data, faceLodSizeRounded, stream->src)) { errorCode = KTX_UNEXPECTED_END_OF_FILE; goto cleanup; } /* Perform endianness conversion on texture data */ if (header.endianness == KTX_ENDIAN_REF_REV && header.glTypeSize == 2) { _ktxSwapEndian16((khronos_uint16_t*)data, faceLodSize / 2); } else if (header.endianness == KTX_ENDIAN_REF_REV && header.glTypeSize == 4) { _ktxSwapEndian32((khronos_uint32_t*)data, faceLodSize / 4); } if (texinfo.textureDimensions == 1) { if (texinfo.compressed) { glCompressedTexImage1D(texinfo.glTarget + face, level, glInternalFormat, pixelWidth, 0, faceLodSize, data); } else { glTexImage1D(texinfo.glTarget + face, level, glInternalFormat, pixelWidth, 0, glFormat, header.glType, data); } } else if (texinfo.textureDimensions == 2) { if (header.numberOfArrayElements) { pixelHeight = header.numberOfArrayElements; } if (texinfo.compressed) { // It is simpler to just attempt to load the format, rather than divine which // formats are supported by the implementation. In the event of an error, // software unpacking can be attempted. glCompressedTexImage2D(texinfo.glTarget + face, level, glInternalFormat, pixelWidth, pixelHeight, 0, faceLodSize, data); } else { glTexImage2D(texinfo.glTarget + face, level, glInternalFormat, pixelWidth, pixelHeight, 0, glFormat, header.glType, data); } } else if (texinfo.textureDimensions == 3) { if (header.numberOfArrayElements) { pixelDepth = header.numberOfArrayElements; } if (texinfo.compressed) { glCompressedTexImage3D(texinfo.glTarget + face, level, glInternalFormat, pixelWidth, pixelHeight, pixelDepth, 0, faceLodSize, data); } else { glTexImage3D(texinfo.glTarget + face, level, glInternalFormat, pixelWidth, pixelHeight, pixelDepth, 0, glFormat, header.glType, data); } } errorTmp = glGetError(); #if SUPPORT_SOFTWARE_ETC_UNPACK // Renderion is returning INVALID_VALUE. Oops!! if ((errorTmp == GL_INVALID_ENUM || errorTmp == GL_INVALID_VALUE) && texinfo.compressed && texinfo.textureDimensions == 2 && (glInternalFormat == GL_ETC1_RGB8_OES || (glInternalFormat >= GL_COMPRESSED_R11_EAC && glInternalFormat <= GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC))) { GLubyte* unpacked; GLenum format, internalFormat, type; errorCode = _ktxUnpackETC((GLubyte*)data, glInternalFormat, pixelWidth, pixelHeight, &unpacked, &format, &internalFormat, &type, R16Formats, supportsSRGB); if (errorCode != KTX_SUCCESS) { goto cleanup; } if (!sizedFormats & _NON_LEGACY_FORMATS) { if (internalFormat == GL_RGB8) internalFormat = GL_RGB; else if (internalFormat == GL_RGBA8) internalFormat = GL_RGBA; } glTexImage2D(texinfo.glTarget + face, level, internalFormat, pixelWidth, pixelHeight, 0, format, type, unpacked); free(unpacked); errorTmp = glGetError(); } #endif if (errorTmp != GL_NO_ERROR) { if (pGlerror) *pGlerror = errorTmp; errorCode = KTX_GL_ERROR; goto cleanup; } } } cleanup: free(data); /* restore previous GL state */ if (previousUnpackAlignment != KTX_GL_UNPACK_ALIGNMENT) { glPixelStorei(GL_UNPACK_ALIGNMENT, previousUnpackAlignment); } if (errorCode == KTX_SUCCESS) { if (texinfo.generateMipmaps && glGenerateMipmap) { glGenerateMipmap(texinfo.glTarget); } *pTarget = texinfo.glTarget; if (pTexture) { *pTexture = texname; } if (pDimensions) { pDimensions->width = header.pixelWidth; pDimensions->height = header.pixelHeight; pDimensions->depth = header.pixelDepth; } if (pIsMipmapped) { if (texinfo.generateMipmaps || header.numberOfMipmapLevels > 1) *pIsMipmapped = GL_TRUE; else *pIsMipmapped = GL_FALSE; } } else { if (ppKvd && *ppKvd) { free(*ppKvd); *ppKvd = NULL; } if (!texnameUser) { glDeleteTextures(1, &texname); } } return errorCode; }
void OGLTexture1D::CreateHWResource(ElementInitData const * init_data) { uint32_t texel_size = NumFormatBytes(format_); GLint glinternalFormat; GLenum glformat; GLenum gltype; OGLMapping::MappingFormat(glinternalFormat, glformat, gltype, format_); if (sample_count_ <= 1) { glBindTexture(target_type_, texture_); glTexParameteri(target_type_, GL_TEXTURE_MAX_LEVEL, num_mip_maps_ - 1); OGLRenderEngine& re = *checked_cast<OGLRenderEngine*>(&Context::Instance().RenderFactoryInstance().RenderEngineInstance()); for (uint32_t array_index = 0; array_index < array_size_; ++ array_index) { for (uint32_t level = 0; level < num_mip_maps_; ++ level) { uint32_t const w = this->Width(level); re.BindBuffer(GL_PIXEL_UNPACK_BUFFER, pbos_[array_index * num_mip_maps_ + level]); if (IsCompressedFormat(format_)) { uint32_t const block_size = NumFormatBytes(format_) * 4; GLsizei const image_size = ((w + 3) / 4) * block_size; glBufferData(GL_PIXEL_UNPACK_BUFFER, image_size, nullptr, GL_STREAM_DRAW); re.BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); if (array_size_ > 1) { if (0 == array_index) { glCompressedTexImage2D(target_type_, level, glinternalFormat, w, array_size_, 0, image_size * array_size_, nullptr); } if (init_data != nullptr) { glCompressedTexSubImage2D(target_type_, level, 0, array_index, w, 1, glformat, image_size, init_data[array_index * num_mip_maps_ + level].data); } } else { glCompressedTexImage1D(target_type_, level, glinternalFormat, w, 0, image_size, (nullptr == init_data) ? nullptr : init_data[array_index * num_mip_maps_ + level].data); } } else { GLsizei const image_size = w * texel_size; glBufferData(GL_PIXEL_UNPACK_BUFFER, image_size, nullptr, GL_STREAM_DRAW); re.BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); if (array_size_ > 1) { if (0 == array_index) { glTexImage2D(target_type_, level, glinternalFormat, w, array_size_, 0, glformat, gltype, nullptr); } if (init_data != nullptr) { glTexSubImage2D(target_type_, level, 0, array_index, w, 1, glformat, gltype, init_data[array_index * num_mip_maps_ + level].data); } } else { glTexImage1D(target_type_, level, glinternalFormat, w, 0, glformat, gltype, (nullptr == init_data) ? nullptr : init_data[array_index * num_mip_maps_ + level].data); } } } } } else { glBindRenderbuffer(GL_RENDERBUFFER, texture_); glRenderbufferStorageMultisample(GL_RENDERBUFFER, sample_count_, glinternalFormat, width_, 1); } hw_res_ready_ = true; }
// Creation / loading methods void GL3PlusTexture::createInternalResourcesImpl(void) { // set HardwareBuffer::Usage for TU_RENDERTARGET if nothing else specified if((mUsage & TU_RENDERTARGET) && (mUsage & ~TU_RENDERTARGET) == 0) mUsage |= HardwareBuffer::HBU_DYNAMIC; // Adjust format if required. mFormat = TextureManager::getSingleton().getNativeFormat(mTextureType, mFormat, mUsage); // Check requested number of mipmaps. uint32 maxMips = getMaxMipmaps(); if (PixelUtil::isCompressed(mFormat) && (mNumMipmaps == 0)) mNumRequestedMipmaps = 0; mNumMipmaps = mNumRequestedMipmaps; if (mNumMipmaps > maxMips) mNumMipmaps = maxMips; // Create a texture object and identify its GL type. OGRE_CHECK_GL_ERROR(glGenTextures(1, &mTextureID)); GLenum texTarget = getGL3PlusTextureTarget(); // Calculate size for all mip levels of the texture. uint32 width, height, depth; if ((mWidth * PixelUtil::getNumElemBytes(mFormat)) & 3) { // Standard alignment of 4 is not right for some formats. OGRE_CHECK_GL_ERROR(glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); } // Bind texture object to its type, making it the active texture object // for that type. mRenderSystem->_getStateCacheManager()->bindGLTexture( texTarget, mTextureID ); mRenderSystem->_getStateCacheManager()->setTexParameteri(texTarget, GL_TEXTURE_BASE_LEVEL, 0); mRenderSystem->_getStateCacheManager()->setTexParameteri(texTarget, GL_TEXTURE_MAX_LEVEL, mNumMipmaps); // Set some misc default parameters, these can of course be changed later. mRenderSystem->_getStateCacheManager()->setTexParameteri(texTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); mRenderSystem->_getStateCacheManager()->setTexParameteri(texTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); mRenderSystem->_getStateCacheManager()->setTexParameteri(texTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); mRenderSystem->_getStateCacheManager()->setTexParameteri(texTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Set up texture swizzling. mRenderSystem->_getStateCacheManager()->setTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_R, GL_RED); mRenderSystem->_getStateCacheManager()->setTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_G, GL_GREEN); mRenderSystem->_getStateCacheManager()->setTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_B, GL_BLUE); mRenderSystem->_getStateCacheManager()->setTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_A, GL_ALPHA); if (PixelUtil::isLuminance(mFormat) && (mRenderSystem->hasMinGLVersion(3, 3) || mRenderSystem->checkExtension("GL_ARB_texture_swizzle"))) { if (PixelUtil::getComponentCount(mFormat) == 2) { mRenderSystem->_getStateCacheManager()->setTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_R, GL_RED); mRenderSystem->_getStateCacheManager()->setTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_G, GL_RED); mRenderSystem->_getStateCacheManager()->setTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_B, GL_RED); mRenderSystem->_getStateCacheManager()->setTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_A, GL_GREEN); } else { mRenderSystem->_getStateCacheManager()->setTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_R, GL_RED); mRenderSystem->_getStateCacheManager()->setTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_G, GL_RED); mRenderSystem->_getStateCacheManager()->setTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_B, GL_RED); mRenderSystem->_getStateCacheManager()->setTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_A, GL_ONE); } } GLenum format = GL3PlusPixelUtil::getGLInternalFormat(mFormat, mHwGamma); GLenum datatype = GL3PlusPixelUtil::getGLOriginDataType(mFormat); width = mWidth; height = mHeight; depth = mDepth; // Allocate texture storage so that glTexSubImageXD can be // used to upload the texture. if (PixelUtil::isCompressed(mFormat)) { // Compressed formats GLsizei size; for (uint32 mip = 0; mip <= mNumMipmaps; mip++) { size = static_cast<GLsizei>(PixelUtil::getMemorySize(width, height, depth, mFormat)); // std::stringstream str; // str << "GL3PlusTexture::create - " << StringConverter::toString(mTextureID) // << " bytes: " << StringConverter::toString(PixelUtil::getMemorySize(mWidth, mHeight, mDepth, mFormat)) // << " Mip: " + StringConverter::toString(mip) // << " Width: " << StringConverter::toString(width) // << " Height: " << StringConverter::toString(height) // << " Format " << PixelUtil::getFormatName(mFormat) // << " Internal Format: 0x" << std::hex << format // << " Origin Format: 0x" << std::hex << GL3PlusPixelUtil::getGLOriginFormat(mFormat) // << " Data type: 0x" << std::hex << datatype; // LogManager::getSingleton().logMessage(LML_NORMAL, str.str()); switch(mTextureType) { case TEX_TYPE_1D: OGRE_CHECK_GL_ERROR(glCompressedTexImage1D(GL_TEXTURE_1D, mip, format, width, 0, size, NULL)); break; case TEX_TYPE_2D: OGRE_CHECK_GL_ERROR(glCompressedTexImage2D(GL_TEXTURE_2D, mip, format, width, height, 0, size, NULL)); break; case TEX_TYPE_2D_RECT: OGRE_CHECK_GL_ERROR(glCompressedTexImage2D(GL_TEXTURE_RECTANGLE, mip, format, width, height, 0, size, NULL)); break; case TEX_TYPE_2D_ARRAY: case TEX_TYPE_3D: OGRE_CHECK_GL_ERROR(glCompressedTexImage3D(texTarget, mip, format, width, height, depth, 0, size, NULL)); break; case TEX_TYPE_CUBE_MAP: for(int face = 0; face < 6; face++) { OGRE_CHECK_GL_ERROR(glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, mip, format, width, height, 0, size, NULL)); } break; default: break; }; if (width > 1) { width = width / 2; } if (height > 1) { height = height / 2; } if (depth > 1 && mTextureType != TEX_TYPE_2D_ARRAY) { depth = depth / 2; } } } else { if (mRenderSystem->hasMinGLVersion(4, 2) || mRenderSystem->checkExtension("GL_ARB_texture_storage")) { switch(mTextureType) { case TEX_TYPE_1D: OGRE_CHECK_GL_ERROR(glTexStorage1D(GL_TEXTURE_1D, GLsizei(mNumMipmaps+1), format, GLsizei(width))); break; case TEX_TYPE_2D: case TEX_TYPE_2D_RECT: OGRE_CHECK_GL_ERROR(glTexStorage2D(GL_TEXTURE_2D, GLsizei(mNumMipmaps+1), format, GLsizei(width), GLsizei(height))); break; case TEX_TYPE_CUBE_MAP: OGRE_CHECK_GL_ERROR(glTexStorage2D(GL_TEXTURE_CUBE_MAP, GLsizei(mNumMipmaps+1), format, GLsizei(width), GLsizei(height))); break; case TEX_TYPE_2D_ARRAY: OGRE_CHECK_GL_ERROR(glTexStorage3D(GL_TEXTURE_2D_ARRAY, GLsizei(mNumMipmaps+1), format, GLsizei(width), GLsizei(height), GLsizei(depth))); break; case TEX_TYPE_3D: OGRE_CHECK_GL_ERROR(glTexStorage3D(GL_TEXTURE_3D, GLsizei(mNumMipmaps+1), format, GLsizei(width), GLsizei(height), GLsizei(depth))); break; } } else { GLenum originFormat = GL3PlusPixelUtil::getGLOriginFormat(mFormat); // Run through this process to pregenerate mipmap pyramid for(uint32 mip = 0; mip <= mNumMipmaps; mip++) { // std::stringstream str; // str << "GL3PlusTexture::create - " << StringConverter::toString(mTextureID) // << " bytes: " << StringConverter::toString(PixelUtil::getMemorySize(width, height, depth, mFormat)) // << " Mip: " + StringConverter::toString(mip) // << " Width: " << StringConverter::toString(width) // << " Height: " << StringConverter::toString(height) // << " Format " << PixelUtil::getFormatName(mFormat) // << " Internal Format: 0x" << std::hex << format // << " Origin Format: 0x" << std::hex << GL3PlusPixelUtil::getGLOriginFormat(mFormat) // << " Data type: 0x" << std::hex << datatype; // LogManager::getSingleton().logMessage(LML_NORMAL, str.str()); // Normal formats switch(mTextureType) { case TEX_TYPE_1D: OGRE_CHECK_GL_ERROR(glTexImage1D(GL_TEXTURE_1D, mip, format, width, 0, originFormat, datatype, NULL)); break; case TEX_TYPE_2D: OGRE_CHECK_GL_ERROR(glTexImage2D(GL_TEXTURE_2D, mip, format, width, height, 0, originFormat, datatype, NULL)); break; case TEX_TYPE_2D_RECT: OGRE_CHECK_GL_ERROR(glTexImage2D(GL_TEXTURE_RECTANGLE, mip, format, width, height, 0, originFormat, datatype, NULL)); break; case TEX_TYPE_3D: case TEX_TYPE_2D_ARRAY: OGRE_CHECK_GL_ERROR(glTexImage3D(texTarget, mip, format, width, height, depth, 0, originFormat, datatype, NULL)); break; case TEX_TYPE_CUBE_MAP: for(int face = 0; face < 6; face++) { OGRE_CHECK_GL_ERROR(glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, mip, format, width, height, 0, originFormat, datatype, NULL)); } break; default: break; }; if (width > 1) { width = width / 2; } if (height > 1) { height = height / 2; } if (depth > 1 && mTextureType != TEX_TYPE_2D_ARRAY) { depth = depth / 2; } } } } // Reset unpack alignment to defaults OGRE_CHECK_GL_ERROR(glPixelStorei(GL_UNPACK_ALIGNMENT, 4)); _createSurfaceList(); // Generate mipmaps after all texture levels have been loaded // This is required for compressed formats such as DXT if (PixelUtil::isCompressed(mFormat) && mUsage & TU_AUTOMIPMAP) { OGRE_CHECK_GL_ERROR(glGenerateMipmap(getGL3PlusTextureTarget())); } // Get final internal format. mFormat = getBuffer(0,0)->getFormat(); }
// Creation / loading methods void GL3PlusTexture::createInternalResourcesImpl(void) { // Adjust format if required mFormat = TextureManager::getSingleton().getNativeFormat(mTextureType, mFormat, mUsage); // Check requested number of mipmaps size_t maxMips = GL3PlusPixelUtil::getMaxMipmaps(mWidth, mHeight, mDepth, mFormat); if(PixelUtil::isCompressed(mFormat) && (mNumMipmaps == 0)) mNumRequestedMipmaps = 0; mNumMipmaps = mNumRequestedMipmaps; if (mNumMipmaps > maxMips) mNumMipmaps = maxMips; // Generate texture name OGRE_CHECK_GL_ERROR(glGenTextures(1, &mTextureID)); GLenum texTarget = getGL3PlusTextureTarget(); // Set texture type OGRE_CHECK_GL_ERROR(glBindTexture(texTarget, mTextureID)); OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_BASE_LEVEL, 0)); OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_MAX_LEVEL, (mMipmapsHardwareGenerated && (mUsage & TU_AUTOMIPMAP)) ? maxMips : mNumMipmaps )); // Set some misc default parameters, these can of course be changed later OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); // Set up texture swizzling if(mGLSupport.checkExtension("GL_ARB_texture_swizzle") || gl3wIsSupported(3, 3)) { OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_R, GL_RED)); OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_G, GL_GREEN)); OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_B, GL_BLUE)); OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_A, GL_ALPHA)); if(mFormat == PF_BYTE_LA) { OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_R, GL_RED)); OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_G, GL_RED)); OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_B, GL_RED)); OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_A, GL_GREEN)); } else if(mFormat == PF_L8 || mFormat == PF_L16) { OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_R, GL_RED)); OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_G, GL_RED)); OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_B, GL_RED)); OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_A, GL_RED)); } } // If we can do automip generation and the user desires this, do so mMipmapsHardwareGenerated = Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_AUTOMIPMAP); // Allocate internal buffer so that glTexSubImageXD can be used // Internal format GLenum format = GL3PlusPixelUtil::getClosestGLInternalFormat(mFormat, mHwGamma); GLenum datatype = GL3PlusPixelUtil::getGLOriginDataType(mFormat); size_t width = mWidth; size_t height = mHeight; size_t depth = mDepth; if (PixelUtil::isCompressed(mFormat)) { // Compressed formats size_t size = PixelUtil::getMemorySize(mWidth, mHeight, mDepth, mFormat); // Provide temporary buffer filled with zeroes as glCompressedTexImageXD does not // accept a 0 pointer like normal glTexImageXD // Run through this process for every mipmap to pregenerate mipmap pyramid uint8* tmpdata = new uint8[size]; memset(tmpdata, 0, size); for (size_t mip = 0; mip <= mNumMipmaps; mip++) { size = PixelUtil::getMemorySize(width, height, depth, mFormat); switch(mTextureType) { case TEX_TYPE_1D: OGRE_CHECK_GL_ERROR(glCompressedTexImage1D(GL_TEXTURE_1D, mip, format, width, 0, size, tmpdata)); break; case TEX_TYPE_2D: OGRE_CHECK_GL_ERROR(glCompressedTexImage2D(GL_TEXTURE_2D, mip, format, width, height, 0, size, tmpdata)); break; case TEX_TYPE_2D_RECT: OGRE_CHECK_GL_ERROR(glCompressedTexImage2D(GL_TEXTURE_RECTANGLE, mip, format, width, height, 0, size, tmpdata)); break; case TEX_TYPE_2D_ARRAY: case TEX_TYPE_3D: OGRE_CHECK_GL_ERROR(glCompressedTexImage3D(texTarget, mip, format, width, height, depth, 0, size, tmpdata)); break; case TEX_TYPE_CUBE_MAP: for(int face = 0; face < 6; face++) { OGRE_CHECK_GL_ERROR(glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, mip, format, width, height, 0, size, tmpdata)); } break; default: break; }; // LogManager::getSingleton().logMessage("GL3PlusTexture::create - " + StringConverter::toString(mTextureID) + // " Mip: " + StringConverter::toString(mip) + // " Width: " + StringConverter::toString(width) + // " Height: " + StringConverter::toString(height) + // " Internal Format: " + StringConverter::toString(format) // ); if(width > 1) { width = width / 2; } if(height > 1) { height = height / 2; } if(depth > 1) { depth = depth / 2; } } delete [] tmpdata; } else { if((mGLSupport.checkExtension("GL_ARB_texture_storage") || gl3wIsSupported(4, 2)) && mTextureType == TEX_TYPE_2D) { OGRE_CHECK_GL_ERROR(glTexStorage2D(GL_TEXTURE_2D, GLint(mNumMipmaps+1), format, GLsizei(width), GLsizei(height))); } else { // Run through this process to pregenerate mipmap pyramid for(size_t mip = 0; mip <= mNumMipmaps; mip++) { // Normal formats switch(mTextureType) { case TEX_TYPE_1D: OGRE_CHECK_GL_ERROR(glTexImage1D(GL_TEXTURE_1D, mip, format, width, 0, GL_RGBA, datatype, 0)); break; case TEX_TYPE_2D: OGRE_CHECK_GL_ERROR(glTexImage2D(GL_TEXTURE_2D, mip, format, width, height, 0, GL3PlusPixelUtil::getGLOriginFormat(mFormat), datatype, 0)); break; case TEX_TYPE_2D_RECT: OGRE_CHECK_GL_ERROR(glTexImage2D(GL_TEXTURE_RECTANGLE, mip, format, width, height, 0, GL3PlusPixelUtil::getGLOriginFormat(mFormat), datatype, 0)); break; case TEX_TYPE_3D: case TEX_TYPE_2D_ARRAY: OGRE_CHECK_GL_ERROR(glTexImage3D(texTarget, mip, format, width, height, depth, 0, GL_RGBA, datatype, 0)); break; case TEX_TYPE_CUBE_MAP: for(int face = 0; face < 6; face++) { OGRE_CHECK_GL_ERROR(glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, mip, format, width, height, 0, GL3PlusPixelUtil::getGLOriginFormat(mFormat), datatype, 0)); } break; default: break; }; if (width > 1) { width = width / 2; } if (height > 1) { height = height / 2; } if (depth > 1) { depth = depth / 2; } } } } _createSurfaceList(); // Get final internal format mFormat = getBuffer(0,0)->getFormat(); }
JNIEXPORT void JNICALL Java_org_lwjgl_opengl_GL13_nglCompressedTexImage1D(JNIEnv *__env, jclass clazz, jint target, jint level, jint internalformat, jint width, jint border, jint imageSize, jlong dataAddress, jlong __functionAddress) { const GLvoid *data = (const GLvoid *)(intptr_t)dataAddress; glCompressedTexImage1DPROC glCompressedTexImage1D = (glCompressedTexImage1DPROC)(intptr_t)__functionAddress; UNUSED_PARAMS(__env, clazz) glCompressedTexImage1D(target, level, internalformat, width, border, imageSize, data); }
void gl4es_glCompressedMultiTexImage1D(GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data) { text(glCompressedTexImage1D(target, level, internalformat, width, border, imageSize, data)); }
void OGLTexture1D::CreateHWResource(ArrayRef<ElementInitData> init_data, float4 const * clear_value_hint) { KFL_UNUSED(clear_value_hint); GLint glinternalFormat; GLenum glformat; GLenum gltype; OGLMapping::MappingFormat(glinternalFormat, glformat, gltype, format_); if (sample_count_ <= 1) { uint32_t const pbo_size = mipmap_start_offset_.back() * array_size_; if (glloader_GL_VERSION_4_5() || glloader_GL_ARB_direct_state_access()) { glTextureParameteri(texture_, GL_TEXTURE_MAX_LEVEL, num_mip_maps_ - 1); glNamedBufferStorage(pbo_, pbo_size, nullptr, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_DYNAMIC_STORAGE_BIT); uint32_t const w0 = this->Width(0); if (array_size_ > 1) { glTextureStorage2D(texture_, num_mip_maps_, glinternalFormat, w0, array_size_); } else { glTextureStorage1D(texture_, num_mip_maps_, glinternalFormat, w0); } if (!init_data.empty()) { for (uint32_t array_index = 0; array_index < array_size_; ++ array_index) { for (uint32_t level = 0; level < num_mip_maps_; ++ level) { uint32_t const w = this->Width(level); GLvoid const * data = init_data[array_index * num_mip_maps_ + level].data; if (IsCompressedFormat(format_)) { uint32_t const block_size = NumFormatBytes(format_) * 4; GLsizei const image_size = ((w + 3) / 4) * block_size; if (array_size_ > 1) { glCompressedTextureSubImage2D(texture_, level, 0, array_index, w, 1, glformat, image_size, data); } else { glCompressedTextureSubImage1D(texture_, level, 0, w, glformat, image_size, data); } } else { if (array_size_ > 1) { glTextureSubImage2D(texture_, level, 0, array_index, w, 1, glformat, gltype, data); } else { glTextureSubImage1D(texture_, level, 0, w, glformat, gltype, data); } } } } } } else { auto& re = *checked_cast<OGLRenderEngine*>(&Context::Instance().RenderFactoryInstance().RenderEngineInstance()); re.BindTexture(0, target_type_, texture_); glTexParameteri(target_type_, GL_TEXTURE_MAX_LEVEL, num_mip_maps_ - 1); re.BindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_); if (glloader_GL_VERSION_4_4() || glloader_GL_ARB_buffer_storage()) { glBufferStorage(GL_PIXEL_UNPACK_BUFFER, pbo_size, nullptr, GL_DYNAMIC_STORAGE_BIT); } else { glBufferData(GL_PIXEL_UNPACK_BUFFER, pbo_size, nullptr, GL_STREAM_COPY); } re.BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); if (glloader_GL_VERSION_4_2() || glloader_GL_ARB_texture_storage()) { uint32_t const w0 = this->Width(0); if (array_size_ > 1) { glTexStorage2D(target_type_, num_mip_maps_, glinternalFormat, w0, array_size_); } else { glTexStorage1D(target_type_, num_mip_maps_, glinternalFormat, w0); } if (!init_data.empty()) { for (uint32_t array_index = 0; array_index < array_size_; ++ array_index) { for (uint32_t level = 0; level < num_mip_maps_; ++ level) { uint32_t const w = this->Width(level); GLvoid const * data = init_data[array_index * num_mip_maps_ + level].data; if (IsCompressedFormat(format_)) { uint32_t const block_size = NumFormatBytes(format_) * 4; GLsizei const image_size = ((w + 3) / 4) * block_size; if (array_size_ > 1) { glCompressedTexSubImage2D(target_type_, level, 0, array_index, w, 1, glformat, image_size, data); } else { glCompressedTexSubImage1D(target_type_, level, 0, w, glformat, image_size, data); } } else { if (array_size_ > 1) { glTexSubImage2D(target_type_, level, 0, array_index, w, 1, glformat, gltype, data); } else { glTexSubImage1D(target_type_, level, 0, w, glformat, gltype, data); } } } } } } else { for (uint32_t array_index = 0; array_index < array_size_; ++ array_index) { for (uint32_t level = 0; level < num_mip_maps_; ++ level) { uint32_t const w = this->Width(level); if (IsCompressedFormat(format_)) { uint32_t const block_size = NumFormatBytes(format_) * 4; GLsizei const image_size = ((w + 3) / 4) * block_size; if (array_size_ > 1) { if (0 == array_index) { glCompressedTexImage2D(target_type_, level, glinternalFormat, w, array_size_, 0, image_size * array_size_, nullptr); } if (!init_data.empty()) { glCompressedTexSubImage2D(target_type_, level, 0, array_index, w, 1, glformat, image_size, init_data[array_index * num_mip_maps_ + level].data); } } else { glCompressedTexImage1D(target_type_, level, glinternalFormat, w, 0, image_size, init_data.empty() ? nullptr : init_data[array_index * num_mip_maps_ + level].data); } } else { if (array_size_ > 1) { if (0 == array_index) { glTexImage2D(target_type_, level, glinternalFormat, w, array_size_, 0, glformat, gltype, nullptr); } if (!init_data.empty()) { glTexSubImage2D(target_type_, level, 0, array_index, w, 1, glformat, gltype, init_data[array_index * num_mip_maps_ + level].data); } } else { glTexImage1D(target_type_, level, glinternalFormat, w, 0, glformat, gltype, init_data.empty() ? nullptr : init_data[array_index * num_mip_maps_ + level].data); } } } } } } } else { glBindRenderbuffer(GL_RENDERBUFFER, texture_); glRenderbufferStorageMultisample(GL_RENDERBUFFER, sample_count_, glinternalFormat, width_, 1); } hw_res_ready_ = true; }
bool Texture :: load1D ( const char * fileName ) { TexImage * image = loadTexImage ( fileName ); if ( image == NULL ) return false; if ( image -> getImageType () != TexImage :: image2D || image -> getHeight () != 1 ) { delete image; return false; } setParamsFromTexImage ( image, GL_TEXTURE_1D ); glGenTextures ( 1, &id ); glBindTexture ( target, id ); glPixelStorei ( GL_UNPACK_ALIGNMENT, 1 ); // set 1-byte alignment glTexParameteri ( target, GL_TEXTURE_WRAP_S, GL_REPEAT ); // set default params for texture if ( !image -> isCompressed () ) // not compressed image { glTexImage1D ( target, 0, getFormat ().getInternalFormat (), width, 0, getFormat ().getFormat (), image -> getGlType (), image -> imageData () ); if ( autoMipmaps ) glGenerateMipmap ( target ); } else { int mipmaps = image -> getNumLevels (); int w = width; int h = height; byte * ptr = image -> imageData ( 0, 0 ); glTexParameteri ( target, GL_TEXTURE_MAX_LEVEL, mipmaps - 1 ); for ( int i = 0; i < mipmaps; i++ ) { int size = image -> imageDataSize ( 0, i ); glCompressedTexImage1D ( target, i, getFormat ().getInternalFormat (), w, 0, size, ptr ); if ( ( w = w / 2 ) < 1 ) w = 1; if ( ( h = h / 2 ) < 1 ) h = 1; ptr += size; } } if ( autoMipmaps ) { glTexParameteri ( target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); glTexParameteri ( target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); } else { glTexParameteri ( target, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri ( target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); } glBindTexture ( target, 0 ); delete image; return true; }