Explorar el Código

.exe icon replacement finalized and working

BearishSun hace 10 años
padre
commit
d90ea6b4a0

+ 2 - 0
BansheeCore/BansheeCore.vcxproj

@@ -280,6 +280,7 @@
   <ItemGroup>
     <ClInclude Include="Include\BsCoreObjectCore.h" />
     <ClInclude Include="Include\BsHString.h" />
+    <ClInclude Include="Include\BsIconUtility.h" />
     <ClInclude Include="Include\BsMeshImportOptions.h" />
     <ClInclude Include="Include\BsMeshImportOptionsRTTI.h" />
     <ClInclude Include="Include\BsMeshUtility.h" />
@@ -442,6 +443,7 @@
     <ClCompile Include="Source\BsCoreObjectCore.cpp" />
     <ClCompile Include="Source\BsCoreThread.cpp" />
     <ClCompile Include="Source\BsHString.cpp" />
+    <ClCompile Include="Source\BsIconUtility.cpp" />
     <ClCompile Include="Source\BsIResourceListener.cpp" />
     <ClCompile Include="Source\BsMaterialParam.cpp" />
     <ClCompile Include="Source\BsMeshImportOptions.cpp" />

+ 6 - 0
BansheeCore/BansheeCore.vcxproj.filters

@@ -569,6 +569,9 @@
     <ClInclude Include="Include\BsPrefabImporter.h">
       <Filter>Header Files\Importer</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsIconUtility.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsCoreApplication.cpp">
@@ -901,5 +904,8 @@
     <ClCompile Include="Source\BsPrefabImporter.cpp">
       <Filter>Source Files\Importer</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsIconUtility.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 33 - 0
BansheeCore/Include/BsIconUtility.h

@@ -0,0 +1,33 @@
+#pragma once
+
+#include "BsCorePrerequisites.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Manipulates icons in executable files.
+	 */
+	class BS_CORE_EXPORT IconUtility
+	{
+	public:
+		/**
+		 * @brief	Updates icons in the provided executable. Only icons that already exist in the executable can be
+		 * 			updated, no new icons can be inserted. Icons must be square.
+		 *
+		 * @param	filePath	Path to the executable.
+		 * @param	icons   	Pixels of images to replace. Each entry maps an icon width (and height, since 
+		 * 						they're square) to its pixels.
+		 */
+		static void updateIconExe(const Path& filePath, const Map<UINT32, PixelDataPtr>& icons);
+
+	private:
+		/**
+		 * @brief	Updates data of an existing icon with new pixels.
+		 *
+		 * @param 	iconData	Existing icon bytes, in Windows ICO format.
+		 * @param	icons		Pixels of images to replace. Each entry maps an icon width (and height, since 
+		 * 						they're square) to its pixels.
+		 */
+		static void updateIconData(UINT8* iconData, const Map<UINT32, PixelDataPtr>& icons);
+	};
+}

+ 400 - 0
BansheeCore/Source/BsIconUtility.cpp

@@ -0,0 +1,400 @@
+#include "BsIconUtility.h"
+#include "BsPixelData.h"
+#include "BsColor.h"
+
+#define MSDOS_SIGNATURE 0x5A4D
+#define PE_SIGNATURE 0x00004550
+#define PE_32BIT_SIGNATURE 0x10B
+#define PE_64BIT_SIGNATURE 0x20B
+#define PE_NUM_DIRECTORY_ENTRIES 16
+#define PE_SECTION_UNINITIALIZED_DATA 0x00000080
+#define	PE_IMAGE_DIRECTORY_ENTRY_RESOURCE 2
+#define PE_IMAGE_RT_ICON 3
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	MS-DOS header found at the beggining in a PE format file.
+	 */
+	struct MSDOSHeader
+	{
+		UINT16 signature;
+		UINT16 lastSize;
+		UINT16 numBlocks;
+		UINT16 numReloc;
+		UINT16 hdrSize;
+		UINT16 minAlloc;
+		UINT16 maxAlloc;
+		UINT16 ss;
+		UINT16 sp;
+		UINT16 checksum;
+		UINT16 ip;
+		UINT16 cs;
+		UINT16 relocPos;
+		UINT16 numOverlay;
+		UINT16 reserved1[4];
+		UINT16 oemId;
+		UINT16 oemInfo;
+		UINT16 reserved2[10];
+		UINT32 lfanew;
+	};
+
+	/**
+	 * @brief	COFF header found in a PE format file.
+	 */
+	struct COFFHeader
+	{
+		UINT16 machine;
+		UINT16 numSections;
+		UINT32 timeDateStamp;
+		UINT32 ptrSymbolTable;
+		UINT32 numSymbols;
+		UINT16 sizeOptHeader;
+		UINT16 characteristics;
+	};
+
+	/**
+	 * @brief	Contains address and size of data areas in a PE image.
+	 */
+	struct PEDataDirectory
+	{
+		UINT32 virtualAddress;
+		UINT32 size;
+	};
+
+	/**
+	 * @brief	Optional header in a 32-bit PE format file.
+	 */
+	struct PEOptionalHeader32
+	{
+		UINT16 signature;
+		UINT8 majorLinkerVersion;
+		UINT8 minorLinkerVersion;
+		UINT32 sizeCode;
+		UINT32 sizeInitializedData;
+		UINT32 sizeUninitializedData;
+		UINT32 addressEntryPoint;
+		UINT32 baseCode;
+		UINT32 baseData;
+		UINT32 baseImage;
+		UINT32 alignmentSection;
+		UINT32 alignmentFile;
+		UINT16 majorOSVersion;
+		UINT16 minorOSVersion;
+		UINT16 majorImageVersion;
+		UINT16 minorImageVersion;
+		UINT16 majorSubsystemVersion;
+		UINT16 minorSubsystemVersion;
+		UINT32 reserved;
+		UINT32 sizeImage;
+		UINT32 sizeHeaders;
+		UINT32 checksum;
+		UINT16 subsystem;
+		UINT16 characteristics;
+		UINT32 sizeStackReserve;
+		UINT32 sizeStackCommit;
+		UINT32 sizeHeapReserve;
+		UINT32 sizeHeapCommit;
+		UINT32 loaderFlags;
+		UINT32 NumRvaAndSizes;
+		PEDataDirectory dataDirectory[16];
+	};
+
+	/**
+	 * @brief	Optional header in a 64-bit PE format file.
+	 */
+	struct PEOptionalHeader64
+	{
+		UINT16 signature;
+		UINT8 majorLinkerVersion;
+		UINT8 minorLinkerVersion;
+		UINT32 sizeCode;
+		UINT32 sizeInitializedData;
+		UINT32 sizeUninitializedData;
+		UINT32 addressEntryPoint;
+		UINT32 baseCode;
+		UINT64 baseImage;
+		UINT32 alignmentSection;
+		UINT32 alignmentFile;
+		UINT16 majorOSVersion;
+		UINT16 minorOSVersion;
+		UINT16 majorImageVersion;
+		UINT16 minorImageVersion;
+		UINT16 majorSubsystemVersion;
+		UINT16 minorSubsystemVersion;
+		UINT32 reserved;
+		UINT32 sizeImage;
+		UINT32 sizeHeaders;
+		UINT32 checksum;
+		UINT16 subsystem;
+		UINT16 characteristics;
+		UINT64 sizeStackReserve;
+		UINT64 sizeStackCommit;
+		UINT64 sizeHeapReserve;
+		UINT64 sizeHeapCommit;
+		UINT32 loaderFlags;
+		UINT32 NumRvaAndSizes;
+		PEDataDirectory dataDirectory[16];
+	};
+
+	/**
+	 * @brief	A section header in a PE format file.
+	 */
+	struct PESectionHeader
+	{
+		char name[8];
+		UINT32 virtualSize;
+		UINT32 relativeVirtualAddress;
+		UINT32 physicalSize;
+		UINT32 physicalAddress;
+		UINT8 deprecated[12];
+		UINT32 flags;
+	};
+
+	/**
+	 * @brief	A resource table header within a .rsrc section in a PE format file.
+	 */
+	struct PEImageResourceDirectory
+	{
+		UINT32 flags;
+		UINT32 timeDateStamp;
+		UINT16 majorVersion;
+		UINT16 minorVersion;
+		UINT16 numNamedEntries;
+		UINT16 numIdEntries;
+	};
+
+	/**
+	 * @brief	A single entry in a resource table within a .rsrc section in a PE format file.
+	 */
+	struct PEImageResourceEntry
+	{
+		UINT32 type;
+		UINT32 offsetDirectory : 31;
+		UINT32 isDirectory : 1;
+	};
+
+	/**
+	 * @brief	An entry in a resource table referencing resource data. Found within a 
+	 * 			.rsrc section in a PE format file.
+	 */
+	struct PEImageResourceEntryData
+	{
+		UINT32 offsetData;
+		UINT32 size;
+		UINT32 codePage;
+		UINT32 resourceHandle;
+	};
+
+	/**
+	 * @brief	Header used in icon file format.
+	 */
+	struct IconHeader
+	{
+		UINT32 size;
+		INT32 width;
+		INT32 height;
+		UINT16 planes;
+		UINT16 bitCount;
+		UINT32 compression;
+		UINT32 sizeImage;
+		INT32 xPelsPerMeter;
+		INT32 yPelsPerMeter;
+		UINT32 clrUsed;
+		UINT32 clrImportant;
+	};
+
+	void IconUtility::updateIconExe(const Path& path, const Map<UINT32, PixelDataPtr>& pixelsPerSize)
+	{
+		// A PE file is structured as such:
+		//  - MSDOS Header
+		//  - PE Signature
+		//  - COFF Header
+		//  - PE Optional Header
+		//  - One or multiple sections
+		//   - .code
+		//   - .data
+		//   - ...
+		//   - .rsrc
+		//    - icon/cursor/etc data
+
+		std::fstream stream;
+		stream.open(path.toString().c_str(), std::ios::in | std::ios::out | std::ios::binary);
+
+		// First check magic number to ensure file is even an executable
+		UINT16 magicNum;
+		stream.read((char*)&magicNum, sizeof(magicNum));
+		if (magicNum != MSDOS_SIGNATURE)
+			BS_EXCEPT(InvalidStateException, "Provided file is not a valid executable.");
+
+		// Read the MSDOS header and skip over it
+		stream.seekg(0);
+
+		MSDOSHeader msdosHeader;
+		stream.read((char*)&msdosHeader, sizeof(MSDOSHeader));
+
+		// Read PE signature
+		stream.seekg(msdosHeader.lfanew);
+
+		UINT32 peSignature;
+		stream.read((char*)&peSignature, sizeof(peSignature));
+
+		if (peSignature != PE_SIGNATURE)
+			BS_EXCEPT(InvalidStateException, "Provided file is not in PE format.");
+
+		// Read COFF header
+		COFFHeader coffHeader;
+		stream.read((char*)&coffHeader, sizeof(COFFHeader));
+
+		if (coffHeader.sizeOptHeader == 0) // .exe files always have an optional header
+			BS_EXCEPT(InvalidStateException, "Provided file is not a valid executable.");
+
+		UINT32 numSectionHeaders = coffHeader.numSections;
+
+		// Read optional header
+		auto optionalHeaderPos = stream.tellg();
+
+		UINT16 optionalHeaderSignature;
+		stream.read((char*)&optionalHeaderSignature, sizeof(optionalHeaderSignature));
+
+		PEDataDirectory* dataDirectory = nullptr;
+		stream.seekg(optionalHeaderPos);
+		if (optionalHeaderSignature == PE_32BIT_SIGNATURE)
+		{
+			PEOptionalHeader32 optionalHeader;
+			stream.read((char*)&optionalHeader, sizeof(optionalHeader));
+
+			dataDirectory = optionalHeader.dataDirectory + PE_IMAGE_DIRECTORY_ENTRY_RESOURCE;
+		}
+		else if (optionalHeaderSignature == PE_64BIT_SIGNATURE)
+		{
+			PEOptionalHeader64 optionalHeader;
+			stream.read((char*)&optionalHeader, sizeof(optionalHeader));
+
+			dataDirectory = optionalHeader.dataDirectory + PE_IMAGE_DIRECTORY_ENTRY_RESOURCE;
+		}
+		else
+			BS_EXCEPT(InvalidStateException, "Unrecognized PE format.");
+
+		// Read section headers
+		auto sectionHeaderPos = optionalHeaderPos + (std::ifstream::pos_type)coffHeader.sizeOptHeader;
+		stream.seekg(sectionHeaderPos);
+
+		PESectionHeader* sectionHeaders = bs_stack_alloc<PESectionHeader>(numSectionHeaders);
+		stream.read((char*)sectionHeaders, sizeof(PESectionHeader) * numSectionHeaders);
+
+		// Look for .rsrc section header
+		std::function<void(PEImageResourceDirectory*, PEImageResourceDirectory*, UINT8*, UINT32)> setIconData =
+			[&](PEImageResourceDirectory* base, PEImageResourceDirectory* current, UINT8* imageData, UINT32 sectionAddress)
+		{
+			UINT32 numEntries = current->numIdEntries; // Not supporting name entries
+			PEImageResourceEntry* entries = (PEImageResourceEntry*)(current + 1);
+
+			for (UINT32 i = 0; i < numEntries; i++)
+			{
+				// Only at root does the type identify resource type
+				if (base == current && entries[i].type != PE_IMAGE_RT_ICON)
+					continue;
+
+				if (entries[i].isDirectory)
+				{
+					PEImageResourceDirectory* child = (PEImageResourceDirectory*)(((UINT8*)base) + entries[i].offsetDirectory);
+					setIconData(base, child, imageData, sectionAddress);
+				}
+				else
+				{
+					PEImageResourceEntryData* data = (PEImageResourceEntryData*)(((UINT8*)base) + entries[i].offsetDirectory);
+
+					UINT8* iconData = imageData + (data->offsetData - sectionAddress);
+					updateIconData(iconData, pixelsPerSize);
+				}
+			}
+		};
+
+		for (UINT32 i = 0; i < numSectionHeaders; i++)
+		{
+			if (sectionHeaders[i].flags & PE_SECTION_UNINITIALIZED_DATA)
+				continue;
+
+			if (strcmp(sectionHeaders[i].name, ".rsrc") == 0)
+			{
+				UINT32 imageSize = sectionHeaders[i].physicalSize;
+				UINT8* imageData = (UINT8*)bs_stack_alloc(imageSize);
+
+				stream.seekg(sectionHeaders[i].physicalAddress);
+				stream.read((char*)imageData, imageSize);
+
+				UINT32 resourceDirOffset = dataDirectory->virtualAddress - sectionHeaders[i].relativeVirtualAddress;
+				PEImageResourceDirectory* resourceDirectory = (PEImageResourceDirectory*)&imageData[resourceDirOffset];
+
+				setIconData(resourceDirectory, resourceDirectory, imageData, sectionHeaders[i].relativeVirtualAddress);
+				stream.seekp(sectionHeaders[i].physicalAddress);
+				stream.write((char*)imageData, imageSize);
+
+				bs_stack_free(imageData);
+			}
+		}
+
+		bs_stack_free(sectionHeaders);
+		stream.close();
+	}
+
+	void IconUtility::updateIconData(UINT8* iconData, const Map<UINT32, PixelDataPtr>& pixelsPerSize)
+	{
+		IconHeader* iconHeader = (IconHeader*)iconData;
+
+		if (iconHeader->size != sizeof(IconHeader) || iconHeader->compression != 0
+			|| iconHeader->planes != 1 || iconHeader->bitCount != 32)
+		{
+			// Unsupported format
+			return;
+		}
+
+		UINT8* iconPixels = iconData + sizeof(IconHeader);
+		UINT32 width = iconHeader->width;
+		UINT32 height = iconHeader->height / 2;
+
+		auto iterFind = pixelsPerSize.find(width);
+		if (iterFind == pixelsPerSize.end() || iterFind->second->getWidth() != width
+			|| iterFind->second->getHeight() != height)
+		{
+			// No icon of this size provided
+			return;
+		}
+
+		// Write colors
+		PixelDataPtr srcPixels = iterFind->second;
+		UINT32* colorData = (UINT32*)iconPixels;
+
+		UINT32 idx = 0;
+		for (INT32 y = (INT32)height - 1; y >= 0; y--)
+		{
+			for (UINT32 x = 0; x < width; x++)
+				colorData[idx++] = srcPixels->getColorAt(x, y).getAsBGRA();
+		}
+
+		// Write AND mask
+		UINT32 colorDataSize = width * height * sizeof(UINT32);
+		UINT8* maskData = iconPixels + colorDataSize;
+
+		UINT32 numPackedPixels = width / 8; // One per bit in byte
+
+		for (INT32 y = (INT32)height - 1; y >= 0; y--)
+		{
+			UINT8 mask = 0;
+			for (UINT32 packedX = 0; packedX < numPackedPixels; packedX++)
+			{
+				for (UINT32 pixelIdx = 0; pixelIdx < 8; pixelIdx++)
+				{
+					UINT32 x = packedX * 8 + pixelIdx;
+					Color color = srcPixels->getColorAt(x, y);
+					if (color.a < 0.25f)
+						mask |= 1 << (7 - pixelIdx);
+				}
+
+				*maskData = mask;
+				maskData++;
+			}
+		}
+	}
+}

+ 2 - 2
BansheeCore/Source/BsTexture.cpp

@@ -416,7 +416,7 @@ namespace BansheeEngine
 	void Texture::createCPUBuffers()
 	{
 		UINT32 numFaces = mProperties.getNumFaces();
-		UINT32 numMips = mProperties.getNumMipmaps();
+		UINT32 numMips = mProperties.getNumMipmaps() + 1;
 
 		UINT32 numSubresources = numFaces * numMips;
 		mCPUSubresourceData.resize(numSubresources);
@@ -427,7 +427,7 @@ namespace BansheeEngine
 			UINT32 curHeight = mProperties.getHeight();
 			UINT32 curDepth = mProperties.getDepth();
 
-			for (UINT32 j = 0; j < mProperties.getNumMipmaps(); j++)
+			for (UINT32 j = 0; j < numMips; j++)
 			{
 				UINT32 subresourceIdx = mProperties.mapToSubresourceIdx(i, j);
 

+ 0 - 366
BansheeEditor/Source/BsEditorApplication.cpp

@@ -46,7 +46,6 @@
 #include "BsMesh.h"
 #include "BsMath.h"
 #include "BsDebug.h"
-#include "../../BansheeFreeImgImporter/Dependencies/Include/FreeImage.h"
 
 namespace BansheeEngine
 {
@@ -232,371 +231,6 @@ namespace BansheeEngine
 		loadPlugin("SBansheeEditor", &mSBansheeEditorPlugin);
 	}
 
-	// DEBUG ONLY
-	
-	struct MSDOSHeader
-	{
-		UINT16 signature;
-		UINT16 lastSize;
-		UINT16 numBlocks;
-		UINT16 numReloc;
-		UINT16 hdrSize;
-		UINT16 minAlloc;
-		UINT16 maxAlloc;
-		UINT16 ss;
-		UINT16 sp;
-		UINT16 checksum;
-		UINT16 ip;
-		UINT16 cs;
-		UINT16 relocPos;
-		UINT16 numOverlay;
-		UINT16 reserved1[4];
-		UINT16 oemId;
-		UINT16 oemInfo;
-		UINT16 reserved2[10];
-		UINT32 lfanew;
-	};
-
-	struct COFFHeader
-	{
-		UINT16 machine;
-		UINT16 numSections;
-		UINT32 timeDateStamp;
-		UINT32 ptrSymbolTable;
-		UINT32 numSymbols;
-		UINT16 sizeOptHeader;
-		UINT16 characteristics;
-	};
-
-	struct PEDataDirectory
-	{
-		UINT32 virtualAddress;
-		UINT32 size;
-	};
-
-	struct PEOptionalHeader32
-	{
-		UINT16 signature; 
-		UINT8 majorLinkerVersion;
-		UINT8 minorLinkerVersion;
-		UINT32 sizeCode;
-		UINT32 sizeInitializedData;
-		UINT32 sizeUninitializedData;
-		UINT32 addressEntryPoint;
-		UINT32 baseCode;
-		UINT32 baseData;
-		UINT32 baseImage;
-		UINT32 alignmentSection;
-		UINT32 alignmentFile;
-		UINT16 majorOSVersion;
-		UINT16 minorOSVersion;
-		UINT16 majorImageVersion;
-		UINT16 minorImageVersion;
-		UINT16 majorSubsystemVersion;
-		UINT16 minorSubsystemVersion;
-		UINT32 reserved;
-		UINT32 sizeImage;
-		UINT32 sizeHeaders;
-		UINT32 checksum;
-		UINT16 subsystem;
-		UINT16 characteristics;
-		UINT32 sizeStackReserve;
-		UINT32 sizeStackCommit;
-		UINT32 sizeHeapReserve;
-		UINT32 sizeHeapCommit;
-		UINT32 loaderFlags;
-		UINT32 NumRvaAndSizes;
-		PEDataDirectory dataDirectory[16];
-	};
-
-	struct PEOptionalHeader64
-	{
-		UINT16 signature;
-		UINT8 majorLinkerVersion;
-		UINT8 minorLinkerVersion;
-		UINT32 sizeCode;
-		UINT32 sizeInitializedData;
-		UINT32 sizeUninitializedData;
-		UINT32 addressEntryPoint;
-		UINT32 baseCode;
-		UINT64 baseImage;
-		UINT32 alignmentSection;
-		UINT32 alignmentFile;
-		UINT16 majorOSVersion;
-		UINT16 minorOSVersion;
-		UINT16 majorImageVersion;
-		UINT16 minorImageVersion;
-		UINT16 majorSubsystemVersion;
-		UINT16 minorSubsystemVersion;
-		UINT32 reserved;
-		UINT32 sizeImage;
-		UINT32 sizeHeaders;
-		UINT32 checksum;
-		UINT16 subsystem;
-		UINT16 characteristics;
-		UINT64 sizeStackReserve;
-		UINT64 sizeStackCommit;
-		UINT64 sizeHeapReserve;
-		UINT64 sizeHeapCommit;
-		UINT32 loaderFlags;
-		UINT32 NumRvaAndSizes;
-		PEDataDirectory dataDirectory[16];
-	};
-
-	struct PESectionHeader
-	{
-		char name[8];
-		UINT32 virtualSize;
-		UINT32 relativeVirtualAddress;
-		UINT32 physicalSize;
-		UINT32 physicalAddress;
-		UINT8 deprecated[12];
-		UINT32 flags;
-	};
-
-	struct PEImageResourceDirectory 
-	{
-		UINT32 flags;
-		UINT32 timeDateStamp;
-		UINT16 majorVersion;
-		UINT16 minorVersion;
-		UINT16 numNamedEntries;
-		UINT16 numIdEntries;
-	};
-
-	struct PEImageResourceEntryData
-	{
-		UINT32 offsetData;
-		UINT32 size;
-		UINT32 codePage;
-		UINT32 resourceHandle;
-	};
-
-	struct PEImageResourceEntry
-	{
-		UINT32 offsetName;
-		UINT32 type;
-		UINT32 offsetDirectory : 31;
-		UINT32 isDirectory : 1;
-	};
-
-#define MSDOS_SIGNATURE 0x5A4D
-#define PE_SIGNATURE 0x0000455
-#define PE_32BIT_SIGNATURE 0x10B
-#define PE_64BIT_SIGNATURE 0x20B
-#define PE_NUM_DIRECTORY_ENTRIES 16
-#define PE_SECTION_UNINITIALIZED_DATA 0x00000080
-#define	PE_IMAGE_DIRECTORY_ENTRY_RESOURCE 2
-#define PE_IMAGE_RT_ICON 3
-
-	struct IconHeader
-	{
-		UINT32 size;
-		INT32 width;
-		INT32 height;
-		UINT16 planes;
-		UINT16 bitCount;
-		UINT32 compression;
-		UINT32 sizeImage;
-		INT32 xPelsPerMeter;
-		INT32 yPelsPerMeter;
-		UINT32 clrUsed;
-		UINT32 clrImportant;
-	};
-
-	void copyPixelsToIcon(const Map<UINT32, PixelDataPtr>& pixelsPerSize, UINT8* iconData)
-	{
-		IconHeader* iconHeader = (IconHeader*)iconData;
-
-		if (iconHeader->size != sizeof(IconHeader) || iconHeader->compression != 0 
-			|| iconHeader->planes != 1 || iconHeader->bitCount != 32)
-		{
-			// Unsupported format
-			return;
-		}
-
-		UINT8* iconPixels = iconData + sizeof(IconHeader);
-		UINT32 width = iconHeader->width;
-		UINT32 height = iconHeader->height / 2;
-
-		auto iterFind = pixelsPerSize.find(width);
-		if (iterFind == pixelsPerSize.end() || iterFind->second->getWidth() != width 
-			|| iterFind->second->getHeight() != height)
-		{
-			// No icon of this size provided
-			return;
-		}
-
-		// Write colors
-		PixelDataPtr srcPixels = iterFind->second;
-		UINT32* colorData = (UINT32*)iconPixels;
-
-		UINT32 idx = 0;
-		for (UINT32 y = 0; y < height; y++)
-		{
-			for (UINT32 x = 0; x < width; x++)
-				colorData[idx] = srcPixels->getColorAt(x, y).getAsBGRA();
-		}
-
-		// Write AND mask
-		UINT32 colorDataSize = width * height * sizeof(UINT32);
-		UINT8* maskData = iconPixels + colorDataSize;
-
-		UINT32 numPackedPixels = width / 8; // One per bit in byte
-
-		for (UINT32 y = 0; y < height; y++)
-		{
-			UINT8 mask = 0;
-			for (UINT32 packedX = 0; packedX < numPackedPixels; packedX++)
-			{
-				for (UINT32 pixelIdx = 0; pixelIdx < 8; pixelIdx++)
-				{
-					UINT32 x = packedX * 8 + pixelIdx;
-					Color color = srcPixels->getColorAt(x, y);
-					if (color.a < 0.25f)
-						mask |= 1 << 7 - pixelIdx;
-				}
-
-				*maskData = mask;
-				maskData++;
-			}
-		}
-	}
-
-	void setIconInEXE(const Path& path, const Map<UINT32, PixelDataPtr>& pixelsPerSize)
-	{
-		// A PE file is structured as such:
-		//  - MSDOS Header
-		//  - PE Signature
-		//  - COFF Header
-		//  - PE Optional Header
-		//  - One or multiple sections
-		//   - .code
-		//   - .data
-		//   - ...
-		//   - .rsrc
-		//    - icon/cursor/etc data
-
-		std::fstream stream;
-		stream.open(path.toString().c_str(), std::ios::in | std::ios::out | std::ios::binary);
-		
-		// First check magic number to ensure file is even an executable
-		UINT16 magicNum;
-		stream.read((char*)&magicNum, sizeof(magicNum));
-		if (magicNum != MSDOS_SIGNATURE)
-			BS_EXCEPT(InvalidStateException, "Provided file is not a valid executable.");
-
-		// Read the MSDOS header and skip over it
-		stream.seekg(0);
-
-		MSDOSHeader msdosHeader;
-		stream.read((char*)&msdosHeader, sizeof(MSDOSHeader));
-
-		// Read PE signature
-		stream.seekg(msdosHeader.lfanew);
-
-		UINT32 peSignature;
-		stream.read((char*)&peSignature, sizeof(peSignature));
-
-		if (peSignature != PE_SIGNATURE)
-			BS_EXCEPT(InvalidStateException, "Provided file is not in PE format.");
-
-		// Read COFF header
-		COFFHeader coffHeader;
-		stream.read((char*)&coffHeader, sizeof(COFFHeader));
-
-		if (coffHeader.sizeOptHeader == 0) // .exe files always have an optional header
-			BS_EXCEPT(InvalidStateException, "Provided file is not a valid executable.");
-
-		UINT32 numSectionHeaders = coffHeader.numSections;
-
-		// Read optional header
-		auto optionalHeaderPos = stream.tellg();
-
-		UINT16 optionalHeaderSignature;
-		stream.read((char*)&optionalHeaderSignature, sizeof(optionalHeaderSignature));
-
-		PEDataDirectory* dataDirectory = nullptr;
-		stream.seekg(optionalHeaderPos);
-		if (optionalHeaderSignature == PE_32BIT_SIGNATURE)
-		{
-			PEOptionalHeader32 optionalHeader;
-			stream.read((char*)&optionalHeader, sizeof(optionalHeader));
-
-			dataDirectory = optionalHeader.dataDirectory;
-		}
-		else if (optionalHeaderSignature == PE_64BIT_SIGNATURE)
-		{
-			PEOptionalHeader64 optionalHeader;
-			stream.read((char*)&optionalHeader, sizeof(optionalHeader));
-
-			dataDirectory = optionalHeader.dataDirectory;
-		}
-		else
-			BS_EXCEPT(InvalidStateException, "Unrecognized PE format.");
-
-		// Read section headers
-		auto sectionHeaderPos = optionalHeaderPos + (std::ifstream::pos_type)coffHeader.sizeOptHeader;
-		stream.seekg(sectionHeaderPos);
-
-		PESectionHeader* sectionHeaders = bs_stack_alloc<PESectionHeader>(numSectionHeaders);
-		stream.read((char*)sectionHeaders, sizeof(PESectionHeader) * numSectionHeaders);
-
-		// Look for .rsrc section header
-		std::function<void(PEImageResourceDirectory*, PEImageResourceDirectory*, UINT8*, UINT32)> setIconData =
-			[&](PEImageResourceDirectory* base, PEImageResourceDirectory* current, UINT8* imageData, UINT32 sectionAddress)
-		{
-			UINT32 numEntries = current->numIdEntries + current->numNamedEntries;
-			PEImageResourceEntry* entries = (PEImageResourceEntry*)(current + 1);
-
-			for (UINT32 i = 0; i < numEntries; i++)
-			{
-				if (entries[i].type != PE_IMAGE_RT_ICON)
-					continue;
-
-				if(entries[i].isDirectory)
-				{
-					PEImageResourceDirectory* child = (PEImageResourceDirectory*)(((UINT8*)base) + entries[i].offsetDirectory);
-					setIconData(base, child, imageData, sectionAddress);
-				}
-				else
-				{
-					PEImageResourceEntryData* data = (PEImageResourceEntryData*)(((UINT8*)base) + entries[i].offsetDirectory);
-
-					UINT8* iconData = imageData + (data->offsetData - sectionAddress);
-					copyPixelsToIcon(pixelsPerSize, iconData);
-				}
-			}
-		};
-
-		for (UINT32 i = 0; i < numSectionHeaders; i++)
-		{
-			if (sectionHeaders[i].flags & PE_SECTION_UNINITIALIZED_DATA)
-				continue;
-
-			if (strcmp(sectionHeaders[i].name, ".rsrc") == 0)
-			{
-				UINT32 imageSize = sectionHeaders[i].physicalSize;
-				UINT8* imageData = (UINT8*)bs_stack_alloc(imageSize);
-
-				stream.seekg(sectionHeaders[i].physicalAddress);
-				stream.read((char*)imageData, imageSize);
-
-				UINT32 resourceDirOffset = dataDirectory->virtualAddress - sectionHeaders[i].relativeVirtualAddress;
-				PEImageResourceDirectory* resourceDirectory = (PEImageResourceDirectory*)&imageData[resourceDirOffset];
-
-				setIconData(resourceDirectory, resourceDirectory, imageData, sectionHeaders[i].relativeVirtualAddress);
-				stream.seekp(sectionHeaders[i].physicalAddress);
-				stream.write((char*)imageData, imageSize);
-
-				bs_stack_free(imageData);
-			}
-		}
-
-		bs_stack_free(sectionHeaders);
-		stream.close();
-	}
-
 	void EditorApplication::startUp(RenderAPIPlugin renderAPI)
 	{
 		CoreApplication::startUp<EditorApplication>(renderAPI);

BIN
BansheeEditorExec/BansheeEditorExec.rc


+ 21 - 0
BansheeEditorExec/BansheeEditorExec.vcxproj

@@ -96,26 +96,32 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <OutDir>..\bin\x86\$(Configuration)\</OutDir>
     <IntDir>.\Intermediate\$(Platform)\$(Configuration)\</IntDir>
+    <TargetName>$(ProjectName)</TargetName>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     <IntDir>.\Intermediate\$(Platform)\$(Configuration)\</IntDir>
     <OutDir>..\bin\$(Platform)\$(Configuration)\</OutDir>
+    <TargetName>$(ProjectName)</TargetName>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     <OutDir>..\bin\x86\$(Configuration)\</OutDir>
     <IntDir>.\Intermediate\$(Platform)\$(Configuration)\</IntDir>
+    <TargetName>$(ProjectName)</TargetName>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
     <IntDir>.\Intermediate\$(Platform)\$(Configuration)\</IntDir>
     <OutDir>..\bin\$(Platform)\$(Configuration)\</OutDir>
+    <TargetName>$(ProjectName)</TargetName>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugRelease|Win32'">
     <OutDir>..\bin\x86\$(Configuration)\</OutDir>
     <IntDir>.\Intermediate\$(Platform)\$(Configuration)\</IntDir>
+    <TargetName>$(ProjectName)</TargetName>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugRelease|x64'">
     <IntDir>.\Intermediate\$(Platform)\$(Configuration)\</IntDir>
     <OutDir>..\bin\$(Platform)\$(Configuration)\</OutDir>
+    <TargetName>$(ProjectName)</TargetName>
   </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <ClCompile>
@@ -132,6 +138,7 @@
       <AdditionalLibraryDirectories>..\lib\x86\$(Configuration);..\Dependencies\lib\x86\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
       <AdditionalDependencies>BansheeCore.lib;BansheeUtility.lib;BansheeEngine.lib;BansheeEditor.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <SubSystem>Windows</SubSystem>
+      <ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
     </Link>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -149,6 +156,7 @@
       <AdditionalLibraryDirectories>..\lib\x64\$(Configuration);..\Dependencies\lib\x64\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
       <AdditionalDependencies>BansheeCore.lib;BansheeUtility.lib;BansheeEngine.lib;BansheeEditor.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <SubSystem>Windows</SubSystem>
+      <ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
     </Link>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -171,6 +179,7 @@
       <AdditionalLibraryDirectories>..\lib\x86\$(Configuration);..\Dependencies\lib\x86\Release</AdditionalLibraryDirectories>
       <AdditionalDependencies>BansheeCore.lib;BansheeUtility.lib;BansheeEngine.lib;BansheeEditor.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <SubSystem>Windows</SubSystem>
+      <ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
     </Link>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -193,6 +202,7 @@
       <AdditionalLibraryDirectories>..\lib\x64\$(Configuration);..\Dependencies\lib\x64\Release</AdditionalLibraryDirectories>
       <AdditionalDependencies>BansheeCore.lib;BansheeUtility.lib;BansheeEngine.lib;BansheeEditor.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <SubSystem>Windows</SubSystem>
+      <ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
     </Link>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugRelease|Win32'">
@@ -215,6 +225,7 @@
       <AdditionalLibraryDirectories>..\lib\x86\$(Configuration);..\Dependencies\lib\x86\DebugRelease</AdditionalLibraryDirectories>
       <AdditionalDependencies>BansheeCore.lib;BansheeUtility.lib;BansheeEngine.lib;BansheeEditor.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <SubSystem>Windows</SubSystem>
+      <ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
     </Link>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugRelease|x64'">
@@ -237,11 +248,21 @@
       <AdditionalLibraryDirectories>..\lib\x64\$(Configuration);..\Dependencies\lib\x64\DebugRelease</AdditionalLibraryDirectories>
       <AdditionalDependencies>BansheeCore.lib;BansheeUtility.lib;BansheeEngine.lib;BansheeEditor.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <SubSystem>Windows</SubSystem>
+      <ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
     <ClCompile Include="BsEditorExec.cpp" />
   </ItemGroup>
+  <ItemGroup>
+    <Image Include="BansheeIcon.ico" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="resource.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="BansheeEditorExec.rc" />
+  </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>

+ 11 - 0
BansheeEditorExec/BansheeEditorExec.vcxproj.filters

@@ -15,4 +15,15 @@
       <Filter>Source Files</Filter>
     </ClCompile>
   </ItemGroup>
+  <ItemGroup>
+    <Image Include="BansheeIcon.ico" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="resource.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="BansheeEditorExec.rc" />
+  </ItemGroup>
 </Project>

BIN
BansheeEditorExec/BansheeIcon.ico


BIN
BansheeEditorExec/resource.h


+ 1 - 1
ExampleProject/Main/Main.cpp

@@ -362,7 +362,7 @@ namespace BansheeEngine
 		rightLayout->addNewElement<GUIFixedSpace>(30);
 
 		// Add a profiler overlay object that is responsible for displaying CPU and GPU profiling GUI
-		profilerOverlay = guiSO->addComponent<ProfilerOverlay>(guiCamera->getViewport());
+		profilerOverlay = guiSO->addComponent<ProfilerOverlay>(guiCamera);
 
 		// Set up video mode list box
 		// First get a list of output devices