/* 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. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/main/polyobj.c,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:43:43 $ * * Hacked-in polygon objects * * $Log: polyobj.c,v $ * Revision 1.1.1.1 2006/03/17 19:43:43 zicodxx * initial import * * Revision 1.2 2002/03/26 08:20:01 donut * fix briefing spinning robot display in OGL * * Revision 1.1.1.1 1999/06/14 22:11:08 donut * Import of d1x 1.37 source. * * Revision 2.1 1995/05/26 16:10:37 john * Support for new 4-byte align v8 pof files. * * Revision 2.0 1995/02/27 11:32:44 john * New version 2.0, which has no anonymous unions, builds with * Watcom 10.0, and doesn't require parsing BITMAPS.TBL. * * Revision 1.64 1995/01/14 19:16:43 john * First version of new bitmap paging code. * * Revision 1.63 1994/12/14 18:06:54 matt * Removed compile warnings * * Revision 1.62 1994/12/09 17:54:31 john * Made the CFILE's close right after reading in data. * * Revision 1.61 1994/12/09 16:13:28 mike * speedup pof file reading, but still horribly slow using hog file...problem somewhere else. * * Revision 1.60 1994/12/08 17:41:20 yuan * Cfiling stuff. * * Revision 1.59 1994/11/21 11:02:19 matt * Added error checking * * Revision 1.58 1994/11/14 11:32:49 matt * Allow switching to simpler models even when alt_textures specified * * Revision 1.57 1994/11/13 21:15:24 matt * Added basic support for more than one level of detail simplification * * Revision 1.56 1994/11/11 19:29:25 matt * Added code to show low detail polygon models * * Revision 1.55 1994/11/10 14:02:57 matt * Hacked in support for player ships with different textures * * Revision 1.54 1994/11/03 11:01:59 matt * Made robot pics lighted * * Revision 1.53 1994/11/02 16:18:34 matt * Moved draw_model_picture() out of editor * * Revision 1.52 1994/10/18 14:38:11 matt * Restored assert now that bug is fixed * * Revision 1.51 1994/10/17 21:35:03 matt * Added support for new Control Center/Main Reactor * * Revision 1.50 1994/10/14 17:46:23 yuan * Made the soft Int3 only work in net mode. * * Revision 1.49 1994/10/14 17:43:47 yuan * Added soft int3's instead of Asserts for some common network bugs. * * Revision 1.48 1994/10/14 17:09:04 yuan * Made Assert on line 610 be if in an attempt * to bypass. * * Revision 1.47 1994/09/09 14:23:42 matt * Added glow code to polygon models for engine glow * * Revision 1.46 1994/08/26 18:03:30 matt * Added code to remap polygon model numbers by matching filenames * * Revision 1.45 1994/08/26 15:35:58 matt * Made eclips usable on more than one object at a time * * Revision 1.44 1994/08/25 18:11:58 matt * Made player's weapons and flares fire from the positions on the 3d model. * Also added support for quad lasers. * * Revision 1.43 1994/07/25 00:14:18 matt * Made a couple of minor changes for the drivethrough * * Revision 1.42 1994/07/25 00:02:41 matt * Various changes to accomodate new 3d, which no longer takes point numbers * as parms, and now only takes pointers to points. * */ #ifdef RCS #pragma off (unreferenced) static char rcsid[] = "$Id: polyobj.c,v 1.1.1.1 2006/03/17 19:43:43 zicodxx Exp $"; #pragma on (unreferenced) #endif #include #include #include #ifdef DRIVE #include "drive.h" #else #include "inferno.h" #endif #include "polyobj.h" #include "vecmat.h" #include "3d.h" #include "error.h" #include "mono.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 "cfile.h" #include "piggy.h" #endif #include "byteswap.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 i; // if (cfread(&i,sizeof(i),1,f) != 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) cfread(&(i),sizeof(i),1,(f)) #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 s; // if (cfread(&s,sizeof(s),1,f) != 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 MODEL_BUF_SIZE) Int3(); } #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 + swapshort(*((short *)(o.old_base + o.offset))); } ubyte * new_dest(chunk o) // return where chunk is (in aligned struct) { return o.new_base + swapshort(*((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 = 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)) = swapshort(cur_ch.correction + swapshort(*((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); } free(pm->model_data); pm->model_data_size += total_correction; pm->model_data = malloc(pm->model_data_size); Assert(pm->model_data != NULL); memcpy(pm->model_data, tmp, pm->model_data_size); 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) { CFILE *ifile; short version; int id,len, next_chunk; ubyte model_buf[MODEL_BUF_SIZE]; if ((ifile=cfopen(filename,"rb"))==NULL) Error("Can't open file <%s>",filename); Assert(ifile->size <= MODEL_BUF_SIZE); Pof_addr = 0; Pof_file_end = cfread(model_buf, 1, cfilelength(ifile), ifile); cfclose(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); if ( FindArg( "-bspgen" )) fprintf( stderr, "bspgen -c1" ); while (new_pof_read_int(id,model_buf) == 1) { //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; //mprintf(0,"Got chunk OHDR, len=%d\n",len); 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); if ( FindArg( "-bspgen" )) { vms_vector v; fix l; vm_vec_sub(&v, &pmmax, &pmmin ); l = v.x; if ( v.y > l ) l = v.y; if ( v.z > l ) l = v.z; fprintf( stderr, " -l%.3f", f2fl(l) ); } break; } case ID_SOBJ: { //Subobject header int n; //mprintf(0,"Got chunk SOBJ, len=%d\n",len); 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 //mprintf(0,"Got chunk GUNS, len=%d\n",len); 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;in_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 //mprintf(0,"Got chunk ANIM, len=%d\n",len); if ( FindArg( "-bspgen" )) fprintf( stderr, " -a" ); if (r) { int n_frames,f,m; n_frames = pof_read_short(model_buf); Assert(n_frames == N_ANIM_STATES); for (m=0;mn_models;m++) for (f=0;f\n",name_buf); } break; } case ID_IDTA: //Interpreter data //mprintf(0,"Got chunk IDTA, len=%d\n",len); pm->model_data = malloc(len); pm->model_data_size = len; pof_cfread(pm->model_data,1,len,model_buf); break; default: //mprintf(0,"Unknown chunk <%c%c%c%c>, len = %d\n",id,id>>8,id>>16,id>>24,len); 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); } // for (i=0;in_models;i++) // pm->submodel_ptrs[i] += (int) pm->model_data; if ( FindArg( "-bspgen" )) { char *p = strchr( filename, '.' ); *p = 0; fprintf( stderr, " %s.3ds\n", filename ); *p = '.'; } #ifdef WORDS_NEED_ALIGNMENT align_polygon_model_data(pm); #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) { CFILE *ifile; short version; int id,len; int n_guns=0; ubyte model_buf[MODEL_BUF_SIZE]; if ((ifile=cfopen(filename,"rb"))==NULL) Error("Can't open file <%s>",filename); Assert(ifile->size <= MODEL_BUF_SIZE); Pof_addr = 0; Pof_file_end = cfread(model_buf, 1, ifile->size, ifile); cfclose(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 = pof_read_int(model_buf); len = pof_read_int(model_buf); if (id == ID_GUNS) { //List of guns on this object //mprintf(0,"Got chunk GUNS, len=%d\n",len); int i; n_guns = pof_read_int(model_buf); for (i=0;i",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) { free(po->model_data); } grs_bitmap *texture_list[MAX_POLYOBJ_TEXTURES]; bitmap_index texture_list_index[MAX_POLYOBJ_TEXTURES]; int Simple_model_threshhold_scale=5; //switch when this times radius far away //draw a polygon model void draw_polygon_model(vms_vector *pos,vms_matrix *orient,vms_angvec *anim_angles,int model_num,int flags,fix light,fix *glow_values,bitmap_index alt_textures[]) { polymodel *po; int i; 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;in_textures;i++) { texture_list_index[i] = alt_textures[i]; texture_list[i] = &GameBitmaps[alt_textures[i].index]; } else for (i=0;in_textures;i++) { texture_list_index[i] = ObjBitmaps[ObjBitmapPtrs[po->first_texture+i]]; texture_list[i] = &GameBitmaps[ObjBitmaps[ObjBitmapPtrs[po->first_texture+i]].index]; } #ifdef PIGGY_USE_PAGING // Make sure the textures for this object are paged in... piggy_page_flushed = 0; for (i=0;in_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;in_textures;i++) PIGGY_PAGE_IN( texture_list_index[i] ); } // Make sure that they can all fit in memory. Assert( piggy_page_flushed == 0 ); #endif 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;imins; big_mx = &pm->maxs; for (m=0;mn_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++; } // printf("Submodel %d: (%8x,%8x) (%8x,%8x) (%8x,%8x)\n",m,mn->x,mx->x,mn->y,mx->y,mn->z,mx->z); } // printf("Whole model: (%8x,%8x) (%8x,%8x) (%8x,%8x)\n",big_mn->x,big_mx->x,big_mn->y,big_mx->y,big_mn->z,big_mx->z); } 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); mprintf(( 0, "Used %d/%d polygon model slots\n", N_polygon_models+1, MAX_POLYGON_MODELS )); 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; atexit((void (*)())free_polygon_models); } //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; #ifndef OGL grs_canvas *save_canv = grd_curcanv,*temp_canv; #endif Assert(mn>=0 && mncv_bitmap.bm_w,grd_curcanv->cv_bitmap.bm_h); #else temp_canv = gr_create_canvas(save_canv->cv_bitmap.bm_w,save_canv->cv_bitmap.bm_h); gr_set_current_canvas(temp_canv); #endif 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,f1_0,NULL,NULL); g3_end_frame(); #ifdef OGL ogl_end_offscreen_render(); #else gr_set_current_canvas(save_canv); gr_bitmap(0,0,&temp_canv->cv_bitmap); gr_free_canvas(temp_canv); #endif } extern int read_int(CFILE *file); extern fix read_fix(CFILE *file); extern short read_short(CFILE *file); extern sbyte read_byte(CFILE *file); extern void read_vector(vms_vector *v,CFILE *file); /* * reads n polymodel structs from a CFILE */ extern int polymodel_read_n(polymodel *pm, int n, CFILE *fp) { int i, j; for (i = 0; i < n; i++) { pm[i].n_models = read_int(fp); pm[i].model_data_size = read_int(fp); pm[i].model_data = (ubyte *) read_int(fp); for (j = 0; j < MAX_SUBMODELS; j++) pm[i].submodel_ptrs[j] = read_int(fp); for (j = 0; j < MAX_SUBMODELS; j++) read_vector(&(pm[i].submodel_offsets[j]), fp); for (j = 0; j < MAX_SUBMODELS; j++) read_vector(&(pm[i].submodel_norms[j]), fp); for (j = 0; j < MAX_SUBMODELS; j++) read_vector(&(pm[i].submodel_pnts[j]), fp); for (j = 0; j < MAX_SUBMODELS; j++) pm[i].submodel_rads[j] = read_fix(fp); cfread(pm[i].submodel_parents, MAX_SUBMODELS, 1, fp); for (j = 0; j < MAX_SUBMODELS; j++) read_vector(&(pm[i].submodel_mins[j]), fp); for (j = 0; j < MAX_SUBMODELS; j++) read_vector(&(pm[i].submodel_maxs[j]), fp); read_vector(&(pm[i].mins), fp); read_vector(&(pm[i].maxs), fp); pm[i].rad = read_fix(fp); pm[i].n_textures = read_byte(fp); pm[i].first_texture = read_short(fp); pm[i].simpler_model = read_byte(fp); } return i; } /* * routine which allocates, reads, and inits a polymodel's model_data */ void polygon_model_data_read(polymodel *pm, CFILE *fp) { pm->model_data = malloc(pm->model_data_size); Assert(pm->model_data != NULL); cfread(pm->model_data, sizeof(ubyte), pm->model_data_size, fp ); #ifdef WORDS_NEED_ALIGNMENT align_polygon_model_data(pm); #endif }