| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300 |
- #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 * channels + 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];
- }
- }
|