Example #1
0
void TextureChooser::onFileTxtRowChanged( int row )
{
	if( row < 0 )
		return;

	QListWidgetItem *item = d_ptr->fileTextures->item( row );
	QString fn = item->text();

	std::string rfn = fn.toUtf8().constData();
	rfn = NLMISC::CPath::lookup( rfn );
	
	NLMISC::CIFile f;
	bool b = f.open( rfn );
	if( !b )
	{
		return;
	}

	NLMISC::CBitmap bm;
	uint8 depth = bm.load( f );
	f.close();
	b = bm.convertToType( NLMISC::CBitmap::RGBA );
	if( !b )
	{
		return;
	}

	setPreviewImage( bm );
}
Example #2
0
// ---------------------------------------------------------------------------
NLMISC::CBitmap *CDataBase::loadBitmap (const std::string &fileName)
{
	NLMISC::CBitmap *pBitmap = new NLMISC::CBitmap();

	try
	{
		CIFile fileIn;
		if (fileIn.open (fileName))
		{
			pBitmap->load (fileIn);
		}
		else
		{
			pBitmap->makeDummy();
			nlwarning ("Bitmap not found : %s", fileName.c_str());
		}
	}
	catch (Exception& e)
	{
		pBitmap->makeDummy();
		theApp.errorMessage ("Error while loading bitmap %s : %s", fileName.c_str(), e.what());
	}

	return pBitmap;
}
Example #3
0
// ***************************************************************************
void				CMovieShooter::getFrameData(CFrameHeader *frame, NLMISC::CBitmap &bmp)
{
	uint	w= frame->Width;
	uint	h= frame->Height;
	// resize
	if(bmp.getWidth()!=w || bmp.getHeight()!=h)
		bmp.resize(w, h);
	// unpack.
	uint16	*src= (uint16*)frame->Data;
	CRGBA	*dst= (CRGBA*)&bmp.getPixels()[0];
	for(uint npix= w*h; npix>0; npix--, src++, dst++)
	{
		dst->set565(*src);
	}
}
Example #4
0
void CIconWnd::modulateIcon(NLMISC::CBitmap &dst, const NLMISC::CRGBA &col)
{
    // modulate an icon by a color

    CObjectVector<uint8> &data = dst.getPixels();

    for (uint y=0 ; y<dst.getHeight() ; y++)
    {
        for (uint x=0 ; x<dst.getWidth() ; x++)
        {
            CRGBA c;
            c.modulateFromColor(col, dst.getPixelColor(x, y));

            data[(x+y*dst.getWidth())*4]   = c.R;
            data[(x+y*dst.getWidth())*4+1] = c.G;
            data[(x+y*dst.getWidth())*4+2] = c.B;
            data[(x+y*dst.getWidth())*4+3] = dst.getPixelColor(x, y).A;
        }
    }
}
Example #5
0
bool CIconWnd::loadIcon(const std::string &filename, NLMISC::CBitmap &bmp)
{
    // Try to get the file path
    string filepath = CPath::lookup(filename, false, false);
    if (filepath == "")
    {
        bmp.makeDummy();
        bmp.convertToType(NLMISC::CBitmap::RGBA);
        bmp.resample(40, 40);
        return false;
    }

    // load icon
    CIFile f;
    f.open(filepath);

    bmp.load(f);
    bmp.convertToType(NLMISC::CBitmap::RGBA);
    bmp.resample(40, 40);

    f.close();

    return true;
}
Example #6
0
void Browse::OnImportBorder() 
{
	// Select a file
	CFileDialog sFile (true, NULL, NULL, OFN_ENABLESIZING,
		"Targa bitmap (*.tga)|*.tga|All files (*.*)|*.*||",NULL);
	if (sFile.DoModal()==IDOK)
	{
		// Get the border of the bank
		std::vector<NLMISC::CBGRA> array(128*128);

		// The bitmap
		NLMISC::CBitmap bitmap;

		// Read the bitmap
		bool error=false;
		CString pathName=sFile.GetPathName();
		try
		{
			CIFile file;
			if (file.open ((const char*)pathName))
			{
				// Export
				bitmap.load (file);
			}
			else
				error=true;
		}
		catch (Exception& e)
		{
			const char *toto=e.what ();
			error=true;
		}

		// Error during import ?
		if (error)
		{
			// Error message
			char tmp[512];
			sprintf (tmp, "Can't read bitmap %s", (const char*)pathName);
			MessageBox (tmp, "Import border", MB_OK|MB_ICONEXCLAMATION);
		}

		// Get pixel
		CRGBA *pPixel=(CRGBA*)&bitmap.getPixels()[0];

		// Good size
		if ((bitmap.getWidth()==128)&&(bitmap.getHeight()==128))
		{
			// Make a copy
			for (int i=0; i<128*128; i++)
			{
				// Copy the pixel
				array[i].R=pPixel->R;
				array[i].G=pPixel->G;
				array[i].B=pPixel->B;
				array[i].A=pPixel->A;
				pPixel++;
			}
		}
		else
		{
			// Error message
			char tmp[512];
			sprintf (tmp, "The bitmap must have a size of 128x128 (%s)", (const char*)pathName);
			MessageBox (tmp, "Import border", MB_OK|MB_ICONEXCLAMATION);
		}

		// 256 or 128 ?
		CTileBorder border;
		border.set (128, 128, array);
		tileBank2.getTileSet (land)->setBorder (m_ctrl.Texture==1?CTile::diffuse:CTile::additive, border);

		// Message
		MessageBox ("The border has been changed.", "Import border", MB_OK|MB_ICONINFORMATION);
	}
}
Example #7
0
void Browse::OnExportBorder() 
{
	// Select a file
	CFileDialog sFile (false, NULL, NULL, OFN_ENABLESIZING,
		"Targa bitmap (*.tga)|*.tga|All files (*.*)|*.*||",NULL);
	if (sFile.DoModal()==IDOK)
	{
		// Get the border of the bank
		std::vector<NLMISC::CBGRA> array;

		// 256 or 128 ?
		int width, height;
		tileBank2.getTileSet (land)->getBorder128 (m_ctrl.Texture==1?CTile::diffuse:CTile::additive)->get (width, height, array);

		// Make a bitmap
		if (width&&height)
		{
			NLMISC::CBitmap bitmap;
			bitmap.resize (width, height, NLMISC::CBitmap::RGBA);

			// Get pixel
			CRGBA *pPixel=(CRGBA*)&bitmap.getPixels()[0];

			// Make a copy
			for (int i=0; i<width*height; i++)
			{
				// Copy the pixel
				pPixel->R=array[i].R;
				pPixel->G=array[i].G;
				pPixel->B=array[i].B;
				pPixel->A=array[i].A;
				pPixel++;
			}

			// Write the bitmap
			bool error=false;
			CString pathName=sFile.GetPathName();
			try
			{
				COFile file;
				if (file.open ((const char*)pathName))
				{
					// Export
					bitmap.writeTGA (file, 32);
				}
				else
					error=true;
			}
			catch (Exception& e)
			{
				const char *toto=e.what ();
				error=true;
			}

			// Error during export ?
			if (error)
			{
				// Error message
				char tmp[512];
				sprintf (tmp, "Can't write bitmap %s", (const char*)pathName);
				MessageBox (tmp, "Export border", MB_OK|MB_ICONEXCLAMATION);
			}
		}
	}
}
Example #8
0
// ---------------------------------------------------------------------------
void CBuilderZone::snapshotCustom (const char *fileName, uint width, uint height, bool keepRatio, uint sizeSource, bool grayscale)
{
	if (_ZoneRegions.size() == 0)
		return;

	// Some bitmaps
	NLMISC::CBitmap bitmapTmp;
	NLMISC::CBitmap bitmapDest;

	const CZoneRegion *pBZR = &(getDocument ()->getZoneRegion (_ZoneRegionSelected));
	sint32 nMinX = pBZR->getMinX();
	sint32 nMaxX = pBZR->getMaxX();
	sint32 nMinY = pBZR->getMinY();
	sint32 nMaxY = pBZR->getMaxY();

	uint nSizeX = (nMaxX - nMinX + 1)*sizeSource;
	uint nSizeY = (nMaxY - nMinY + 1)*sizeSource;
	sint x, y, j;

	// Keep ratio ?
	if (keepRatio)
		height = (width * nSizeY) / nSizeX;

	// Resize the bitmaps
	bitmapDest.resize (nSizeX, nSizeY, NLMISC::CBitmap::RGBA);

	// white all
	NLMISC::CObjectVector<uint8> &rPixels = bitmapDest.getPixels();
	memset (&rPixels[0], 0xff, rPixels.size ());
	
	// Copy ZoneBitmaps in the bitmap
	CUV uvMin, uvMax;
	ITexture *pTexture;
	CZoneBankElement *pZBE;
	uint8 nRot, nFlip;

	// For each tiles
	for (y = nMinY; y <= nMaxY; ++y)
	for (x = nMinX; x <= nMaxX; ++x)
	{
		const string &rsZoneName = pBZR->getName (x, y);
		if ((rsZoneName == STRING_OUT_OF_BOUND) && (rsZoneName == STRING_UNUSED))
			continue;

		pZBE = _ZoneBank.getElementByZoneName (rsZoneName);
		if (pZBE == NULL)
			continue;

		// Get the texture
		pTexture = _DataBase.getTexture (rsZoneName, pBZR->getPosX(x, y), 
										pBZR->getPosY(x, y), uvMin, uvMax);

		// Generate it
		pTexture->generate ();

		// Be sure it is tga
		pTexture->convertToType (NLMISC::CBitmap::RGBA);

		// Get rot
		nRot = pBZR->getRot(x, y);

		// Get flip
		nFlip = pBZR->getFlip(x, y);

		// Copy the texture

		// Dest bitmap size
		uint destWidth = 1+(uint)((float)pTexture->getWidth() * (uvMax.U - uvMin.U));
		uint destHeight = 1+(uint)((float)pTexture->getHeight() * (uvMax.V - uvMin.V));
		bitmapTmp.resize (destWidth, destHeight, NLMISC::CBitmap::RGBA);

		// Source bitmap size and position
		uint u = (uint)((float)pTexture->getWidth() * uvMin.U);
		uint v = (uint)((float)pTexture->getHeight() * uvMin.V);
		uint sourceWidth = pTexture->getWidth();
		uint sourceHeight = pTexture->getHeight();

		// Source pointer
		uint8 *srcPixels = &(pTexture->getPixels ()[0]);

		// Destination pointer
		uint8 *destPixels = &(bitmapTmp.getPixels ()[0]);

		// Copy the temp bitmap
		for (j = 0; j < (sint)destHeight; ++j)
			// Copy the line
			memcpy (destPixels+(4*j*destWidth), srcPixels + 4 * ( (v + j) * sourceWidth + u), destWidth*4);

		// Flip ?
		if (nFlip)
			bitmapTmp.flipH();

		// Rot ?
		while (nRot)
		{
			bitmapTmp.rot90CW ();
			nRot--;
		}

		// Resize the bitmap to normal size
		if ( (bitmapTmp.getWidth () != sizeSource) || (bitmapTmp.getHeight () != sizeSource) )
			bitmapTmp.resample (sizeSource, sizeSource);

		// Copy it in the map
		bitmapDest.blit (&bitmapTmp, (x-nMinX)*sizeSource, (y-nMinY)*sizeSource);

		pTexture->release ();
	}

	// Resample the final bitmap
	bitmapDest.resample (width, height);
	bitmapDest.flipV ();

	COFile f(fileName, false, false, true);

	if (grayscale)
	{
		bitmapDest.convertToType (NLMISC::CBitmap::Luminance);
		if (bitmapDest.writeTGA (f, 8))
			f.close();
	}
	else
	{
		if (bitmapDest.writeTGA (f, 32))
			f.close();
	}
}
Example #9
0
// ---------------------------------------------------------------------------
bool CDataBase::init (const string &Path, CZoneBank &zb)
{
	string sDirBackup = NLMISC::CPath::getCurrentPath();

	// "Path" can be relative to the doc path so we have to be first in the doc path
	string s2 = NLMISC::CFile::getPath ((LPCTSTR)getMainFrame()->getDocument()->GetPathName());
	NLMISC::CPath::setCurrentPath(s2.c_str());
	string ss = NLMISC::CPath::getFullPath(Path);
	NLMISC::CPath::setCurrentPath (ss.c_str());

	uint32 i, m, n, o, p;
	uint8 k, l;

	vector<string> ZoneNames;
	zb.getCategoryValues ("zone", ZoneNames);
	for (i = 0; i < ZoneNames.size(); ++i)
	{
		// Progress
		getMainFrame ()->progressLoadingDialog ((float)i / (float)ZoneNames.size());

		SElement zdbTmp;
		CZoneBankElement *pZBE = zb.getElementByZoneName (ZoneNames[i]);
		// Read the texture file
		string zdbTmpName = ZoneNames[i];
		zdbTmp.SizeX = pZBE->getSizeX ();
		zdbTmp.SizeY = pZBE->getSizeY ();
		const vector<bool> &rMask = pZBE->getMask();

		NLMISC::CBitmap *pBitmap = loadBitmap (getTextureFile(zdbTmpName));

		// Should not return NULL !
		nlassert (pBitmap);

		// Wanted zone size
		uint width = _RefSizeX * zdbTmp.SizeX;
		uint height = _RefSizeY * zdbTmp.SizeY;

		// Good size ?
		if ((pBitmap->getWidth () != width) || (pBitmap->getHeight () != height))
		{
			// Resize it
			pBitmap->resample (width, height);
		}

		zdbTmp.WinBitmap = convertToWin (pBitmap);
		pBitmap->flipV ();

		for (l = 0; l < zdbTmp.SizeY; ++l)
		for (k = 0; k < zdbTmp.SizeX; ++k)
		if (rMask[k+l*zdbTmp.SizeX])
		{
			SCacheZone czTmp;

			czTmp.PosX = k;
			czTmp.PosY = l;

			// Found first non full texture cache
			for (m = 0; m < 64; ++m)
			if (_CacheTexture[m].Enabled == false)
			{
				// Create the texture
				_CacheTexture[m].FreePlace.resize (_RefCacheTextureNbEltX*_RefCacheTextureNbEltY, true);
				_CacheTexture[m].Texture = new CTextureMem();
				_CacheTexture[m].Texture->setAllowDegradation (true);
				_CacheTexture[m].PtrMem.resize (4*_RefCacheTextureSizeX*_RefCacheTextureSizeY);
				_CacheTexture[m].Texture->resize (_RefCacheTextureSizeX, _RefCacheTextureSizeY);
				_CacheTexture[m].Texture->setPointer (&_CacheTexture[m].PtrMem[0], 4*_RefCacheTextureSizeX*_RefCacheTextureSizeY,
											false, false, _RefCacheTextureSizeX, _RefCacheTextureSizeY);

				_CacheTexture[m].Enabled = true;
				break;
			}
			else
			{
				if (!_CacheTexture[m].isFull())
					break;
			}

			nlassert (m<64);

			// Found first place in this texture

			for (n = 0; n < _CacheTexture[m].FreePlace.size(); ++n)
			if (_CacheTexture[m].FreePlace[n])
			{
				sint32 xSrc = k*_RefSizeX;
				sint32 ySrc = l*_RefSizeY;
				sint32 xDst = (n%_RefCacheTextureNbEltX)*_RefSizeX;
				sint32 yDst = (n/_RefCacheTextureNbEltX)*_RefSizeY;
				uint8 *pSrc = &pBitmap->getPixels()[(xSrc+ySrc*pBitmap->getWidth())*4];
				uint8 *pDst = &_CacheTexture[m].PtrMem[(xDst+yDst*_RefCacheTextureSizeX)*4];
				// Copy part of the bitmap into cache texture
				for (p = 0; p < _RefSizeY; ++p)
				for (o = 0; o < _RefSizeX; ++o)
				{
					pDst[(o+p*_RefCacheTextureSizeX)*4+0] = pSrc[(o+p*pBitmap->getWidth())*4+0];
					pDst[(o+p*_RefCacheTextureSizeX)*4+1] = pSrc[(o+p*pBitmap->getWidth())*4+1];
					pDst[(o+p*_RefCacheTextureSizeX)*4+2] = pSrc[(o+p*pBitmap->getWidth())*4+2];
					pDst[(o+p*_RefCacheTextureSizeX)*4+3] = pSrc[(o+p*pBitmap->getWidth())*4+3];
				}
				czTmp.PosUV.U = ((float)xDst) / ((float)_RefCacheTextureSizeX);
				czTmp.PosUV.V = ((float)yDst) / ((float)_RefCacheTextureSizeY);
				czTmp.CacheTexture = _CacheTexture[m].Texture;
				_CacheTexture[m].FreePlace[n] = false;
				break;
			}
			//nlassert (m<_CacheTexture[m].FreePlace.size());
			zdbTmp.ZonePieces.push_back (czTmp);
		}
		// Add the entry in the DataBase
		_ZoneDBmap.insert (pair<string,SElement>(zdbTmpName, zdbTmp));
		delete pBitmap;
	}

	// Upload all textures in VRAM
	for (m = 0; m < 64; ++m)
	if (_CacheTexture[m].Enabled)
		_CacheTexture[m].Texture->touch ();

	_UnusedTexture = loadTexture (getTextureFile("_UNUSED_"));

	NLMISC::CPath::setCurrentPath(sDirBackup);
	return true;
}
Example #10
0
void CIconWnd::blendIcons(NLMISC::CBitmap &dst, const NLMISC::CBitmap &src)
{
    // blend between two icons

    nlassert(dst.getWidth() == src.getWidth());
    nlassert(dst.getHeight() == src.getHeight());

    CObjectVector<uint8> &data = dst.getPixels();

    for (uint y=0 ; y<dst.getHeight() ; y++)
    {
        for (uint x=0 ; x<dst.getWidth() ; x++)
        {
            CRGBA c;
            c.blendFromui(dst.getPixelColor(x, y), src.getPixelColor(x, y), src.getPixelColor(x, y).A);

            data[(x+y*dst.getWidth())*4]   = c.R;
            data[(x+y*dst.getWidth())*4+1] = c.G;
            data[(x+y*dst.getWidth())*4+2] = c.B;
            data[(x+y*dst.getWidth())*4+3] = c.A;

        }
    }
}
Example #11
0
// ---------------------------------------------------------------------------
// main
// ---------------------------------------------------------------------------
int main(int nNbArg, char **ppArgs)
{
	
	if (nNbArg <3 || nNbArg >5)
	{
		outString ("ERROR : Wrong number of arguments\n");
		outString ("USAGE : lightmap_optimizer <path_lightmaps> <path_shapes> [path_tags] [path_flag8bit]\n");
		return -1;
	}
	
	vector<string> AllShapeNames;
	vector<CMeshBase*> AllShapes;
	std::vector<std::string> tags;	
	char sLMPDir[MAX_PATH];
	char sSHPDir[MAX_PATH];

	
	GetCurrentDirectory (MAX_PATH, sExeDir);

	
	// Get absolute directory for lightmaps
	if (!SetCurrentDirectory(ppArgs[1]))
	{
		outString (string("ERROR : directory ") + ppArgs[1] + " do not exists\n");
		return -1;
	}
	GetCurrentDirectory (MAX_PATH, sLMPDir);
	SetCurrentDirectory (sExeDir);
	// Get absolute directory for shapes
	if (!SetCurrentDirectory(ppArgs[2]))
	{
		outString (string("ERROR : directory ") + ppArgs[2] + " do not exists\n");
		return -1;
	}
	GetCurrentDirectory (MAX_PATH, sSHPDir);
	dir ("*.shape", AllShapeNames, false);
	registerSerial3d ();
	for (uint32 nShp = 0; nShp < AllShapeNames.size(); ++nShp)
	{
		try
		{
			CShapeStream mesh;
			NLMISC::CIFile meshfile (AllShapeNames[nShp]);
			meshfile.serial( mesh );
			meshfile.close();

			// Add the shape to the map.
			CMeshBase *pMB = dynamic_cast<CMeshBase*>(mesh.getShapePointer());
			AllShapes.push_back (pMB);
		}
		catch (NLMISC::EPathNotFound &e)
		{
			outString(string("ERROR: shape not found ")+AllShapeNames[nShp]+" - "+e.what());
			return -1;
		}
	}

	if (nNbArg > 3 && ppArgs[3] && strlen(ppArgs[3]) > 0)
	{
		SetCurrentDirectory (sExeDir);
		if (!SetCurrentDirectory(ppArgs[3]))
		{
			outString (string("ERROR : directory ") + ppArgs[3] + " do not exists\n");
			return -1;
		}
		dir ("*.tag", tags, false);
		for(uint k = 0; k < tags.size(); ++k)
		{
			std::string::size_type pos = tags[k].find('.');
			if (pos != std::string::npos)
			{
				tags[k] = tags[k].substr(0, pos);
			}
		}
	}


	// **** Parse all mesh loaded, to flag each lightmap if 8 bit or not (NB: all layers should be same mode)
	std::set<string>	setLM8Bit;
	for(uint i=0;i<AllShapes.size();i++)
	{
		CMeshBase *pMB= AllShapes[i];
		if(!pMB)
			continue;

		uint32		nbMat= pMB->getNbMaterial();
		for (uint32 m = 0; m < nbMat; ++m)
		{
			CMaterial& rMat = const_cast<CMaterial&>(pMB->getMaterial (m));
			if (rMat.getShader() == CMaterial::LightMap)
			{
				// Begin with stage 0
				uint8 stage = 0;
				while (rMat.getLightMap(stage) != NULL)
				{
					ITexture *pIT = rMat.getLightMap (stage);
					CTextureFile *pTF = dynamic_cast<CTextureFile*>(pIT);
					if (pTF != NULL)
					{
						string sTexName = NLMISC::strlwr(pTF->getFileName());
						if(pTF->getUploadFormat()==ITexture::Luminance)
							setLM8Bit.insert(sTexName);
					}
					++stage;
				}
			}
		}
	}


	// **** Parse all lightmaps, sorted by layer, and 8 or 16 bit mode
	SetCurrentDirectory (sExeDir);
	for (uint32 lmc8bitMode = 0; lmc8bitMode < 2; ++lmc8bitMode)
	for (uint32 nNbLayer = 0; nNbLayer < 256; ++nNbLayer)
	{
		// Get all lightmaps with same number of layer == nNbLayer
		// merge lightmaps only if they are in same mode (8bits or 16 bits)

		vector<string> AllLightmapNames;
		vector<sint>   AllLightmapTags;
		vector<NLMISC::CBitmap*> AllLightmaps;
		sint32 i, j, k, m, n;
		string sFilter;

		// **** Get All Lightmaps that have this number of layer, and this mode
		sFilter = "*_" + NLMISC::toString(nNbLayer) + ".tga";
		SetCurrentDirectory (sLMPDir);
		dir (sFilter, AllLightmapNames, false);

		// filter by layer
		vector<string>		tmpLMs;
		tmpLMs.reserve(AllLightmapNames.size());
		for (i = 0; i < (sint32)AllLightmapNames.size(); ++i)
		{
			string sTmp2 = getBaseName (AllLightmapNames[i]);
			sTmp2 += NLMISC::toString(nNbLayer+1) + ".tga";
			// if not More layer than expected, ok
			if (!fileExist(sTmp2))
			{	
				tmpLMs.push_back(AllLightmapNames[i]);
			}
		}
		AllLightmapNames= tmpLMs;
	
		// filter by 8bit or not mode.
		tmpLMs.clear();
		for (i = 0; i < (sint32)AllLightmapNames.size(); ++i)
		{
			bool	lm8Bit= setLM8Bit.find( NLMISC::strlwr(AllLightmapNames[i]) ) !=setLM8Bit.end();
			// if same mode
			if( lm8Bit == (lmc8bitMode==1) )
			{
				tmpLMs.push_back(AllLightmapNames[i]);
			}
		}
		AllLightmapNames= tmpLMs;

		
		// **** Build tag info
		/*
		for(uint k = 0; k < tags.size(); ++k)
		{
			nlinfo("tag %d = %s", (int) k, tags[k].c_str());
		}
		*/
		AllLightmapTags.resize(AllLightmapNames.size());
		for(uint k = 0; k < AllLightmapNames.size(); ++k)
		{
			nlinfo("k = %d", (int) k);
			AllLightmapTags[k] = -1;
			// search for longest tag that match
			uint bestLength = 0;
			for(uint l = 0; l < tags.size(); ++l)
			{
				if (AllLightmapNames[k].size() > tags[l].size())
				{
					if (tags[l].size() > bestLength)
					{					
						std::string start = AllLightmapNames[k].substr(0, tags[l].size());
						if (NLMISC::nlstricmp(start, tags[l]) == 0)
						{
							bestLength = (uint)tags[l].size();
							// the tag matchs
							AllLightmapTags[k] = l;						
						}
					}
				}
			}						
			if (AllLightmapTags[k] == -1)
			{
				nlinfo(NLMISC::toString("Lightmap %s has no tag", AllLightmapNames[k].c_str()).c_str());
			}
			else
			{			
				nlinfo(NLMISC::toString("Lightmap %s has tag %d : %s", AllLightmapNames[k].c_str(), (int) AllLightmapTags[k], tags[AllLightmapTags[k]].c_str()).c_str());
			}			
		}




		// Check if all layer of the same lightmap has the same size
		if (nNbLayer > 0)
		for (i = 0; i < (sint32)AllLightmapNames.size(); ++i)
		{
			string sTmp2;
			sTmp2 = getBaseName (AllLightmapNames[i]) + "0.tga";
			uint32 wRef, hRef;
			try
			{
				NLMISC::CIFile inFile;
				inFile.open(sTmp2);
				CBitmap::loadSize(inFile, wRef, hRef);
			}
			catch (NLMISC::Exception &e)
			{
				outString (string("ERROR :") + e.what());
				return -1;
			}

			bool bFound = false;
			for (k = 1; k <= (sint32)nNbLayer; ++k)
			{
				string sTmp3 = getBaseName (AllLightmapNames[i]) + NLMISC::toString(k) + ".tga";
				uint32 wCur = wRef, hCur = hRef;
				try
				{
					NLMISC::CIFile inFile;
					inFile.open(sTmp3);
					CBitmap::loadSize(inFile, wCur, hCur);
				}
				catch (NLMISC::Exception &)
				{
				}

				if ((wCur != wRef) || (hCur != hRef))
				{
					bFound = true;
					break;
				}
			}
			// Should delete all layers of this lightmap (in fact in lightmapnames list we have
			// only the name of the current layer)
			if (bFound)
			{
				sTmp2 = getBaseName (AllLightmapNames[i]);
				outString(string("ERROR: lightmaps ")+sTmp2+"*.tga not all the same size\n");
				for (k = 0; k < (sint32)AllLightmapNames.size(); ++k)
				{
					if (strnicmp(AllLightmapNames[k].c_str(), sTmp2.c_str(), sTmp2.size()) == 0)
					{
						for (j = k+1; j < (sint32)AllLightmapNames.size(); ++j)
						{
							AllLightmapNames[j-1] = AllLightmapNames[j];
							AllLightmapTags[j - 1] = AllLightmapTags[j];
						}
						AllLightmapNames.resize (AllLightmapNames.size()-1);
						AllLightmapTags.resize(AllLightmapTags.size()  - 1);
						k = -1;
						i = -1;
					}
				}
			}
		}
		
		if (AllLightmapNames.size() == 0)
			continue;
		
		// Load all the lightmaps
		AllLightmaps.resize (AllLightmapNames.size());
		for (i = 0; i < (sint32)AllLightmaps.size(); ++i)
		{
			try
			{
				NLMISC::CBitmap *pBtmp = new NLMISC::CBitmap;
				NLMISC::CIFile inFile;
				inFile.open(AllLightmapNames[i]);
				pBtmp->load(inFile);
				AllLightmaps[i] = pBtmp;
			}
			catch (NLMISC::Exception &e)
			{
				outString (string("ERROR :") + e.what());
				return -1;
			}
		}

		// Sort all lightmaps by decreasing size
		for (i = 0; i < (sint32)(AllLightmaps.size()-1); ++i)
		for (j = i+1; j < (sint32)AllLightmaps.size(); ++j)
		{
			NLMISC::CBitmap *pBI = AllLightmaps[i];
			NLMISC::CBitmap *pBJ = AllLightmaps[j];
			if ((pBI->getWidth()*pBI->getHeight()) < (pBJ->getWidth()*pBJ->getHeight()))
			{
				NLMISC::CBitmap *pBTmp = AllLightmaps[i];
				AllLightmaps[i] = AllLightmaps[j];
				AllLightmaps[j] = pBTmp;

				string sTmp = AllLightmapNames[i];
				AllLightmapNames[i] = AllLightmapNames[j];
				AllLightmapNames[j] = sTmp;

				sint tagTmp = AllLightmapTags[i];
				AllLightmapTags[i] = AllLightmapTags[j];
				AllLightmapTags[j] = tagTmp;
			}
		}
		nlassert(AllLightmapTags.size() == AllLightmapNames.size());
		for (i = 0; i < (sint32)AllLightmapNames.size(); ++i)
		{
			outString(NLMISC::toString("%d / %d\n", (int) i, (int) AllLightmapNames.size()));
			bool bAssigned = false;
			for (j = 0; j < i; ++j)
			{				
				// Tags of both textures must match. We don't want to spread lightmap chunk in bitmap whose other part aren't used by current ig lightmaps (this wastes vram for nothing)
				if (AllLightmapTags[i] != AllLightmapTags[j]) continue;

				// Try to place the texture i into the texture j
				// This can be done only if texture was exported from the same zone. To ensure that, check 
				NLMISC::CBitmap *pBI = AllLightmaps[i];
				NLMISC::CBitmap *pBJ = AllLightmaps[j];
				sint32 x, y;
				if (tryAllPos (pBI, pBJ, x, y))
				{
					bAssigned = true;

					if (!putIn (pBI, pBJ, x, y))
					{
						outString (string("ERROR : cannot put reference lightmap ")+AllLightmapNames[i]+
									" in "+AllLightmapNames[j]);
						return -1;
					}
					// Put texture i into texture j for all layers of the lightmap !
					for (k = 0; k <= (sint32)nNbLayer; ++k)
					{
						string sTexNameI = getBaseName (AllLightmapNames[i]) + NLMISC::toString(k) + ".tga";
						string sTexNameJ = getBaseName (AllLightmapNames[j]) + NLMISC::toString(k) + ".tga";
						NLMISC::CBitmap BitmapI;
						NLMISC::CBitmap BitmapJ;
						NLMISC::CIFile inFile;

						outString (NLMISC::toString("INFO : Transfering %s (tag = %d) in %s (tag = %d)", 
													sTexNameI.c_str(), (int) AllLightmapTags[i],
													sTexNameJ.c_str(), (int) AllLightmapTags[j]) +
													" at ("+NLMISC::toString(x)+","+NLMISC::toString(y)+")\n");

						try
						{
							inFile.open (sTexNameI);
							BitmapI.load (inFile);
							inFile.close ();
							inFile.open (sTexNameJ);
							BitmapJ.load (inFile);
							inFile.close ();
						}
						catch (NLMISC::Exception &e)
						{
							outString (string("ERROR :") + e.what());
							return -1;
						}
						
						if (!putIn (&BitmapI, &BitmapJ, x, y))
						{
							outString (string("ERROR : cannot put lightmap ")+sTexNameI+" in "+sTexNameJ+"\n");
							return -1;
						}

						// Delete File
						DeleteFile (sTexNameI.c_str());
						outString (string("INFO : Deleting file ")+sTexNameI+"\n");

						// Save destination image
						NLMISC::COFile outFile;
						outFile.open (sTexNameJ);
						BitmapJ.writeTGA (outFile, 32);
						outString (string("INFO : Saving file ")+sTexNameJ+"\n");
					}

					// Change shapes uvs related and names to the lightmap
					// ---------------------------------------------------

					SetCurrentDirectory (sSHPDir);

					for (k = 0; k < (sint32)AllShapes.size(); ++k)
					{
						CMeshBase *pMB = AllShapes[k];
						if (!pMB)
							continue;

						uint nNbMat = pMB->getNbMaterial ();
						vector< vector<bool> > VerticesNeedRemap;
						bool bMustSave = false;
						// Initialize all VerticesNeedRemap
						CMesh *pMesh = dynamic_cast<CMesh*>(pMB);
						CMeshMRM *pMeshMRM = dynamic_cast<CMeshMRM*>(pMB);
						CMeshMultiLod *pMeshML = dynamic_cast<CMeshMultiLod*>(pMB);

						if (pMesh != NULL)
						{
							VerticesNeedRemap.resize(1); // Only one meshgeom
							vector<bool> &rVNR = VerticesNeedRemap[0];
							rVNR.resize (pMesh->getMeshGeom().getVertexBuffer().getNumVertices(), false);
						}
						else if (pMeshMRM != NULL)
						{
							VerticesNeedRemap.resize(1); // Only one meshmrmgeom
							vector<bool> &rVNR = VerticesNeedRemap[0];
							rVNR.resize (pMeshMRM->getMeshGeom().getVertexBuffer().getNumVertices(), false);
						}
						else if (pMeshML != NULL)
						{
							sint32 nNumSlot = pMeshML->getNumSlotMesh();
							VerticesNeedRemap.resize(nNumSlot);
							for (m = 0; m < nNumSlot; ++m)
							{
								vector<bool> &rVNR = VerticesNeedRemap[m];
								const CMeshGeom *pMG = dynamic_cast<const CMeshGeom*>(&pMeshML->getMeshGeom(m));
								if (pMG != NULL)
									rVNR.resize (pMG->getVertexBuffer().getNumVertices(), false);
								else
									rVNR.resize(0);
							}
						}
						else continue; // Next mesh
						

						// All materials must have the lightmap names changed
						for (m = 0; m < (sint32)nNbMat; ++m)
						{
							bool bMustRemapUV = false;
							CMaterial& rMat = const_cast<CMaterial&>(pMB->getMaterial (m));
							if (rMat.getShader() == CMaterial::LightMap)
							{
								// Begin with stage 0
								uint8 stage = 0;
								while (rMat.getLightMap(stage) != NULL)
								{
									ITexture *pIT = rMat.getLightMap (stage);
									CTextureFile *pTF = dynamic_cast<CTextureFile*>(pIT);
									if (pTF != NULL)
									{
										string sTexName = NLMISC::strlwr(getBaseName(pTF->getFileName()));
										string sTexNameMoved = NLMISC::strlwr(getBaseName(AllLightmapNames[i]));
										if (sTexName == sTexNameMoved)
										{
											// We must remap the name and indicate to remap uvs
											bMustRemapUV = true;
											//string sNewTexName = NLMISC::strlwr(getBaseName(AllLightmapNames[j]));
											//sNewTexName += NLMISC::toString(getLayerNb(pTF->getFileName())) + ".tga";
											//pTF->setFileName (sNewTexName);
										}
									}
									++stage;
								}
							}
							// We have to remap the uvs of this mesh for this material
							if (bMustRemapUV) // Flaggage of the vertices to remap
							{
								if (pMesh != NULL)
								{
									// Flag all vertices linked to face with material m
									FlagVertices (const_cast<CMeshGeom&>(pMesh->getMeshGeom()), m, VerticesNeedRemap[0]);
								}
								else if (pMeshMRM != NULL)
								{
									FlagVerticesMRM (const_cast<CMeshMRMGeom&>(pMeshMRM->getMeshGeom()), m, VerticesNeedRemap[0]);
								}
								else if (pMeshML != NULL)
								{
									sint32 nNumSlot = pMeshML->getNumSlotMesh();
									for (n = 0; n < nNumSlot; ++n)
									{
										// Get the mesh geom
										CMeshGeom *pMG = const_cast<CMeshGeom*>(dynamic_cast<const CMeshGeom*>(&pMeshML->getMeshGeom(n)));
										if (pMG)
										{
											// Flag the vertices
											FlagVertices (*pMG, m, VerticesNeedRemap[n]);
										}
										else
										{
											// Get the mesh MRM geom
											CMeshMRMGeom *pMMRMG = const_cast<CMeshMRMGeom*>(dynamic_cast<const CMeshMRMGeom*>(&pMeshML->getMeshGeom(n)));
											if (pMMRMG)
											{
												// Flag the vertices
												FlagVerticesMRM (*pMMRMG, m, VerticesNeedRemap[n]);
											}
										}
									}
								}
							}
						}

						// Change lightmap names
						for (m = 0; m < (sint32)nNbMat; ++m)
						{
							CMaterial& rMat = const_cast<CMaterial&>(pMB->getMaterial (m));
							if (rMat.getShader() == CMaterial::LightMap)
							{
								// Begin with stage 0
								uint8 stage = 0;
								while (rMat.getLightMap(stage) != NULL)
								{
									ITexture *pIT = rMat.getLightMap (stage);
									CTextureFile *pTF = dynamic_cast<CTextureFile*>(pIT);
									if (pTF != NULL)
									{
										string sTexName = NLMISC::strlwr(getBaseName(pTF->getFileName()));
										string sTexNameMoved = NLMISC::strlwr(getBaseName(AllLightmapNames[i]));
										if (sTexName == sTexNameMoved)
										{
											string sNewTexName = NLMISC::strlwr(getBaseName(AllLightmapNames[j]));
											sNewTexName += NLMISC::toString(getLayerNb(pTF->getFileName())) + ".tga";
											pTF->setFileName (sNewTexName);
										}
									}
									++stage;
								}
							}
						}

						// We have now the list of vertices to remap for all material that have been changed
						// So parse this list and apply the transformation : (uv * TexSizeI + decalXY) / TexSizeJ
						for (m = 0; m < (sint32)VerticesNeedRemap.size(); ++m)
						{
							CVertexBuffer *pVB;							
							if (pMesh != NULL)
							{
								pVB = const_cast<CVertexBuffer*>(&pMesh->getMeshGeom().getVertexBuffer());
							}
							else if (pMeshMRM != NULL)
							{
								pVB = const_cast<CVertexBuffer*>(&pMeshMRM->getMeshGeom().getVertexBuffer());
							}
							else if (pMeshML != NULL)
							{
								const CMeshGeom *pMG = dynamic_cast<const CMeshGeom*>(&pMeshML->getMeshGeom(m));
								pVB = const_cast<CVertexBuffer*>(&pMG->getVertexBuffer());
							}
							CVertexBufferReadWrite vba; 
							pVB->lock (vba);

							vector<bool> &rVNR = VerticesNeedRemap[m];
							for (n = 0; n < (sint32)rVNR.size(); ++n)
							if (rVNR[n])
							{
								CUV *pUV = (CUV*)vba.getTexCoordPointer (n,1);
								pUV->U = (pUV->U*pBI->getWidth() + x) / pBJ->getWidth();
								pUV->V = (pUV->V*pBI->getHeight() + y) / pBJ->getHeight();
								bMustSave = true;
							}
						}

						if (bMustSave)
						{
							try
							{
								if (AllShapes[k])
								{
									CShapeStream mesh;
									mesh.setShapePointer (AllShapes[k]);
									NLMISC::COFile meshfile (AllShapeNames[k]);
									meshfile.serial (mesh);
									meshfile.close ();
								}
							}
							catch (NLMISC::EPathNotFound &e)
							{
								outString(string("ERROR: cannot save shape ")+AllShapeNames[k]+" - "+e.what());
								return -1;
							}
						}
					}

					SetCurrentDirectory (sLMPDir);

					// Get out of the j loop
					break;
				}
			}		
			// if assigned to another bitmap -> delete the bitmap i
			if (bAssigned)
			{
				// Delete Names && tags
				for (j = i+1; j < (sint32)AllLightmapNames.size(); ++j)
				{
					AllLightmapNames[j-1] = AllLightmapNames[j];
					AllLightmapTags[j-1] = AllLightmapTags[j];
				}
				AllLightmapNames.resize (AllLightmapNames.size()-1);
				AllLightmapTags.resize (AllLightmapTags.size()-1);
				// Delete Lightmaps
				delete AllLightmaps[i];
				for (j = i+1; j < (sint32)AllLightmaps.size(); ++j)
					AllLightmaps[j-1] = AllLightmaps[j];
				AllLightmaps.resize (AllLightmaps.size()-1);
				i = i - 1;
			}
		}

	}
	

	// **** Additionally, output or clear a "flag file" in a dir to info if a 8bit lihgtmap or not
	if (nNbArg >=5 && ppArgs[4] && strlen(ppArgs[4]) > 0)
	{
		SetCurrentDirectory (sExeDir);

		// out a text file, with list of
		FILE	*out= fopen(ppArgs[4], "wt");
		if(!out)
		{
			outString(string("ERROR: cannot save ")+ppArgs[4]);
		}

		set<string>::iterator	it(setLM8Bit.begin()), end(setLM8Bit.end());
		for(;it!=end;it++)
		{
			string	temp= (*it);
			temp+= "\n";
			fputs(temp.c_str(), out);
		}

		fclose(out);
	}

	return 0;
}
// *************************************************************************************
void CDriverD3D::addCursor(const std::string &name, const NLMISC::CBitmap &cursorBitmap)
{
	if (!isAlphaBlendedCursorSupported()) return;

	nlassert(cursorBitmap.getWidth() != 0);
	nlassert(cursorBitmap.getHeight() != 0);

	// find used part base on alpha, to avoid too much shrinking
	const CRGBA *pixels = (const CRGBA *) &cursorBitmap.getPixels()[0];
	uint minX, maxX, minY, maxY;
	uint width = cursorBitmap.getWidth();
	uint height = cursorBitmap.getHeight();
	//
	minX = 0;
	for (uint x = 0; x < width; ++x)
	{
		bool stop = false;
		minX = x;
		for (uint y = 0; y < height; ++y)
		{
			if(pixels[x + y * width].A != 0)
			{
				stop = true;
				break;
			}
		}
		if (stop) break;
	}
	//
	maxX = width - 1;
	for (sint x = width - 1; x >= 0; --x)
	{
		bool stop = false;
		maxX = (uint) x;
		for (uint y = 0; y < height; ++y)
		{
			if(pixels[x + y * width].A != 0)
			{
				stop = true;
				break;
			}
		}
		if (stop) break;
	}
	//
	minY = 0;
	for (uint y = 0; y < height; ++y)
	{
		bool stop = false;
		minY = y;
		for (uint x = 0; x < width; ++x)
		{
			if(pixels[x + y * width].A != 0)
			{
				stop = true;
				break;
			}
		}
		if (stop) break;
	}
	//
	maxY = height - 1;
	for (sint y = height - 1; y >= 0; --y)
	{
		bool stop = false;
		maxY = (uint) y;
		for (uint x = 0; x < width; ++x)
		{
			if(pixels[x + y * width].A != 0)
			{
				stop = true;
				break;
			}
		}
		if (stop) break;
	}
	//
	CCursor &curs = _Cursors[name];
	curs = CCursor(); // erase possible previous cursor

	uint destWidth = GetSystemMetrics(SM_CXCURSOR);
	uint destHeight = GetSystemMetrics(SM_CYCURSOR);

	// build a square bitmap
	uint tmpSize = std::max(maxX - minX + 1, maxY - minY + 1);
	curs.Src.resize(tmpSize, tmpSize);
	// blit at top left corner
	curs.Src.blit(cursorBitmap, minX, minY, maxX - minX + 1, maxY - minY + 1, 0, 0);

	curs.OrigHeight = cursorBitmap.getHeight();
	curs.HotspotOffsetX = minX;
	curs.HotspotOffsetY = minY;
	//
	curs.HotspotScale = _CursorScale;
	clamp(curs.HotspotScale, 0.f, 1.f);
	// first resampling, same for all cursors
	tmpSize = (uint) (tmpSize * curs.HotspotScale);
	if (tmpSize == 0) tmpSize = 1;

	if (curs.HotspotScale < 1.f)
	{
		curs.Src.resample(tmpSize, tmpSize);
	}

	// shrink if necessary
	if (tmpSize > destWidth || tmpSize > destHeight) // need to shrink ?
	{
		// constraint proportions
		curs.HotspotScale *= std::min(float(destWidth) / tmpSize, float(destHeight) / tmpSize);
		curs.Src.resample(destWidth, destHeight);
	}
	else
	{
		CBitmap final;
		final.resize(destWidth, destHeight);
		final.blit(&curs.Src, 0, 0);
//TODO titegus: What's the point in Importing a new border if there is no Pixel Compatibility check ?
void CTile_browser_dlg::on_importBorderPushButton_clicked()
{
	QFileDialog::Options options;
	QString selectedFilter;
	QString fileName = QFileDialog::getOpenFileName(this, tr("Choose Bitmap"), QString(tileBankBrowser.getAbsPath().c_str()) , "Targa Bitmap(*.tga);;All Files (*.*);;", &selectedFilter, options);
	
	if (!fileName.isEmpty())
	{
		fileName = QDir::toNativeSeparators(fileName);
		// Get the border of the bank
		std::vector<NLMISC::CBGRA> array(128*128);

		// The bitmap
		NLMISC::CBitmap bitmap;

		// Read the bitmap
		bool error=false;
		try
		{
			CIFile file;
			if (file.open (fileName.toStdString().c_str()))
			{
				// Export
				bitmap.load (file);
			}
			else
				error=true;
		}
		catch (Exception& e)
		{
			const char *toto=e.what ();
			error=true;
		}

		// Error during import ?
		if (error)
		{
			// Error message
			QString s = tr("Can't read bitmap %1").arg(fileName);
			QMessageBox::information (this, tr("Import border"), s);
		}

		// Get pixel
		CRGBA *pPixel=(CRGBA*)&bitmap.getPixels()[0];

		// Good size
		if ((bitmap.getWidth()==128)&&(bitmap.getHeight()==128))
		{
			// Make a copy
			for (int i=0; i<128*128; i++)
			{
				// Copy the pixel
				array[i].R=pPixel->R;
				array[i].G=pPixel->G;
				array[i].B=pPixel->B;
				array[i].A=pPixel->A;
				pPixel++;
			}
		}
		else
		{
			// Error message
			QString s = tr("The bitmap must have a size of 128x128 (%1)").arg(fileName);
			QMessageBox::information (this, tr("Import border"), s);
		}

		// 256 or 128 ?
		CTileBorder border;
		border.set (128, 128, array);
		tileBankBrowser.getTileSet (tileSetIndex)->setBorder ((CTile::TBitmap) tileTextureButtonGroup->checkedId(), border);

		// Message
		QMessageBox::information (this, tr("Import border"), tr("The border has been changed."));
	}

}
//TODO titegus: replace that by 4 buttons Export128Diffuse, Export128Additive, Export256Diffuse, Export256Diffuse ?
void CTile_browser_dlg::on_exportBorderPushButton_clicked()
{
	// Select a file
	QFileDialog::Options options;
	QString selectedFilter;
	QString fileName = QFileDialog::getSaveFileName(this, tr("Choose Bitmap"), QString(tileBankBrowser.getAbsPath().c_str()) , "Targa Bitmap(*.tga);;All Files (*.*);;", &selectedFilter, options);
	
	if (!fileName.isEmpty())
	{
		fileName = QDir::toNativeSeparators(fileName);
		// Get the border of the bank
		std::vector<NLMISC::CBGRA> array;

		// 256 or 128 ?
		int width, height;
		//TODO titegus: And So what if Alpha ??? and what about border256 ???
		tileBankBrowser.getTileSet (tileSetIndex)->getBorder128 ((CTile::TBitmap)tileTextureButtonGroup->checkedId())->get (width, height, array);

		// Make a bitmap
		if (width&&height)
		{
			NLMISC::CBitmap bitmap;
			bitmap.resize (width, height, NLMISC::CBitmap::RGBA);

			// Get pixel
			CRGBA *pPixel=(CRGBA*)&bitmap.getPixels()[0];

			// Make a copy
			for (int i=0; i<width*height; i++)
			{
				// Copy the pixel
				pPixel->R=array[i].R;
				pPixel->G=array[i].G;
				pPixel->B=array[i].B;
				pPixel->A=array[i].A;
				pPixel++;
			}

			// Write the bitmap
			bool error=false;
			try
			{
				COFile file;
				if (file.open (fileName.toStdString().c_str()))
				{
					// Export
					bitmap.writeTGA (file, 32);
				}
				else
					error=true;
			}
			catch (Exception& e)
			{
				const char *toto=e.what ();
				error=true;
			}

			// Error during export ?
			if (error)
			{
				// Error message
				QString s = tr("Can't write bitmap %1").arg(fileName);
				QMessageBox::information (this, tr("Export border"), s);
			}
		}
	}

}