Daniele Bartolini před 13 roky
rodič
revize
60ea2ed777
1 změnil soubory, kde provedl 300 přidání a 0 odebrání
  1. 300 0
      tools/resource-compilers/tga-compiler.cpp

+ 300 - 0
tools/resource-compilers/tga-compiler.cpp

@@ -0,0 +1,300 @@
+#include <stdio.h>
+#include "Filesystem.h"
+#include "Stream.h"
+#include "Path.h"
+#include "String.h"
+#include "Hash.h"
+#include "Resource.h"
+#include "ResourceArchive.h"
+#include "FileStream.h"
+#include "Pixel.h"
+#include "TextureResource.h"
+#include <cstring>
+
+using namespace crown;
+
+struct TGAHeader
+{
+
+	char		id_length;			// 00h  Size of Image ID field
+	char		color_map_type;		// 01h  Color map type
+	char		image_type;			// 02h  Image type code
+	char		c_map_spec[5];		// 03h  Color map origin 05h Color map length 07h Depth of color map entries
+	uint16_t	x_offset;			// 08h  X origin of image
+	uint16_t	y_offset;			// 0Ah  Y origin of image
+	uint16_t	width;				// 0Ch  Width of image
+	uint16_t	height;				// 0Eh  Height of image
+	char		pixel_depth;     	// 10h  Image pixel size
+	char		image_descriptor;	// 11h  Image descriptor byte
+};
+
+void load_uncompressed(void* dest, Stream* stream, uint32_t width, uint32_t height, uint32_t channels);
+void load_compressed(void* dest, Stream* stream, uint32_t width, uint32_t height, uint32_t channels);
+void swap_red_blue(uint8_t* data, uint64_t size, uint32_t channels);
+
+/// TGA compiler for "tga" resource type
+/// TODO: Explain supported formats, usage etc.
+int main(int argc, char** argv)
+{
+	if (argc != 4)
+	{
+		printf("Usage: %s /path/to/resources /path/to/compiled resource.tga\n", argv[0]);
+		return -1;
+	}
+
+	Filesystem fs_root(argv[1]);
+	Filesystem fs_dest(argv[2]);
+	
+	const char* resource = argv[3];
+	
+	if (!fs_root.exists(resource))
+	{
+		printf("Fatal: resource %s does not exists. Aborting.\n", resource);
+		return -1;
+	}
+	
+	char resource_basename[256];
+	char resource_extension[256];
+	
+	path::basename(resource, resource_basename, 256);
+	path::extension(resource, resource_extension, 256);
+	
+	printf("Resource basename  : %s\n", resource_basename);
+	printf("Resource extension : %s\n", resource_extension);
+	
+	uint32_t resource_basename_hash = hash::fnv1a_32(resource_basename, string::strlen(resource_basename));
+	uint32_t resource_extension_hash = hash::fnv1a_32(resource_extension, string::strlen(resource_extension));
+	
+	printf("Resource basename  (hash) : %X\n", resource_basename_hash);
+	printf("Resource extension (hash) : %X\n", resource_extension_hash);
+
+	FileStream* src_file = (FileStream*)fs_root.open(resource, SOM_READ);
+	
+	//-------------------------------------------------------------------------
+	// Read TGA Header
+	//-------------------------------------------------------------------------
+	
+	// The TGA header used throughout the code
+	TGAHeader header;
+	memset(&header, 0, sizeof(TGAHeader));
+	
+	// Read the header
+	src_file->read(&header, sizeof(TGAHeader));
+
+	// Skip TGA ID
+	src_file->skip(header.id_length);
+
+	// Pixel format currently unknown
+	PixelFormat format = PF_UNKNOWN;
+
+	// Compute color channels	
+	uint32_t channels = header.pixel_depth / 8;
+	
+	// Compute image size
+	uint64_t image_size = header.width * header.height;
+	
+	uint8_t* image_data = NULL;
+
+	// Select the appropriate pixel format and allocate resource data based on tga size and channels
+	switch (channels)
+	{
+		case 2:
+		case 3:
+		{
+			format = PF_RGB_8;
+			image_data = new uint8_t[(uint32_t)(image_size * 3)];
+			
+			break;
+		}
+		case 4:
+		{
+			format = PF_RGBA_8;
+			image_data = new uint8_t[(uint32_t)(image_size * channels)];
+			
+			break;
+		}
+		default:
+		{
+			printf("Fatal: Unable to determine TGA channels. Aborting.\n");
+			return -1;
+		}
+	}
+	
+	printf("Debug: w = %d, h = %d, channels = %d\n", header.width, header.height, channels);
+
+	// Determine image type (compressed/uncompressed) and call proper function to load TGA
+	switch (header.image_type)
+	{
+		case 0:
+		{
+			printf("Fatal: The resource does not contain image data. Aborting.");
+			return -1;
+		}
+		case 2:
+		{
+			printf("Debug: loading uncompressed...\n");
+			load_uncompressed(image_data, src_file, header.width, header.height, channels);
+			break;
+		}
+
+		case 10:
+		{
+			printf("Debug: loading compressed...\n");
+			load_compressed(image_data, src_file, header.width, header.height, channels);
+			break;
+		}
+
+		default:
+		{
+			printf("Fatal: Image type not supported. Aborting.");
+			return -1;
+		}
+	}
+
+	// FIXME Fixed options for now until proper settings management implemented
+	TextureMode		mode = TM_MODULATE;
+	TextureFilter	filter = TF_BILINEAR;
+	TextureWrap		wrap = TW_REPEAT;
+	
+	// Open output file
+	FileStream* dest_file = (FileStream*)fs_dest.open(resource, SOM_WRITE);
+	
+	ArchiveEntry archive_entry;
+	archive_entry.name = resource_basename_hash;
+	archive_entry.type = resource_extension_hash;
+	archive_entry.offset = sizeof(ArchiveEntry);
+	archive_entry.size = image_size + sizeof(PixelFormat) + sizeof(uint16_t) * 2 +
+							sizeof(TextureMode) + sizeof(TextureFilter) + sizeof(TextureWrap);
+							
+	// Write out the archive entry
+	dest_file->write(&archive_entry, sizeof(ArchiveEntry));
+
+	// Write out the data
+	dest_file->write(&format, sizeof(PixelFormat));
+	dest_file->write(&header.width, sizeof(uint16_t));
+	dest_file->write(&header.height, sizeof(uint16_t));
+	
+	dest_file->write(&mode, sizeof(TextureMode));
+	dest_file->write(&filter, sizeof(TextureFilter));
+	dest_file->write(&wrap, sizeof(TextureWrap));
+	
+	dest_file->write(image_data, image_size * channels);
+	
+	// Done, free the resources and exit
+	if (image_data != NULL)
+	{
+		delete[] image_data;
+	}
+
+	return 0;
+}
+
+//-----------------------------------------------------------------------------
+void load_uncompressed(void* dest, Stream* stream, uint32_t width, uint32_t height, uint32_t channels)
+{
+	uint64_t size = width * height;
+	
+	uint8_t* data = (uint8_t*)dest;
+
+	if (channels == 2)
+	{
+		int32_t j = 0;
+
+		for (uint64_t i = 0; i < size * channels; i++)
+		{
+			uint16_t pixel_data;
+			
+			stream->read(&pixel_data, sizeof(pixel_data));
+			
+			data[j + 0] = (pixel_data & 0x7c) >> 10;
+			data[j + 1] = (pixel_data & 0x3e) >> 5;
+			data[j + 2] = (pixel_data & 0x1f);
+			
+			j += 3;
+		}
+	}
+	else
+	{
+		stream->read(data, (size_t)(size * channels));
+
+		swap_red_blue(data, size * channels, channels);
+	}
+}
+
+//-----------------------------------------------------------------------------
+void load_compressed(void* dest, Stream* stream, uint32_t width, uint32_t height, uint32_t channels)
+{
+	uint8_t rle_id = 0;
+	uint32_t i = 0;
+	uint32_t colors_read = 0;
+	uint64_t size = width * height;
+	
+	uint8_t* data = (uint8_t*)dest;
+
+	uint8_t* colors = new uint8_t[channels];
+
+	while (i < size)
+	{
+		stream->read(&rle_id, sizeof(uint8_t));
+
+		// If MSB == 1
+		if (rle_id & 0x80)
+		{
+			rle_id -= 127;
+			
+			stream->read(colors, channels);
+
+			while (rle_id)
+			{
+				data[colors_read + 0] = colors[2];
+				data[colors_read + 1] = colors[1];
+				data[colors_read + 2] = colors[0];
+
+				if (channels == 4)
+				{
+					data[colors_read + 3] = colors[3];
+				}
+
+				rle_id--;
+				colors_read += channels;
+				i++;
+			}
+		}
+		else
+		{
+			rle_id++;
+
+			while (rle_id)
+			{
+				stream->read(colors, channels);
+				
+				data[colors_read + 0] = colors[2];
+				data[colors_read + 1] = colors[1];
+				data[colors_read + 2] = colors[0];
+
+				if (channels == 4)
+				{
+					data[colors_read + 3] = colors[3];
+				}
+
+				rle_id--;
+				colors_read += channels;
+				i++;
+			}
+		}
+	}
+
+	delete[] colors;
+}
+
+//-----------------------------------------------------------------------------
+void swap_red_blue(uint8_t* data, uint64_t size, uint32_t channels)
+{
+	for (uint64_t i = 0; i < size; i += channels)
+	{
+		data[i] ^= data[i+2];
+		data[i+2] ^= data[i];
+		data[i] ^= data[i+2];
+	}
+}
+