void PhysicsSim::addTerrain(stringw heightfield_file, stringw texture_file, Vector3D scale) { stringw filename = mediaDirectory + heightfield_file; stringw texfilename = mediaDirectory + texture_file; IImage* hfimg = driver->createImageFromFile (filename.c_str()); int img_width = hfimg->getDimension().Width; int img_height = hfimg->getDimension().Height; float xScale = scale.X, yScale = scale.Y, zScale = scale.Z; ITerrainSceneNode* terrain = smgr->addTerrainSceneNode( filename.c_str(), smgr->getRootSceneNode(), // parent node -1, // node id vector3df(0.f, 0.f, 0.f), // position vector3df(0.f, 0.f, 0.f), // rotation vector3df(1.f, 1.0f, 1.f), // scale video::SColor ( 255, 255, 255, 255 ), // vertexColor 5, // maxLOD ETPS_17, // patchSize 4 // smoothFactor ); terrain->setMaterialTexture(0, driver->getTexture(texfilename.c_str())); terrain->scaleTexture(200.0f, 0); terrain->setScale(vector3df(xScale, yScale, zScale)); terrain->setPosition(vector3df(-((img_width-1.0)*xScale)/2.0, 0.0, -((img_height-1.0)*zScale)/2.0)); this->terrain = new Terrain(terrain, hfimg, Vector3D(xScale, yScale, zScale)); dynamicsWorld->addRigidBody(this->terrain->getRigidBody()); }
IImage* createRainbowImage( u32 w, u32 h, u8 transparency, f64 gamma) { // create image core::dimension2du size(w,h); IImage* img = (IImage*)new CImage(ECF_A8R8G8B8, size); if (!img) return 0; size = img->getDimension(); // loop pixels per col for (u32 y=0; y<size.Height; y++) { // calculate rainbow-color SColor c = createRainbowColor( y, size.Height, gamma); // set transparency c.setAlpha(transparency); // write one row with same color for (u32 x=0; x<size.Width; x++) { // write rainbow-color img->setPixel(x,y,c,false); } } return img; }
void RenderTarget::getImageData(floatv &data) { IImage* img = driver->createImage(target, position2d<s32>(0,0), target->getSize()); uint y = img->getDimension().Height; uint x = img->getDimension().Width; for(uint i = 0; i < y; i++) { for(uint j = 0; j < x; j++) { SColor color = img->getPixel(j,i); data.push_back((float)(color.getRed()/255.0)); data.push_back((float)(color.getGreen()/255.0)); data.push_back((float)(color.getBlue()/255.0)); } } img->drop(); //delete img; }
//--------------------------------------------------------------------------------------- //Converte uma textura para o tamanho da tela, partindo do que seria 800x600 video::ITexture* Interface::LeTexturaConvertida(const c8 *filename) { IImage *temp = central->Device()->getVideoDriver()->createImageFromFile(filename); if (temp == NULL) return NULL; //deu pau core::dimension2di tamanhoOriginal = temp->getDimension(); //calculo qual deveria ser o tamanho core::dimension2di novoTamanho(ConverteX(tamanhoOriginal.Width), ConverteY(tamanhoOriginal.Height)); ITexture* buf = central->Device()->getVideoDriver()->addTexture(novoTamanho, "Texture"); IImage *nova = central->Device()->getVideoDriver()->createImageFromData(temp->getColorFormat(), novoTamanho, buf->lock()); buf->unlock(); temp->copyToScaling(nova); ITexture *retorno = central->Device()->getVideoDriver()->addTexture(filename, nova); nova->drop(); //free(buffer); return retorno; }
void drawCircle( IImage* dst, const core::position2di& center, s32 radius, const SColor& color, s32 border, bool blend) { if (!dst) return; if ( radius < 0 ) return; else if ( radius == 0 ) { drawPixel( dst, center.X, center.Y, color, blend); } else if (radius == 1) { if (border==0) { drawPixel( dst, center.X,center.Y,color,blend); } drawPixel( dst, center.X-1,center.Y,color,blend); drawPixel( dst, center.X,center.Y-1,color,blend); drawPixel( dst, center.X,center.Y+1,color,blend); drawPixel( dst, center.X+1,center.Y,color,blend); } else if (radius == 2) { if (border==0) { drawPixel( dst, center.X-1,center.Y+1,color,blend); drawPixel( dst, center.X-1,center.Y,color,blend); drawPixel( dst, center.X,center.Y+1,color,blend); drawPixel( dst, center.X,center.Y,color,blend); } drawPixel( dst, center.X-2,center.Y+1,color,blend); drawPixel( dst, center.X-2,center.Y, color,blend); drawPixel( dst, center.X-1,center.Y+2,color,blend); drawPixel( dst, center.X-1,center.Y-1,color,blend); drawPixel( dst, center.X, center.Y+2,color,blend); drawPixel( dst, center.X, center.Y-1,color,blend); drawPixel( dst, center.X+1,center.Y+1,color,blend); drawPixel( dst, center.X+1,center.Y, color,blend); } else { // 'Bresenham' Algorithmus (Achtelkreis Symmetrie) // ohne Trigonometrische- und Wurzel-Funktionen // und Spiegelung auf Restliche 7/8 if (border==0) // filled { s32 i,j,F; i = 0; j = radius; F = 1 - radius; while (i < j) { ++i; if (F < 0) { F += (i<<1) - 1; } else { F += ((i - j)<<1); --j; } // Verbesserungen by Benjamin Hampe (c) 2012 drawLine( dst, center.X-i, center.Y+j-1, center.X+i-1,center.Y+j-1, color, blend ); drawLine( dst, center.X-j, center.Y+i-1, center.X+j-1,center.Y+i-1, color, blend ); drawLine( dst, center.X-j, center.Y-i, center.X+j-1, center.Y-i, color, blend ); drawLine( dst, center.X-i, center.Y-j, center.X+i-1, center.Y-j, color, blend ); } } // 'Bresenham' Algorithmus (Achtelkreis Symmetrie) // ohne Trigonometrische- und Wurzel-Funktionen // und Spiegelung auf Restliche 7/8 else if (border == 1) { s32 i,j,F; i = 0; j = radius; F = 1 - radius; while (i < j) { ++i; if (F < 0) { F += (i<<1) - 1; } else { F += ((i - j)<<1); --j; } // Verbesserungen by Benjamin Hampe (c) 2012 drawPixel( dst, center.X+i-1,center.Y-j,color, blend); // 1st quadrant drawPixel( dst, center.X+j-1,center.Y-i,color, blend); // 1st quadrant drawPixel( dst, center.X+i-1,center.Y+j-1,color, blend); // 2nd quadrant drawPixel( dst, center.X+j-1,center.Y+i-1,color, blend); // 2nd quadrant drawPixel( dst, center.X-i,center.Y+j-1,color, blend); // 3rd quadrant drawPixel( dst, center.X-j,center.Y+i-1,color, blend); // 3rd quadrant drawPixel( dst, center.X-i,center.Y-j,color, blend); // 4th quadrant drawPixel( dst, center.X-j,center.Y-i,color, blend); // 4th quadrant } } // by Benjamin Hampe // create circle from undistorted temporary image else if (border > 1) { if (radius - border > 1) { IImage* tmp = new CImage( dst->getColorFormat(), core::dimension2du( radius<<1, radius<<1) ); if (!tmp) return; // tmp->enableColorKey(); tmp->fill( 0 ); drawCircle( tmp, core::position2di(radius,radius), radius, color, 0, blend); drawCircle( tmp, core::position2di(radius,radius), radius - border, 0, 0, blend); drawImage( tmp, dst, center - core::position2di(radius,radius), tmp->getDimension(), true, false); tmp->drop(); } } } }
//! copies the the texture into an open gl texture. void COpenGLTexture::uploadTexture(bool newTexture, void* mipmapData, u32 level) { // check which image needs to be uploaded IImage* image = level ? MipImage : Image; IRR_ASSERT(image); // get correct opengl color data values GLenum oldInternalFormat = InternalFormat; GLint filtering; InternalFormat = getOpenGLFormatAndParametersFromColorFormat( ColorFormat, filtering, PixelFormat, PixelType); // make sure we don't change the internal format of existing images if (!newTexture) InternalFormat = oldInternalFormat; static_cast<COpenGLDriver *>(Driver)->setActiveTexture(0, this); IRR_ASSERT(!Driver->haveError()); // mipmap handling for main texture if (!level && newTexture) { #ifndef DISABLE_MIPMAPPING #ifdef GL_SGIS_generate_mipmap // auto generate if possible and no mipmap data is given if (HasMipMaps && !mipmapData //FIXME //&& Driver->queryFeature(EVDF_MIP_MAP_AUTO_UPDATE) ) { // if (Driver->getTextureCreationFlag( // ETCF_OPTIMIZED_FOR_SPEED)) // glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_FASTEST); // else if (Driver->getTextureCreationFlag( // ETCF_OPTIMIZED_FOR_QUALITY)) // glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST); // else glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_DONT_CARE); // automatically generate and update mipmaps glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); //FIXME // AutomaticMipmapUpdate=true; } else #endif { // Either generate manually due to missing capability // or use predefined mipmap data // AutomaticMipmapUpdate = false; // regenerateMipMapLevels(mipmapData); } //FIXME: refactor it if (false) // if (HasMipMaps) // might have changed in regenerateMipMapLevels { // enable bilinear mipmap filter glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } else #else //Did not create OpenGL texture mip maps. HasMipMaps=false; #endif { // enable bilinear filter without mipmaps glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } } // now get image data and upload to GPU void* source = image->lock(); if (newTexture) { glTexImage2D(GL_TEXTURE_2D, level, InternalFormat, image->getDimension().Width, image->getDimension().Height, 0, PixelFormat, PixelType, source); } else { glTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, image->getDimension().Width, image->getDimension().Height, PixelFormat, PixelType, source); } image->unlock(); IRR_ASSERT(!Driver->haveError()); }
IImage* CImageLoaderWAL::loadImage(irr::io::IReadFile* file) const { // Try to get the color palette from elsewhere (usually in a pak along with the WAL). // If this fails we use the DefaultPaletteQ2. static s32 * palette = 0; #if TRY_LOADING_PALETTE_FROM_FILE s32 loadedPalette[256]; #endif if (!palette) { #if TRY_LOADING_PALETTE_FROM_FILE IImage * paletteImage; // Look in a couple different places... paletteImage = createImageFromFile("pics/colormap.pcx"); if (!paletteImage) paletteImage = createImageFromFile("pics/colormap.tga"); if (!paletteImage) paletteImage = createImageFromFile("colormap.pcx"); if (!paletteImage) paletteImage = createImageFromFile("colormap.tga"); if (paletteImage && (paletteImage->getDimension().Width == 256) ) { palette = &loadedPalette; for (u32 i = 0; i < 256; ++i) { palette[i] = paletteImage->getPixel(i, 0).color; } } else { //FIXME: try reading a simple palette from "wal.pal" palette = DefaultPaletteQ2; } if (paletteImage) paletteImage->drop(); #endif } else { palette = DefaultPaletteQ2; } SWALHeader header; file->seek(0); if (file->read(&header, sizeof(SWALHeader)) != sizeof(SWALHeader) ) return 0; if (file->getSize() < header.MipmapOffset[0]) return 0; file->seek(header.MipmapOffset[0]); // read image const u32 imageSize = header.ImageHeight * header.ImageWidth; if (file->getSize() < (long)(imageSize + header.MipmapOffset[0])) return 0; u8* data = new u8[imageSize]; file->read(data, imageSize); IImage* image = 0; image = new CImage(ECF_A1R5G5B5, core::dimension2d<u32>(header.ImageWidth, header.ImageHeight)); // I wrote an 8 to 32 converter, but this works with released Irrlicht code. CColorConverter::convert8BitTo16Bit(data, (s16*)image->lock(), header.ImageWidth, header.ImageHeight, palette); image->unlock(); delete [] data; return image; }
//! @brief render big software image of any size using either screen to render or offscreen texture ( can flicker ) bool renderToImage( IrrlichtDevice* device, IImage* dst, s32 nSamples, const SColor& clearColor, bool renderGUI, bool debugLog) { // print call params if (debugLog) printf( "renderToImage( nSamples=%i, clearColor(%i,%i,%i,%i)\n", nSamples, clearColor.getAlpha(), clearColor.getRed(), clearColor.getGreen(), clearColor.getBlue() ); // abort if (!device) { printf("No Irrlicht-Device found.\n"); return false; } // abort if (!dst) { printf("No destination image found.\n"); return false; } // local pointers IVideoDriver* driver = device->getVideoDriver(); gui::IGUIEnvironment* guienv = device->getGUIEnvironment(); scene::ISceneManager* smgr = device->getSceneManager(); scene::ICameraSceneNode* camera = smgr->getActiveCamera(); // abort if (!camera) { printf("No active camera found.\n"); return false; } //! decompose camera's projection-matrix in d3d semantics core::matrix4 projMat = camera->getProjectionMatrix(); bool IsOrthogonal = true; if ( core::equals( projMat(3,3), 0.f ) ) IsOrthogonal = false; if ( !core::equals( projMat(2,3), 0.f ) ) IsOrthogonal = false; f32 Left; f32 Right; f32 Bottom; f32 Top; f32 Near; f32 Far; if (IsOrthogonal) { Near = -projMat(3,2)/projMat(2,2); Far = -(projMat(3,2)-1.f)/projMat(2,2); Left = -(projMat(3,0)+1.f)/projMat(0,0); Right = -(projMat(3,0)-1.f)/projMat(0,0); Top = -(projMat(3,1)-1.f)/projMat(1,1); Bottom = -(projMat(3,1)+1.f)/projMat(1,1); } else { Near = -projMat(3,2)/projMat(2,2); Far = -projMat(3,2)/(projMat(2,2)-1.f); Left = -Near*(projMat(2,0)+1.f)/projMat(0,0); Right = -Near*(projMat(2,0)-1.f)/projMat(0,0); Top = -Near*(projMat(2,1)-1.f)/projMat(1,1); Bottom = -Near*(projMat(2,1)+1.f)/projMat(1,1); } Near = camera->getNearValue(); // take the values directly from Camera Far = camera->getFarValue(); // due to f32 rounding errors //! ---------------------------------------------------------------------- //! calculate Border / get max thickness used by all registered materials //! ---------------------------------------------------------------------- s32 Border = 0; f32 thickness = 0.0f; const core::list<scene::ISceneNode*>& children = smgr->getRootSceneNode()->getChildren(); core::list<scene::ISceneNode*>::ConstIterator it = children.begin(); while (it != children.end()) { scene::ISceneNode* node = (*it); if (node) { u32 matCount = node->getMaterialCount(); for (u32 m = 0; m < matCount; ++m) { if (thickness < node->getMaterial(m).Thickness) thickness = node->getMaterial(m).Thickness; } } it++; } Border = core::ceil32( thickness ); //! ------------------------------------------------------------------------------------------ //! choose render-mode: offscreen or onscreen depending on AA, nSamples and RTT capabilities //! ------------------------------------------------------------------------------------------ //! @var nSamples - AntiAliasing depth > 1 make bigger rtts or downscale render-result by factor nSamples while having filter-methods enabled //! the framebuffer will always be downscaled by fast software bilinear filtering using colorkey/transparency to blend better into final image //! hardware-scaling: bilinear, trilinear or anisotropic texture-filtering available with irrlicht-engine //! software scaling: nearest, bilinear, bicubic downscaling available: //! bilinear has best compromise for downscaling ( there is much more information-loss due to resize than interpolation) //! default: 1 (<2) - no AA/downscaling done //! @var clearColor - argb32 color, the final image will filled with //! before writing into it and be used as colorkey for AA/software bilinear downscaling operation //! @var DoOffscreen - default=false, onscreen (framebuffer) //! false - onscreen-rendering using framebuffer/display. //! doublebuffer is possible, but will not prevent the showing of each rendered tile-texture //! true - offscreen-rendering using render-target-textures bool DoOffscreen = false; //! ---------------------------------------------------------------- //! collect video-driver infos //! ---------------------------------------------------------------- const core::dimension2du ScreenSize = driver->getScreenSize(); const ECOLOR_FORMAT ScreenFormat = driver->getColorFormat(); const u32 ScreenBits = IImage::getBitsPerPixelFromFormat( ScreenFormat ); const io::IAttributes& info = driver->getDriverAttributes(); const core::dimension2du MaxRTTSize = driver->getMaxTextureSize(); const u32 MaxAA = info.getAttributeAsInt( "AntiAlias" ); const u32 MaxAF = info.getAttributeAsInt( "MaxAnisotropy" ); const bool HasNPOT = driver->queryFeature( EVDF_TEXTURE_NPOT ); const bool HasNSQR = driver->queryFeature( EVDF_TEXTURE_NSQUARE ); const bool HasRTT = driver->queryFeature( EVDF_RENDER_TO_TARGET); const bool HasMTT = driver->queryFeature( EVDF_MULTITEXTURE); const bool HasMRT = driver->queryFeature( EVDF_MULTIPLE_RENDER_TARGETS); const bool HasATC = driver->queryFeature( EVDF_ALPHA_TO_COVERAGE); const bool HasBTF = driver->queryFeature( EVDF_BILINEAR_FILTER); const bool HasCMK = driver->queryFeature( EVDF_COLOR_MASK); const bool HasMMP = driver->queryFeature( EVDF_MIP_MAP); const bool HasMMA = driver->queryFeature( EVDF_MIP_MAP_AUTO_UPDATE); const bool HasOCC = driver->queryFeature( EVDF_OCCLUSION_QUERY); const bool HasPOF = driver->queryFeature( EVDF_POLYGON_OFFSET); if (debugLog) { printf("ScreenSize = %i x %i x %i\n", ScreenSize.Width, ScreenSize.Height, ScreenBits); printf("MaxRTTSize = %i x %i\n", MaxRTTSize.Width, MaxRTTSize.Height); printf("MaxAA = %i\n", MaxAA); printf("MaxAF = %i\n", MaxAF); printf("HasNPOT = %s\n", HasNPOT?"true":"false"); printf("HasNSQR = %s\n", HasNSQR?"true":"false"); printf("HasRTT = %s\n", HasRTT?"true":"false"); printf("HasMTT = %s\n", HasMTT?"true":"false"); printf("HasMRT = %s\n", HasMRT?"true":"false"); printf("HasATC = %s\n", HasATC?"true":"false"); printf("HasBTF = %s\n", HasBTF?"true":"false"); printf("HasCMK = %s\n", HasCMK?"true":"false"); printf("HasMMP = %s\n", HasMMP?"true":"false"); printf("HasMMA = %s\n", HasMMA?"true":"false"); printf("HasOCC = %s\n", HasOCC?"true":"false"); printf("HasPOF = %s\n", HasPOF?"true":"false"); } s32 RTTWidth = ScreenSize.Width; // equals the actual rtt size before down scaling factor nSamples AA and writing to final Image s32 RTTHeight = ScreenSize.Height; // the render-target is always a texture (offscreen) or the framebuffer (onscreen) s32 RTTWidthNB = RTTWidth - 2*Border; // the border equals the overlapping during rendering due to material-thickness > 0 s32 RTTHeightNB = RTTHeight - 2*Border; // the area that gets written to unique places, while the border regions can overlapp ( same pos, but writing/adding different image-content ) // so the position increment for the final writing is always RTTWidthNB or RTTHeightNB const s32 ImageWidth = (s32)dst->getDimension().Width; // width of the final image const s32 ImageHeight = (s32)dst->getDimension().Height; // height of the final image const ECOLOR_FORMAT ImageFormat = dst->getColorFormat(); // color-format of the final image, i.e. ECF_A8R8G8B8, ECF_R8G8B8, ECF_R16 for heightmaps ( bilinear, anisotropic ) const s32 CountX = core::ceil32( (f32)ImageWidth / (f32)RTTWidthNB ); const s32 CountY = core::ceil32( (f32)ImageHeight / (f32)RTTHeightNB ); //! ------------------------------------------------------------------------------------------ //! start render loop //! ------------------------------------------------------------------------------------------ s32 IndexX = 0; s32 IndexY = 0; s32 dstX = -Border; s32 dstY = -Border; for ( IndexY = 0; IndexY < CountY; ++IndexY) { // reset row dstX = -Border; for ( IndexX = 0; IndexX < CountX; ++IndexX) { const f32 fLeft = Left + (Right - Left) * (f32)( IndexX * RTTWidthNB - Border )/(f32)ImageWidth; const f32 fRight = fLeft + (Right - Left) * (f32)RTTWidth / (f32)ImageWidth; const f32 fTop = Top - (Top - Bottom) * (f32)( IndexY * RTTHeightNB - Border )/(f32)ImageHeight; const f32 fBottom = fTop - (Top - Bottom) * (f32)RTTHeight / (f32)ImageHeight; const f32 fNear = Near; const f32 fFar = Far; //! ------------------------------------------------------------------------------------------ //! build and set current projection-matrix //! ------------------------------------------------------------------------------------------ core::matrix4 tmpProj = core::IdentityMatrix; if (IsOrthogonal) { tmpProj(0,0) = 2.f / (fRight - fLeft); tmpProj(1,1) = 2.f / (fTop - fBottom); tmpProj(2,2) = 1.f / (fFar - fNear); tmpProj(3,3) = 1.f; tmpProj(3,0) = (fLeft + fRight) / (fLeft - fRight); tmpProj(3,1) = (fTop + fBottom) / (fBottom - fTop); tmpProj(3,2) = fNear / (fNear - fFar); } else { tmpProj(0,0) = 2.f*fNear / (fRight - fLeft); tmpProj(1,1) = 2.f*fNear / (fTop - fBottom); tmpProj(2,0) = (fLeft + fRight) / (fLeft - fRight); tmpProj(2,1) = (fTop + fBottom) / (fBottom - fTop); tmpProj(2,2) = fFar / (fFar - fNear); tmpProj(2,3) = 1.f; tmpProj(3,2) = fNear*fFar / (fNear - fFar); tmpProj(3,3) = 0.f; } camera->setProjectionMatrix(tmpProj); //! ------------------------------------------------------------------------------------------ //! now render all to current render-target //! ------------------------------------------------------------------------------------------ driver->beginScene( true, true, clearColor ); // SColor(255,200,200,255) smgr->drawAll(); if (renderGUI) guienv->drawAll(); driver->endScene(); //! ------------------------------------------------------------------------------------------ //! write current render-target to final image //! ------------------------------------------------------------------------------------------ IImage* src = driver->createScreenShot( ImageFormat, ERT_FRAME_BUFFER); if (src) { s32 x2 = src->getDimension().Width; s32 y2 = src->getDimension().Height; blitImageToImage( dst, core::position2di(dstX, dstY), src, core::recti(Border, Border, x2-Border, y2-Border), debugLog ); src->drop(); } dstX += RTTWidthNB; } dstY += RTTHeightNB; } //! ------------------------------------------------------------------------------------------ //! reset camera's projection-matrix //! ------------------------------------------------------------------------------------------ camera->setProjectionMatrix( projMat, IsOrthogonal); return true; }
bool CreatureSet::RegisterTextures(IVideoDriver* videoDriver, ResourceManager* resourceManager) { bool result = false; //STEP 1: Build an atlas index of all the images needed for textures from the backing file. LOGI("Initializing tile images from file %s", _resourceName.c_str()); ResourceBundle* spriteResourceBundle = resourceManager->GetResourceBundle( "Creatures"); //WARNING: Early returns here! I don't normally like this but the alternative is //huge if/else blocks. if (NULL == spriteResourceBundle) { LOGE("Could not find the 'Creatures' resource bundle in the resource manager."); return false; } if (NULL == videoDriver) { LOGE( "The video driver is null. Since this is needed for creating images this is unrecoverable."); return false; } //END WARNING IImage* image = videoDriver->createImageFromFile(spriteResourceBundle->Find( _resourceName)); int totalSpriteCountScope = 0; if (NULL == image) { LOGE("Unable to load image associated with map png file."); } else { LOGD("Image size is %d x %d", image->getDimension().Width, image->getDimension().Height); //Tiles are identified by an atlas index which tells the system which image in a tilesheet //numbered starting from 0 in the upper left corner and proceeding width first belongs //to a tile. map<int, IImage*> spriteAtlasImageIndexMap; int spritesPerRow = image->getDimension().Width / spriteWidth; int spritesPerColumn = image->getDimension().Height / spriteHeight; const int totalSpriteCount = spritesPerRow * spritesPerColumn; totalSpriteCountScope = totalSpriteCount; int atlasIndex = 0; position2d<s32> position(0, 0); //TODO: Round up to the nearest power of two per image dimension2d<u32> dimensions(64, 64); //Indices for the tilesheets increase breatdth first then depth. for (int y = 0; y < spritesPerColumn; y++) { for (int x = 0; x < spritesPerRow; x++) { IImage* imageTile = videoDriver->createImage(image->getColorFormat(), dimensions); imageTile->fill(image->getPixel(0, 0)); rect<s32> sourceRect(x * spriteWidth, y * spriteHeight, (x * spriteWidth) + spriteWidth, (y * spriteHeight) + spriteHeight); image->copyTo(imageTile, position, sourceRect); if (NULL != imageTile) { LOGD( "Image of sprite being associated with the atlasIndex %d is %d x %d", atlasIndex, imageTile->getDimension().Width, imageTile->getDimension().Height); spriteAtlasImageIndexMap.set(atlasIndex, imageTile); } else { LOGE("Unable to properly cut out a sprite at upper left (%d, %d)", sourceRect.UpperLeftCorner.X, sourceRect.UpperLeftCorner.Y); } atlasIndex++; } } LOGD("Dropping no longer needed image."); image->drop(); image = NULL; //STEP 2: Iterate over tiles in this set and fetch their image from the atlasIndexMap map<stringc, CreatureDefinition*>::Iterator spriteMapIterator = _creatures.getIterator(); while (!spriteMapIterator.atEnd()) { map<stringc, CreatureDefinition*>::Node* node = spriteMapIterator.getNode(); CreatureDefinition* creatureDefinition = node->getValue(); stringc textureName(_worldName); textureName.append("-"); textureName.append(creatureDefinition->GetName()); if (NULL == videoDriver->getTexture(textureName)) { LOGI( "Texture named %s is not registered with the driver. Registering.", textureName.c_str()); //TODO: This is holdover from the code for pulling in more than //one map tile for a specific type. Replace with specific handling //should animations become necessary. What follows is the //ORIGINAL comment from the HexTileSet texture builder. //Tiles can have a length greater than 0 which means //including the starting index x grab the next LENGTH tiles for (int i = 0; i < creatureDefinition->GetIndexLength(); i++) { int spriteAtlasIndex = creatureDefinition->GetAtlasIndex() + i; if (creatureDefinition->GetIndexLength() > 1) { char spriteIndex[5]; sprintf(spriteIndex, "%d", spriteAtlasIndex); stringc incrTextureName(_worldName); incrTextureName.append("-"); incrTextureName.append(creatureDefinition->GetName()); incrTextureName.append("-"); incrTextureName.append(spriteIndex); incrTextureName.trim(); textureName = incrTextureName; } map<int, IImage*>::Node* node = spriteAtlasImageIndexMap.find( spriteAtlasIndex); if (NULL != node) { IImage* textureResource = node->getValue(); if (NULL != textureResource) { LOGI("Started registering %s.", textureName.c_str()); ITexture* createdTexture = videoDriver->addTexture(textureName, textureResource); LOGI("Finished registering %s.", textureName.c_str()); } else { LOGE( "The image created for texture named %s is null or corrupted.", textureName.c_str()); } } } } spriteMapIterator++; } //STEP 3: Clean up //For all entries remaining in the map, delete the image as they were unused. map<int, IImage*>::Iterator mapIterator = spriteAtlasImageIndexMap.getIterator(); while (!mapIterator.atEnd()) { map<int, IImage*>::Node* node = mapIterator.getNode(); if (NULL != node && NULL != node->getValue()) { node->getValue()->drop(); } else { LOGE( "An entry in the temporary map is null or the image contained therein is null. This is a potential resource leak!"); } mapIterator++; } spriteAtlasImageIndexMap.clear(); LOGD("Sprite texture resource cleanup complete."); result = true; } return result; }