30c7274c17
Prior to the Bazaar import, an unidentified committer moved some function declarations from 3d.h to interp.h, but only for Descent II. Replicate those changes in Descent I, and move the Descent II header interp.h to become common.
788 lines
20 KiB
C
788 lines
20 KiB
C
/*
|
|
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
|
|
SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
|
|
END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
|
|
ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
|
|
IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
|
|
SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
|
|
FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
|
|
CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
|
|
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
|
|
COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
|
*/
|
|
|
|
/*
|
|
*
|
|
* Hacked-in polygon objects
|
|
*
|
|
*/
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#ifdef DRIVE
|
|
#include "drive.h"
|
|
#else
|
|
#include "inferno.h"
|
|
#endif
|
|
#include "polyobj.h"
|
|
#include "vecmat.h"
|
|
#include "interp.h"
|
|
#include "dxxerror.h"
|
|
#include "u_mem.h"
|
|
#include "args.h"
|
|
#ifndef DRIVE
|
|
#include "texmap.h"
|
|
#include "bm.h"
|
|
#include "textures.h"
|
|
#include "object.h"
|
|
#include "lighting.h"
|
|
#include "piggy.h"
|
|
#endif
|
|
#include "byteswap.h"
|
|
#include "render.h"
|
|
#ifdef OGL
|
|
#include "ogl_init.h"
|
|
#endif
|
|
|
|
polymodel Polygon_models[MAX_POLYGON_MODELS]; // = {&bot11,&bot17,&robot_s2,&robot_b2,&bot11,&bot17,&robot_s2,&robot_b2};
|
|
|
|
int N_polygon_models = 0;
|
|
|
|
#define MAX_POLYGON_VECS 1000
|
|
g3s_point robot_points[MAX_POLYGON_VECS];
|
|
|
|
#define PM_COMPATIBLE_VERSION 6
|
|
#define PM_OBJFILE_VERSION 8
|
|
|
|
int Pof_file_end;
|
|
int Pof_addr;
|
|
|
|
#define MODEL_BUF_SIZE 32768
|
|
|
|
void _pof_cfseek(int len,int type)
|
|
{
|
|
switch (type) {
|
|
case SEEK_SET: Pof_addr = len; break;
|
|
case SEEK_CUR: Pof_addr += len; break;
|
|
case SEEK_END:
|
|
Assert(len <= 0); // seeking from end, better be moving back.
|
|
Pof_addr = Pof_file_end + len;
|
|
break;
|
|
}
|
|
|
|
if (Pof_addr > MODEL_BUF_SIZE)
|
|
Int3();
|
|
}
|
|
|
|
#define pof_cfseek(_buf,_len,_type) _pof_cfseek((_len),(_type))
|
|
|
|
int pof_read_int(ubyte *bufp)
|
|
{
|
|
int i;
|
|
|
|
i = *((int *) &bufp[Pof_addr]);
|
|
Pof_addr += 4;
|
|
return INTEL_INT(i);
|
|
|
|
// if (PHYSFS_read(f,&i,sizeof(i),1) != 1)
|
|
// Error("Unexpected end-of-file while reading object");
|
|
//
|
|
// return i;
|
|
}
|
|
|
|
size_t pof_cfread(void *dst, size_t elsize, size_t nelem, ubyte *bufp)
|
|
{
|
|
if (Pof_addr + nelem*elsize > Pof_file_end)
|
|
return 0;
|
|
|
|
memcpy(dst, &bufp[Pof_addr], elsize*nelem);
|
|
|
|
Pof_addr += elsize*nelem;
|
|
|
|
if (Pof_addr > MODEL_BUF_SIZE)
|
|
Int3();
|
|
|
|
return nelem;
|
|
}
|
|
|
|
// #define new_read_int(i,f) PHYSFS_read((f),&(i),sizeof(i),1)
|
|
#define new_pof_read_int(i,f) pof_cfread(&(i),sizeof(i),1,(f))
|
|
|
|
short pof_read_short(ubyte *bufp)
|
|
{
|
|
short s;
|
|
|
|
s = *((short *) &bufp[Pof_addr]);
|
|
Pof_addr += 2;
|
|
return INTEL_SHORT(s);
|
|
// if (PHYSFS_read(f,&s,sizeof(s),1) != 1)
|
|
// Error("Unexpected end-of-file while reading object");
|
|
//
|
|
// return s;
|
|
}
|
|
|
|
void pof_read_string(char *buf,int max, ubyte *bufp)
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i<max; i++) {
|
|
if ((*buf++ = bufp[Pof_addr++]) == 0)
|
|
break;
|
|
}
|
|
|
|
// while (max-- && (*buf=PHYSFSX_fgetc(f)) != 0) buf++;
|
|
|
|
}
|
|
|
|
void pof_read_vecs(vms_vector *vecs,int n,ubyte *bufp)
|
|
{
|
|
int i;
|
|
// PHYSFS_read(f,vecs,sizeof(vms_vector),n);
|
|
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
vecs[i].x = pof_read_int(bufp);
|
|
vecs[i].y = pof_read_int(bufp);
|
|
vecs[i].z = pof_read_int(bufp);
|
|
}
|
|
}
|
|
|
|
void pof_read_angvecs(vms_angvec *vecs,int n,ubyte *bufp)
|
|
{
|
|
int i;
|
|
// PHYSFS_read(f,vecs,sizeof(vms_vector),n);
|
|
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
vecs[i].p = pof_read_short(bufp);
|
|
vecs[i].b = pof_read_short(bufp);
|
|
vecs[i].h = pof_read_short(bufp);
|
|
}
|
|
}
|
|
|
|
#define ID_OHDR 0x5244484f // 'RDHO' //Object header
|
|
#define ID_SOBJ 0x4a424f53 // 'JBOS' //Subobject header
|
|
#define ID_GUNS 0x534e5547 // 'SNUG' //List of guns on this object
|
|
#define ID_ANIM 0x4d494e41 // 'MINA' //Animation data
|
|
#define ID_IDTA 0x41544449 // 'ATDI' //Interpreter data
|
|
#define ID_TXTR 0x52545854 // 'RTXT' //Texture filename list
|
|
|
|
#ifdef DRIVE
|
|
#define robot_info void
|
|
#else
|
|
vms_angvec anim_angs[N_ANIM_STATES][MAX_SUBMODELS];
|
|
|
|
//set the animation angles for this robot. Gun fields of robot info must
|
|
//be filled in.
|
|
void robot_set_angles(robot_info *r,polymodel *pm,vms_angvec angs[N_ANIM_STATES][MAX_SUBMODELS]);
|
|
#endif
|
|
|
|
#ifdef WORDS_NEED_ALIGNMENT
|
|
ubyte * old_dest(chunk o) // return where chunk is (in unaligned struct)
|
|
{
|
|
return o.old_base + INTEL_SHORT(*((short *)(o.old_base + o.offset)));
|
|
}
|
|
|
|
ubyte * new_dest(chunk o) // return where chunk is (in aligned struct)
|
|
{
|
|
return o.new_base + INTEL_SHORT(*((short *)(o.old_base + o.offset))) + o.correction;
|
|
}
|
|
|
|
/*
|
|
* find chunk with smallest address
|
|
*/
|
|
int get_first_chunks_index(chunk *chunk_list, int no_chunks)
|
|
{
|
|
int i, first_index = 0;
|
|
Assert(no_chunks >= 1);
|
|
for (i = 1; i < no_chunks; i++)
|
|
if (old_dest(chunk_list[i]) < old_dest(chunk_list[first_index]))
|
|
first_index = i;
|
|
return first_index;
|
|
}
|
|
#define SHIFT_SPACE 500 // increase if insufficent
|
|
|
|
void align_polygon_model_data(polymodel *pm)
|
|
{
|
|
int i, chunk_len;
|
|
int total_correction = 0;
|
|
ubyte *cur_old, *cur_new;
|
|
chunk cur_ch;
|
|
chunk ch_list[MAX_CHUNKS];
|
|
int no_chunks = 0;
|
|
int tmp_size = pm->model_data_size + SHIFT_SPACE;
|
|
ubyte *tmp = d_malloc(tmp_size); // where we build the aligned version of pm->model_data
|
|
|
|
Assert(tmp != NULL);
|
|
//start with first chunk (is always aligned!)
|
|
cur_old = pm->model_data;
|
|
cur_new = tmp;
|
|
chunk_len = get_chunks(cur_old, cur_new, ch_list, &no_chunks);
|
|
memcpy(cur_new, cur_old, chunk_len);
|
|
while (no_chunks > 0) {
|
|
int first_index = get_first_chunks_index(ch_list, no_chunks);
|
|
cur_ch = ch_list[first_index];
|
|
// remove first chunk from array:
|
|
no_chunks--;
|
|
for (i = first_index; i < no_chunks; i++)
|
|
ch_list[i] = ch_list[i + 1];
|
|
// if (new) address unaligned:
|
|
if ((u_int32_t)new_dest(cur_ch) % 4L != 0) {
|
|
// calculate how much to move to be aligned
|
|
short to_shift = 4 - (u_int32_t)new_dest(cur_ch) % 4L;
|
|
// correct chunks' addresses
|
|
cur_ch.correction += to_shift;
|
|
for (i = 0; i < no_chunks; i++)
|
|
ch_list[i].correction += to_shift;
|
|
total_correction += to_shift;
|
|
Assert((u_int32_t)new_dest(cur_ch) % 4L == 0);
|
|
Assert(total_correction <= SHIFT_SPACE); // if you get this, increase SHIFT_SPACE
|
|
}
|
|
//write (corrected) chunk for current chunk:
|
|
*((short *)(cur_ch.new_base + cur_ch.offset))
|
|
= INTEL_SHORT(cur_ch.correction
|
|
+ INTEL_SHORT(*((short *)(cur_ch.old_base + cur_ch.offset))));
|
|
//write (correctly aligned) chunk:
|
|
cur_old = old_dest(cur_ch);
|
|
cur_new = new_dest(cur_ch);
|
|
chunk_len = get_chunks(cur_old, cur_new, ch_list, &no_chunks);
|
|
memcpy(cur_new, cur_old, chunk_len);
|
|
//correct submodel_ptr's for pm, too
|
|
for (i = 0; i < MAX_SUBMODELS; i++)
|
|
if (pm->model_data + pm->submodel_ptrs[i] >= cur_old
|
|
&& pm->model_data + pm->submodel_ptrs[i] < cur_old + chunk_len)
|
|
pm->submodel_ptrs[i] += (cur_new - tmp) - (cur_old - pm->model_data);
|
|
}
|
|
d_free(pm->model_data);
|
|
pm->model_data_size += total_correction;
|
|
pm->model_data =
|
|
d_malloc(pm->model_data_size);
|
|
Assert(pm->model_data != NULL);
|
|
memcpy(pm->model_data, tmp, pm->model_data_size);
|
|
d_free(tmp);
|
|
}
|
|
#endif //def WORDS_NEED_ALIGNMENT
|
|
|
|
|
|
//reads a binary file containing a 3d model
|
|
polymodel *read_model_file(polymodel *pm,char *filename,robot_info *r)
|
|
{
|
|
PHYSFS_file *ifile;
|
|
short version;
|
|
int id,len, next_chunk;
|
|
ubyte model_buf[MODEL_BUF_SIZE];
|
|
|
|
if ((ifile=PHYSFSX_openReadBuffered(filename))==NULL)
|
|
Error("Can't open file <%s>",filename);
|
|
|
|
Assert(PHYSFS_fileLength(ifile) <= MODEL_BUF_SIZE);
|
|
|
|
Pof_addr = 0;
|
|
Pof_file_end = PHYSFS_read(ifile, model_buf, 1, PHYSFS_fileLength(ifile));
|
|
PHYSFS_close(ifile);
|
|
|
|
id = pof_read_int(model_buf);
|
|
|
|
if (id!=0x4f505350) /* 'OPSP' */
|
|
Error("Bad ID in model file <%s>",filename);
|
|
|
|
version = pof_read_short(model_buf);
|
|
|
|
if (version < PM_COMPATIBLE_VERSION || version > PM_OBJFILE_VERSION)
|
|
Error("Bad version (%d) in model file <%s>",version,filename);
|
|
|
|
while (new_pof_read_int(id,model_buf) == 1) {
|
|
id = INTEL_INT(id);
|
|
//id = pof_read_int(model_buf);
|
|
len = pof_read_int(model_buf);
|
|
next_chunk = Pof_addr + len;
|
|
|
|
switch (id) {
|
|
|
|
case ID_OHDR: { //Object header
|
|
vms_vector pmmin,pmmax;
|
|
|
|
pm->n_models = pof_read_int(model_buf);
|
|
pm->rad = pof_read_int(model_buf);
|
|
|
|
Assert(pm->n_models <= MAX_SUBMODELS);
|
|
|
|
pof_read_vecs(&pmmin,1,model_buf);
|
|
pof_read_vecs(&pmmax,1,model_buf);
|
|
|
|
break;
|
|
}
|
|
|
|
case ID_SOBJ: { //Subobject header
|
|
int n;
|
|
|
|
n = pof_read_short(model_buf);
|
|
|
|
Assert(n < MAX_SUBMODELS);
|
|
|
|
pm->submodel_parents[n] = pof_read_short(model_buf);
|
|
|
|
pof_read_vecs(&pm->submodel_norms[n],1,model_buf);
|
|
pof_read_vecs(&pm->submodel_pnts[n],1,model_buf);
|
|
pof_read_vecs(&pm->submodel_offsets[n],1,model_buf);
|
|
|
|
pm->submodel_rads[n] = pof_read_int(model_buf); //radius
|
|
|
|
pm->submodel_ptrs[n] = pof_read_int(model_buf); //offset
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#ifndef DRIVE
|
|
case ID_GUNS: { //List of guns on this object
|
|
|
|
if (r) {
|
|
int i;
|
|
vms_vector gun_dir;
|
|
|
|
r->n_guns = pof_read_int(model_buf);
|
|
|
|
Assert(r->n_guns <= MAX_GUNS);
|
|
|
|
for (i=0;i<r->n_guns;i++) {
|
|
int id;
|
|
|
|
id = pof_read_short(model_buf);
|
|
r->gun_submodels[id] = pof_read_short(model_buf);
|
|
Assert(r->gun_submodels[id] != 0xff);
|
|
pof_read_vecs(&r->gun_points[id],1,model_buf);
|
|
|
|
if (version >= 7)
|
|
pof_read_vecs(&gun_dir,1,model_buf);
|
|
}
|
|
}
|
|
else
|
|
pof_cfseek(model_buf,len,SEEK_CUR);
|
|
|
|
break;
|
|
}
|
|
|
|
case ID_ANIM: //Animation data
|
|
if (r) {
|
|
int n_frames,f,m;
|
|
|
|
n_frames = pof_read_short(model_buf);
|
|
|
|
Assert(n_frames == N_ANIM_STATES);
|
|
|
|
for (m=0;m<pm->n_models;m++)
|
|
for (f=0;f<n_frames;f++)
|
|
pof_read_angvecs(&anim_angs[f][m], 1, model_buf);
|
|
|
|
robot_set_angles(r,pm,anim_angs);
|
|
|
|
}
|
|
else
|
|
pof_cfseek(model_buf,len,SEEK_CUR);
|
|
|
|
break;
|
|
#endif
|
|
|
|
case ID_TXTR: { //Texture filename list
|
|
int n;
|
|
char name_buf[128];
|
|
|
|
n = pof_read_short(model_buf);
|
|
while (n--) {
|
|
pof_read_string(name_buf,128,model_buf);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ID_IDTA: //Interpreter data
|
|
pm->model_data = d_malloc(len);
|
|
pm->model_data_size = len;
|
|
|
|
pof_cfread(pm->model_data,1,len,model_buf);
|
|
|
|
break;
|
|
|
|
default:
|
|
pof_cfseek(model_buf,len,SEEK_CUR);
|
|
break;
|
|
|
|
}
|
|
if ( version >= 8 ) // Version 8 needs 4-byte alignment!!!
|
|
pof_cfseek(model_buf,next_chunk,SEEK_SET);
|
|
}
|
|
|
|
#ifdef WORDS_NEED_ALIGNMENT
|
|
align_polygon_model_data(pm);
|
|
#endif
|
|
#ifdef WORDS_BIGENDIAN
|
|
swap_polygon_model_data(pm->model_data);
|
|
#endif
|
|
|
|
return pm;
|
|
}
|
|
|
|
//reads the gun information for a model
|
|
//fills in arrays gun_points & gun_dirs, returns the number of guns read
|
|
int read_model_guns(char *filename,vms_vector *gun_points, vms_vector *gun_dirs, int *gun_submodels)
|
|
{
|
|
PHYSFS_file *ifile;
|
|
short version;
|
|
int id,len;
|
|
int n_guns=0;
|
|
ubyte model_buf[MODEL_BUF_SIZE];
|
|
|
|
if ((ifile=PHYSFSX_openReadBuffered(filename))==NULL)
|
|
Error("Can't open file <%s>",filename);
|
|
|
|
Assert(PHYSFS_fileLength(ifile) <= MODEL_BUF_SIZE);
|
|
|
|
Pof_addr = 0;
|
|
Pof_file_end = PHYSFS_read(ifile, model_buf, 1, PHYSFS_fileLength(ifile));
|
|
PHYSFS_close(ifile);
|
|
|
|
id = pof_read_int(model_buf);
|
|
|
|
if (id!=0x4f505350) /* 'OPSP' */
|
|
Error("Bad ID in model file <%s>",filename);
|
|
|
|
version = pof_read_short(model_buf);
|
|
|
|
Assert(version >= 7); //must be 7 or higher for this data
|
|
|
|
if (version < PM_COMPATIBLE_VERSION || version > PM_OBJFILE_VERSION)
|
|
Error("Bad version (%d) in model file <%s>",version,filename);
|
|
|
|
while (new_pof_read_int(id,model_buf) == 1) {
|
|
id = INTEL_INT(id);
|
|
//id = pof_read_int(model_buf);
|
|
len = pof_read_int(model_buf);
|
|
|
|
if (id == ID_GUNS) { //List of guns on this object
|
|
|
|
int i;
|
|
|
|
n_guns = pof_read_int(model_buf);
|
|
|
|
for (i=0;i<n_guns;i++) {
|
|
int id,sm;
|
|
|
|
id = pof_read_short(model_buf);
|
|
sm = pof_read_short(model_buf);
|
|
if (gun_submodels)
|
|
gun_submodels[id] = sm;
|
|
else if (sm!=0)
|
|
Error("Invalid gun submodel in file <%s>",filename);
|
|
pof_read_vecs(&gun_points[id],1,model_buf);
|
|
|
|
pof_read_vecs(&gun_dirs[id],1,model_buf);
|
|
}
|
|
|
|
}
|
|
else
|
|
pof_cfseek(model_buf,len,SEEK_CUR);
|
|
|
|
}
|
|
|
|
return n_guns;
|
|
}
|
|
|
|
//free up a model, getting rid of all its memory
|
|
void free_model(polymodel *po)
|
|
{
|
|
d_free(po->model_data);
|
|
}
|
|
|
|
grs_bitmap *texture_list[MAX_POLYOBJ_TEXTURES];
|
|
bitmap_index texture_list_index[MAX_POLYOBJ_TEXTURES];
|
|
|
|
//draw a polygon model
|
|
|
|
void draw_polygon_model(vms_vector *pos,vms_matrix *orient,vms_angvec *anim_angles,int model_num,int flags,g3s_lrgb light,fix *glow_values,bitmap_index alt_textures[])
|
|
{
|
|
polymodel *po;
|
|
int i;
|
|
|
|
if (model_num < 0)
|
|
return;
|
|
|
|
Assert(model_num < N_polygon_models);
|
|
|
|
po=&Polygon_models[model_num];
|
|
|
|
//check if should use simple model
|
|
if (po->simpler_model ) //must have a simpler model
|
|
if (flags==0) //can't switch if this is debris
|
|
//!!if (!alt_textures) { //alternate textures might not match
|
|
//alt textures might not match, but in the one case we're using this
|
|
//for on 11/14/94, they do match. So we leave it in.
|
|
{
|
|
int cnt=1;
|
|
fix depth;
|
|
|
|
depth = g3_calc_point_depth(pos); //gets 3d depth
|
|
|
|
while (po->simpler_model && depth > cnt++ * Simple_model_threshhold_scale * po->rad)
|
|
po = &Polygon_models[po->simpler_model-1];
|
|
}
|
|
|
|
if (alt_textures)
|
|
for (i=0;i<po->n_textures;i++) {
|
|
texture_list_index[i] = alt_textures[i];
|
|
texture_list[i] = &GameBitmaps[alt_textures[i].index];
|
|
}
|
|
else
|
|
for (i=0;i<po->n_textures;i++) {
|
|
texture_list_index[i] = ObjBitmaps[ObjBitmapPtrs[po->first_texture+i]];
|
|
texture_list[i] = &GameBitmaps[ObjBitmaps[ObjBitmapPtrs[po->first_texture+i]].index];
|
|
}
|
|
|
|
// Make sure the textures for this object are paged in...
|
|
piggy_page_flushed = 0;
|
|
for (i=0;i<po->n_textures;i++)
|
|
PIGGY_PAGE_IN( texture_list_index[i] );
|
|
// Hmmm... cache got flushed in the middle of paging all these in,
|
|
// so we need to reread them all in.
|
|
if (piggy_page_flushed) {
|
|
piggy_page_flushed = 0;
|
|
for (i=0;i<po->n_textures;i++)
|
|
PIGGY_PAGE_IN( texture_list_index[i] );
|
|
}
|
|
// Make sure that they can all fit in memory.
|
|
Assert( piggy_page_flushed == 0 );
|
|
|
|
g3_start_instance_matrix(pos,orient);
|
|
|
|
g3_set_interp_points(robot_points);
|
|
|
|
if (flags == 0) //draw entire object
|
|
|
|
g3_draw_polygon_model(po->model_data,texture_list,anim_angles,light,glow_values);
|
|
|
|
else {
|
|
int i;
|
|
|
|
for (i=0;flags;flags>>=1,i++)
|
|
if (flags & 1) {
|
|
vms_vector ofs;
|
|
|
|
Assert(i < po->n_models);
|
|
|
|
//if submodel, rotate around its center point, not pivot point
|
|
|
|
vm_vec_avg(&ofs,&po->submodel_mins[i],&po->submodel_maxs[i]);
|
|
vm_vec_negate(&ofs);
|
|
g3_start_instance_matrix(&ofs,NULL);
|
|
|
|
g3_draw_polygon_model(&po->model_data[po->submodel_ptrs[i]],texture_list,anim_angles,light,glow_values);
|
|
|
|
g3_done_instance();
|
|
}
|
|
}
|
|
|
|
g3_done_instance();
|
|
|
|
}
|
|
|
|
void free_polygon_models()
|
|
{
|
|
int i;
|
|
|
|
for (i=0;i<N_polygon_models;i++) {
|
|
free_model(&Polygon_models[i]);
|
|
}
|
|
|
|
}
|
|
|
|
void polyobj_find_min_max(polymodel *pm)
|
|
{
|
|
ushort nverts;
|
|
vms_vector *vp;
|
|
ushort *data,type;
|
|
int m;
|
|
vms_vector *big_mn,*big_mx;
|
|
|
|
big_mn = &pm->mins;
|
|
big_mx = &pm->maxs;
|
|
|
|
for (m=0;m<pm->n_models;m++) {
|
|
vms_vector *mn,*mx,*ofs;
|
|
|
|
mn = &pm->submodel_mins[m];
|
|
mx = &pm->submodel_maxs[m];
|
|
ofs= &pm->submodel_offsets[m];
|
|
|
|
data = (ushort *)&pm->model_data[pm->submodel_ptrs[m]];
|
|
|
|
type = *data++;
|
|
|
|
Assert(type == 7 || type == 1);
|
|
|
|
nverts = *data++;
|
|
|
|
if (type==7)
|
|
data+=2; //skip start & pad
|
|
|
|
vp = (vms_vector *) data;
|
|
|
|
*mn = *mx = *vp++; nverts--;
|
|
|
|
if (m==0)
|
|
*big_mn = *big_mx = *mn;
|
|
|
|
while (nverts--) {
|
|
if (vp->x > mx->x) mx->x = vp->x;
|
|
if (vp->y > mx->y) mx->y = vp->y;
|
|
if (vp->z > mx->z) mx->z = vp->z;
|
|
|
|
if (vp->x < mn->x) mn->x = vp->x;
|
|
if (vp->y < mn->y) mn->y = vp->y;
|
|
if (vp->z < mn->z) mn->z = vp->z;
|
|
|
|
if (vp->x+ofs->x > big_mx->x) big_mx->x = vp->x+ofs->x;
|
|
if (vp->y+ofs->y > big_mx->y) big_mx->y = vp->y+ofs->y;
|
|
if (vp->z+ofs->z > big_mx->z) big_mx->z = vp->z+ofs->z;
|
|
|
|
if (vp->x+ofs->x < big_mn->x) big_mn->x = vp->x+ofs->x;
|
|
if (vp->y+ofs->y < big_mn->y) big_mn->y = vp->y+ofs->y;
|
|
if (vp->z+ofs->z < big_mn->z) big_mn->z = vp->z+ofs->z;
|
|
|
|
vp++;
|
|
}
|
|
}
|
|
}
|
|
|
|
char Pof_names[MAX_POLYGON_MODELS][13];
|
|
|
|
//returns the number of this model
|
|
#ifndef DRIVE
|
|
int load_polygon_model(char *filename,int n_textures,int first_texture,robot_info *r)
|
|
#else
|
|
int load_polygon_model(char *filename,int n_textures,grs_bitmap ***textures)
|
|
#endif
|
|
{
|
|
#ifdef DRIVE
|
|
#define r NULL
|
|
#endif
|
|
|
|
Assert(N_polygon_models < MAX_POLYGON_MODELS);
|
|
Assert(n_textures < MAX_POLYOBJ_TEXTURES);
|
|
|
|
Assert(strlen(filename) <= 12);
|
|
strcpy(Pof_names[N_polygon_models],filename);
|
|
|
|
read_model_file(&Polygon_models[N_polygon_models],filename,r);
|
|
|
|
polyobj_find_min_max(&Polygon_models[N_polygon_models]);
|
|
|
|
g3_init_polygon_model(Polygon_models[N_polygon_models].model_data);
|
|
|
|
if (highest_texture_num+1 != n_textures)
|
|
Error("Model <%s> references %d textures but specifies %d.",filename,highest_texture_num+1,n_textures);
|
|
|
|
Polygon_models[N_polygon_models].n_textures = n_textures;
|
|
Polygon_models[N_polygon_models].first_texture = first_texture;
|
|
Polygon_models[N_polygon_models].simpler_model = 0;
|
|
|
|
// Assert(polygon_models[N_polygon_models]!=NULL);
|
|
|
|
N_polygon_models++;
|
|
|
|
return N_polygon_models-1;
|
|
|
|
}
|
|
|
|
|
|
void init_polygon_models()
|
|
{
|
|
N_polygon_models = 0;
|
|
}
|
|
|
|
//compare against this size when figuring how far to place eye for picture
|
|
#define BASE_MODEL_SIZE 0x28000
|
|
|
|
#define DEFAULT_VIEW_DIST 0x60000
|
|
|
|
//draws the given model in the current canvas. The distance is set to
|
|
//more-or-less fill the canvas. Note that this routine actually renders
|
|
//into an off-screen canvas that it creates, then copies to the current
|
|
//canvas.
|
|
void draw_model_picture(int mn,vms_angvec *orient_angles)
|
|
{
|
|
vms_vector temp_pos=ZERO_VECTOR;
|
|
vms_matrix temp_orient = IDENTITY_MATRIX;
|
|
g3s_lrgb lrgb = { f1_0, f1_0, f1_0 };
|
|
|
|
Assert(mn>=0 && mn<N_polygon_models);
|
|
|
|
gr_clear_canvas( BM_XRGB(0,0,0) );
|
|
g3_start_frame();
|
|
g3_set_view_matrix(&temp_pos,&temp_orient,0x9000);
|
|
|
|
if (Polygon_models[mn].rad != 0)
|
|
temp_pos.z = fixmuldiv(DEFAULT_VIEW_DIST,Polygon_models[mn].rad,BASE_MODEL_SIZE);
|
|
else
|
|
temp_pos.z = DEFAULT_VIEW_DIST;
|
|
|
|
vm_angles_2_matrix(&temp_orient, orient_angles);
|
|
draw_polygon_model(&temp_pos,&temp_orient,NULL,mn,0,lrgb,NULL,NULL);
|
|
g3_end_frame();
|
|
}
|
|
|
|
/*
|
|
* reads n polymodel structs from a PHYSFS_file
|
|
*/
|
|
extern int polymodel_read_n(polymodel *pm, int n, PHYSFS_file *fp)
|
|
{
|
|
int i, j;
|
|
|
|
for (i = 0; i < n; i++) {
|
|
pm[i].n_models = PHYSFSX_readInt(fp);
|
|
pm[i].model_data_size = PHYSFSX_readInt(fp);
|
|
pm[i].model_data = (ubyte *) (size_t)PHYSFSX_readInt(fp);
|
|
for (j = 0; j < MAX_SUBMODELS; j++)
|
|
pm[i].submodel_ptrs[j] = PHYSFSX_readInt(fp);
|
|
for (j = 0; j < MAX_SUBMODELS; j++)
|
|
PHYSFSX_readVector(&(pm[i].submodel_offsets[j]), fp);
|
|
for (j = 0; j < MAX_SUBMODELS; j++)
|
|
PHYSFSX_readVector(&(pm[i].submodel_norms[j]), fp);
|
|
for (j = 0; j < MAX_SUBMODELS; j++)
|
|
PHYSFSX_readVector(&(pm[i].submodel_pnts[j]), fp);
|
|
for (j = 0; j < MAX_SUBMODELS; j++)
|
|
pm[i].submodel_rads[j] = PHYSFSX_readFix(fp);
|
|
PHYSFS_read(fp, pm[i].submodel_parents, MAX_SUBMODELS, 1);
|
|
for (j = 0; j < MAX_SUBMODELS; j++)
|
|
PHYSFSX_readVector(&(pm[i].submodel_mins[j]), fp);
|
|
for (j = 0; j < MAX_SUBMODELS; j++)
|
|
PHYSFSX_readVector(&(pm[i].submodel_maxs[j]), fp);
|
|
PHYSFSX_readVector(&(pm[i].mins), fp);
|
|
PHYSFSX_readVector(&(pm[i].maxs), fp);
|
|
pm[i].rad = PHYSFSX_readFix(fp);
|
|
pm[i].n_textures = PHYSFSX_readByte(fp);
|
|
pm[i].first_texture = PHYSFSX_readShort(fp);
|
|
pm[i].simpler_model = PHYSFSX_readByte(fp);
|
|
}
|
|
return i;
|
|
}
|
|
|
|
|
|
/*
|
|
* routine which allocates, reads, and inits a polymodel's model_data
|
|
*/
|
|
void polygon_model_data_read(polymodel *pm, PHYSFS_file *fp)
|
|
{
|
|
pm->model_data = d_malloc(pm->model_data_size);
|
|
Assert(pm->model_data != NULL);
|
|
PHYSFS_read(fp, pm->model_data, sizeof(ubyte), pm->model_data_size);
|
|
#ifdef WORDS_NEED_ALIGNMENT
|
|
align_polygon_model_data(pm);
|
|
#endif
|
|
#ifdef WORDS_BIGENDIAN
|
|
swap_polygon_model_data(pm->model_data);
|
|
#endif
|
|
}
|