2007-06-28 10:47:08 -07:00
|
|
|
/***************************************************************************/
|
|
|
|
/*
|
|
|
|
* imdload.c
|
|
|
|
*
|
|
|
|
* updated to load version 4 files
|
2006-06-02 12:34:58 -07:00
|
|
|
*
|
2007-06-28 10:47:08 -07:00
|
|
|
* changes at version 4;
|
|
|
|
* pcx name as string
|
|
|
|
* pcx filepath
|
|
|
|
* cut down vertex list
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2006-06-02 12:34:58 -07:00
|
|
|
#include "lib/framework/frame.h"
|
2007-06-28 10:47:08 -07:00
|
|
|
//#include "piematrix.h" //for surface normals
|
|
|
|
#include "ivisdef.h" // for imd structures
|
|
|
|
#include "imd.h" // for imd structures
|
|
|
|
#include "rendmode.h"
|
|
|
|
#include "ivispatch.h"
|
|
|
|
#include "bug.h"
|
|
|
|
#include "tex.h" // texture page loading
|
|
|
|
#include "bspfunc.h" // for imd functions
|
|
|
|
|
|
|
|
|
|
|
|
// Static variables
|
|
|
|
static uint32 _IMD_FLAGS;
|
|
|
|
static char _IMD_NAME[MAX_FILE_PATH];
|
|
|
|
static int32 _IMD_VER;
|
|
|
|
static VERTEXID vertexTable[iV_IMD_MAX_POINTS];
|
|
|
|
static char imagePath[MAX_FILE_PATH] = {""};
|
|
|
|
|
|
|
|
// kludge
|
|
|
|
extern void pie_SurfaceNormal(iVector *p1, iVector *p2, iVector *p3, iVector *v);
|
|
|
|
|
|
|
|
// local prototypes
|
2006-06-02 12:34:58 -07:00
|
|
|
static iIMDShape *_imd_load_level(STRING **FileData, STRING *FileDataEnd, int nlevels,
|
2007-06-28 10:47:08 -07:00
|
|
|
int texpage);
|
|
|
|
static char *_imd_get_path(STRING *filename, STRING *path);
|
|
|
|
BOOL CheckColourKey(iIMDShape *psShape);
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef WIN32
|
|
|
|
// convert a string to lower case... by Tim ... dedicated to JS ... with love
|
|
|
|
void strlwr(STRING *String)
|
|
|
|
{
|
|
|
|
while (*String != 0) {
|
|
|
|
// loop around till we reach the end of the zero terminated string
|
|
|
|
if ((*String >= 'A') && (*String <= 'Z')) {
|
|
|
|
// if the current letter is in upper case...
|
|
|
|
*String += ('a'-'A'); // ... convert it to lower case
|
|
|
|
}
|
|
|
|
String++; // move to the next letter
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
BOOL AtEndOfFile(STRING *CurPos, STRING *EndOfFile)
|
|
|
|
{
|
|
|
|
while ((*CurPos==0x09)||(*CurPos==0x0a)||(*CurPos==0x0d)||(*CurPos==0x20)||(*CurPos==0x00))
|
|
|
|
{
|
|
|
|
CurPos++;
|
|
|
|
if (CurPos>=EndOfFile) return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CurPos >= EndOfFile) {
|
|
|
|
return TRUE;
|
|
|
|
} else {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//*************************************************************************
|
|
|
|
//*** load IMD shape
|
|
|
|
//*
|
|
|
|
//* params filename = IMD file to load (including extention)
|
|
|
|
//*
|
|
|
|
//* returns pointer to imd shape def
|
|
|
|
//*
|
|
|
|
//******
|
|
|
|
BOOL TESTDEBUG = FALSE;
|
|
|
|
// load the polygon level ... then load the texture .... Gareths code
|
|
|
|
#define POST_LEVEL_TEXTURELOAD
|
|
|
|
iIMDShape *iV_IMDLoad(STRING *filename, iBool palkeep)
|
|
|
|
{
|
|
|
|
iIMDShape *pIMD;
|
|
|
|
STRING *pFileData,*pFileDataStart;
|
|
|
|
UDWORD FileSize;
|
|
|
|
BOOL res;
|
2006-08-15 11:20:36 -07:00
|
|
|
char path[MAX_FILE_PATH];
|
2007-06-28 10:47:08 -07:00
|
|
|
UDWORD *tp;
|
|
|
|
UDWORD tt;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
iV_DEBUG1("imd[IMDLoad] = loading shape file '%s':",filename);
|
|
|
|
|
|
|
|
strcpy(_IMD_NAME,filename);
|
|
|
|
strlwr(_IMD_NAME);
|
|
|
|
|
|
|
|
_imd_get_path(filename,path);
|
|
|
|
|
|
|
|
if (strlen(path) != 0) {
|
|
|
|
if (strlen(imagePath) != 0) {
|
2006-06-02 12:34:58 -07:00
|
|
|
if ((strlen(path) + strlen(imagePath)) > MAX_FILE_PATH) {
|
2007-06-28 10:47:08 -07:00
|
|
|
iV_Error(0xff,"(iv_IMDLoad) image path too long for load file");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
strcat(imagePath,path);
|
|
|
|
}
|
|
|
|
}
|
2006-06-02 12:34:58 -07:00
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
res = loadFile(_IMD_NAME,&pFileData, &FileSize);
|
|
|
|
if (res == FALSE) {
|
|
|
|
iV_Error(0xff,"(iv_IMDLoad) unable to load file");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tp = (UDWORD *)pFileData;
|
|
|
|
|
|
|
|
tt = *tp;
|
|
|
|
// 'BPIE'
|
|
|
|
if (tt == 0x45495042) {
|
|
|
|
FREE(pFileData); // free the file up
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
pFileDataStart = pFileData;
|
|
|
|
pIMD = iV_ProcessIMD(&pFileData, pFileData + FileSize, path, imagePath, palkeep);
|
|
|
|
|
|
|
|
FREE(pFileDataStart); // free the file up
|
|
|
|
return (pIMD);
|
|
|
|
}
|
|
|
|
|
|
|
|
static UDWORD IMDcount = 0;
|
|
|
|
static UDWORD IMDPolycount = 0;
|
|
|
|
static UDWORD IMDVertexcount = 0;
|
|
|
|
static UDWORD IMDPoints = 0;
|
|
|
|
static UDWORD IMDTexAnims = 0;
|
|
|
|
static UDWORD IMDConnectors = 0;
|
|
|
|
|
|
|
|
void DumpIMDInfo(void)
|
|
|
|
{
|
2006-08-22 07:28:49 -07:00
|
|
|
debug( LOG_NEVER, "imds loaded =%d - using %d bytes\n", IMDcount, IMDcount*sizeof(iIMDShape) );
|
|
|
|
debug( LOG_NEVER, "polys loaded =%d - using %d bytes\n", IMDPolycount, IMDPolycount*sizeof(iIMDPoly) );
|
|
|
|
debug( LOG_NEVER, "vertices loaded=%d - using %d bytes\n", IMDVertexcount, IMDVertexcount*(sizeof(VERTEXID)+sizeof(iVertex)) );
|
|
|
|
debug( LOG_NEVER, "points loaded =%d - using %d bytes\n", IMDPoints, IMDPoints*sizeof(iVector) );
|
|
|
|
debug( LOG_NEVER, "connectors =%d - using %d bytes\n", IMDConnectors, IMDConnectors*sizeof(iVector) );
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static STRING texfile[64]; //Last loaded texture page filename
|
|
|
|
|
|
|
|
char *GetLastLoadedTexturePage(void)
|
|
|
|
{
|
|
|
|
return texfile;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ppFileData is incremented to the end of the file on exit!
|
2006-06-02 12:34:58 -07:00
|
|
|
iIMDShape *iV_ProcessIMD(STRING **ppFileData, STRING *FileDataEnd, STRING *IMDpath,
|
2007-06-28 10:47:08 -07:00
|
|
|
STRING *PCXpath,iBool palkeep)
|
|
|
|
{
|
|
|
|
STRING *pFileData = *ppFileData;
|
|
|
|
int cnt;
|
|
|
|
char buffer[MAX_FILE_PATH], texType[MAX_FILE_PATH], ch; //, *str;
|
|
|
|
int i, nlevels, ptype, pwidth, pheight, texpage;
|
|
|
|
iIMDShape *s, *psShape;
|
|
|
|
BOOL bColourKey = TRUE;
|
|
|
|
BOOL bTextured = FALSE;
|
|
|
|
#ifdef BSPIMD
|
|
|
|
UDWORD level;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
IMDcount++;
|
|
|
|
|
|
|
|
if (sscanf(pFileData, "%s %d%n", buffer, &_IMD_VER, &cnt) != 2) {
|
|
|
|
debug(LOG_ERROR, "iV_ProcessIMD file corrupt -A (%s)", buffer);
|
|
|
|
assert(FALSE);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
pFileData += cnt;
|
|
|
|
|
|
|
|
if ((strcmp(IMD_NAME,buffer) != 0) && (strcmp(PIE_NAME, buffer) !=0 )) {
|
|
|
|
debug(LOG_ERROR, "iV_ProcessIMD: not an IMD file (%s %d)", buffer, _IMD_VER);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Now supporting version 4 files
|
|
|
|
if ((_IMD_VER < 1) || (_IMD_VER > 4)) {
|
|
|
|
debug(LOG_ERROR, "iV_ProcessIMD: file version not supported (%s)", buffer);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sscanf(pFileData, "%s %x%n", buffer, &_IMD_FLAGS, &cnt) != 2) {
|
|
|
|
debug(LOG_ERROR, "iV_ProcessIMD: file corrupt -B (%s)", buffer);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
pFileData += cnt;
|
|
|
|
|
|
|
|
texpage = -1;
|
|
|
|
|
|
|
|
// get texture page if specified
|
|
|
|
if (_IMD_FLAGS & iV_IMD_XTEX){
|
|
|
|
if (_IMD_VER == 1) {
|
2006-06-02 12:34:58 -07:00
|
|
|
if (sscanf(pFileData, "%s %d %s %d %d%n", buffer, &ptype, texfile, &pwidth,
|
2007-06-28 10:47:08 -07:00
|
|
|
&pheight, &cnt) != 5) {
|
|
|
|
debug(LOG_ERROR, "iV_ProcessIMD: file corrupt -C (%s)", buffer);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
pFileData += cnt;
|
|
|
|
if (strcmp(buffer,"TEXTURE") != 0) {
|
|
|
|
debug(LOG_ERROR, "iV_ProcessIMD: expecting 'TEXTURE' directive (%s)", buffer);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
bTextured = TRUE;
|
|
|
|
}
|
|
|
|
else //version 2 copes with long file names
|
|
|
|
{
|
|
|
|
if (sscanf(pFileData,"%s %d%n", buffer, &ptype,&cnt) != 2) {
|
|
|
|
debug(LOG_ERROR, "iV_ProcessIMD: file corrupt -D (%s)", buffer);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
pFileData += cnt;
|
|
|
|
|
|
|
|
if (strcmp(buffer,"TEXTURE") == 0) {
|
|
|
|
ch = *pFileData++;
|
|
|
|
|
|
|
|
for( i = 0; (i < 80) && ((ch = *pFileData++) != EOF) && (ch != '.'); i++ ) // yummy
|
|
|
|
{
|
|
|
|
texfile[i] = (char)ch;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sscanf(pFileData,"%s%n", texType,&cnt) != 1) {
|
|
|
|
debug(LOG_ERROR, "iV_ProcessIMD: file corrupt -E (%s)", buffer);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
pFileData += cnt;
|
|
|
|
|
|
|
|
if (strcmp(texType,"png") != 0) {
|
|
|
|
debug(LOG_ERROR, "iV_ProcessIMD: file corrupt -F (%s)", buffer);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
texfile[i] = 0;
|
|
|
|
|
|
|
|
strcat(texfile,".png");
|
|
|
|
|
|
|
|
if (sscanf(pFileData,"%d %d%n", &pwidth, &pheight,&cnt) != 2) {
|
|
|
|
debug(LOG_ERROR, "iV_ProcessIMD: file corrupt -G (%s)", buffer);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
pFileData += cnt;
|
|
|
|
bTextured = TRUE;
|
|
|
|
} else if (strcmp(buffer,"NOTEXTURE") == 0) {
|
|
|
|
if (sscanf(pFileData, "%s %d %d%n", texfile, &pwidth, &pheight, &cnt) != 3) {
|
|
|
|
debug(LOG_ERROR, "iV_ProcessIMD: file corrupt -H (%s)", buffer);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
pFileData += cnt;
|
|
|
|
} else {
|
|
|
|
debug(LOG_ERROR, "iV_ProcessIMD(2): expecting 'TEXTURE' directive (%s)", buffer);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef PIETOOL // The BSP tool should not reduce the texture page name down (please)
|
|
|
|
// Super scrummy hack to reduce texture page names down to the page id
|
|
|
|
if (bTextured) {
|
|
|
|
//resToLower(texfile);
|
|
|
|
// printf("texfile cmp in imdload.c :%s\n", texfile);
|
|
|
|
if (strncasecmp(texfile, "page-", 5) == 0) {
|
|
|
|
for(i = 5; i < (SDWORD)strlen(texfile); i++) {
|
|
|
|
if (!isdigit(texfile[i])) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
texfile[i] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sscanf(pFileData, "%s %d%n", buffer, &nlevels, &cnt) !=2) {
|
|
|
|
debug(LOG_ERROR, "iV_ProcessIMD: file corrupt -I (%s)", buffer);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
pFileData += cnt;
|
|
|
|
|
|
|
|
if (strcmp(buffer,"LEVELS") != 0) {
|
|
|
|
debug(LOG_ERROR, "iV_ProcessIMD: expecting 'LEVELS' directive (%s)", buffer);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef BSPIMD
|
|
|
|
// if we might have BSP then we need to preread the LEVEL directive
|
|
|
|
if (sscanf(pFileData,"%s %d%n",buffer,&level,&cnt) != 2) {
|
|
|
|
iV_Error(0xff,"(_load_level) file corrupt -J");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
pFileData += cnt;
|
|
|
|
|
|
|
|
if (strcmp(buffer,"LEVEL") != 0) {
|
|
|
|
debug(LOG_ERROR, "iV_ProcessIMD(2): expecting 'LEVELS' directive (%s)", buffer);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
s = _imd_load_level(&pFileData,FileDataEnd,nlevels,texpage);
|
|
|
|
|
|
|
|
#ifdef POST_LEVEL_TEXTURELOAD
|
|
|
|
// load texture page if specified
|
|
|
|
if ( (s != NULL) && (_IMD_FLAGS & iV_IMD_XTEX)) {
|
|
|
|
bColourKey = FALSE;// CheckColourKey( s );//TRUE not the only imd using this texture
|
|
|
|
|
|
|
|
if(bTextured) {
|
|
|
|
texpage = iV_GetTexture(texfile);
|
|
|
|
if (texpage < 0) {
|
|
|
|
debug(LOG_ERROR, "iV_ProcessIMD: could not load tex page %s", texfile);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
texpage = -1;
|
|
|
|
}
|
|
|
|
/* assign tex page to levels */
|
|
|
|
psShape = s;
|
|
|
|
while (psShape != NULL) {
|
|
|
|
psShape->texpage = texpage;
|
|
|
|
psShape = psShape->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (s == NULL) {
|
|
|
|
debug(LOG_ERROR, "iV_ProcessIMD: unsuccessful (%s)", buffer);
|
|
|
|
}
|
|
|
|
*ppFileData = pFileData;
|
|
|
|
return (s);
|
|
|
|
}
|
|
|
|
|
|
|
|
//*************************************************************************
|
|
|
|
//*** load shape level polygons
|
|
|
|
//*
|
|
|
|
//* pre fp open
|
|
|
|
//* s allocated, s->npolys set
|
|
|
|
//*
|
|
|
|
//* params fp = currently open shape file pointer
|
|
|
|
//* s = pointer to shape level
|
|
|
|
//*
|
|
|
|
//* on exit s->polys allocated (iFSDPoly * s->npolys
|
|
|
|
//* s->pindex allocated for each poly
|
|
|
|
//* returns FALSE on error (memory allocation failure/bad file format)
|
|
|
|
//*
|
|
|
|
//******
|
|
|
|
static iBool _imd_load_polys(STRING **ppFileData, STRING *FileDataEnd, iIMDShape *s)
|
|
|
|
{
|
|
|
|
STRING *pFileData = *ppFileData;
|
|
|
|
int cnt;
|
|
|
|
int i, j; //, anim;
|
|
|
|
iVector p0, p1, p2, *points;
|
|
|
|
iIMDPoly *poly;
|
|
|
|
int nFrames,pbRate,tWidth,tHeight;
|
|
|
|
|
|
|
|
//assumes points already set
|
|
|
|
points = s->points;
|
|
|
|
|
|
|
|
IMDPolycount+= s->npolys;
|
|
|
|
|
|
|
|
s->numFrames = 0;
|
|
|
|
s->animInterval = 0;
|
|
|
|
|
|
|
|
s->polys = (iIMDPoly *) iV_HeapAlloc(sizeof(iIMDPoly) * s->npolys);
|
|
|
|
|
|
|
|
if (s->polys) {
|
|
|
|
poly = s->polys;
|
|
|
|
|
|
|
|
for (i = 0; i < s->npolys; i++, poly++) {
|
|
|
|
UDWORD flags,npnts;
|
|
|
|
|
|
|
|
if (sscanf(pFileData, "%x %d%n", &flags, &npnts, &cnt) != 2) {
|
|
|
|
iV_Error(0xff,"(_load_polys) [poly %d] error loading flags and npoints",i);
|
|
|
|
}
|
|
|
|
pFileData += cnt;
|
|
|
|
|
|
|
|
poly->flags=flags;
|
|
|
|
|
|
|
|
if (flags & PIE_NO_CULL) {
|
|
|
|
s->flags |= iV_IMD_NOCULLSOME;
|
|
|
|
}
|
|
|
|
|
|
|
|
poly->npnts=npnts;
|
|
|
|
|
|
|
|
IMDVertexcount+= poly->npnts;
|
|
|
|
|
|
|
|
poly->pindex = (VERTEXID *) iV_HeapAlloc(sizeof(VERTEXID) * poly->npnts);
|
|
|
|
|
|
|
|
if ((poly->vrt = (iVertex *) iV_HeapAlloc(sizeof(iVertex) * poly->npnts)) == NULL) {
|
|
|
|
iV_Error(0xff,"(_load_polys) [poly %d] memory alloc fail (vertex struct)",i);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (poly->pindex) {
|
|
|
|
for (j=0; j<poly->npnts; j++) {
|
|
|
|
int NewID;
|
|
|
|
|
|
|
|
if (sscanf(pFileData, "%d%n", &NewID,&cnt) != 1) {
|
2006-08-22 07:28:49 -07:00
|
|
|
debug( LOG_NEVER, "failed poly %d. point %d [%s]\n", i, j, _IMD_NAME );
|
2007-06-28 10:47:08 -07:00
|
|
|
iV_Error(0xff,"(_load_polys) [poly %d] error reading poly indices",i);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
pFileData += cnt;
|
|
|
|
poly->pindex[j]=vertexTable[NewID];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
iV_Error(0xff,"(_load_polys) [poly %d] memory alloc fail (poly indices)",i);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// calc poly normal
|
|
|
|
if (poly->npnts > 2) {
|
|
|
|
p0.x = points[poly->pindex[0]].x;
|
|
|
|
p0.y = points[poly->pindex[0]].y;
|
|
|
|
p0.z = points[poly->pindex[0]].z;
|
|
|
|
|
|
|
|
p1.x = points[poly->pindex[1]].x;
|
|
|
|
p1.y = points[poly->pindex[1]].y;
|
|
|
|
p1.z = points[poly->pindex[1]].z;
|
|
|
|
|
|
|
|
p2.x = points[poly->pindex[poly->npnts-1]].x;
|
|
|
|
p2.y = points[poly->pindex[poly->npnts-1]].y;
|
|
|
|
p2.z = points[poly->pindex[poly->npnts-1]].z;
|
|
|
|
|
|
|
|
pie_SurfaceNormal(&p0,&p1,&p2,&poly->normal);
|
|
|
|
//iV_DEBUG3("normal %d %d %d\n",poly->normal.x,poly->normal.y,poly->normal.z);
|
|
|
|
} else {
|
|
|
|
poly->normal.x = poly->normal.y = poly->normal.z = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (poly->flags & iV_IMD_TEXANIM) {
|
|
|
|
IMDTexAnims++;
|
|
|
|
|
|
|
|
if ((poly->pTexAnim = (iTexAnim *)iV_HeapAlloc(sizeof(iTexAnim))) == NULL) {
|
|
|
|
iV_Error(0xff,"(_load_polys) [poly %d] memory alloc fail (iTexAnim struct)",i);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// even the psx needs to skip the data
|
|
|
|
if (sscanf(pFileData,"%d %d %d %d%n",
|
|
|
|
&nFrames,
|
|
|
|
&pbRate,
|
|
|
|
&tWidth,
|
2006-06-02 12:34:58 -07:00
|
|
|
&tHeight,&cnt) != 4)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
|
|
|
iV_Error(0xff,"(_load_polys) [poly %d] error reading texanim data",i);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
pFileData += cnt;
|
|
|
|
|
|
|
|
ASSERT( (tWidth>0, "_imd_load_polys: texture width = %i", tWidth) );
|
|
|
|
ASSERT( (tHeight>0, "_imd_load_polys: texture height = %i", tHeight) );
|
|
|
|
|
|
|
|
poly->pTexAnim->nFrames = nFrames;
|
2006-06-02 12:34:58 -07:00
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
/* Assumes same number of frames per poly */
|
2006-06-02 12:34:58 -07:00
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
s->numFrames = nFrames;
|
|
|
|
poly->pTexAnim->playbackRate =pbRate;
|
|
|
|
|
|
|
|
/* Uses Max metric playback rate */
|
|
|
|
s->animInterval = pbRate;
|
|
|
|
poly->pTexAnim->textureWidth =tWidth;
|
|
|
|
poly->pTexAnim->textureHeight =tHeight;
|
|
|
|
} else {
|
2006-06-02 12:34:58 -07:00
|
|
|
poly->pTexAnim = NULL;
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
// PC texture coord routine
|
|
|
|
if (poly->vrt && (poly->flags & (iV_IMD_TEX|iV_IMD_PSXTEX))) {
|
|
|
|
for (j=0; j<poly->npnts; j++) {
|
|
|
|
int32 VertexU,VertexV;
|
|
|
|
if (sscanf(pFileData, "%d %d%n", &VertexU, &VertexV, &cnt) != 2) {
|
|
|
|
iV_Error(0xff,"(_load_polys) [poly %d] error reading tex outline",i);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
pFileData += cnt;
|
|
|
|
|
|
|
|
poly->vrt[j].u=VertexU;
|
|
|
|
poly->vrt[j].v=VertexV;
|
|
|
|
poly->vrt[j].g=255;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef BSPIMD
|
|
|
|
poly->BSP_NextPoly=BSPPOLYID_TERMINATE; // make it end end of the BSP chain by default
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*ppFileData = pFileData;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef BSPIMD
|
|
|
|
|
|
|
|
// The order for the BSP section of the IMD is :-
|
|
|
|
// LEFTLINK FORWARD_POLYGONS_LIST_TEMRINATED_BY_-1 BACKWARD_POLYGONS_LIST_TEMRINATED_BY_-1 RIGHTLINK
|
|
|
|
|
|
|
|
#define GETBSPTRIANGLE(polyid) (&(s->polys[(polyid)]))
|
|
|
|
|
|
|
|
static iBool _imd_load_bsp(STRING **ppFileData, STRING *FileDataEnd, iIMDShape *s, UWORD BSPNodeCount)
|
|
|
|
{
|
|
|
|
STRING *pFileData = *ppFileData;
|
|
|
|
int cnt;
|
|
|
|
UWORD Node;
|
|
|
|
PSBSPTREENODE NodeList; // An pointer to an array of nodes
|
|
|
|
iIMDPoly *IMDTri; // pointer to a polygon ... for handling the link list in the bsp
|
|
|
|
iV_DEBUG1("imd[_load_bsp] = number of nodes =%d\n",BSPNodeCount);
|
|
|
|
|
|
|
|
if (s->npolys > BSPPOLYID_MAXPOLYID) {
|
|
|
|
iV_Error(0xff,"(_imd_load_bsp) Too many polygons in IMD for BSP to handle");
|
|
|
|
}
|
|
|
|
|
2006-06-02 12:34:58 -07:00
|
|
|
// Build table of nodes - we sort out the links later
|
2007-06-28 10:47:08 -07:00
|
|
|
NodeList=MALLOC((sizeof(BSPTREENODE))*BSPNodeCount); // Allocate the entire node tree
|
|
|
|
|
|
|
|
memset(NodeList,0,(sizeof(BSPTREENODE))*BSPNodeCount); // Zero it out ... we need to make all pointers NULL
|
|
|
|
|
|
|
|
for (Node = 0; Node < BSPNodeCount; Node++) {
|
|
|
|
BSPTREENODE *psNode;
|
|
|
|
|
|
|
|
SDWORD NodeID; // Temp storage area for a node ID
|
|
|
|
SDWORD PolygonID,FirstPolygonID; // Temp storage area for a polygon ID
|
|
|
|
|
|
|
|
psNode = &(NodeList[Node]);
|
|
|
|
|
|
|
|
FirstPolygonID=-1; // This indicates the first polygon in the forward facing BSP list
|
|
|
|
|
|
|
|
InitNode(psNode);
|
2006-06-02 12:34:58 -07:00
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
if (sscanf(pFileData,"%d%n",&NodeID,&cnt) != 1) // Check that we read 1 parameter ok
|
|
|
|
{
|
|
|
|
iV_Error(0xff,"(_load_bsp) - needed a left node!");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
pFileData += cnt;
|
2006-06-02 12:34:58 -07:00
|
|
|
psNode->link[LEFT]=(PSBSPTREENODE)NodeID; // This could be -1 indicating an empty node
|
2007-06-28 10:47:08 -07:00
|
|
|
|
2006-06-02 12:34:58 -07:00
|
|
|
// Get forward facing polygon list - never empty apart from root node
|
2007-06-28 10:47:08 -07:00
|
|
|
while(1) {
|
|
|
|
if (sscanf(pFileData,"%d%n",&PolygonID,&cnt) != 1) // Get a valid polygon number
|
|
|
|
{
|
|
|
|
iV_Error(0xff,"(_load_bsp) - needed a polygon number");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
pFileData += cnt;
|
2006-06-02 12:34:58 -07:00
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
if (PolygonID==-1) break;
|
|
|
|
|
|
|
|
if ((PolygonID<0) || (PolygonID >= s->npolys)) {
|
|
|
|
iV_Error(0xff,"(_load_bsp) - bad polygon number");
|
|
|
|
return FALSE;
|
|
|
|
}
|
2006-06-02 12:34:58 -07:00
|
|
|
|
|
|
|
if (FirstPolygonID==-1) FirstPolygonID=PolygonID;
|
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
IMDTri=GETBSPTRIANGLE(PolygonID);
|
|
|
|
if (IMDTri->BSP_NextPoly != BSPPOLYID_TERMINATE) {
|
|
|
|
iV_Error(0xff,"(_load_bsp) - Polygon is mentioned more than once in the BSP");
|
|
|
|
}
|
2006-06-02 12:34:58 -07:00
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
IMDTri->BSP_NextPoly=psNode->TriSameDir;
|
|
|
|
psNode->TriSameDir=PolygonID;
|
|
|
|
// list_Add( psNode->psTriSameDir , &(s->polys[PolygonID]) );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate the plane equation - if weve got any polygons
|
|
|
|
if (FirstPolygonID != -1) {
|
|
|
|
GetPlane(s, FirstPolygonID, &(psNode->Plane));
|
|
|
|
} else {
|
2006-06-02 12:34:58 -07:00
|
|
|
memset((char *)&(psNode->Plane),0,sizeof(PLANE)); // Clear the plane equation
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get reverse facing polygon list - frequently empty
|
|
|
|
while(1) {
|
|
|
|
if (sscanf(pFileData,"%d%n",&PolygonID,&cnt) != 1) // Get a valid polygon number
|
|
|
|
{
|
|
|
|
iV_Error(0xff,"(_load_bsp) - needed a polygon number");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
pFileData += cnt;
|
2006-06-02 12:34:58 -07:00
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
if (PolygonID == -1) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if ((PolygonID < 0) || (PolygonID >= s->npolys)) {
|
|
|
|
iV_Error(0xff,"(_load_bsp) - bad polygon number");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2006-06-02 12:34:58 -07:00
|
|
|
// Insert into the list
|
2007-06-28 10:47:08 -07:00
|
|
|
IMDTri=GETBSPTRIANGLE(PolygonID);
|
|
|
|
if (IMDTri->BSP_NextPoly != BSPPOLYID_TERMINATE) {
|
|
|
|
iV_Error(0xff,"(_load_bsp) - Polygon is mentioned more than once in the BSP");
|
|
|
|
}
|
2006-06-02 12:34:58 -07:00
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
IMDTri->BSP_NextPoly=psNode->TriOppoDir;
|
|
|
|
psNode->TriOppoDir=PolygonID;
|
|
|
|
|
|
|
|
// list_Add( psNode->psTriOppoDir , &(s->polys[PolygonID]) );
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sscanf(pFileData,"%d%n",&NodeID,&cnt) != 1) // Check that we read 1 parameter ok
|
|
|
|
{
|
|
|
|
iV_Error(0xff,"(_load_bsp) - needed a right node!");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
pFileData += cnt;
|
2006-06-02 12:34:58 -07:00
|
|
|
psNode->link[RIGHT]=(PSBSPTREENODE)NodeID; // This could be -1 indicating an empty node
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now fix all the links
|
|
|
|
for (Node = 0; Node < BSPNodeCount; Node++) {
|
|
|
|
BSPTREENODE *psNode;
|
|
|
|
int NodeID;
|
|
|
|
|
|
|
|
psNode = &(NodeList[Node]);
|
|
|
|
|
|
|
|
if ((SDWORD)(psNode->link[LEFT]) == -1) {
|
2006-06-02 12:34:58 -07:00
|
|
|
psNode->link[LEFT]=0; // if its zero then its an empty link
|
2007-06-28 10:47:08 -07:00
|
|
|
} else {
|
|
|
|
NodeID = (int) psNode->link[LEFT];
|
|
|
|
psNode->link[LEFT] = &NodeList[NodeID];
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((SDWORD)(psNode->link[RIGHT]) == -1) {
|
2006-06-02 12:34:58 -07:00
|
|
|
psNode->link[RIGHT]=0; // if its zero then its an empty link
|
2007-06-28 10:47:08 -07:00
|
|
|
} else {
|
|
|
|
NodeID = (int) psNode->link[RIGHT];
|
|
|
|
psNode->link[RIGHT] = &NodeList[NodeID];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-06-02 12:34:58 -07:00
|
|
|
// Set the shape node list to the root node ... this can be used to
|
2007-06-28 10:47:08 -07:00
|
|
|
// FREE up the BSP memory if we needed to
|
|
|
|
s->BSPNode = &NodeList[0];
|
|
|
|
iV_DEBUG0("BSP Loaded AOK\n");
|
|
|
|
|
|
|
|
*ppFileData = pFileData;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
BOOL ReadPoints(STRING **ppFileData, STRING *FileDataEnd, iIMDShape *s)
|
|
|
|
{
|
|
|
|
STRING *pFileData = *ppFileData;
|
|
|
|
int cnt;
|
|
|
|
int i;
|
|
|
|
iVector *p;
|
|
|
|
int lastPoint,match,j;
|
|
|
|
SDWORD newX,newY,newZ;
|
|
|
|
|
|
|
|
p = s->points;
|
|
|
|
|
|
|
|
lastPoint = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < s->npoints; i++) {
|
|
|
|
if (sscanf(pFileData, "%d %d %d%n", &(newX), &(newY), &(newZ), &cnt) != 3) {
|
|
|
|
iV_Error(0xff,"(_load_points) file corrupt -K");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
pFileData += cnt;
|
2006-06-02 12:34:58 -07:00
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
// DBPRINTF(("%d) x=%d y=%x z=%d\n",i,newX,newY,newZ));
|
|
|
|
//check for duplicate points
|
|
|
|
match = -1;
|
|
|
|
j = 0;
|
|
|
|
|
|
|
|
// scan through list upto the number of points added (lastPoint) ... not up to the number of points scanned in (i) (which will include duplicates)
|
|
|
|
while((j < lastPoint) && (match == -1))
|
|
|
|
// while((j < i) && (match == -1))
|
|
|
|
{
|
|
|
|
if (newX == p[j].x) {
|
|
|
|
if (newY == p[j].y) {
|
|
|
|
if (newZ == p[j].z) {
|
|
|
|
match = j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (match == -1) {
|
|
|
|
// new point
|
|
|
|
p[lastPoint].x=newX;
|
|
|
|
p[lastPoint].y=newY;
|
|
|
|
p[lastPoint].z=newZ;
|
|
|
|
vertexTable[i] = lastPoint;
|
|
|
|
lastPoint++;
|
|
|
|
} else {
|
|
|
|
vertexTable[i] = match;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//clear remaining table
|
|
|
|
for (i = s->npoints; i < iV_IMD_MAX_POINTS; i++) {
|
|
|
|
vertexTable[i] = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
s->npoints = lastPoint;
|
|
|
|
|
|
|
|
*ppFileData = pFileData;
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//*************************************************************************
|
|
|
|
//*** load shape level vertices
|
|
|
|
//*
|
|
|
|
//* pre fp open
|
|
|
|
//* s allocated, s->npoints set
|
|
|
|
//*
|
|
|
|
//* params fp = currently open shape file pointer
|
|
|
|
//* s = pointer to shape level
|
|
|
|
//*
|
|
|
|
//* on exit s->points allocated (iVector * s->npoints
|
|
|
|
//* returns FALSE on error (memory allocation failure/bad file format)
|
|
|
|
//*
|
|
|
|
//******
|
|
|
|
static iBool _imd_load_points(STRING **ppFileData, STRING *FileDataEnd, iIMDShape *s)
|
|
|
|
{
|
|
|
|
int i ;
|
|
|
|
iVector *p;
|
|
|
|
int32 tempXMax,tempXMin,tempZMax,tempZMin,extremeX,extremeZ;
|
|
|
|
int32 xmax, ymax, zmax;
|
|
|
|
double dx, dy, dz, rad_sq, rad, old_to_p_sq, old_to_p, old_to_new;
|
|
|
|
double xspan, yspan, zspan, maxspan;
|
|
|
|
iVectorf dia1, dia2, cen;
|
|
|
|
iVectorf vxmin = { 0, 0, 0 }, vymin = { 0, 0, 0 }, vzmin = { 0, 0, 0 },
|
|
|
|
vxmax = { 0, 0, 0 }, vymax = { 0, 0, 0 }, vzmax = { 0, 0, 0 };
|
|
|
|
|
|
|
|
//load the points then pass through a second time to setup bounding datavalues
|
|
|
|
|
|
|
|
IMDPoints+=s->npoints;
|
|
|
|
|
|
|
|
s->points = p = (iVector *) iV_HeapAlloc(sizeof(iVector) * s->npoints);
|
|
|
|
if (p == NULL) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read in points and remove duplicates (!)
|
|
|
|
if (ReadPoints(ppFileData,FileDataEnd, s)==FALSE) return FALSE;
|
|
|
|
|
|
|
|
s->xmax = s->ymax = s->zmax = tempXMax = tempZMax = -FP12_MULTIPLIER;
|
|
|
|
s->xmin = s->ymin = s->zmin = tempXMin = tempZMin = FP12_MULTIPLIER;
|
|
|
|
|
|
|
|
vxmax.x = vymax.y = vzmax.z = (double) -FP12_MULTIPLIER;
|
|
|
|
vxmin.x = vymin.y = vzmin.z = (double) FP12_MULTIPLIER;
|
|
|
|
|
2006-06-02 12:34:58 -07:00
|
|
|
// set up bounding data for minimum number of vertices
|
2007-06-28 10:47:08 -07:00
|
|
|
for (i = 0; i < s->npoints; i++, p++) {
|
|
|
|
if (p->x > s->xmax)
|
|
|
|
s->xmax = p->x;
|
|
|
|
if (p->x < s->xmin)
|
|
|
|
s->xmin = p->x;
|
|
|
|
|
|
|
|
/* Biggest x coord so far within our height window? */
|
|
|
|
if( (p->x > tempXMax) && (p->y > DROID_VIS_LOWER) && (p->y < DROID_VIS_UPPER) )
|
|
|
|
{
|
|
|
|
tempXMax = p->x;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Smallest x coord so far within our height window? */
|
|
|
|
if( (p->x < tempXMin) && (p->y > DROID_VIS_LOWER) && (p->y < DROID_VIS_UPPER) )
|
|
|
|
{
|
|
|
|
tempXMin = p->x;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p->y > s->ymax)
|
|
|
|
s->ymax = p->y;
|
|
|
|
if (p->y < s->ymin)
|
|
|
|
s->ymin = p->y;
|
2006-06-02 12:34:58 -07:00
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
if (p->z > s->zmax)
|
|
|
|
s->zmax = p->z;
|
|
|
|
if (p->z < s->zmin)
|
|
|
|
s->zmin = p->z;
|
|
|
|
|
|
|
|
/* Biggest z coord so far within our height window? */
|
|
|
|
if( (p->z > tempZMax) && (p->y > DROID_VIS_LOWER) && (p->y < DROID_VIS_UPPER) )
|
|
|
|
{
|
|
|
|
tempZMax = p->z;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Smallest z coord so far within our height window? */
|
|
|
|
if( (p->z < tempZMax) && (p->y > DROID_VIS_LOWER) && (p->y < DROID_VIS_UPPER) )
|
|
|
|
{
|
|
|
|
tempZMin = p->z;
|
|
|
|
}
|
|
|
|
|
|
|
|
// for tight sphere calculations
|
|
|
|
|
|
|
|
if ((double) p->x < vxmin.x) {
|
|
|
|
vxmin.x = (double) p->x;
|
|
|
|
vxmin.y = (double) p->y;
|
|
|
|
vxmin.z = (double) p->z;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((double) p->x > vxmax.x) {
|
|
|
|
vxmax.x = (double) p->x;
|
|
|
|
vxmax.y = (double) p->y;
|
|
|
|
vxmax.z = (double) p->z;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((double) p->y < vymin.y) {
|
|
|
|
vymin.x = (double) p->x;
|
|
|
|
vymin.y = (double) p->y;
|
|
|
|
vymin.z = (double) p->z;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((double) p->y > vymax.y) {
|
|
|
|
vymax.x = (double) p->x;
|
|
|
|
vymax.y = (double) p->y;
|
|
|
|
vymax.z = (double) p->z;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((double) p->z < vzmin.z) {
|
|
|
|
vzmin.x = (double) p->x;
|
|
|
|
vzmin.y = (double) p->y;
|
|
|
|
vzmin.z = (double) p->z;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ((double) p->z > vzmax.z) {
|
|
|
|
vzmax.x = (double) p->x;
|
|
|
|
vzmax.y = (double) p->y;
|
|
|
|
vzmax.z = (double) p->z;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Centered about origin I can do the '-' thing below!! */
|
|
|
|
extremeX = pie_MAX(tempXMax,-tempXMin);
|
|
|
|
extremeZ = pie_MAX(tempZMax,-tempZMin);
|
|
|
|
|
|
|
|
s->visRadius = pie_MAX(extremeX,extremeZ);
|
|
|
|
// no need to scale an IMD shape (only FSD)
|
|
|
|
|
|
|
|
xmax = pie_MAX(s->xmax,-s->xmin);
|
|
|
|
ymax = pie_MAX(s->ymax,-s->ymin);
|
|
|
|
zmax = pie_MAX(s->zmax,-s->zmin);
|
|
|
|
|
|
|
|
s->radius = pie_MAX(xmax,(pie_MAX(ymax,zmax)));
|
|
|
|
|
|
|
|
|
|
|
|
s->sradius = (SDWORD)((float)sqrt( xmax*xmax + ymax*ymax + zmax*zmax));
|
|
|
|
|
|
|
|
// START: tight bounding sphere
|
|
|
|
|
|
|
|
// set xspan = distance between 2 points xmin & xmax (squared)
|
|
|
|
|
|
|
|
dx = vxmax.x - vxmin.x;
|
|
|
|
dy = vxmax.y - vxmin.y;
|
|
|
|
dz = vxmax.z - vxmin.z;
|
|
|
|
xspan = dx*dx + dy*dy + dz*dz;
|
|
|
|
|
|
|
|
// same for yspan
|
|
|
|
|
|
|
|
dx = vymax.x - vymin.x;
|
|
|
|
dy = vymax.y - vymin.y;
|
|
|
|
dz = vymax.z - vymin.z;
|
|
|
|
yspan = dx*dx + dy*dy + dz*dz;
|
|
|
|
|
|
|
|
// and ofcourse zspan
|
|
|
|
|
|
|
|
dx = vzmax.x - vzmin.x;
|
|
|
|
dy = vzmax.y - vzmin.y;
|
|
|
|
dz = vzmax.z - vzmin.z;
|
|
|
|
zspan = dx*dx + dy*dy + dz*dz;
|
|
|
|
|
|
|
|
// set points dia1 & dia2 to maximally seperated pair
|
|
|
|
|
|
|
|
// assume xspan biggest
|
|
|
|
|
|
|
|
dia1 = vxmin;
|
|
|
|
dia2 = vxmax;
|
|
|
|
maxspan = xspan;
|
|
|
|
|
|
|
|
if (yspan>maxspan) {
|
|
|
|
maxspan = yspan;
|
|
|
|
dia1 = vymin;
|
|
|
|
dia2 = vymax;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (zspan>maxspan) {
|
|
|
|
maxspan = zspan;
|
|
|
|
dia1 = vzmin;
|
|
|
|
dia2 = vzmax;
|
|
|
|
}
|
|
|
|
|
|
|
|
// dia1, dia2 diameter of initial sphere
|
|
|
|
|
|
|
|
cen.x = (dia1.x + dia2.x) / 2.;
|
|
|
|
cen.y = (dia1.y + dia2.y) / 2.;
|
|
|
|
cen.z = (dia1.z + dia2.z) / 2.;
|
|
|
|
|
|
|
|
// calc initial radius
|
|
|
|
|
|
|
|
dx = dia2.x - cen.x;
|
|
|
|
dy = dia2.y - cen.y;
|
|
|
|
dz = dia2.z - cen.z;
|
|
|
|
|
|
|
|
rad_sq = dx*dx + dy*dy + dz*dz;
|
|
|
|
rad = sqrt(rad_sq);
|
|
|
|
|
|
|
|
// second pass (find tight sphere)
|
|
|
|
|
|
|
|
for (p = s->points, i=0; i<s->npoints; i++, p++) {
|
|
|
|
dx = p->x - cen.x;
|
|
|
|
dy = p->y - cen.y;
|
|
|
|
dz = p->z - cen.z;
|
|
|
|
old_to_p_sq = dx*dx + dy*dy + dz*dz;
|
|
|
|
|
|
|
|
// do r**2 first
|
|
|
|
if (old_to_p_sq>rad_sq) {
|
|
|
|
// this point outside current sphere
|
|
|
|
old_to_p = sqrt(old_to_p_sq);
|
|
|
|
// radius of new sphere
|
|
|
|
rad = (rad + old_to_p) / 2.;
|
|
|
|
// rad**2 for next compare
|
|
|
|
rad_sq = rad*rad;
|
|
|
|
old_to_new = old_to_p - rad;
|
|
|
|
// centre of new sphere
|
|
|
|
cen.x = (rad*cen.x + old_to_new*p->x) / old_to_p;
|
|
|
|
cen.y = (rad*cen.y + old_to_new*p->y) / old_to_p;
|
|
|
|
cen.z = (rad*cen.z + old_to_new*p->z) / old_to_p;
|
|
|
|
iV_DEBUG4("NEW SPHERE: cen,rad = %d %d %d, %d\n",(int32) cen.x, (int32) cen.y, (int32) cen.z, (int32) rad);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
s->ocen.x = (int32) cen.x;
|
|
|
|
s->ocen.y = (int32) cen.y;
|
|
|
|
s->ocen.z = (int32) cen.z;
|
|
|
|
s->oradius = (int32) rad;
|
|
|
|
iV_DEBUG2("radius, sradius, %d, %d\n",s->radius,s->sradius);
|
|
|
|
iV_DEBUG4("SPHERE: cen,rad = %d %d %d, %d\n",s->ocen.x,s->ocen.y,s->ocen.z,s->oradius);
|
|
|
|
|
|
|
|
// END: tight bounding sphere
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static iBool _imd_load_connectors(STRING **ppFileData, STRING *FileDataEnd, iIMDShape *s)
|
|
|
|
{
|
|
|
|
STRING *pFileData = *ppFileData;
|
|
|
|
int cnt;
|
|
|
|
int i;
|
|
|
|
iVector *p;
|
|
|
|
SDWORD newX,newY,newZ;
|
|
|
|
|
|
|
|
IMDConnectors+=s->nconnectors;
|
|
|
|
|
|
|
|
if ((s->connectors = (iVector *) iV_HeapAlloc(sizeof(iVector) * s->nconnectors)) == NULL)
|
|
|
|
{
|
|
|
|
iV_Error(0xff,"(_load_connectors) iV_HeapAlloc fail");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = s->connectors;
|
|
|
|
|
2006-06-02 12:34:58 -07:00
|
|
|
for (i=0; i<s->nconnectors; i++, p++)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
2006-06-02 12:34:58 -07:00
|
|
|
if (sscanf(pFileData,"%d %d %d%n",&(newX),&(newY),&(newZ),&cnt) != 3)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
|
|
|
iV_Error(0xff,"(_load_connectors) file corrupt -M");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
pFileData += cnt;
|
|
|
|
p->x=newX;
|
|
|
|
p->y=newY;
|
|
|
|
p->z=newZ;
|
|
|
|
}
|
|
|
|
|
|
|
|
*ppFileData = pFileData;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//*************************************************************************
|
|
|
|
//*** load shape levels recurrsively
|
|
|
|
//*
|
|
|
|
//* pre fp open
|
|
|
|
//*
|
|
|
|
//* params fp = currently open shape file pointer
|
|
|
|
//* s = pointer to shape level
|
|
|
|
//* texpage = texture page number if iV_IMD_TEX
|
|
|
|
//*
|
|
|
|
//* on exit s allocated
|
|
|
|
//* returns pointer to iFSDShape structure (or NULL on error)
|
|
|
|
//*
|
|
|
|
//******
|
|
|
|
static iIMDShape *_imd_load_level(STRING **ppFileData, STRING *FileDataEnd, int nlevels, int texpage)
|
|
|
|
{
|
|
|
|
STRING *pFileData = *ppFileData;
|
|
|
|
int cnt;
|
|
|
|
iIMDShape *s;
|
|
|
|
char buffer[MAX_FILE_PATH];
|
|
|
|
// int level;
|
|
|
|
int n;
|
|
|
|
int npolys;
|
|
|
|
|
|
|
|
#ifdef BSPIMD
|
|
|
|
// UWORD NumberOfParameters;
|
|
|
|
// UDWORD count;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (nlevels == 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
s = (iIMDShape *) iV_HeapAlloc(sizeof(iIMDShape));
|
|
|
|
|
|
|
|
if (s) {
|
|
|
|
s->points = NULL;
|
|
|
|
s->polys = NULL;
|
|
|
|
s->connectors = NULL;
|
|
|
|
s->texanims = NULL;
|
|
|
|
s->next=NULL;
|
|
|
|
|
|
|
|
// if we can be sure that there is no bsp ... the we check for level number at this point
|
|
|
|
#ifndef BSPIMD
|
|
|
|
if (sscanf(pFileData,"%s %d%n",buffer,&level,&cnt) != 2) {
|
|
|
|
debug(LOG_ERROR, "_imd_load_level: file corrupt");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
pFileData += cnt;
|
|
|
|
|
|
|
|
if (strcmp(buffer,"LEVEL") != 0) {
|
|
|
|
debug(LOG_ERROR, "_imd_load_level: excepting 'LEVEL' directive");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
s->flags = _IMD_FLAGS;
|
|
|
|
s->texpage = texpage;
|
|
|
|
|
|
|
|
if (sscanf(pFileData,"%s %d%n",buffer,&n,&cnt) != 2) {
|
|
|
|
debug(LOG_ERROR, "_imd_load_level(2): file corrupt");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
pFileData += cnt;
|
|
|
|
|
|
|
|
// load texture anims if specified
|
|
|
|
|
|
|
|
// load points
|
|
|
|
|
|
|
|
if (strcmp(buffer,"POINTS") != 0) {
|
|
|
|
debug(LOG_ERROR, "_imd_load_level: expecting 'POINTS' directive");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (n>iV_IMD_MAX_POINTS) {
|
|
|
|
debug(LOG_ERROR, "_imd_load_level: too many points in IMD");
|
|
|
|
}
|
|
|
|
|
|
|
|
s->npoints = n;
|
|
|
|
|
|
|
|
// DBPRINTF(("%s %d , %d \n",buffer,n,s->npoints));
|
|
|
|
|
|
|
|
// Some imd/pie's were greater than the max number of points causing all sorts of memory overflows (blfact2)
|
|
|
|
//
|
|
|
|
// There was no check / error handling!
|
|
|
|
//
|
|
|
|
|
|
|
|
_imd_load_points(&pFileData,FileDataEnd,s);
|
|
|
|
|
|
|
|
if (sscanf(pFileData,"%s %d%n",buffer,&npolys,&cnt) != 2) {
|
|
|
|
debug(LOG_ERROR, "_imd_load_level(3): file corrupt");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
pFileData += cnt;
|
|
|
|
|
|
|
|
s->npolys=npolys;
|
2006-06-02 12:34:58 -07:00
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
if (strcmp(buffer,"POLYGONS") != 0) {
|
|
|
|
debug(LOG_ERROR,"_imd_load_level: expecting 'POLYGONS' directive");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// DBPRINTF(("loading polygons - %d\n",s->npolys));
|
|
|
|
_imd_load_polys(&pFileData,FileDataEnd,s);
|
|
|
|
|
|
|
|
|
|
|
|
//NOW load optional stuff
|
|
|
|
{
|
|
|
|
BOOL OptionalsCompleted;
|
|
|
|
#ifdef BSPIMD
|
|
|
|
s->BSPNode=NULL; // Zero the bsp node pointer to zero as a default
|
|
|
|
#endif
|
|
|
|
|
|
|
|
s->nconnectors = 0; // Default number of connectors must be 0 ( this was'nt being done PBD. )
|
|
|
|
|
|
|
|
OptionalsCompleted=FALSE;
|
|
|
|
|
|
|
|
while(OptionalsCompleted == FALSE) {
|
|
|
|
|
|
|
|
// DBPRINTF(("current file pos = %p (%x)(%x)(%x) - endoffile = %p\n",*ppFileData,**ppFileData,*((*ppFileData)+1),*((*ppFileData)+2),FileDataEnd));
|
|
|
|
|
|
|
|
// check for end of file (give or take white space)
|
|
|
|
if (AtEndOfFile(*&pFileData,FileDataEnd)==TRUE)
|
|
|
|
{
|
|
|
|
OptionalsCompleted=TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Scans in the line ... if we don't get 2 parameters then quit
|
|
|
|
if (sscanf(pFileData,"%s %d%n",buffer,&n,&cnt) != 2)
|
|
|
|
{
|
|
|
|
OptionalsCompleted=TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
pFileData += cnt;
|
|
|
|
|
|
|
|
|
|
|
|
// check for next level ... or might be a BSP - This should handle an imd if it has a BSP tree attached to it
|
|
|
|
// might be "BSP" or "LEVEL"
|
|
|
|
if (strcmp(buffer,"LEVEL") == 0)
|
|
|
|
{
|
|
|
|
iV_DEBUG2("imd[_load_level] = npoints %d, npolys %d\n",s->npoints,s->npolys);
|
|
|
|
s->next = _imd_load_level(&pFileData,FileDataEnd,nlevels-1,texpage);
|
|
|
|
}
|
|
|
|
#ifdef BSPIMD
|
|
|
|
else if (strcmp(buffer,"BSP") == 0)
|
|
|
|
{
|
|
|
|
_imd_load_bsp(&pFileData,FileDataEnd,s,(UWORD)n);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
else if (strcmp(buffer,"CONNECTORS") == 0)
|
|
|
|
{
|
|
|
|
//load connector stuff
|
|
|
|
s->nconnectors = n;
|
|
|
|
_imd_load_connectors(&pFileData,FileDataEnd,s);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// DBPRINTF(("1) current file pos = %p (%x) - endoffile = %p\n",*ppFileData,**ppFileData,FileDataEnd));
|
|
|
|
iV_Error(0xff,"(_load_level) unexpected directive %s %d",buffer,&n);
|
|
|
|
OptionalsCompleted=TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Failed to allocate memory for s */
|
|
|
|
debug(LOG_ERROR, "_imd_load_level: Memory allocation error");
|
|
|
|
}
|
|
|
|
*ppFileData = pFileData;
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL iV_setImagePath(STRING *path)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
strcpy(imagePath,path);
|
|
|
|
i = strlen(imagePath);
|
|
|
|
if (imagePath[i] != '\\')
|
|
|
|
{
|
2006-06-02 12:34:58 -07:00
|
|
|
imagePath[i] = '\\';
|
2007-06-28 10:47:08 -07:00
|
|
|
imagePath[i+1] = 0;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static char *_imd_get_path(STRING *filename, STRING *path)
|
|
|
|
{
|
|
|
|
int n, i;
|
|
|
|
|
|
|
|
n = strlen(filename);
|
|
|
|
|
|
|
|
for (i=n-1; i>=0 && (filename[i] != '\\'); i--)
|
|
|
|
;
|
|
|
|
|
|
|
|
if (i<0)
|
|
|
|
path[0] = '\0';
|
|
|
|
else {
|
|
|
|
memcpy(path,filename,i+1);
|
|
|
|
path[i+1] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
|
|
BOOL CheckColourKey( iIMDShape *psShape ) {
|
|
|
|
iIMDShape *psShapeLevel;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if ( rendSurface.usr >= REND_D3D_RGB &&
|
|
|
|
rendSurface.usr <= REND_D3D_REF )
|
|
|
|
{
|
|
|
|
/* check model override flags else check all polys for colorkey flag */
|
|
|
|
if ( _IMD_FLAGS & iV_IMD_XTRANS ) {
|
|
|
|
return TRUE;
|
|
|
|
} else {
|
|
|
|
psShapeLevel = psShape;
|
|
|
|
|
|
|
|
/* loop over levels in model */
|
|
|
|
while ( psShape != NULL ) {
|
|
|
|
/* loop over polys in level */
|
|
|
|
for ( i=0; i<psShape->npolys; i++ ) {
|
|
|
|
/* break if transparent poly found */
|
|
|
|
if ( psShape->polys[i].flags & PIE_COLOURKEYED ) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* next level */
|
|
|
|
psShape = psShape->next;
|
2006-06-02 12:34:58 -07:00
|
|
|
}
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|