//============================================================================== static ANKI_USE_RESULT Error loadUncompressedTga( File& fs, U32& width, U32& height, U32& bpp, DArray<U8>& data, GenericMemoryPoolAllocator<U8>& alloc) { Array<U8, 6> header6; // read the info from header ANKI_CHECK(fs.read((char*)&header6[0], sizeof(header6))); width = header6[1] * 256 + header6[0]; height = header6[3] * 256 + header6[2]; bpp = header6[4]; if((width == 0) || (height == 0) || ((bpp != 24) && (bpp != 32))) { ANKI_LOGE("Invalid image information"); return ErrorCode::USER_DATA; } // read the data I bytesPerPxl = (bpp / 8); I imageSize = bytesPerPxl * width * height; data.create(alloc, imageSize); ANKI_CHECK(fs.read(reinterpret_cast<char*>(&data[0]), imageSize)); // swap red with blue for(I i = 0; i < imageSize; i += bytesPerPxl) { U32 temp = data[i]; data[i] = data[i + 2]; data[i + 2] = temp; } return ErrorCode::NONE; }
//============================================================================== static ANKI_USE_RESULT Error loadCompressedTga( File& fs, U32& width, U32& height, U32& bpp, DArray<U8>& data, GenericMemoryPoolAllocator<U8>& alloc) { Array<U8, 6> header6; ANKI_CHECK(fs.read(reinterpret_cast<char*>(&header6[0]), sizeof(header6))); width = header6[1] * 256 + header6[0]; height = header6[3] * 256 + header6[2]; bpp = header6[4]; if((width <= 0) || (height <= 0) || ((bpp != 24) && (bpp != 32))) { ANKI_LOGE("Invalid texture information"); return ErrorCode::USER_DATA; } I bytesPerPxl = (bpp / 8); I imageSize = bytesPerPxl * width * height; data.create(alloc, imageSize); U pixelcount = height * width; U currentpixel = 0; U currentbyte = 0; U8 colorbuffer[4]; do { U8 chunkheader = 0; ANKI_CHECK(fs.read((char*)&chunkheader, sizeof(U8))); if(chunkheader < 128) { chunkheader++; for(int counter = 0; counter < chunkheader; counter++) { ANKI_CHECK(fs.read((char*)&colorbuffer[0], bytesPerPxl)); data[currentbyte] = colorbuffer[2]; data[currentbyte + 1] = colorbuffer[1]; data[currentbyte + 2] = colorbuffer[0]; if(bytesPerPxl == 4) { data[currentbyte + 3] = colorbuffer[3]; } currentbyte += bytesPerPxl; currentpixel++; if(currentpixel > pixelcount) { ANKI_LOGE("Too many pixels read"); return ErrorCode::USER_DATA; } } } else { chunkheader -= 127; ANKI_CHECK(fs.read((char*)&colorbuffer[0], bytesPerPxl)); for(int counter = 0; counter < chunkheader; counter++) { data[currentbyte] = colorbuffer[2]; data[currentbyte + 1] = colorbuffer[1]; data[currentbyte + 2] = colorbuffer[0]; if(bytesPerPxl == 4) { data[currentbyte + 3] = colorbuffer[3]; } currentbyte += bytesPerPxl; currentpixel++; if(currentpixel > pixelcount) { ANKI_LOGE("Too many pixels read"); data.destroy(alloc); return ErrorCode::USER_DATA; } } } } while(currentpixel < pixelcount); return ErrorCode::NONE; }
//============================================================================== static ANKI_USE_RESULT Error loadAnkiTexture( const CString& filename, U32 maxTextureSize, ImageLoader::DataCompression& preferredCompression, DArray<ImageLoader::Surface>& surfaces, GenericMemoryPoolAllocator<U8>& alloc, U8& depth, U8& mipLevels, ImageLoader::TextureType& textureType, ImageLoader::ColorFormat& colorFormat) { File file; ANKI_CHECK(file.open(filename, File::OpenFlag::READ | File::OpenFlag::BINARY | File::OpenFlag::LITTLE_ENDIAN)); // // Read and check the header // AnkiTextureHeader header; ANKI_CHECK(file.read(&header, sizeof(AnkiTextureHeader))); if(std::memcmp(&header.m_magic[0], "ANKITEX1", 8) != 0) { ANKI_LOGE("Wrong magic word"); return ErrorCode::USER_DATA; } if(header.m_width == 0 || !isPowerOfTwo(header.m_width) || header.m_width > 4096 || header.m_height == 0 || !isPowerOfTwo(header.m_height) || header.m_height > 4096) { ANKI_LOGE("Incorrect width/height value"); return ErrorCode::USER_DATA; } if(header.m_depth < 1 || header.m_depth > 16) { ANKI_LOGE("Zero or too big depth"); return ErrorCode::USER_DATA; } if(header.m_type < ImageLoader::TextureType::_2D || header.m_type > ImageLoader::TextureType::_2D_ARRAY) { ANKI_LOGE("Incorrect header: texture type"); return ErrorCode::USER_DATA; } if(header.m_colorFormat < ImageLoader::ColorFormat::RGB8 || header.m_colorFormat > ImageLoader::ColorFormat::RGBA8) { ANKI_LOGE("Incorrect header: color format"); return ErrorCode::USER_DATA; } if((header.m_compressionFormats & preferredCompression) == ImageLoader::DataCompression::NONE) { ANKI_LOGI("File does not contain the requested compression"); // Fallback preferredCompression = ImageLoader::DataCompression::RAW; if((header.m_compressionFormats & preferredCompression) == ImageLoader::DataCompression::NONE) { ANKI_LOGI("File does not contain raw compression"); return ErrorCode::USER_DATA; } } if(header.m_normal != 0 && header.m_normal != 1) { ANKI_LOGE("Incorrect header: normal"); return ErrorCode::USER_DATA; } // Check mip levels U size = min(header.m_width, header.m_height); U maxsize = max(header.m_width, header.m_height); mipLevels = 0; U tmpMipLevels = 0; while(size >= 4) // The minimum size is 4x4 { ++tmpMipLevels; if(maxsize <= maxTextureSize) { ++mipLevels; } size /= 2; maxsize /= 2; } if(header.m_mipLevels > tmpMipLevels) { ANKI_LOGE("Incorrect number of mip levels"); return ErrorCode::USER_DATA; } mipLevels = min<U>(mipLevels, header.m_mipLevels); colorFormat = header.m_colorFormat; switch(header.m_type) { case ImageLoader::TextureType::_2D: depth = 1; break; case ImageLoader::TextureType::CUBE: depth = 6; break; case ImageLoader::TextureType::_3D: case ImageLoader::TextureType::_2D_ARRAY: depth = header.m_depth; break; default: ANKI_ASSERT(0); } textureType = header.m_type; // // Move file pointer // if(preferredCompression == ImageLoader::DataCompression::RAW) { // Do nothing } else if(preferredCompression == ImageLoader::DataCompression::S3TC) { if((header.m_compressionFormats & ImageLoader::DataCompression::RAW) != ImageLoader::DataCompression::NONE) { // If raw compression is present then skip it ANKI_CHECK(file.seek( calcSizeOfSegment(header, ImageLoader::DataCompression::RAW), File::SeekOrigin::CURRENT)); } } else if(preferredCompression == ImageLoader::DataCompression::ETC) { if((header.m_compressionFormats & ImageLoader::DataCompression::RAW) != ImageLoader::DataCompression::NONE) { // If raw compression is present then skip it ANKI_CHECK(file.seek( calcSizeOfSegment(header, ImageLoader::DataCompression::RAW), File::SeekOrigin::CURRENT)); } if((header.m_compressionFormats & ImageLoader::DataCompression::S3TC) != ImageLoader::DataCompression::NONE) { // If s3tc compression is present then skip it ANKI_CHECK(file.seek( calcSizeOfSegment(header, ImageLoader::DataCompression::S3TC), File::SeekOrigin::CURRENT)); } } // // It's time to read // // Allocate the surfaces surfaces.create(alloc, mipLevels * depth); // Read all surfaces U mipWidth = header.m_width; U mipHeight = header.m_height; U index = 0; for(U mip = 0; mip < header.m_mipLevels; mip++) { for(U d = 0; d < depth; d++) { U dataSize = calcSurfaceSize( mipWidth, mipHeight, preferredCompression, header.m_colorFormat); // Check if this mipmap can be skipped because of size if(max(mipWidth, mipHeight) <= maxTextureSize) { ImageLoader::Surface& surf = surfaces[index++]; surf.m_width = mipWidth; surf.m_height = mipHeight; surf.m_data.create(alloc, dataSize); ANKI_CHECK(file.read(&surf.m_data[0], dataSize)); } else { ANKI_CHECK(file.seek(dataSize, File::SeekOrigin::CURRENT)); } } mipWidth /= 2; mipHeight /= 2; } return ErrorCode::NONE; }