brender-v1.1.2/FMT/LOADSCR.C
2022-05-04 18:14:23 -07:00

744 lines
14 KiB
C

/*
* Copyright (c) 1993-1995 by Argonaut Technologies Limited. All rights reserved.
*
* $Id: loadscr.c 1.7 1995/08/31 16:28:18 sam Exp $
* $Locker: $
* $BC<"make -f zbtest.mak %s.obj;">
*
* Load a Material Script file
*/
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "brender.h"
#include "fmt.h"
#define LEX_DEBUG 0
static char rscid[] = "$Id: loadscr.c 1.7 1995/08/31 16:28:18 sam Exp $";
/*
* Parsing macros
*/
#if LEX_DEBUG
#define LexAdvance LexAdvanceDebug
#else
#define LexAdvance LexAdvanceReal
#endif
#define ADVANCE() LexAdvance()
#define EXPECT(t) {if(CURRENT != (t)) LexTokenError(t); else LexAdvance();}
#define CHECK(t) {if(CURRENT != (t)) LexTokenError(t);}
#define ERROR(s) LexError(s)
#define CURRENT (Current.id)
#define CURRENT_SCALAR (Current.scalar)
#define CURRENT_STRING (Current.string)
/*
* Default material fields
*/
br_material _DefaultScriptMaterial = {
NULL,
BR_COLOUR_RGB(255,255,255), /* colour */
255, /* opacity */
BR_UFRACTION(0.10), /* Indexed ka */
BR_UFRACTION(0.70), /* kd */
BR_UFRACTION(0.0), /* ks */
BR_SCALAR(20), /* power */
BR_MATF_LIGHT, /* flags */
{{
BR_VECTOR2(1,0), /* map transform */
BR_VECTOR2(0,1),
BR_VECTOR2(0,0),
}},
0,63, /* index base/range */
};
/*
* Token IDs
*/
typedef enum {
T_EOF,
/*
* Constants
*/
T_SCALAR,
T_STRING,
T_IDENT,
/*
* Single characters
*/
T_LSQUARE = '[',
T_RSQUARE = ']',
T_SEMI = ';',
T_EQUALS = '=',
T_COMMA = ',',
/*
* Keywords - see below
*/
T_MATERIAL = 128,
/*
* Members of material
*/
T_IDENTIFIER,
T_NAME,
T_FLAGS,
T_COLOUR,
T_OPACITY,
T_AMBIENT,
T_KA,
T_DIFFUSE,
T_KD,
T_SPECULAR,
T_KS,
T_POWER,
T_MAP_TRANSFORM,
T_INDEX_BASE,
T_INDEX_RANGE,
T_COLOUR_MAP,
T_SCREEN_DOOR,
T_INDEX_SHADE,
T_INDEX_BLEND,
/*
* Material flags
*/
T_LIGHT,
T_PRELIT,
T_SMOOTH,
T_GOURAUD,
T_ENVIRONMENT,
T_ENVIRONMENT_I,
T_ENVIRONMENT_LOCAL,
T_ENVIRONMENT_L,
T_PERSPECTIVE,
T_DECAL,
T_ALWAYS_VISIBLE,
T_TWO_SIDED,
T_FORCE_Z_0,
T_DITHER
} scr_token_id;
STATIC char * token_names[] = {
"end of file",
"scalar",
"string",
"identfier",
};
STATIC char * token_keywords[] = {
"material",
"identifier",
"name",
"flags",
"colour",
"opacity",
"ambient",
"ka",
"diffuse",
"kd",
"specular",
"ks",
"power",
"map_transform",
"index_base",
"index_range",
"colour_map",
"screen_door",
"index_shade",
"index_blend",
"light",
"prelit",
"smooth",
"gouraud",
"environment",
"environment_i",
"environment_local",
"environment_l",
"perspective",
"decal",
"always_visible",
"two_sided",
"force_z_0",
"dither",
};
/*
* A token - id + value
*/
struct scr_token {
/*
* Token ID
*/
scr_token_id id;
/*
* Numerical value
*/
br_scalar scalar;
/*
* String value
*/
char * string;
};
/*
* The current token
*/
STATIC struct scr_token Current;
/*
* The current file
*/
struct lex_file {
int line;
char *name;
void *handle;
int next_char;
} CurrentFile;
/*
* Start processing a file
*/
STATIC int LexAddFile(char *filename)
{
int mode = BR_FS_MODE_TEXT;
#if LEX_DEBUG
printf("LexAddFile(%s)\n",filename);
#endif
CurrentFile.line = 1;
CurrentFile.name = filename;
CurrentFile.handle = BrFileOpenRead(filename, 0, NULL, &mode);
if(CurrentFile.handle == NULL) {
#if LEX_DEBUG
printf("LexAddFile - could not open file\n");
#endif
return 0;
}
/*
* File is always one character ahead of the current token
*/
CurrentFile.next_char = BrFileGetChar(CurrentFile.handle);
return 1;
}
/*
* Close file
*/
STATIC void LexCloseFile(void)
{
#if LEX_DEBUG
printf("LexCloseFile\n");
#endif
BrFileClose(CurrentFile.handle);
}
/*
* Report an error, including file name and line number
*/
STATIC int LexError(char *string)
{
LexCloseFile();
BR_ERROR3("%s in %s, line %d",string,CurrentFile.name,CurrentFile.line);
return 0;
}
/*
* Report an expected token
*/
STATIC int LexTokenError(scr_token_id token)
{
LexCloseFile();
if(token >= 128) {
/*
* Token is >= 128, it is a keyword
*/
BR_ERROR3("Expected '%s' in %s, line %d",token_keywords[token-128],CurrentFile.name,CurrentFile.line);
} else if(token <= ' ') {
/*
* Token is <= ' ' - it is a constant or some other named ID
*/
BR_ERROR3("Expected %s in %s, line %d",token_names[token],CurrentFile.name,CurrentFile.line);
} else {
/*
* Otherwise it is a printable character
*/
BR_ERROR3("Expected '%c' in %s, line %d",token,CurrentFile.name,CurrentFile.line);
}
return 0;
}
/*
* Collect next token from script file
*/
STATIC void LexAdvanceReal(void)
{
int n;
static char lex_buffer[256];
for(;;) {
if(CurrentFile.next_char == BR_EOF) {
Current.id = T_EOF;
return;
} else if(CurrentFile.next_char == '#') {
/*
* Comment - skip until EOL or EOF
*/
for(;;) {
CurrentFile.next_char = BrFileGetChar(CurrentFile.handle);
if(CurrentFile.next_char == '\n' ||
CurrentFile.next_char == BR_EOF)
break;
}
continue;
} else if(CurrentFile.next_char == '\n') {
/*
* Newline - track line number
*/
CurrentFile.line++;
CurrentFile.next_char = BrFileGetChar(CurrentFile.handle);
continue;
} else if(CurrentFile.next_char == '"') {
/*
* Read a string - read characters until '"', newline, or EOF
*/
n = 0;
for(n=0; n < BR_ASIZE(lex_buffer)-1; ) {
CurrentFile.next_char = BrFileGetChar(CurrentFile.handle);
if(CurrentFile.next_char == '"' ||
CurrentFile.next_char == '\n' ||
CurrentFile.next_char == BR_EOF)
break;
lex_buffer[n++] = CurrentFile.next_char;
}
if(CurrentFile.next_char != '"')
LexError("Unterminated string");
lex_buffer[n] = '\0';
Current.string = lex_buffer;
Current.id = T_STRING;
CurrentFile.next_char = BrFileGetChar(CurrentFile.handle);
return;
} else if(isspace(CurrentFile.next_char) || CurrentFile.next_char == '\032') {
/*
* white space - ignore
*/
CurrentFile.next_char = BrFileGetChar(CurrentFile.handle);
continue;
} else if(isalpha(CurrentFile.next_char) || CurrentFile.next_char == '_') {
/*
* Idenitifier - read characters until not alpha, _ or 0-9
*/
lex_buffer[0] = CurrentFile.next_char;
for(n=1; n < BR_ASIZE(lex_buffer)-1; ) {
CurrentFile.next_char = BrFileGetChar(CurrentFile.handle);
if(!(isalpha(CurrentFile.next_char) ||
isdigit(CurrentFile.next_char) ||
CurrentFile.next_char == '_'))
break;
lex_buffer[n++] = CurrentFile.next_char;
}
lex_buffer[n] = '\0';
Current.string = lex_buffer;
/*
* Try to look up a keyword
*/
for(n=0; n < BR_ASIZE(token_keywords); n++) {
if(token_keywords[n][0] == lex_buffer[0] &&
!stricmp(token_keywords[n],lex_buffer)) {
/*
* Found a keyword - which are based at 128
*/
Current.id = n + 128;
return;
}
}
Current.id = T_IDENT;
return;
} else if(isdigit(CurrentFile.next_char) || CurrentFile.next_char == '-') {
/*
* Read a number
*/
lex_buffer[0] = CurrentFile.next_char;
for(n=1; n < BR_ASIZE(lex_buffer)-1; ) {
CurrentFile.next_char = BrFileGetChar(CurrentFile.handle);
if(!(isdigit(CurrentFile.next_char) ||
CurrentFile.next_char == '.'))
break;
lex_buffer[n++] = CurrentFile.next_char;
}
lex_buffer[n] = '\0';
Current.scalar = BrFloatToScalar(atof(lex_buffer));
Current.string = lex_buffer;
Current.id = T_SCALAR;
return;
} else if(isprint(CurrentFile.next_char)) {
/*
* All other printable characters turn into tokens
*/
Current.id = CurrentFile.next_char;
CurrentFile.next_char = BrFileGetChar(CurrentFile.handle);
return;
} else
LexError("Unexpected character");
}
}
#if LEX_DEBUG
STATIC void LexAdvanceDebug(void)
{
int i;
static struct {
char *name;
scr_token_id id;
} token_names[] = {
"T_EOF", T_EOF,
"T_SCALAR", T_SCALAR,
"T_STRING", T_STRING,
"T_IDENT", T_IDENT,
"T_LSQUARE", T_LSQUARE,
"T_RSQUARE", T_RSQUARE,
"T_SEMI", T_SEMI,
"T_EQUALS", T_EQUALS,
"T_COMMA", T_COMMA,
"T_MATERIAL", T_MATERIAL,
"T_IDENTIFIER", T_IDENTIFIER,
"T_NAME", T_NAME,
"T_FLAGS", T_FLAGS,
"T_COLOUR", T_COLOUR,
"T_OPACITY", T_OPACITY,
"T_AMBIENT", T_AMBIENT,
"T_KA", T_KA,
"T_DIFFUSE", T_DIFFUSE,
"T_KD", T_KD,
"T_SPECULAR", T_SPECULAR,
"T_KS", T_KS,
"T_POWER", T_POWER,
"T_MAP_TRANSFORM", T_MAP_TRANSFORM,
"T_INDEX_BASE", T_INDEX_BASE,
"T_INDEX_RANGE", T_INDEX_RANGE,
"T_COLOUR_MAP", T_COLOUR_MAP,
"T_SCREEN_DOOR", T_SCREEN_DOOR,
"T_INDEX_SHADE", T_INDEX_SHADE,
"T_INDEX_BLEND", T_INDEX_BLEND,
"T_LIGHT", T_LIGHT,
"T_PRELIT", T_PRELIT,
"T_SMOOTH", T_SMOOTH,
"T_GOURAUD", T_GOURAUD,
"T_ENVIRONMENT", T_ENVIRONMENT,
"T_ENVIRONMENT_I", T_ENVIRONMENT_I,
"T_ENVIRONMENT_LOCAL", T_ENVIRONMENT_LOCAL,
"T_ENVIRONMENT_L", T_ENVIRONMENT_L,
"T_PERSPECTIVE", T_PERSPECTIVE,
"T_DECAL", T_DECAL,
"T_ALWAYS_VISIBLE", T_ALWAYS_VISIBLE,
"T_TWO_SIDED", T_TWO_SIDED,
"T_FORCE_Z_0", T_FORCE_Z_0,
"T_DITHER", T_DITHER,
};
LexAdvanceReal();
for(i=0; i < BR_ASIZE(token_names); i++) {
if(Current.id == token_names[i].id)
break;
}
if(i < BR_ASIZE(token_names))
printf("<%s>",token_names[i].name);
else
printf("<%03X>",token_names[i].id);
if(Current.id == T_SCALAR)
printf(" = %f (%s)",BrScalarToFloat(Current.scalar),Current.string);
if(Current.id == T_STRING || Current.id == T_IDENT)
printf(" = \"%s\"",Current.string);
if(isgraph(CurrentFile.next_char))
printf(" next_char = '%c'\n",CurrentFile.next_char);
else
printf(" next_char = %d\n",CurrentFile.next_char);
}
#endif
br_uint_32 ParseMatFlags(void)
{
br_uint_32 f = 0;
EXPECT(T_LSQUARE);
if(CURRENT == T_RSQUARE) {
ADVANCE();
return 0;
}
/*
* Read flag keywords until ]
*/
for(;;) {
switch(CURRENT) {
case T_LIGHT: f |= BR_MATF_LIGHT; break;
case T_PRELIT: f |= BR_MATF_PRELIT; break;
case T_SMOOTH:
case T_GOURAUD: f |= BR_MATF_SMOOTH; break;
case T_ENVIRONMENT_I:
case T_ENVIRONMENT: f |= BR_MATF_ENVIRONMENT_I; break;
case T_ENVIRONMENT_L:
case T_ENVIRONMENT_LOCAL: f |= BR_MATF_ENVIRONMENT_L; break;
case T_PERSPECTIVE: f |= BR_MATF_PERSPECTIVE; break;
case T_DECAL: f |= BR_MATF_DECAL; break;
case T_ALWAYS_VISIBLE: f |= BR_MATF_ALWAYS_VISIBLE; break;
case T_TWO_SIDED: f |= BR_MATF_TWO_SIDED; break;
case T_FORCE_Z_0: f |= BR_MATF_FORCE_Z_0; break;
case T_DITHER: f |= BR_MATF_DITHER; break;
default:
ERROR("Unknown material flag");
}
ADVANCE();
if(CURRENT == T_RSQUARE)
break;
EXPECT(T_COMMA);
}
EXPECT(T_RSQUARE);
return f;
}
int ParseVector(br_scalar *v, int max)
{
int n;
EXPECT(T_LSQUARE);
for(n=0;n < max; n++) {
CHECK(T_SCALAR);
*v++ = CURRENT_SCALAR;
ADVANCE();
if(CURRENT == T_RSQUARE)
break;
EXPECT(T_COMMA);
}
EXPECT(T_RSQUARE);
return n+1;
}
int ParseMatrix(br_scalar *m, int width, int max_h)
{
int n;
EXPECT(T_LSQUARE);
for(n=0; n < max_h; n++, m+= width) {
ParseVector(m,width);
if(CURRENT == T_RSQUARE)
break;
EXPECT(T_COMMA);
}
EXPECT(T_RSQUARE);
return n;
}
br_material *ParseMaterial(void)
{
br_material *mat;
br_vector3 v3;
mat = BrMaterialAllocate(NULL);
*mat = _DefaultScriptMaterial;
/*
* material = [
*/
EXPECT(T_MATERIAL);
EXPECT(T_EQUALS);
EXPECT(T_LSQUARE);
while(CURRENT != T_RSQUARE) {
switch(CURRENT) {
case T_IDENTIFIER:
case T_NAME:
ADVANCE(); EXPECT(T_EQUALS); CHECK(T_STRING);
mat->identifier = BrResStrDup(mat,CURRENT_STRING);
ADVANCE();
break;
case T_FLAGS:
ADVANCE(); EXPECT(T_EQUALS);
mat->flags = ParseMatFlags();
break;
case T_COLOUR:
ADVANCE(); EXPECT(T_EQUALS);
if(ParseVector(&v3.v[0],3) != 3)
ERROR("Colour has too few entries");
mat->colour = BR_COLOUR_RGB(
BrScalarToInt(v3.v[0]),
BrScalarToInt(v3.v[1]),
BrScalarToInt(v3.v[2]));
break;
case T_OPACITY:
ADVANCE(); EXPECT(T_EQUALS); CHECK(T_SCALAR);
mat->opacity = CURRENT_SCALAR;
ADVANCE();
break;
case T_KA:
case T_AMBIENT:
ADVANCE(); EXPECT(T_EQUALS); CHECK(T_SCALAR);
mat->ka = CURRENT_SCALAR;
ADVANCE();
break;
case T_KD:
case T_DIFFUSE:
ADVANCE(); EXPECT(T_EQUALS); CHECK(T_SCALAR);
mat->kd = CURRENT_SCALAR;
ADVANCE();
break;
case T_KS:
case T_SPECULAR:
ADVANCE(); EXPECT(T_EQUALS); CHECK(T_SCALAR);
mat->ks = CURRENT_SCALAR;
ADVANCE();
break;
case T_POWER:
ADVANCE(); EXPECT(T_EQUALS); CHECK(T_SCALAR);
mat->power = CURRENT_SCALAR;
ADVANCE();
break;
case T_MAP_TRANSFORM:
ADVANCE(); EXPECT(T_EQUALS);
ParseMatrix(&mat->map_transform.m[0][0],2,3);
break;
case T_INDEX_BASE:
ADVANCE(); EXPECT(T_EQUALS); CHECK(T_SCALAR);
mat->index_base = BrScalarToInt(CURRENT_SCALAR);
ADVANCE();
break;
case T_INDEX_RANGE:
ADVANCE(); EXPECT(T_EQUALS); CHECK(T_SCALAR);
mat->index_range = BrScalarToInt(CURRENT_SCALAR);
ADVANCE();
break;
case T_COLOUR_MAP:
ADVANCE(); EXPECT(T_EQUALS); CHECK(T_STRING);
mat->colour_map = BrMapFind(CURRENT_STRING);
ADVANCE();
break;
case T_SCREEN_DOOR:
ADVANCE(); EXPECT(T_EQUALS); CHECK(T_STRING);
mat->screendoor = BrTableFind(CURRENT_STRING);
ADVANCE();
break;
case T_INDEX_SHADE:
ADVANCE(); EXPECT(T_EQUALS); CHECK(T_STRING);
mat->index_shade = BrTableFind(CURRENT_STRING);
ADVANCE();
break;
case T_INDEX_BLEND:
ADVANCE(); EXPECT(T_EQUALS); CHECK(T_STRING);
mat->index_blend = BrTableFind(CURRENT_STRING);
ADVANCE();
break;
default:
ERROR("Incorrect material member name");
}
EXPECT(T_SEMI);
}
/*
* ];
*/
ADVANCE();
EXPECT(T_SEMI);
return mat;
};
br_uint_32 BR_PUBLIC_ENTRY BrFmtScriptMaterialLoadMany(char *filename,br_material **materials,br_uint_16 num)
{
int count;
if(LexAddFile(filename) == 0)
return 0;
ADVANCE();
for (count=0; CURRENT != T_EOF && count<num; count++) {
materials[count] = ParseMaterial();
}
LexCloseFile();
return count;
}
br_material * BR_PUBLIC_ENTRY BrFmtScriptMaterialLoad(char *filename)
{
br_material *ptr;
return (BrFmtScriptMaterialLoadMany(filename,&ptr,1) != 1)?NULL:ptr;
}