From 952c5c128f9efaea89d41d882c4ea3ade7df4591 Mon Sep 17 00:00:00 2001 From: zakk Date: Fri, 26 Aug 2005 04:48:05 +0000 Subject: Itsa me, quake3io! git-svn-id: svn://svn.icculus.org/quake3/trunk@2 edf5b092-35ff-0310-97b2-ce42778d08ea --- q3asm/Makefile | 13 + q3asm/README.Id | 10 + q3asm/cmdlib.c | 1206 ++++++++++++++++++++++++++++++++++++++++++++++++++++ q3asm/cmdlib.h | 160 +++++++ q3asm/lib.txt | 31 ++ q3asm/mathlib.h | 94 ++++ q3asm/notes.txt | 16 + q3asm/ops.txt | 132 ++++++ q3asm/opstrings.h | 175 ++++++++ q3asm/q3asm.c | 1047 +++++++++++++++++++++++++++++++++++++++++++++ q3asm/q3asm.sln | 28 ++ q3asm/q3asm.vcproj | 195 +++++++++ q3asm/qfiles.h | 485 +++++++++++++++++++++ 13 files changed, 3592 insertions(+) create mode 100755 q3asm/Makefile create mode 100755 q3asm/README.Id create mode 100755 q3asm/cmdlib.c create mode 100755 q3asm/cmdlib.h create mode 100755 q3asm/lib.txt create mode 100755 q3asm/mathlib.h create mode 100755 q3asm/notes.txt create mode 100755 q3asm/ops.txt create mode 100755 q3asm/opstrings.h create mode 100755 q3asm/q3asm.c create mode 100755 q3asm/q3asm.sln create mode 100755 q3asm/q3asm.vcproj create mode 100755 q3asm/qfiles.h (limited to 'q3asm') diff --git a/q3asm/Makefile b/q3asm/Makefile new file mode 100755 index 0000000..b53640a --- /dev/null +++ b/q3asm/Makefile @@ -0,0 +1,13 @@ +# yeah, couldn't do more simple really + +CC=gcc +CFLAGS=-g -Wall + +default: q3asm + +q3asm: q3asm.c cmdlib.c + $(CC) $(CFLAGS) -o $@ $^ + +clean: + rm -f q3asm *~ *.o + diff --git a/q3asm/README.Id b/q3asm/README.Id new file mode 100755 index 0000000..30f44b2 --- /dev/null +++ b/q3asm/README.Id @@ -0,0 +1,10 @@ +2002-10-25 Timothee Besset +If you are looking for a faster version of the q3asm tool, try: +http://www.icculus.org/~phaethon/q3/q3asm-turbo/q3asm-turbo.html + +2001-10-31 Timothee Besset +updated from the $/source/q3asm code +modified for portability and use with >= 1.31 mod source release + +the cmdlib.c cmdlib.h mathlib.h qfiles.h have been copied from +$/source/common diff --git a/q3asm/cmdlib.c b/q3asm/cmdlib.c new file mode 100755 index 0000000..630ac57 --- /dev/null +++ b/q3asm/cmdlib.c @@ -0,0 +1,1206 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// cmdlib.c + +#include "cmdlib.h" +#include +#include + +#ifdef WIN32 +#include +#include +#endif + +#ifdef __linux +#include +#endif + +#ifdef NeXT +#include +#endif + +#define BASEDIRNAME "quake" // assumed to have a 2 or 3 following +#define PATHSEPERATOR '/' + +// set these before calling CheckParm +int myargc; +char **myargv; + +char com_token[1024]; +qboolean com_eof; + +qboolean archive; +char archivedir[1024]; + + +/* +=================== +ExpandWildcards + +Mimic unix command line expansion +=================== +*/ +#define MAX_EX_ARGC 1024 +int ex_argc; +char *ex_argv[MAX_EX_ARGC]; +#ifdef _WIN32 +#include "io.h" +void ExpandWildcards( int *argc, char ***argv ) +{ + struct _finddata_t fileinfo; + int handle; + int i; + char filename[1024]; + char filebase[1024]; + char *path; + + ex_argc = 0; + for (i=0 ; i<*argc ; i++) + { + path = (*argv)[i]; + if ( path[0] == '-' + || ( !strstr(path, "*") && !strstr(path, "?") ) ) + { + ex_argv[ex_argc++] = path; + continue; + } + + handle = _findfirst (path, &fileinfo); + if (handle == -1) + return; + + ExtractFilePath (path, filebase); + + do + { + sprintf (filename, "%s%s", filebase, fileinfo.name); + ex_argv[ex_argc++] = copystring (filename); + } while (_findnext( handle, &fileinfo ) != -1); + + _findclose (handle); + } + + *argc = ex_argc; + *argv = ex_argv; +} +#else +void ExpandWildcards (int *argc, char ***argv) +{ +} +#endif + +#ifdef WIN_ERROR +#include +/* +================= +Error + +For abnormal program terminations in windowed apps +================= +*/ +void Error( const char *error, ... ) +{ + va_list argptr; + char text[1024]; + char text2[1024]; + int err; + + err = GetLastError (); + + va_start (argptr,error); + vsprintf (text, error,argptr); + va_end (argptr); + + sprintf (text2, "%s\nGetLastError() = %i", text, err); + MessageBox(NULL, text2, "Error", 0 /* MB_OK */ ); + + exit (1); +} + +#else +/* +================= +Error + +For abnormal program terminations in console apps +================= +*/ +void Error( const char *error, ...) +{ + va_list argptr; + + _printf ("\n************ ERROR ************\n"); + + va_start (argptr,error); + vprintf (error,argptr); + va_end (argptr); + _printf ("\r\n"); + + exit (1); +} +#endif + +// only printf if in verbose mode +qboolean verbose = qfalse; +void qprintf( const char *format, ... ) { + va_list argptr; + + if (!verbose) + return; + + va_start (argptr,format); + vprintf (format,argptr); + va_end (argptr); + +} + +#ifdef WIN32 +HWND hwndOut = NULL; +qboolean lookedForServer = qfalse; +UINT wm_BroadcastCommand = -1; +#endif + +void _printf( const char *format, ... ) { + va_list argptr; + char text[4096]; +#ifdef WIN32 + ATOM a; +#endif + va_start (argptr,format); + vsprintf (text, format, argptr); + va_end (argptr); + + printf(text); + +#ifdef WIN32 + if (!lookedForServer) { + lookedForServer = qtrue; + hwndOut = FindWindow(NULL, "Q3Map Process Server"); + if (hwndOut) { + wm_BroadcastCommand = RegisterWindowMessage( "Q3MPS_BroadcastCommand" ); + } + } + if (hwndOut) { + a = GlobalAddAtom(text); + PostMessage(hwndOut, wm_BroadcastCommand, 0, (LPARAM)a); + } +#endif +} + + +/* + +qdir will hold the path up to the quake directory, including the slash + + f:\quake\ + /raid/quake/ + +gamedir will hold qdir + the game directory (id1, id2, etc) + + */ + +char qdir[1024]; +char gamedir[1024]; +char writedir[1024]; + +void SetQdirFromPath( const char *path ) +{ + char temp[1024]; + const char *c; + const char *sep; + int len, count; + + if (!(path[0] == '/' || path[0] == '\\' || path[1] == ':')) + { // path is partial + Q_getwd (temp); + strcat (temp, path); + path = temp; + } + + // search for "quake2" in path + + len = strlen(BASEDIRNAME); + for (c=path+strlen(path)-1 ; c != path ; c--) + { + int i; + + if (!Q_strncasecmp (c, BASEDIRNAME, len)) + { + // + //strncpy (qdir, path, c+len+2-path); + // the +2 assumes a 2 or 3 following quake which is not the + // case with a retail install + // so we need to add up how much to the next separator + sep = c + len; + count = 1; + while (*sep && *sep != '/' && *sep != '\\') + { + sep++; + count++; + } + strncpy (qdir, path, c+len+count-path); + qprintf ("qdir: %s\n", qdir); + for ( i = 0; i < strlen( qdir ); i++ ) + { + if ( qdir[i] == '\\' ) + qdir[i] = '/'; + } + + c += len+count; + while (*c) + { + if (*c == '/' || *c == '\\') + { + strncpy (gamedir, path, c+1-path); + + for ( i = 0; i < strlen( gamedir ); i++ ) + { + if ( gamedir[i] == '\\' ) + gamedir[i] = '/'; + } + + qprintf ("gamedir: %s\n", gamedir); + + if ( !writedir[0] ) + strcpy( writedir, gamedir ); + else if ( writedir[strlen( writedir )-1] != '/' ) + { + writedir[strlen( writedir )] = '/'; + writedir[strlen( writedir )+1] = 0; + } + + return; + } + c++; + } + Error ("No gamedir in %s", path); + return; + } + } + Error ("SetQdirFromPath: no '%s' in %s", BASEDIRNAME, path); +} + +char *ExpandArg (const char *path) +{ + static char full[1024]; + + if (path[0] != '/' && path[0] != '\\' && path[1] != ':') + { + Q_getwd (full); + strcat (full, path); + } + else + strcpy (full, path); + return full; +} + +char *ExpandPath (const char *path) +{ + static char full[1024]; + if (!qdir) + Error ("ExpandPath called without qdir set"); + if (path[0] == '/' || path[0] == '\\' || path[1] == ':') { + strcpy( full, path ); + return full; + } + sprintf (full, "%s%s", qdir, path); + return full; +} + +char *ExpandGamePath (const char *path) +{ + static char full[1024]; + if (!qdir) + Error ("ExpandGamePath called without qdir set"); + if (path[0] == '/' || path[0] == '\\' || path[1] == ':') { + strcpy( full, path ); + return full; + } + sprintf (full, "%s%s", gamedir, path); + return full; +} + +char *ExpandPathAndArchive (const char *path) +{ + char *expanded; + char archivename[1024]; + + expanded = ExpandPath (path); + + if (archive) + { + sprintf (archivename, "%s/%s", archivedir, path); + QCopyFile (expanded, archivename); + } + return expanded; +} + + +char *copystring(const char *s) +{ + char *b; + b = malloc(strlen(s)+1); + strcpy (b, s); + return b; +} + + + +/* +================ +I_FloatTime +================ +*/ +double I_FloatTime (void) +{ + time_t t; + + time (&t); + + return t; +#if 0 +// more precise, less portable + struct timeval tp; + struct timezone tzp; + static int secbase; + + gettimeofday(&tp, &tzp); + + if (!secbase) + { + secbase = tp.tv_sec; + return tp.tv_usec/1000000.0; + } + + return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0; +#endif +} + +void Q_getwd (char *out) +{ + int i = 0; + +#ifdef WIN32 + _getcwd (out, 256); + strcat (out, "\\"); +#else + getcwd (out, 256); + strcat (out, "/"); +#endif + + while ( out[i] != 0 ) + { + if ( out[i] == '\\' ) + out[i] = '/'; + i++; + } +} + + +void Q_mkdir (const char *path) +{ +#ifdef WIN32 + if (_mkdir (path) != -1) + return; +#else + if (mkdir (path, 0777) != -1) + return; +#endif + if (errno != EEXIST) + Error ("mkdir %s: %s",path, strerror(errno)); +} + +/* +============ +FileTime + +returns -1 if not present +============ +*/ +int FileTime (const char *path) +{ + struct stat buf; + + if (stat (path,&buf) == -1) + return -1; + + return buf.st_mtime; +} + + + +/* +============== +COM_Parse + +Parse a token out of a string +============== +*/ +char *COM_Parse (char *data) +{ + int c; + int len; + + len = 0; + com_token[0] = 0; + + if (!data) + return NULL; + +// skip whitespace +skipwhite: + while ( (c = *data) <= ' ') + { + if (c == 0) + { + com_eof = qtrue; + return NULL; // end of file; + } + data++; + } + +// skip // comments + if (c=='/' && data[1] == '/') + { + while (*data && *data != '\n') + data++; + goto skipwhite; + } + + +// handle quoted strings specially + if (c == '\"') + { + data++; + do + { + c = *data++; + if (c=='\"') + { + com_token[len] = 0; + return data; + } + com_token[len] = c; + len++; + } while (1); + } + +// parse single characters + if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') + { + com_token[len] = c; + len++; + com_token[len] = 0; + return data+1; + } + +// parse a regular word + do + { + com_token[len] = c; + data++; + len++; + c = *data; + if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') + break; + } while (c>32); + + com_token[len] = 0; + return data; +} + + +int Q_strncasecmp (const char *s1, const char *s2, int n) +{ + int c1, c2; + + do + { + c1 = *s1++; + c2 = *s2++; + + if (!n--) + return 0; // strings are equal until end point + + if (c1 != c2) + { + if (c1 >= 'a' && c1 <= 'z') + c1 -= ('a' - 'A'); + if (c2 >= 'a' && c2 <= 'z') + c2 -= ('a' - 'A'); + if (c1 != c2) + return -1; // strings not equal + } + } while (c1); + + return 0; // strings are equal +} + +int Q_stricmp (const char *s1, const char *s2) +{ + return Q_strncasecmp (s1, s2, 99999); +} + + +char *strupr (char *start) +{ + char *in; + in = start; + while (*in) + { + *in = toupper(*in); + in++; + } + return start; +} + +char *strlower (char *start) +{ + char *in; + in = start; + while (*in) + { + *in = tolower(*in); + in++; + } + return start; +} + + +/* +============================================================================= + + MISC FUNCTIONS + +============================================================================= +*/ + + +/* +================= +CheckParm + +Checks for the given parameter in the program's command line arguments +Returns the argument number (1 to argc-1) or 0 if not present +================= +*/ +int CheckParm (const char *check) +{ + int i; + + for (i = 1;i 0) { + nAllocSize += MEM_BLOCKSIZE - nBlock; + } + buffer = malloc (nAllocSize+1); + memset(buffer, 0, nAllocSize+1); + SafeRead (f, buffer, length); + fclose (f); + + *bufferptr = buffer; + return length; +} + + +/* +============== +TryLoadFile + +Allows failure +============== +*/ +int TryLoadFile (const char *filename, void **bufferptr) +{ + FILE *f; + int length; + void *buffer; + + *bufferptr = NULL; + + f = fopen (filename, "rb"); + if (!f) + return -1; + length = Q_filelength (f); + buffer = malloc (length+1); + ((char *)buffer)[length] = 0; + SafeRead (f, buffer, length); + fclose (f); + + *bufferptr = buffer; + return length; +} + + +/* +============== +SaveFile +============== +*/ +void SaveFile (const char *filename, const void *buffer, int count) +{ + FILE *f; + + f = SafeOpenWrite (filename); + SafeWrite (f, buffer, count); + fclose (f); +} + + + +void DefaultExtension (char *path, const char *extension) +{ + char *src; +// +// if path doesnt have a .EXT, append extension +// (extension should include the .) +// + src = path + strlen(path) - 1; + + while (*src != '/' && *src != '\\' && src != path) + { + if (*src == '.') + return; // it has an extension + src--; + } + + strcat (path, extension); +} + + +void DefaultPath (char *path, const char *basepath) +{ + char temp[128]; + + if (path[0] == PATHSEPERATOR) + return; // absolute path location + strcpy (temp,path); + strcpy (path,basepath); + strcat (path,temp); +} + + +void StripFilename (char *path) +{ + int length; + + length = strlen(path)-1; + while (length > 0 && path[length] != PATHSEPERATOR) + length--; + path[length] = 0; +} + +void StripExtension (char *path) +{ + int length; + + length = strlen(path)-1; + while (length > 0 && path[length] != '.') + { + length--; + if (path[length] == '/') + return; // no extension + } + if (length) + path[length] = 0; +} + + +/* +==================== +Extract file parts +==================== +*/ +// FIXME: should include the slash, otherwise +// backing to an empty path will be wrong when appending a slash +void ExtractFilePath (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '\\' && *(src-1) != '/') + src--; + + memcpy (dest, path, src-path); + dest[src-path] = 0; +} + +void ExtractFileBase (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != PATHSEPERATOR) + src--; + + while (*src && *src != '.') + { + *dest++ = *src++; + } + *dest = 0; +} + +void ExtractFileExtension (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a . or the start +// + while (src != path && *(src-1) != '.') + src--; + if (src == path) + { + *dest = 0; // no extension + return; + } + + strcpy (dest,src); +} + + +/* +============== +ParseNum / ParseHex +============== +*/ +int ParseHex (const char *hex) +{ + const char *str; + int num; + + num = 0; + str = hex; + + while (*str) + { + num <<= 4; + if (*str >= '0' && *str <= '9') + num += *str-'0'; + else if (*str >= 'a' && *str <= 'f') + num += 10 + *str-'a'; + else if (*str >= 'A' && *str <= 'F') + num += 10 + *str-'A'; + else + Error ("Bad hex number: %s",hex); + str++; + } + + return num; +} + + +int ParseNum (const char *str) +{ + if (str[0] == '$') + return ParseHex (str+1); + if (str[0] == '0' && str[1] == 'x') + return ParseHex (str+2); + return atol (str); +} + + + +/* +============================================================================ + + BYTE ORDER FUNCTIONS + +============================================================================ +*/ + +#ifdef _SGI_SOURCE +#define __BIG_ENDIAN__ +#endif + +#ifdef __BIG_ENDIAN__ + +short LittleShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short BigShort (short l) +{ + return l; +} + + +int LittleLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int BigLong (int l) +{ + return l; +} + + +float LittleFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float BigFloat (float l) +{ + return l; +} + + +#else + + +short BigShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short LittleShort (short l) +{ + return l; +} + + +int BigLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int LittleLong (int l) +{ + return l; +} + +float BigFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float LittleFloat (float l) +{ + return l; +} + + +#endif + + +//======================================================= + + +// FIXME: byte swap? + +// this is a 16 bit, non-reflected CRC using the polynomial 0x1021 +// and the initial and final xor values shown below... in other words, the +// CCITT standard CRC used by XMODEM + +#define CRC_INIT_VALUE 0xffff +#define CRC_XOR_VALUE 0x0000 + +static unsigned short crctable[256] = +{ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +void CRC_Init(unsigned short *crcvalue) +{ + *crcvalue = CRC_INIT_VALUE; +} + +void CRC_ProcessByte(unsigned short *crcvalue, byte data) +{ + *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data]; +} + +unsigned short CRC_Value(unsigned short crcvalue) +{ + return crcvalue ^ CRC_XOR_VALUE; +} +//============================================================================= + +/* +============ +CreatePath +============ +*/ +void CreatePath (const char *path) +{ + const char *ofs; + char c; + char dir[1024]; + +#ifdef _WIN32 + int olddrive = -1; + + if ( path[1] == ':' ) + { + olddrive = _getdrive(); + _chdrive( toupper( path[0] ) - 'A' + 1 ); + } +#endif + + if (path[1] == ':') + path += 2; + + for (ofs = path+1 ; *ofs ; ofs++) + { + c = *ofs; + if (c == '/' || c == '\\') + { // create the directory + memcpy( dir, path, ofs - path ); + dir[ ofs - path ] = 0; + Q_mkdir( dir ); + } + } + +#ifdef _WIN32 + if ( olddrive != -1 ) + { + _chdrive( olddrive ); + } +#endif +} + + +/* +============ +QCopyFile + + Used to archive source files +============ +*/ +void QCopyFile (const char *from, const char *to) +{ + void *buffer; + int length; + + length = LoadFile (from, &buffer); + CreatePath (to); + SaveFile (to, buffer, length); + free (buffer); +} diff --git a/q3asm/cmdlib.h b/q3asm/cmdlib.h new file mode 100755 index 0000000..b7be51b --- /dev/null +++ b/q3asm/cmdlib.h @@ -0,0 +1,160 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// cmdlib.h + +#ifndef __CMDLIB__ +#define __CMDLIB__ + +#ifdef _WIN32 +#pragma warning(disable : 4244) // MIPS +#pragma warning(disable : 4136) // X86 +#pragma warning(disable : 4051) // ALPHA + +#pragma warning(disable : 4018) // signed/unsigned mismatch +#pragma warning(disable : 4305) // truncate from double to float + +#pragma check_stack(off) + +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 + +#pragma intrinsic( memset, memcpy ) + +#endif + +#ifndef __BYTEBOOL__ +#define __BYTEBOOL__ +typedef enum { qfalse, qtrue } qboolean; +typedef unsigned char byte; +#endif + +#define MAX_OS_PATH 1024 +#define MEM_BLOCKSIZE 4096 + +// the dec offsetof macro doesnt work very well... +#define myoffsetof(type,identifier) ((size_t)&((type *)0)->identifier) + + +// set these before calling CheckParm +extern int myargc; +extern char **myargv; + +char *strupr (char *in); +char *strlower (char *in); +int Q_strncasecmp( const char *s1, const char *s2, int n ); +int Q_stricmp( const char *s1, const char *s2 ); +void Q_getwd( char *out ); + +int Q_filelength (FILE *f); +int FileTime( const char *path ); + +void Q_mkdir( const char *path ); + +extern char qdir[1024]; +extern char gamedir[1024]; +extern char writedir[1024]; +void SetQdirFromPath( const char *path ); +char *ExpandArg( const char *path ); // from cmd line +char *ExpandPath( const char *path ); // from scripts +char *ExpandGamePath (const char *path); +char *ExpandPathAndArchive( const char *path ); + + +double I_FloatTime( void ); + +void Error( const char *error, ... ); +int CheckParm( const char *check ); + +FILE *SafeOpenWrite( const char *filename ); +FILE *SafeOpenRead( const char *filename ); +void SafeRead (FILE *f, void *buffer, int count); +void SafeWrite (FILE *f, const void *buffer, int count); + +int LoadFile( const char *filename, void **bufferptr ); +int LoadFileBlock( const char *filename, void **bufferptr ); +int TryLoadFile( const char *filename, void **bufferptr ); +void SaveFile( const char *filename, const void *buffer, int count ); +qboolean FileExists( const char *filename ); + +void DefaultExtension( char *path, const char *extension ); +void DefaultPath( char *path, const char *basepath ); +void StripFilename( char *path ); +void StripExtension( char *path ); + +void ExtractFilePath( const char *path, char *dest ); +void ExtractFileBase( const char *path, char *dest ); +void ExtractFileExtension( const char *path, char *dest ); + +int ParseNum (const char *str); + +short BigShort (short l); +short LittleShort (short l); +int BigLong (int l); +int LittleLong (int l); +float BigFloat (float l); +float LittleFloat (float l); + + +char *COM_Parse (char *data); + +extern char com_token[1024]; +extern qboolean com_eof; + +char *copystring(const char *s); + + +void CRC_Init(unsigned short *crcvalue); +void CRC_ProcessByte(unsigned short *crcvalue, byte data); +unsigned short CRC_Value(unsigned short crcvalue); + +void CreatePath( const char *path ); +void QCopyFile( const char *from, const char *to ); + +extern qboolean archive; +extern char archivedir[1024]; + + +extern qboolean verbose; +void qprintf( const char *format, ... ); +void _printf( const char *format, ... ); + +void ExpandWildcards( int *argc, char ***argv ); + + +// for compression routines +typedef struct +{ + void *data; + int count, width, height; +} cblock_t; + + +#endif diff --git a/q3asm/lib.txt b/q3asm/lib.txt new file mode 100755 index 0000000..7abf270 --- /dev/null +++ b/q3asm/lib.txt @@ -0,0 +1,31 @@ + +strlen +strcasecmp +tolower +strcat +strncpy +strcmp +strcpy +strchr + +vsprintf + +memcpy +memset +rand + +atoi +atof + +abs + +floor +fabs +tan +atan +sqrt +log +cos +sin +atan2 + diff --git a/q3asm/mathlib.h b/q3asm/mathlib.h new file mode 100755 index 0000000..8034808 --- /dev/null +++ b/q3asm/mathlib.h @@ -0,0 +1,94 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +#ifndef __MATHLIB__ +#define __MATHLIB__ + +// mathlib.h + +#include + +#ifdef DOUBLEVEC_T +typedef double vec_t; +#else +typedef float vec_t; +#endif +typedef vec_t vec2_t[3]; +typedef vec_t vec3_t[3]; +typedef vec_t vec4_t[4]; + +#define SIDE_FRONT 0 +#define SIDE_ON 2 +#define SIDE_BACK 1 +#define SIDE_CROSS -2 + +#define Q_PI 3.14159265358979323846 +#define DEG2RAD( a ) ( ( (a) * Q_PI ) / 180.0F ) +#define RAD2DEG( a ) ( ( (a) * 180.0f ) / Q_PI ) + +extern vec3_t vec3_origin; + +#define EQUAL_EPSILON 0.001 + +// plane types are used to speed some tests +// 0-2 are axial planes +#define PLANE_X 0 +#define PLANE_Y 1 +#define PLANE_Z 2 +#define PLANE_NON_AXIAL 3 + +qboolean VectorCompare( const vec3_t v1, const vec3_t v2 ); + +#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2]) +#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];} +#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];} +#define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];} +#define VectorScale(a,b,c) {c[0]=b*a[0];c[1]=b*a[1];c[2]=b*a[2];} +#define VectorClear(x) {x[0] = x[1] = x[2] = 0;} +#define VectorNegate(x) {x[0]=-x[0];x[1]=-x[1];x[2]=-x[2];} +void Vec10Copy( vec_t *in, vec_t *out ); + +vec_t Q_rint (vec_t in); +vec_t _DotProduct (vec3_t v1, vec3_t v2); +void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out); +void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out); +void _VectorCopy (vec3_t in, vec3_t out); +void _VectorScale (vec3_t v, vec_t scale, vec3_t out); + +double VectorLength( const vec3_t v ); + +void VectorMA( const vec3_t va, double scale, const vec3_t vb, vec3_t vc ); + +void CrossProduct( const vec3_t v1, const vec3_t v2, vec3_t cross ); +vec_t VectorNormalize( const vec3_t in, vec3_t out ); +vec_t ColorNormalize( const vec3_t in, vec3_t out ); +void VectorInverse (vec3_t v); + +void ClearBounds (vec3_t mins, vec3_t maxs); +void AddPointToBounds( const vec3_t v, vec3_t mins, vec3_t maxs ); + +qboolean PlaneFromPoints( vec4_t plane, const vec3_t a, const vec3_t b, const vec3_t c ); + +void NormalToLatLong( const vec3_t normal, byte bytes[2] ); + +int PlaneTypeForNormal (vec3_t normal); + +#endif diff --git a/q3asm/notes.txt b/q3asm/notes.txt new file mode 100755 index 0000000..4a016f0 --- /dev/null +++ b/q3asm/notes.txt @@ -0,0 +1,16 @@ + +don't do any paramter conversion (double to float, etc) + + + +Why? + +Security. +Portability. + +It may be more aproachable. + +can still use regular dlls for development purposes + +lcc +q3asm diff --git a/q3asm/ops.txt b/q3asm/ops.txt new file mode 100755 index 0000000..992e288 --- /dev/null +++ b/q3asm/ops.txt @@ -0,0 +1,132 @@ +CNSTF, +CNSTI, +CNSTP, +CNSTU, + +ARGB, +ARGF, +ARGI, +ARGP, +ARGU, + +ASGNB, +ASGNF, +ASGNI, +ASGNP, +ASGNU, + +INDIRB, +INDIRF, +INDIRI, +INDIRP, +INDIRU, + +CVFF, +CVFI, + +CVIF, +CVII, +CVIU, + +CVPU, + +CVUI, +CVUP, +CVUU, + +NEGF, +NEGI, + +CALLB, +CALLF, +CALLI, +CALLP, +CALLU, +CALLV, + +RETF, +RETI, +RETP, +RETU, +RETV, + +ADDRGP, + +ADDRFP, + +ADDRLP, + +ADDF, +ADDI, +ADDP, +ADDU, + +SUBF, +SUBI, +SUBP, +SUBU, + +LSHI, +LSHU, + +MODI, +MODU, + +RSHI, +RSHU, + +BANDI, +BANDU, + +BCOMI, +BCOMU, + +BORI, +BORU, + +BXORI, +BXORU, + +DIVF, +DIVI, +DIVU, + +MULF, +MULI, +MULU, + +EQF, +EQI, +EQU, + +GEF, +GEI, +GEU, + +GTF, +GTI, +GTU, + +LEF, +LEI, +LEU, + +LTF, +LTI, +LTU, + +NEF, +NEI, +NEU, + +JUMPV, + +LABELV, + +LOADB, +LOADF, +LOADI, +LOADP, +LOADU, + + diff --git a/q3asm/opstrings.h b/q3asm/opstrings.h new file mode 100755 index 0000000..51f2bf3 --- /dev/null +++ b/q3asm/opstrings.h @@ -0,0 +1,175 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +{ "BREAK", OP_BREAK }, + +{ "CNSTF4", OP_CONST }, +{ "CNSTI4", OP_CONST }, +{ "CNSTP4", OP_CONST }, +{ "CNSTU4", OP_CONST }, + +{ "CNSTI2", OP_CONST }, +{ "CNSTU2", OP_CONST }, + +{ "CNSTI1", OP_CONST }, +{ "CNSTU1", OP_CONST }, + +//{ "ARGB", OP_ARG }, +//{ "ARGF", OP_ARG }, +//{ "ARGI", OP_ARG }, +//{ "ARGP", OP_ARG }, +//{ "ARGU", OP_ARG }, + +{ "ASGNB", OP_BLOCK_COPY }, +{ "ASGNF4", OP_STORE4 }, +{ "ASGNI4", OP_STORE4 }, +{ "ASGNP4", OP_STORE4 }, +{ "ASGNU4", OP_STORE4 }, + +{ "ASGNI2", OP_STORE2 }, +{ "ASGNU2", OP_STORE2 }, + +{ "ASGNI1", OP_STORE1 }, +{ "ASGNU1", OP_STORE1 }, + +{ "INDIRB", OP_IGNORE }, // block copy deals with this +{ "INDIRF4", OP_LOAD4 }, +{ "INDIRI4", OP_LOAD4 }, +{ "INDIRP4", OP_LOAD4 }, +{ "INDIRU4", OP_LOAD4 }, + +{ "INDIRI2", OP_LOAD2 }, +{ "INDIRU2", OP_LOAD2 }, + +{ "INDIRI1", OP_LOAD1 }, +{ "INDIRU1", OP_LOAD1 }, + +{ "CVFF4", OP_UNDEF }, +{ "CVFI4", OP_CVFI }, + +{ "CVIF4", OP_CVIF }, +{ "CVII4", OP_SEX8 }, // will be either SEX8 or SEX16 +{ "CVII1", OP_IGNORE }, +{ "CVII2", OP_IGNORE }, +{ "CVIU4", OP_IGNORE }, + +{ "CVPU4", OP_IGNORE }, + +{ "CVUI4", OP_IGNORE }, +{ "CVUP4", OP_IGNORE }, +{ "CVUU4", OP_IGNORE }, + +{ "CVUU1", OP_IGNORE }, + +{ "NEGF4", OP_NEGF }, +{ "NEGI4", OP_NEGI }, + +//{ "CALLB", OP_UNDEF }, +//{ "CALLF", OP_UNDEF }, +//{ "CALLI", OP_UNDEF }, +//{ "CALLP", OP_UNDEF }, +//{ "CALLU", OP_UNDEF }, +//{ "CALLV", OP_CALL }, + +//{ "RETF", OP_UNDEF }, +//{ "RETI", OP_UNDEF }, +//{ "RETP", OP_UNDEF }, +//{ "RETU", OP_UNDEF }, +//{ "RETV", OP_UNDEF }, + +{ "ADDRGP4", OP_CONST }, + +//{ "ADDRFP", OP_PARM }, +//{ "ADDRLP", OP_LOCAL }, + +{ "ADDF4", OP_ADDF }, +{ "ADDI4", OP_ADD }, +{ "ADDP4", OP_ADD }, +{ "ADDP", OP_ADD }, +{ "ADDU4", OP_ADD }, + +{ "SUBF4", OP_SUBF }, +{ "SUBI4", OP_SUB }, +{ "SUBP4", OP_SUB }, +{ "SUBU4", OP_SUB }, + +{ "LSHI4", OP_LSH }, +{ "LSHU4", OP_LSH }, + +{ "MODI4", OP_MODI }, +{ "MODU4", OP_MODU }, + +{ "RSHI4", OP_RSHI }, +{ "RSHU4", OP_RSHU }, + +{ "BANDI4", OP_BAND }, +{ "BANDU4", OP_BAND }, + +{ "BCOMI4", OP_BCOM }, +{ "BCOMU4", OP_BCOM }, + +{ "BORI4", OP_BOR }, +{ "BORU4", OP_BOR }, + +{ "BXORI4", OP_BXOR }, +{ "BXORU4", OP_BXOR }, + +{ "DIVF4", OP_DIVF }, +{ "DIVI4", OP_DIVI }, +{ "DIVU4", OP_DIVU }, + +{ "MULF4", OP_MULF }, +{ "MULI4", OP_MULI }, +{ "MULU4", OP_MULU }, + +{ "EQF4", OP_EQF }, +{ "EQI4", OP_EQ }, +{ "EQU4", OP_EQ }, + +{ "GEF4", OP_GEF }, +{ "GEI4", OP_GEI }, +{ "GEU4", OP_GEU }, + +{ "GTF4", OP_GTF }, +{ "GTI4", OP_GTI }, +{ "GTU4", OP_GTU }, + +{ "LEF4", OP_LEF }, +{ "LEI4", OP_LEI }, +{ "LEU4", OP_LEU }, + +{ "LTF4", OP_LTF }, +{ "LTI4", OP_LTI }, +{ "LTU4", OP_LTU }, + +{ "NEF4", OP_NEF }, +{ "NEI4", OP_NE }, +{ "NEU4", OP_NE }, + +{ "JUMPV", OP_JUMP }, + +{ "LOADB4", OP_UNDEF }, +{ "LOADF4", OP_UNDEF }, +{ "LOADI4", OP_UNDEF }, +{ "LOADP4", OP_UNDEF }, +{ "LOADU4", OP_UNDEF }, + + diff --git a/q3asm/q3asm.c b/q3asm/q3asm.c new file mode 100755 index 0000000..836e427 --- /dev/null +++ b/q3asm/q3asm.c @@ -0,0 +1,1047 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "cmdlib.h" +#include "mathlib.h" +#include "qfiles.h" + +/* MSVC-ism fix. */ +#define atoi(s) strtoul(s,NULL,10) + +char outputFilename[MAX_OS_PATH]; + +// the zero page size is just used for detecting run time faults +#define ZERO_PAGE_SIZE 0 // 256 + +typedef enum { + OP_UNDEF, + + OP_IGNORE, + + OP_BREAK, + + OP_ENTER, + OP_LEAVE, + OP_CALL, + OP_PUSH, + OP_POP, + + OP_CONST, + OP_LOCAL, + + OP_JUMP, + + //------------------- + + OP_EQ, + OP_NE, + + OP_LTI, + OP_LEI, + OP_GTI, + OP_GEI, + + OP_LTU, + OP_LEU, + OP_GTU, + OP_GEU, + + OP_EQF, + OP_NEF, + + OP_LTF, + OP_LEF, + OP_GTF, + OP_GEF, + + //------------------- + + OP_LOAD1, + OP_LOAD2, + OP_LOAD4, + OP_STORE1, + OP_STORE2, + OP_STORE4, // *(stack[top-1]) = stack[yop + OP_ARG, + OP_BLOCK_COPY, + + //------------------- + + OP_SEX8, + OP_SEX16, + + OP_NEGI, + OP_ADD, + OP_SUB, + OP_DIVI, + OP_DIVU, + OP_MODI, + OP_MODU, + OP_MULI, + OP_MULU, + + OP_BAND, + OP_BOR, + OP_BXOR, + OP_BCOM, + + OP_LSH, + OP_RSHI, + OP_RSHU, + + OP_NEGF, + OP_ADDF, + OP_SUBF, + OP_DIVF, + OP_MULF, + + OP_CVIF, + OP_CVFI +} opcode_t; + +typedef struct { + int imageBytes; // after decompression + int entryPoint; + int stackBase; + int stackSize; +} executableHeader_t; + +typedef enum { + CODESEG, + DATASEG, // initialized 32 bit data, will be byte swapped + LITSEG, // strings + BSSSEG, // 0 filled + NUM_SEGMENTS +} segmentName_t; + +#define MAX_IMAGE 0x400000 + +typedef struct { + byte image[MAX_IMAGE]; + int imageUsed; + int segmentBase; // only valid on second pass +} segment_t; + +typedef struct symbol_s { + struct symbol_s *next; + int hash; + segment_t *segment; + char *name; + int value; +} symbol_t; + + +segment_t segment[NUM_SEGMENTS]; +segment_t *currentSegment; + +int passNumber; + +int numSymbols; +int errorCount; + +symbol_t *symbols; +symbol_t *lastSymbol; + + +#define MAX_ASM_FILES 256 +int numAsmFiles; +char *asmFiles[MAX_ASM_FILES]; +char *asmFileNames[MAX_ASM_FILES]; + +int currentFileIndex; +char *currentFileName; +int currentFileLine; + +//int stackSize = 16384; +int stackSize = 0x10000; + +// we need to convert arg and ret instructions to +// stores to the local stack frame, so we need to track the +// characteristics of the current functions stack frame +int currentLocals; // bytes of locals needed by this function +int currentArgs; // bytes of largest argument list called from this function +int currentArgOffset; // byte offset in currentArgs to store next arg, reset each call + +#define MAX_LINE_LENGTH 1024 +char lineBuffer[MAX_LINE_LENGTH]; +int lineParseOffset; +char token[MAX_LINE_LENGTH]; + +int instructionCount; + +typedef struct { + char *name; + int opcode; +} sourceOps_t; + +sourceOps_t sourceOps[] = { +#include "opstrings.h" +}; + +#define NUM_SOURCE_OPS ( sizeof( sourceOps ) / sizeof( sourceOps[0] ) ) + +int opcodesHash[ NUM_SOURCE_OPS ]; + + +/* +============= +HashString +============= +*/ +int HashString( char *s ) { + int v = 0; + + while ( *s ) { + v += *s; + s++; + } + return v; +} + + +/* +============ +CodeError +============ +*/ +void CodeError( char *fmt, ... ) { + va_list argptr; + + errorCount++; + + printf( "%s:%i ", currentFileName, currentFileLine ); + + va_start( argptr,fmt ); + vprintf( fmt,argptr ); + va_end( argptr ); +} + +/* +============ +EmitByte +============ +*/ +void EmitByte( segment_t *seg, int v ) { + if ( seg->imageUsed >= MAX_IMAGE ) { + Error( "MAX_IMAGE" ); + } + seg->image[ seg->imageUsed ] = v; + seg->imageUsed++; +} + +/* +============ +EmitInt +============ +*/ +void EmitInt( segment_t *seg, int v ) { + if ( seg->imageUsed >= MAX_IMAGE - 4) { + Error( "MAX_IMAGE" ); + } + seg->image[ seg->imageUsed ] = v & 255; + seg->image[ seg->imageUsed + 1 ] = ( v >> 8 ) & 255; + seg->image[ seg->imageUsed + 2 ] = ( v >> 16 ) & 255; + seg->image[ seg->imageUsed + 3 ] = ( v >> 24 ) & 255; + seg->imageUsed += 4; +} + +/* +============ +DefineSymbol + +Symbols can only be defined on pass 0 +============ +*/ +void DefineSymbol( char *sym, int value ) { + symbol_t *s, *after; + char expanded[MAX_LINE_LENGTH]; + int hash; + + if ( passNumber == 1 ) { + return; + } + + // TTimo + // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=381 + // as a security, bail out if vmMain entry point is not first + if (!Q_stricmp(sym, "vmMain")) + if (value) + Error( "vmMain must be the first symbol in the qvm (got offset %d)\n", value ); + + // add the file prefix to local symbols to guarantee unique + if ( sym[0] == '$' ) { + sprintf( expanded, "%s_%i", sym, currentFileIndex ); + sym = expanded; + } + + hash = HashString( sym ); + + for ( s = symbols ; s ; s = s->next ) { + if ( hash == s->hash && !strcmp( sym, s->name ) ) { + CodeError( "Multiple definitions for %s\n", sym ); + return; + } + } + + s = malloc( sizeof( *s ) ); + s->name = copystring( sym ); + s->hash = hash; + s->value = value; + s->segment = currentSegment; + + lastSymbol = s; /* for the move-to-lit-segment byteswap hack */ + + // insert it in order + if ( !symbols || s->value < symbols->value ) { + s->next = symbols; + symbols = s; + return; + } + + for ( after = symbols ; after->next && after->next->value < value ; after = after->next ) { + } + s->next = after->next; + after->next = s; +} + + +/* +============ +LookupSymbol + +Symbols can only be evaluated on pass 1 +============ +*/ +int LookupSymbol( char *sym ) { + symbol_t *s; + char expanded[MAX_LINE_LENGTH]; + int hash; + + if ( passNumber == 0 ) { + return 0; + } + + // add the file prefix to local symbols to guarantee unique + if ( sym[0] == '$' ) { + sprintf( expanded, "%s_%i", sym, currentFileIndex ); + sym = expanded; + } + + hash = HashString( sym ); + for ( s = symbols ; s ; s = s->next ) { + if ( hash == s->hash && !strcmp( sym, s->name ) ) { + return s->segment->segmentBase + s->value; + } + } + + CodeError( "ERROR: symbol %s undefined\n", sym ); + passNumber = 0; + DefineSymbol( sym, 0 ); // so more errors aren't printed + passNumber = 1; + return 0; +} + + +/* +============== +ExtractLine + +Extracts the next line from the given text block. +If a full line isn't parsed, returns NULL +Otherwise returns the updated parse pointer +=============== +*/ +char *ExtractLine( char *data ) { + int i; + + currentFileLine++; + lineParseOffset = 0; + token[0] = 0; + + if ( data[0] == 0 ) { + lineBuffer[0] = 0; + return NULL; + } + + for ( i = 0 ; i < MAX_LINE_LENGTH ; i++ ) { + if ( data[i] == 0 || data[i] == '\n' ) { + break; + } + } + if ( i == MAX_LINE_LENGTH ) { + CodeError( "MAX_LINE_LENGTH" ); + return data; + } + memcpy( lineBuffer, data, i ); + lineBuffer[i] = 0; + data += i; + if ( data[0] == '\n' ) { + data++; + } + return data; +} + + +/* +============== +Parse + +Parse a token out of linebuffer +============== +*/ +qboolean Parse( void ) { + int c; + int len; + + len = 0; + token[0] = 0; + + // skip whitespace + while ( lineBuffer[ lineParseOffset ] <= ' ' ) { + if ( lineBuffer[ lineParseOffset ] == 0 ) { + return qfalse; + } + lineParseOffset++; + } + + // skip ; comments + c = lineBuffer[ lineParseOffset ]; + if ( c == ';' ) { + return qfalse; + } + + + // parse a regular word + do { + token[len] = c; + len++; + lineParseOffset++; + c = lineBuffer[ lineParseOffset ]; + } while (c>32); + + token[len] = 0; + return qtrue; +} + + +/* +============== +ParseValue +============== +*/ +int ParseValue( void ) { + Parse(); + return atoi( token ); +} + + +/* +============== +ParseExpression +============== +*/ +int ParseExpression(void) { + int i, j; + char sym[MAX_LINE_LENGTH]; + int v; + + if ( token[0] == '-' ) { + i = 1; + } else { + i = 0; + } + + for ( ; i < MAX_LINE_LENGTH ; i++ ) { + if ( token[i] == '+' || token[i] == '-' || token[i] == 0 ) { + break; + } + } + + memcpy( sym, token, i ); + sym[i] = 0; + + if ( ( sym[0] >= '0' && sym[0] <= '9' ) || sym[0] == '-' ) { + v = atoi( sym ); + } else { + v = LookupSymbol( sym ); + } + + // parse add / subtract offsets + while ( token[i] != 0 ) { + for ( j = i + 1 ; j < MAX_LINE_LENGTH ; j++ ) { + if ( token[j] == '+' || token[j] == '-' || token[j] == 0 ) { + break; + } + } + + memcpy( sym, token+i+1, j-i-1 ); + sym[j-i-1] = 0; + + if ( token[i] == '+' ) { + v += atoi( sym ); + } + if ( token[i] == '-' ) { + v -= atoi( sym ); + } + i = j; + } + + return v; +} + + +/* +============== +HackToSegment + +BIG HACK: I want to put all 32 bit values in the data +segment so they can be byte swapped, and all char data in the lit +segment, but switch jump tables are emited in the lit segment and +initialized strng variables are put in the data segment. + +I can change segments here, but I also need to fixup the +label that was just defined + +Note that the lit segment is read-write in the VM, so strings +aren't read only as in some architectures. +============== +*/ +void HackToSegment( segmentName_t seg ) { + if ( currentSegment == &segment[seg] ) { + return; + } + + currentSegment = &segment[seg]; + if ( passNumber == 0 ) { + lastSymbol->segment = currentSegment; + lastSymbol->value = currentSegment->imageUsed; + } +} + +/* +============== +AssembleLine + +============== +*/ +void AssembleLine( void ) { + int v, v2; + int i; + int hash; + + Parse(); + if ( !token[0] ) { + return; + } + + hash = HashString( token ); + + for ( i = 0 ; i < NUM_SOURCE_OPS ; i++ ) { + if ( hash == opcodesHash[i] && !strcmp( token, sourceOps[i].name ) ) { + int opcode; + int expression; + + if ( sourceOps[i].opcode == OP_UNDEF ) { + CodeError( "Undefined opcode: %s\n", token ); + } + if ( sourceOps[i].opcode == OP_IGNORE ) { + return; // we ignore most conversions + } + + // sign extensions need to check next parm + opcode = sourceOps[i].opcode; + if ( opcode == OP_SEX8 ) { + Parse(); + if ( token[0] == '1' ) { + opcode = OP_SEX8; + } else if ( token[0] == '2' ) { + opcode = OP_SEX16; + } else { + CodeError( "Bad sign extension: %s\n", token ); + return; + } + } + + // check for expression + Parse(); + if ( token[0] && sourceOps[i].opcode != OP_CVIF + && sourceOps[i].opcode != OP_CVFI ) { + expression = ParseExpression(); + + // code like this can generate non-dword block copies: + // auto char buf[2] = " "; + // we are just going to round up. This might conceivably + // be incorrect if other initialized chars follow. + if ( opcode == OP_BLOCK_COPY ) { + expression = ( expression + 3 ) & ~3; + } + + EmitByte( &segment[CODESEG], opcode ); + EmitInt( &segment[CODESEG], expression ); + } else { + EmitByte( &segment[CODESEG], opcode ); + } + + instructionCount++; + return; + } + } + + // call instructions reset currentArgOffset + if ( !strncmp( token, "CALL", 4 ) ) { + EmitByte( &segment[CODESEG], OP_CALL ); + instructionCount++; + currentArgOffset = 0; + return; + } + + // arg is converted to a reversed store + if ( !strncmp( token, "ARG", 3 ) ) { + EmitByte( &segment[CODESEG], OP_ARG ); + instructionCount++; + if ( 8 + currentArgOffset >= 256 ) { + CodeError( "currentArgOffset >= 256" ); + return; + } + EmitByte( &segment[CODESEG], 8 + currentArgOffset ); + currentArgOffset += 4; + return; + } + + // ret just leaves something on the op stack + if ( !strncmp( token, "RET", 3 ) ) { + EmitByte( &segment[CODESEG], OP_LEAVE ); + instructionCount++; + EmitInt( &segment[CODESEG], 8 + currentLocals + currentArgs ); + return; + } + + // pop is needed to discard the return value of + // a function + if ( !strncmp( token, "pop", 3 ) ) { + EmitByte( &segment[CODESEG], OP_POP ); + instructionCount++; + return; + } + + // address of a parameter is converted to OP_LOCAL + if ( !strncmp( token, "ADDRF", 5 ) ) { + instructionCount++; + Parse(); + v = ParseExpression(); + v = 16 + currentArgs + currentLocals + v; + EmitByte( &segment[CODESEG], OP_LOCAL ); + EmitInt( &segment[CODESEG], v ); + return; + } + + // address of a local is converted to OP_LOCAL + if ( !strncmp( token, "ADDRL", 5 ) ) { + instructionCount++; + Parse(); + v = ParseExpression(); + v = 8 + currentArgs + v; + EmitByte( &segment[CODESEG], OP_LOCAL ); + EmitInt( &segment[CODESEG], v ); + return; + } + + if ( !strcmp( token, "proc" ) ) { + char name[1024]; + + Parse(); // function name + strcpy( name, token ); + + DefineSymbol( token, instructionCount ); // segment[CODESEG].imageUsed ); + + currentLocals = ParseValue(); // locals + currentLocals = ( currentLocals + 3 ) & ~3; + currentArgs = ParseValue(); // arg marshalling + currentArgs = ( currentArgs + 3 ) & ~3; + + if ( 8 + currentLocals + currentArgs >= 32767 ) { + CodeError( "Locals > 32k in %s\n", name ); + } + + instructionCount++; + EmitByte( &segment[CODESEG], OP_ENTER ); + EmitInt( &segment[CODESEG], 8 + currentLocals + currentArgs ); + return; + } + if ( !strcmp( token, "endproc" ) ) { + Parse(); // skip the function name + v = ParseValue(); // locals + v2 = ParseValue(); // arg marshalling + + // all functions must leave something on the opstack + instructionCount++; + EmitByte( &segment[CODESEG], OP_PUSH ); + + instructionCount++; + EmitByte( &segment[CODESEG], OP_LEAVE ); + EmitInt( &segment[CODESEG], 8 + currentLocals + currentArgs ); + + return; + } + + + if ( !strcmp( token, "address" ) ) { + Parse(); + v = ParseExpression(); + + HackToSegment( DATASEG ); + EmitInt( currentSegment, v ); + return; + } + if ( !strcmp( token, "export" ) ) { + return; + } + if ( !strcmp( token, "import" ) ) { + return; + } + if ( !strcmp( token, "code" ) ) { + currentSegment = &segment[CODESEG]; + return; + } + if ( !strcmp( token, "bss" ) ) { + currentSegment = &segment[BSSSEG]; + return; + } + if ( !strcmp( token, "data" ) ) { + currentSegment = &segment[DATASEG]; + return; + } + if ( !strcmp( token, "lit" ) ) { + currentSegment = &segment[LITSEG]; + return; + } + if ( !strcmp( token, "line" ) ) { + return; + } + if ( !strcmp( token, "file" ) ) { + return; + } + + if ( !strcmp( token, "equ" ) ) { + char name[1024]; + + Parse(); + strcpy( name, token ); + Parse(); + DefineSymbol( name, atoi(token) ); + return; + } + + if ( !strcmp( token, "align" ) ) { + v = ParseValue(); + currentSegment->imageUsed = (currentSegment->imageUsed + v - 1 ) & ~( v - 1 ); + return; + } + + if ( !strcmp( token, "skip" ) ) { + v = ParseValue(); + currentSegment->imageUsed += v; + return; + } + + if ( !strcmp( token, "byte" ) ) { + v = ParseValue(); + v2 = ParseValue(); + + if ( v == 1 ) { + HackToSegment( LITSEG ); + } else if ( v == 4 ) { + HackToSegment( DATASEG ); + } else if ( v == 2 ) { + CodeError( "16 bit initialized data not supported" ); + } + + // emit little endien + for ( i = 0 ; i < v ; i++ ) { + EmitByte( currentSegment, v2 ); + v2 >>= 8; + } + return; + } + + // code labels are emited as instruction counts, not byte offsets, + // because the physical size of the code will change with + // different run time compilers and we want to minimize the + // size of the required translation table + if ( !strncmp( token, "LABEL", 5 ) ) { + Parse(); + if ( currentSegment == &segment[CODESEG] ) { + DefineSymbol( token, instructionCount ); + } else { + DefineSymbol( token, currentSegment->imageUsed ); + } + return; + } + + CodeError( "Unknown token: %s\n", token ); +} + +/* +============== +InitTables +============== +*/ +void InitTables( void ) { + int i; + + for ( i = 0 ; i < NUM_SOURCE_OPS ; i++ ) { + opcodesHash[i] = HashString( sourceOps[i].name ); + } +} + + +/* +============== +WriteMapFile +============== +*/ +void WriteMapFile( void ) { + FILE *f; + symbol_t *s; + char imageName[MAX_OS_PATH]; + int seg; + + strcpy( imageName, outputFilename ); + StripExtension( imageName ); + strcat( imageName, ".map" ); + + printf( "Writing %s...\n", imageName ); + f = SafeOpenWrite( imageName ); + for ( seg = CODESEG ; seg <= BSSSEG ; seg++ ) { + for ( s = symbols ; s ; s = s->next ) { + if ( s->name[0] == '$' ) { + continue; // skip locals + } + if ( &segment[seg] != s->segment ) { + continue; + } + fprintf( f, "%i %8x %s\n", seg, s->value, s->name ); + } + } + fclose( f ); +} + +/* +=============== +WriteVmFile +=============== +*/ +void WriteVmFile( void ) { + char imageName[MAX_OS_PATH]; + vmHeader_t header; + FILE *f; + + printf( "%i total errors\n", errorCount ); + strcpy( imageName, outputFilename ); + StripExtension( imageName ); + strcat( imageName, ".qvm" ); + + remove( imageName ); + + printf( "code segment: %7i\n", segment[CODESEG].imageUsed ); + printf( "data segment: %7i\n", segment[DATASEG].imageUsed ); + printf( "lit segment: %7i\n", segment[LITSEG].imageUsed ); + printf( "bss segment: %7i\n", segment[BSSSEG].imageUsed ); + printf( "instruction count: %i\n", instructionCount ); + if ( errorCount != 0 ) { + printf( "Not writing a file due to errors\n" ); + return; + } + + header.vmMagic = VM_MAGIC; + header.instructionCount = instructionCount; + header.codeOffset = sizeof( header ); + header.codeLength = segment[CODESEG].imageUsed; + header.dataOffset = header.codeOffset + segment[CODESEG].imageUsed; + header.dataLength = segment[DATASEG].imageUsed; + header.litLength = segment[LITSEG].imageUsed; + header.bssLength = segment[BSSSEG].imageUsed; + + printf( "Writing to %s\n", imageName ); + + CreatePath( imageName ); + f = SafeOpenWrite( imageName ); + SafeWrite( f, &header, sizeof( header ) ); + SafeWrite( f, &segment[CODESEG].image, segment[CODESEG].imageUsed ); + SafeWrite( f, &segment[DATASEG].image, segment[DATASEG].imageUsed ); + SafeWrite( f, &segment[LITSEG].image, segment[LITSEG].imageUsed ); + fclose( f ); +} + +/* +=============== +Assemble +=============== +*/ +void Assemble( void ) { + int i; + char filename[MAX_OS_PATH]; + char *ptr; + + printf( "outputFilename: %s\n", outputFilename ); + + for ( i = 0 ; i < numAsmFiles ; i++ ) { + strcpy( filename, asmFileNames[ i ] ); + DefaultExtension( filename, ".asm" ); + LoadFile( filename, (void **)&asmFiles[i] ); + } + + // assemble + for ( passNumber = 0 ; passNumber < 2 ; passNumber++ ) { + segment[LITSEG].segmentBase = segment[DATASEG].imageUsed; + segment[BSSSEG].segmentBase = segment[LITSEG].segmentBase + segment[LITSEG].imageUsed; + for ( i = 0 ; i < NUM_SEGMENTS ; i++ ) { + segment[i].imageUsed = 0; + } + segment[DATASEG].imageUsed = 4; // skip the 0 byte, so NULL pointers are fixed up properly + instructionCount = 0; + + for ( i = 0 ; i < numAsmFiles ; i++ ) { + currentFileIndex = i; + currentFileName = asmFileNames[ i ]; + currentFileLine = 0; + printf("pass %i: %s\n", passNumber, currentFileName ); + ptr = asmFiles[i]; + while ( ptr ) { + ptr = ExtractLine( ptr ); + AssembleLine(); + } + } + + // align all segment + for ( i = 0 ; i < NUM_SEGMENTS ; i++ ) { + segment[i].imageUsed = (segment[i].imageUsed + 3) & ~3; + } + } + + // reserve the stack in bss + DefineSymbol( "_stackStart", segment[BSSSEG].imageUsed ); + segment[BSSSEG].imageUsed += stackSize; + DefineSymbol( "_stackEnd", segment[BSSSEG].imageUsed ); + + // write the image + WriteVmFile(); + + // write the map file even if there were errors + WriteMapFile(); +} + + +/* +============= +ParseOptionFile + +============= +*/ +void ParseOptionFile( const char *filename ) { + char expanded[MAX_OS_PATH]; + char *text, *text_p; + + strcpy( expanded, filename ); + DefaultExtension( expanded, ".q3asm" ); + LoadFile( expanded, (void **)&text ); + if ( !text ) { + return; + } + + text_p = text; + + while( ( text_p = COM_Parse( text_p ) ) != 0 ) { + if ( !strcmp( com_token, "-o" ) ) { + // allow output override in option file + text_p = COM_Parse( text_p ); + if ( text_p ) { + strcpy( outputFilename, com_token ); + } + continue; + } + + asmFileNames[ numAsmFiles ] = copystring( com_token ); + numAsmFiles++; + } +} + +/* +============== +main +============== +*/ +int main( int argc, char **argv ) { + int i; + double start, end; + +// _chdir( "/quake3/jccode/cgame/lccout" ); // hack for vc profiler + + if ( argc < 2 ) { + Error( "usage: q3asm [-o output] or q3asm -f \n" ); + } + + start = I_FloatTime (); + InitTables(); + + // default filename is "q3asm" + strcpy( outputFilename, "q3asm" ); + numAsmFiles = 0; + + for ( i = 1 ; i < argc ; i++ ) { + if ( argv[i][0] != '-' ) { + break; + } + if ( !strcmp( argv[i], "-o" ) ) { + if ( i == argc - 1 ) { + Error( "-o must preceed a filename" ); + } + strcpy( outputFilename, argv[ i+1 ] ); + i++; + continue; + } + + if ( !strcmp( argv[i], "-f" ) ) { + if ( i == argc - 1 ) { + Error( "-f must preceed a filename" ); + } + ParseOptionFile( argv[ i+1 ] ); + i++; + continue; + } + Error( "Unknown option: %s", argv[i] ); + } + + // the rest of the command line args are asm files + for ( ; i < argc ; i++ ) { + asmFileNames[ numAsmFiles ] = copystring( argv[ i ] ); + numAsmFiles++; + } + + Assemble(); + + end = I_FloatTime (); + printf ("%5.0f seconds elapsed\n", end-start); + + return 0; +} + diff --git a/q3asm/q3asm.sln b/q3asm/q3asm.sln new file mode 100755 index 0000000..5f44a09 --- /dev/null +++ b/q3asm/q3asm.sln @@ -0,0 +1,28 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "q3asm", "q3asm.vcproj", "{E0D6B319-6F95-4ABA-9BE0-5454CAA5C8CD}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SourceCodeControl) = preSolution + SccNumberOfProjects = 1 + SccProjectUniqueName0 = q3asm.vcproj + SccProjectName0 = \u0022$/source/q3asm\u0022,\u0020YUCAAAAA + SccLocalPath0 = . + SccProvider0 = MSSCCI:Perforce\u0020SCM + EndGlobalSection + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {E0D6B319-6F95-4ABA-9BE0-5454CAA5C8CD}.Debug.ActiveCfg = Debug|Win32 + {E0D6B319-6F95-4ABA-9BE0-5454CAA5C8CD}.Debug.Build.0 = Debug|Win32 + {E0D6B319-6F95-4ABA-9BE0-5454CAA5C8CD}.Release.ActiveCfg = Release|Win32 + {E0D6B319-6F95-4ABA-9BE0-5454CAA5C8CD}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/q3asm/q3asm.vcproj b/q3asm/q3asm.vcproj new file mode 100755 index 0000000..49266b4 --- /dev/null +++ b/q3asm/q3asm.vcproj @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/q3asm/qfiles.h b/q3asm/qfiles.h new file mode 100755 index 0000000..9515acf --- /dev/null +++ b/q3asm/qfiles.h @@ -0,0 +1,485 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +#ifndef __QFILES_H__ +#define __QFILES_H__ + +// +// qfiles.h: quake file formats +// This file must be identical in the quake and utils directories +// + +// surface geometry should not exceed these limits +#define SHADER_MAX_VERTEXES 1000 +#define SHADER_MAX_INDEXES (6*SHADER_MAX_VERTEXES) + + +// the maximum size of game reletive pathnames +#define MAX_QPATH 64 + +/* +======================================================================== + +QVM files + +======================================================================== +*/ + +#define VM_MAGIC 0x12721444 +typedef struct { + int vmMagic; + + int instructionCount; + + int codeOffset; + int codeLength; + + int dataOffset; + int dataLength; + int litLength; // ( dataLength - litLength ) should be byteswapped on load + int bssLength; // zero filled memory appended to datalength +} vmHeader_t; + + +/* +======================================================================== + +PCX files are used for 8 bit images + +======================================================================== +*/ + +typedef struct { + char manufacturer; + char version; + char encoding; + char bits_per_pixel; + unsigned short xmin,ymin,xmax,ymax; + unsigned short hres,vres; + unsigned char palette[48]; + char reserved; + char color_planes; + unsigned short bytes_per_line; + unsigned short palette_type; + char filler[58]; + unsigned char data; // unbounded +} pcx_t; + + +/* +======================================================================== + +TGA files are used for 24/32 bit images + +======================================================================== +*/ + +typedef struct _TargaHeader { + unsigned char id_length, colormap_type, image_type; + unsigned short colormap_index, colormap_length; + unsigned char colormap_size; + unsigned short x_origin, y_origin, width, height; + unsigned char pixel_size, attributes; +} TargaHeader; + + + +/* +======================================================================== + +.MD3 triangle model file format + +======================================================================== +*/ + +#define MD3_IDENT (('3'<<24)+('P'<<16)+('D'<<8)+'I') +#define MD3_VERSION 15 + +// limits +#define MD3_MAX_LODS 3 +#define MD3_MAX_TRIANGLES 8192 // per surface +#define MD3_MAX_VERTS 4096 // per surface +#define MD3_MAX_SHADERS 256 // per surface +#define MD3_MAX_FRAMES 1024 // per model +#define MD3_MAX_SURFACES 32 // per model +#define MD3_MAX_TAGS 16 // per frame + +// vertex scales +#define MD3_XYZ_SCALE (1.0/64) + +typedef struct md3Frame_s { + vec3_t bounds[2]; + vec3_t localOrigin; + float radius; + char name[16]; +} md3Frame_t; + +typedef struct md3Tag_s { + char name[MAX_QPATH]; // tag name + vec3_t origin; + vec3_t axis[3]; +} md3Tag_t; + +/* +** md3Surface_t +** +** CHUNK SIZE +** header sizeof( md3Surface_t ) +** shaders sizeof( md3Shader_t ) * numShaders +** triangles[0] sizeof( md3Triangle_t ) * numTriangles +** st sizeof( md3St_t ) * numVerts +** XyzNormals sizeof( md3XyzNormal_t ) * numVerts * numFrames +*/ +typedef struct { + int ident; // + + char name[MAX_QPATH]; // polyset name + + int flags; + int numFrames; // all surfaces in a model should have the same + + int numShaders; // all surfaces in a model should have the same + int numVerts; + + int numTriangles; + int ofsTriangles; + + int ofsShaders; // offset from start of md3Surface_t + int ofsSt; // texture coords are common for all frames + int ofsXyzNormals; // numVerts * numFrames + + int ofsEnd; // next surface follows +} md3Surface_t; + +typedef struct { + char name[MAX_QPATH]; + int shaderIndex; // for in-game use +} md3Shader_t; + +typedef struct { + int indexes[3]; +} md3Triangle_t; + +typedef struct { + float st[2]; +} md3St_t; + +typedef struct { + short xyz[3]; + short normal; +} md3XyzNormal_t; + +typedef struct { + int ident; + int version; + + char name[MAX_QPATH]; // model name + + int flags; + + int numFrames; + int numTags; + int numSurfaces; + + int numSkins; + + int ofsFrames; // offset for first frame + int ofsTags; // numFrames * numTags + int ofsSurfaces; // first surface, others follow + + int ofsEnd; // end of file +} md3Header_t; + +/* +============================================================================== + +MD4 file format + +============================================================================== +*/ + +#define MD4_IDENT (('4'<<24)+('P'<<16)+('D'<<8)+'I') +#define MD4_VERSION 1 +#define MD4_MAX_BONES 128 + +typedef struct { + int boneIndex; // these are indexes into the boneReferences, + float boneWeight; // not the global per-frame bone list + vec3_t offset; +} md4Weight_t; + +typedef struct { + vec3_t normal; + vec2_t texCoords; + int numWeights; + md4Weight_t weights[1]; // variable sized +} md4Vertex_t; + +typedef struct { + int indexes[3]; +} md4Triangle_t; + +typedef struct { + int ident; + + char name[MAX_QPATH]; // polyset name + char shader[MAX_QPATH]; + int shaderIndex; // for in-game use + + int ofsHeader; // this will be a negative number + + int numVerts; + int ofsVerts; + + int numTriangles; + int ofsTriangles; + + // Bone references are a set of ints representing all the bones + // present in any vertex weights for this surface. This is + // needed because a model may have surfaces that need to be + // drawn at different sort times, and we don't want to have + // to re-interpolate all the bones for each surface. + int numBoneReferences; + int ofsBoneReferences; + + int ofsEnd; // next surface follows +} md4Surface_t; + +typedef struct { + float matrix[3][4]; +} md4Bone_t; + +typedef struct { + vec3_t bounds[2]; // bounds of all surfaces of all LOD's for this frame + vec3_t localOrigin; // midpoint of bounds, used for sphere cull + float radius; // dist from localOrigin to corner + char name[16]; + md4Bone_t bones[1]; // [numBones] +} md4Frame_t; + +typedef struct { + int numSurfaces; + int ofsSurfaces; // first surface, others follow + int ofsEnd; // next lod follows +} md4LOD_t; + +typedef struct { + int ident; + int version; + + char name[MAX_QPATH]; // model name + + // frames and bones are shared by all levels of detail + int numFrames; + int numBones; + int ofsFrames; // md4Frame_t[numFrames] + + // each level of detail has completely separate sets of surfaces + int numLODs; + int ofsLODs; + + int ofsEnd; // end of file +} md4Header_t; + + +/* +============================================================================== + + .BSP file format + +============================================================================== +*/ + + +#define BSP_IDENT (('P'<<24)+('S'<<16)+('B'<<8)+'I') + // little-endian "IBSP" + +#define BSP_VERSION 46 + + +// there shouldn't be any problem with increasing these values at the +// expense of more memory allocation in the utilities +#define MAX_MAP_MODELS 0x400 +#define MAX_MAP_BRUSHES 0x8000 +#define MAX_MAP_ENTITIES 0x800 +#define MAX_MAP_ENTSTRING 0x40000 +#define MAX_MAP_SHADERS 0x400 + +#define MAX_MAP_AREAS 0x100 // MAX_MAP_AREA_BYTES in q_shared must match! +#define MAX_MAP_FOGS 0x100 +#define MAX_MAP_PLANES 0x20000 +#define MAX_MAP_NODES 0x20000 +#define MAX_MAP_BRUSHSIDES 0x20000 +#define MAX_MAP_LEAFS 0x20000 +#define MAX_MAP_LEAFFACES 0x20000 +#define MAX_MAP_LEAFBRUSHES 0x40000 +#define MAX_MAP_PORTALS 0x20000 +#define MAX_MAP_LIGHTING 0x800000 +#define MAX_MAP_LIGHTGRID 0x800000 +#define MAX_MAP_VISIBILITY 0x200000 + +#define MAX_MAP_DRAW_SURFS 0x20000 +#define MAX_MAP_DRAW_VERTS 0x80000 +#define MAX_MAP_DRAW_INDEXES 0x80000 + + +// key / value pair sizes in the entities lump +#define MAX_KEY 32 +#define MAX_VALUE 1024 + +// the editor uses these predefined yaw angles to orient entities up or down +#define ANGLE_UP -1 +#define ANGLE_DOWN -2 + +#define LIGHTMAP_WIDTH 128 +#define LIGHTMAP_HEIGHT 128 + + +//============================================================================= + + +typedef struct { + int fileofs, filelen; +} lump_t; + +#define LUMP_ENTITIES 0 +#define LUMP_SHADERS 1 +#define LUMP_PLANES 2 +#define LUMP_NODES 3 +#define LUMP_LEAFS 4 +#define LUMP_LEAFSURFACES 5 +#define LUMP_LEAFBRUSHES 6 +#define LUMP_MODELS 7 +#define LUMP_BRUSHES 8 +#define LUMP_BRUSHSIDES 9 +#define LUMP_DRAWVERTS 10 +#define LUMP_DRAWINDEXES 11 +#define LUMP_FOGS 12 +#define LUMP_SURFACES 13 +#define LUMP_LIGHTMAPS 14 +#define LUMP_LIGHTGRID 15 +#define LUMP_VISIBILITY 16 +#define HEADER_LUMPS 17 + +typedef struct { + int ident; + int version; + + lump_t lumps[HEADER_LUMPS]; +} dheader_t; + +typedef struct { + float mins[3], maxs[3]; + int firstSurface, numSurfaces; + int firstBrush, numBrushes; +} dmodel_t; + +typedef struct { + char shader[MAX_QPATH]; + int surfaceFlags; + int contentFlags; +} dshader_t; + +// planes x^1 is allways the opposite of plane x + +typedef struct { + float normal[3]; + float dist; +} dplane_t; + +typedef struct { + int planeNum; + int children[2]; // negative numbers are -(leafs+1), not nodes + int mins[3]; // for frustom culling + int maxs[3]; +} dnode_t; + +typedef struct { + int cluster; // -1 = opaque cluster (do I still store these?) + int area; + + int mins[3]; // for frustum culling + int maxs[3]; + + int firstLeafSurface; + int numLeafSurfaces; + + int firstLeafBrush; + int numLeafBrushes; +} dleaf_t; + +typedef struct { + int planeNum; // positive plane side faces out of the leaf + int shaderNum; +} dbrushside_t; + +typedef struct { + int firstSide; + int numSides; + int shaderNum; // the shader that determines the contents flags +} dbrush_t; + +typedef struct { + char shader[MAX_QPATH]; + int brushNum; + int visibleSide; // the brush side that ray tests need to clip against (-1 == none) +} dfog_t; + +typedef struct { + vec3_t xyz; + float st[2]; + float lightmap[2]; + vec3_t normal; + byte color[4]; +} drawVert_t; + +typedef enum { + MST_BAD, + MST_PLANAR, + MST_PATCH, + MST_TRIANGLE_SOUP, + MST_FLARE +} mapSurfaceType_t; + +typedef struct { + int shaderNum; + int fogNum; + int surfaceType; + + int firstVert; + int numVerts; + + int firstIndex; + int numIndexes; + + int lightmapNum; + int lightmapX, lightmapY; + int lightmapWidth, lightmapHeight; + + vec3_t lightmapOrigin; + vec3_t lightmapVecs[3]; // for patches, [0] and [1] are lodbounds + + int patchWidth; + int patchHeight; +} dsurface_t; + + +#endif -- cgit v1.2.3