Colormap conversion tool; from 3DO 32x15bitx8 to 256x24bit

git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@1511 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
avolkov
2005-02-03 07:57:47 +00:00
parent 5eadd60631
commit d47a32435d
6 changed files with 670 additions and 0 deletions
+33
View File
@@ -0,0 +1,33 @@
########################################################################
# This is a GNU makefile - tested on CYGWIN and Linux
#
# You may need to compile or install libpng and/or zlib before
# compiling this.
#
TARGET = ctconv
# These flags are needed to get it to compile with libpngX.dll on CYGWIN
# CYGWINFLAGS = -DPNG_USE_DLL
CYGWINFLAGS =
CC = gcc
CFLAGS = -W -Wall -O0 # -g
LIBS = -L/usr/local/lib -lm
LDFLAGS=
BINS = $(TARGET) $(TARGET).exe
SRCS = ctconv.c
OBJS = ctconv.o
.SUFFIXES: .c .o
.c.o:
$(CC) -c $(CFLAGS) -o $@ $*.c $(CYGWINFLAGS)
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) -o $(TARGET) $(OBJS) $(LIBS) $(LDFLAGS)
clean:
rm -f $(BINS) *.o
+15
View File
@@ -0,0 +1,15 @@
/* Dummy compile-time configuration options
* Only used when compiling in MS VC++ using UQM's getopt.c
*/
#ifndef _CONFIG_H
#define _CONFIG_H
/* Define if words are stored with the most significant byte first */
#undef WORDS_BIGENDIAN
/* Defined if your system has getopt.h */
#undef HAVE_GETOPT_H
#endif /* _CONFIG_H */
+421
View File
@@ -0,0 +1,421 @@
/**
* 3DO SC2 colortab files converter (.ct)
* By Alex Volkov (codepro@usa.net), 20050202
*
* GPL applies
*
**/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <malloc.h>
#ifdef WIN32
# include <getopt.h>
#else
# include <unistd.h>
#endif
#include "ctres.h"
int opt_verbose = 0;
char* opt_inname = 0;
char* opt_outname = 0;
char* opt_actfile = 0;
typedef struct
{
uint32_t size;
uint32_t ccluts;
clut_tab_t* data;
} clut_entry_t;
typedef struct
{
uint32_t size;
pal_tab_t* data;
} pal_entry_t;
int ctabs = 0;
clut_entry_t* clut_entries = 0;
pal_entry_t* pal_entries = 0;
// internals
void verbose(const char* fmt, ...);
void verbose(const char* fmt, ...)
{
va_list args;
if (!opt_verbose)
return;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
}
uint8_t fread_8(FILE *f)
{
return (uint8_t) fgetc(f);
}
uint16_t fread_16_BE(FILE *f)
{
return (fread_8(f) << 8) | fread_8(f);
}
uint32_t fread_32_BE(FILE *f)
{
return (fread_16_BE(f) << 16) | fread_16_BE(f);
}
void fwrite_16_BE(FILE *f, uint16_t val)
{
fputc((val >> 8) & 0xff, f);
fputc(val & 0xff, f);
}
void fwrite_32_BE(FILE *f, uint32_t val)
{
fwrite_16_BE(f, (uint16_t) ((val >> 16) & 0xffff));
fwrite_16_BE(f, (uint16_t) (val & 0xffff));
}
int read_head(FILE* f)
{
uint32_t magic;
int v;
int i;
magic = fread_32_BE(f);
if (magic != CTTAB_MAGIC)
{
verbose("Invalid magic found: 0x%08x\n", magic);
return -10;
}
v = fread_16_BE(f);
if (v != 0)
{
verbose("Do not know what to do with value 0x%04x in the header\n", v);
return -11;
}
ctabs = fread_16_BE(f);
verbose("CLUT tables: %u\n", ctabs);
v = fread_32_BE(f);
if (v != 0)
{
verbose("Do not know what to do with offset 0x%08x in the header\n", v);
return -11;
}
clut_entries = malloc(sizeof(clut_entries[0]) * ctabs);
if (!clut_entries)
{
verbose("Not enough memory to store entries\n");
return -12;
}
memset(clut_entries, 0, sizeof(clut_entries[0]) * ctabs);
for (i = 0; i < ctabs; ++i)
{
clut_entries[i].size = fread_32_BE(f);
}
return 0;
}
int write_head(FILE* f)
{
int i;
fwrite_32_BE(f, CTTAB_MAGIC); // magic
fwrite_16_BE(f, 0); // unknown
fwrite_16_BE(f, (uint16_t)ctabs); // number of tabs
fwrite_32_BE(f, 0); // offset
for (i = 0; i < ctabs; ++i)
{
fwrite_32_BE(f, pal_entries[i].size); // offset
}
return 0;
}
int read_cluts(FILE* f)
{
int i;
verbose("Reading %d entries...\n", ctabs);
for (i = 0; i < ctabs; ++i)
{
uint32_t size = clut_entries[i].size;
clut_tab_t* p;
uint32_t j;
if (!size)
continue;
p = malloc(size);
if (!p)
{
verbose("Not enough memory to store entry %d, needed %u bytes\n", i, clut_entries[i].size);
return -20;
}
p->start_clut = fread_8(f);
if (size > 1)
p->end_clut = fread_8(f);
else
p->end_clut = p->start_clut;
clut_entries[i].ccluts = (size - 2) / sizeof(clut_t);
if (size > 1 && p->end_clut - p->start_clut + 1 != (int)clut_entries[i].ccluts)
{
verbose("Unsupported colortab format or already in new format, entry %d\n", i);
return -20;
}
for (j = 0; j < clut_entries[i].ccluts; ++j)
{
int k;
for (k = 0; k < CLUT_COLORS; ++k)
p->cluts[j][k] = fread_16_BE(f);
}
clut_entries[i].data = p;
}
return 0;
}
int write_pals(FILE *f)
{
int i;
verbose("Writing %d entries...\n", ctabs);
for (i = 0; i < ctabs; ++i)
{
if (!pal_entries[i].size)
continue;
if (1 != fwrite(pal_entries[i].data, pal_entries[i].size, 1, f))
{
verbose("Could not write pal entry %d\n", i);
return -30;
}
}
return 0;
}
int convert_clut(pal_t dst, clut_t src)
{
int i, j, k;
clut_color_t cval;
pal_channel_t r, g, b, rtot, gtot, btot;
for (i = 0; i < CLUT_COLORS; ++i)
{
cval = src[i];
rtot = r = (pal_channel_t)((cval >> 10) & 0x1f); // bits 10-14
gtot = g = (pal_channel_t)((cval >> 5) & 0x1f); // bits 5-9
btot = b = (pal_channel_t)((cval ) & 0x1f); // bits 0-4
for (j = 0; j < CLUT_STEPS; ++j)
{
k = ((j << 5) + i);
dst[k].chan.r = rtot;
rtot += r;
dst[k].chan.g = gtot;
gtot += g;
dst[k].chan.b = btot;
btot += b;
}
}
return 0;
}
int convert_cluts(pal_t* dst, clut_t* src, int cnt)
{
int i;
for (i = 0; i < cnt; ++i)
convert_clut(dst[i], src[i]);
return 0;
}
int convert_clut_tabs()
{
int i;
pal_entries = malloc(sizeof(pal_entries[0]) * ctabs);
if (!pal_entries)
{
verbose("Not enough memory to store entries\n");
return -40;
}
memset(pal_entries, 0, sizeof(pal_entries[0]) * ctabs);
for (i = 0; i < ctabs; ++i)
{
clut_tab_t* pc;
pal_tab_t* pp;
uint32_t size;
uint32_t c;
pc = clut_entries[i].data;
size = clut_entries[i].size;
c = clut_entries[i].ccluts;
if (!size || !pc)
continue;
if (c > 0)
{ // convert colors
pal_entries[i].size = 2 + sizeof(pal_t) * c;
pp = malloc(pal_entries[i].size);
if (!pp)
{
verbose("Not enough memory to store entry %d\n", i);
return -41;
}
convert_cluts(pp->pals, pc->cluts, c);
}
else
{ // just space for start and end indices
pp = malloc(size);
if (!pp)
{
verbose("Not enough memory to store entry %d\n", i);
return -41;
}
}
pp->start_clut = pc->start_clut;
if (size > 1)
pp->end_clut = pc->end_clut;
pal_entries[i].data = pp;
}
return 0;
}
void free_data()
{
int i;
for (i = 0; i < ctabs; ++i)
{
if (clut_entries && clut_entries[i].data)
free(clut_entries[i].data);
if (pal_entries && pal_entries[i].data)
free(pal_entries[i].data);
}
if (clut_entries)
free(clut_entries);
if (pal_entries)
free(pal_entries);
}
void usage()
{
fprintf(stderr, "usage: ctconv [-v] [-o out-file] <ct-file>\n");
fprintf(stderr, "\tconverts 3DO CLUT strtab file to RRGGBB palette strtab\n");
fprintf(stderr, "options:\n");
fprintf(stderr, " -v\t\t : be verbose, explains things no human should know\n");
fprintf(stderr, " -o out-file\t : specifies output file [default: same as input]\n");
}
void parse_arguments(int argc, char *argv[])
{
char ch;
while ((ch = getopt(argc, argv, "?hvo:")) != -1)
{
switch(ch)
{
case 'o':
opt_outname = optarg;
break;
case 'v':
opt_verbose = 1;
break;
case '?':
case 'h':
default:
usage();
exit(EXIT_FAILURE);
}
}
argc -= optind;
argv += optind;
if (argc != 1)
{
usage();
exit(EXIT_FAILURE);
}
opt_inname = argv[0];
}
int main(int argc, char* argv[])
{
FILE *f;
int ret = 0;
parse_arguments(argc, argv);
if (!opt_outname)
opt_outname = opt_inname;
verbose("Output name: %s\n", opt_outname);
f = fopen(opt_inname, "rb");
if (!f)
{
fprintf(stderr, "Cannot open %s\n", opt_inname);
return -1;
}
verbose("Reading file %s\n", opt_inname);
ret = read_head(f);
if (!ret)
ret = read_cluts(f);
fclose(f);
if (!ret)
ret = convert_clut_tabs();
if (!ret)
{
f = fopen(opt_outname, "wb");
if (!f)
{
fprintf(stderr, "Cannot open %s\n", opt_outname);
return -2;
}
verbose("Writing file %s\n", opt_outname);
}
if (!ret)
ret = write_head(f);
if (!ret)
ret = write_pals(f);
fclose(f);
free_data();
return ret;
}
+110
View File
@@ -0,0 +1,110 @@
# Microsoft Developer Studio Project File - Name="ctconv" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=ctconv - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "ctconv.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "ctconv.mak" CFG="ctconv - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "ctconv - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "ctconv - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=xicl6.exe
RSC=rc.exe
!IF "$(CFG)" == "ctconv - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\src\getopt" /I "." /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "PNG_USE_DLL" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=xilink6.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib advapi32.lib shell32.lib libpng10.lib libz.lib /nologo /subsystem:console /machine:I386
!ELSEIF "$(CFG)" == "ctconv - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /MD /W3 /Gm /GX /ZI /Od /I "..\..\src\getopt" /I "." /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "PNG_USE_DLL" /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=xilink6.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib advapi32.lib shell32.lib libpng10.lib libz.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "ctconv - Win32 Release"
# Name "ctconv - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\config.h
# End Source File
# Begin Source File
SOURCE=.\ctconv.c
# End Source File
# Begin Source File
SOURCE=..\..\src\getopt\getopt.c
# End Source File
# Begin Source File
SOURCE=..\..\src\getopt\getopt.h
# End Source File
# Begin Source File
SOURCE=.\strres.h
# End Source File
# End Group
# End Target
# End Project
+29
View File
@@ -0,0 +1,29 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "ctconv"=.\ctconv.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################
+62
View File
@@ -0,0 +1,62 @@
#include <stdint.h>
#if defined(_MSC_VER)
# define PACKED
# pragma pack(push, 1)
#elif defined(__GNUC__)
# define PACKED __attribute__ ((packed))
#endif
/* string res structures from unstr.h */
#define CTTAB_MAGIC 0xffffffff
typedef struct
{
uint32_t PACKED magic;
uint16_t PACKED unknown1; // always 0
uint16_t PACKED num_entries;
uint32_t PACKED offset; // should always be 0
uint32_t PACKED entry_size[1]; // 1 or more entry sizes
} cttab_header_t;
#define CLUT_COLORS 0x20
#define CLUT_STEPS 8
typedef uint16_t clut_color_t;
typedef clut_color_t clut_t[CLUT_COLORS];
typedef struct
{
uint8_t PACKED start_clut;
uint8_t PACKED end_clut; // inclusive
clut_t PACKED cluts[1]; // 0 or more cluts
} clut_tab_t;
#define PAL_COLORS 0x100
#define PAL_CHANNELS 3
typedef uint8_t pal_channel_t;
typedef union
{
struct {
pal_channel_t r, g, b;
} chan;
pal_channel_t channels[PAL_CHANNELS];
} pal_color_t;
typedef pal_color_t pal_t[PAL_COLORS];
typedef struct
{
uint8_t PACKED start_clut;
uint8_t PACKED end_clut; // inclusive
pal_t PACKED pals[1]; // 0 or more pals
} pal_tab_t;
#if defined(_MSC_VER)
# pragma pack(pop)
#endif
#undef PACKED