2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
19 static char rcsid[] = "$Id: polyobj.c,v 1.6 2002-07-26 09:22:05 btb Exp $";
26 // -- I hate this warning in make depend! -- #ifdef DRIVE
27 // -- I hate this warning in make depend! -- #include "drive.h"
28 // -- I hate this warning in make depend! -- #else
30 // -- I hate this warning in make depend! -- #endif
57 polymodel Polygon_models[MAX_POLYGON_MODELS]; // = {&bot11,&bot17,&robot_s2,&robot_b2,&bot11,&bot17,&robot_s2,&robot_b2};
59 int N_polygon_models = 0;
61 #define MAX_POLYGON_VECS 1000
62 g3s_point robot_points[MAX_POLYGON_VECS];
64 #define PM_COMPATIBLE_VERSION 6
65 #define PM_OBJFILE_VERSION 8
70 #define MODEL_BUF_SIZE 32768
72 void _pof_cfseek(int len,int type)
75 case SEEK_SET: Pof_addr = len; break;
76 case SEEK_CUR: Pof_addr += len; break;
78 Assert(len <= 0); // seeking from end, better be moving back.
79 Pof_addr = Pof_file_end + len;
83 if (Pof_addr > MODEL_BUF_SIZE)
87 #define pof_cfseek(_buf,_len,_type) _pof_cfseek((_len),(_type))
89 int pof_read_int(ubyte *bufp)
93 i = *((int *) &bufp[Pof_addr]);
97 // if (cfread(&i,sizeof(i),1,f) != 1)
98 // Error("Unexpected end-of-file while reading object");
103 size_t pof_cfread(void *dst, size_t elsize, size_t nelem, ubyte *bufp)
105 if (Pof_addr + nelem*elsize > Pof_file_end)
108 memcpy(dst, &bufp[Pof_addr], elsize*nelem);
110 Pof_addr += elsize*nelem;
112 if (Pof_addr > MODEL_BUF_SIZE)
118 // #define new_read_int(i,f) cfread(&(i),sizeof(i),1,(f))
119 #define new_pof_read_int(i,f) pof_cfread(&(i),sizeof(i),1,(f))
121 short pof_read_short(ubyte *bufp)
125 s = *((short *) &bufp[Pof_addr]);
128 // if (cfread(&s,sizeof(s),1,f) != 1)
129 // Error("Unexpected end-of-file while reading object");
134 void pof_read_string(char *buf,int max_char, ubyte *bufp)
138 for (i=0; i<max_char; i++) {
139 if ((*buf++ = bufp[Pof_addr++]) == 0)
143 // while (max_char-- && (*buf=cfgetc(f)) != 0) buf++;
147 void pof_read_vecs(vms_vector *vecs,int n,ubyte *bufp)
149 // cfread(vecs,sizeof(vms_vector),n,f);
151 memcpy(vecs, &bufp[Pof_addr], n*sizeof(*vecs));
152 Pof_addr += n*sizeof(*vecs);
154 if (Pof_addr > MODEL_BUF_SIZE)
158 #define ID_OHDR 0x5244484f // 'RDHO' //Object header
159 #define ID_SOBJ 0x4a424f53 // 'JBOS' //Subobject header
160 #define ID_GUNS 0x534e5547 // 'SNUG' //List of guns on this object
161 #define ID_ANIM 0x4d494e41 // 'MINA' //Animation data
162 #define ID_IDTA 0x41544449 // 'ATDI' //Interpreter data
163 #define ID_TXTR 0x52545854 // 'RTXT' //Texture filename list
166 #define robot_info void
168 vms_angvec anim_angs[N_ANIM_STATES][MAX_SUBMODELS];
170 //set the animation angles for this robot. Gun fields of robot info must
172 void robot_set_angles(robot_info *r,polymodel *pm,vms_angvec angs[N_ANIM_STATES][MAX_SUBMODELS]);
175 //reads a binary file containing a 3d model
176 polymodel *read_model_file(polymodel *pm,char *filename,robot_info *r)
180 int id,len, next_chunk;
184 model_buf = (ubyte *)d_malloc( MODEL_BUF_SIZE * sizeof(ubyte) );
186 Error("Can't allocate space to read model %s\n", filename);
188 if ((ifile=cfopen(filename,"rb"))==NULL)
189 Error("Can't open file <%s>",filename);
191 Assert(ifile->size <= MODEL_BUF_SIZE);
194 Pof_file_end = cfread(model_buf, 1, cfilelength(ifile), ifile);
197 id = pof_read_int(model_buf);
199 if (id!=0x4f505350) /* 'OPSP' */
200 Error("Bad ID in model file <%s>",filename);
202 version = pof_read_short(model_buf);
204 if (version < PM_COMPATIBLE_VERSION || version > PM_OBJFILE_VERSION)
205 Error("Bad version (%d) in model file <%s>",version,filename);
207 if ( FindArg( "-bspgen" ))
208 printf( "bspgen -c1" );
210 while (new_pof_read_int(id,model_buf) == 1) {
212 //id = pof_read_int(model_buf);
213 len = pof_read_int(model_buf);
214 next_chunk = Pof_addr + len;
218 case ID_OHDR: { //Object header
219 vms_vector pmmin,pmmax;
221 //mprintf(0,"Got chunk OHDR, len=%d\n",len);
223 pm->n_models = pof_read_int(model_buf);
224 pm->rad = pof_read_int(model_buf);
226 Assert(pm->n_models <= MAX_SUBMODELS);
228 pof_read_vecs(&pmmin,1,model_buf);
229 pof_read_vecs(&pmmax,1,model_buf);
231 if ( FindArg( "-bspgen" )) {
235 vm_vec_sub(&v, &pmmax, &pmmin );
237 if ( v.y > l ) l = v.y;
238 if ( v.z > l ) l = v.z;
240 printf( " -l%.3f", f2fl(l) );
246 case ID_SOBJ: { //Subobject header
251 //mprintf(0,"Got chunk SOBJ, len=%d\n",len);
253 n = pof_read_short(model_buf);
255 Assert(n < MAX_SUBMODELS);
257 pm->submodel_parents[n] = pof_read_short(model_buf);
259 pof_read_vecs(&pm->submodel_norms[n],1,model_buf);
260 pof_read_vecs(&pm->submodel_pnts[n],1,model_buf);
261 pof_read_vecs(&pm->submodel_offsets[n],1,model_buf);
263 pm->submodel_rads[n] = pof_read_int(model_buf); //radius
265 pm->submodel_ptrs[n] = pof_read_int(model_buf); //offset
272 case ID_GUNS: { //List of guns on this object
274 //mprintf(0,"Got chunk GUNS, len=%d\n",len);
279 ubyte gun_used[MAX_GUNS];
281 r->n_guns = pof_read_int(model_buf);
286 Assert(r->n_guns <= MAX_GUNS);
288 for (i=0;i<r->n_guns;i++)
291 for (i=0;i<r->n_guns;i++) {
294 id = pof_read_short(model_buf);
295 Assert(id < r->n_guns);
296 Assert(gun_used[id] == 0);
298 r->gun_submodels[id] = pof_read_short(model_buf);
299 Assert(r->gun_submodels[id] != 0xff);
300 pof_read_vecs(&r->gun_points[id],1,model_buf);
303 pof_read_vecs(&gun_dir,1,model_buf);
307 pof_cfseek(model_buf,len,SEEK_CUR);
312 case ID_ANIM: //Animation data
313 //mprintf(0,"Got chunk ANIM, len=%d\n",len);
320 n_frames = pof_read_short(model_buf);
322 Assert(n_frames == N_ANIM_STATES);
324 for (m=0;m<pm->n_models;m++)
325 for (f=0;f<n_frames;f++)
326 pof_cfread(&anim_angs[f][m],1,sizeof(vms_angvec),model_buf);
328 robot_set_angles(r,pm,anim_angs);
332 pof_cfseek(model_buf,len,SEEK_CUR);
337 case ID_TXTR: { //Texture filename list
341 //mprintf(0,"Got chunk TXTR, len=%d\n",len);
343 n = pof_read_short(model_buf);
344 //mprintf(0," num textures = %d\n",n);
346 pof_read_string(name_buf,128,model_buf);
347 //mprintf(0,"<%s>\n",name_buf);
353 case ID_IDTA: //Interpreter data
354 //mprintf(0,"Got chunk IDTA, len=%d\n",len);
356 pm->model_data = d_malloc(len);
357 pm->model_data_size = len;
359 pof_cfread(pm->model_data,1,len,model_buf);
364 //mprintf(0,"Unknown chunk <%c%c%c%c>, len = %d\n",id,id>>8,id>>16,id>>24,len);
365 pof_cfseek(model_buf,len,SEEK_CUR);
369 if ( version >= 8 ) // Version 8 needs 4-byte alignment!!!
370 pof_cfseek(model_buf,next_chunk,SEEK_SET);
373 // for (i=0;i<pm->n_models;i++)
374 // pm->submodel_ptrs[i] += (int) pm->model_data;
376 if ( FindArg( "-bspgen" )) {
377 char *p = strchr( filename, '.' );
383 printf( " %s.3ds\n", filename );
392 //reads the gun information for a model
393 //fills in arrays gun_points & gun_dirs, returns the number of guns read
394 int read_model_guns(char *filename,vms_vector *gun_points, vms_vector *gun_dirs, int *gun_submodels)
402 model_buf = (ubyte *)d_malloc( MODEL_BUF_SIZE * sizeof(ubyte) );
404 Error("Can't allocate space to read model %s\n", filename);
406 if ((ifile=cfopen(filename,"rb"))==NULL)
407 Error("Can't open file <%s>",filename);
409 Assert(ifile->size <= MODEL_BUF_SIZE);
412 Pof_file_end = cfread(model_buf, 1, ifile->size, ifile);
415 id = pof_read_int(model_buf);
417 if (id!=0x4f505350) /* 'OPSP' */
418 Error("Bad ID in model file <%s>",filename);
420 version = pof_read_short(model_buf);
422 Assert(version >= 7); //must be 7 or higher for this data
424 if (version < PM_COMPATIBLE_VERSION || version > PM_OBJFILE_VERSION)
425 Error("Bad version (%d) in model file <%s>",version,filename);
427 while (new_pof_read_int(id,model_buf) == 1) {
429 //id = pof_read_int(model_buf);
430 len = pof_read_int(model_buf);
432 if (id == ID_GUNS) { //List of guns on this object
434 //mprintf(0,"Got chunk GUNS, len=%d\n",len);
438 n_guns = pof_read_int(model_buf);
440 for (i=0;i<n_guns;i++) {
443 id = pof_read_short(model_buf);
444 sm = pof_read_short(model_buf);
446 gun_submodels[id] = sm;
448 Error("Invalid gun submodel in file <%s>",filename);
449 pof_read_vecs(&gun_points[id],1,model_buf);
451 pof_read_vecs(&gun_dirs[id],1,model_buf);
456 pof_cfseek(model_buf,len,SEEK_CUR);
465 //free up a model, getting rid of all its memory
466 void free_model(polymodel *po)
468 d_free(po->model_data);
471 grs_bitmap *texture_list[MAX_POLYOBJ_TEXTURES];
472 bitmap_index texture_list_index[MAX_POLYOBJ_TEXTURES];
474 int Simple_model_threshhold_scale=5; //switch when this times radius far away
477 //draw a polygon model
479 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[])
483 PA_DFX (int save_light);
485 Assert(model_num < N_polygon_models);
487 po=&Polygon_models[model_num];
489 //check if should use simple model
490 if (po->simpler_model ) //must have a simpler model
491 if (flags==0) //can't switch if this is debris
492 //!!if (!alt_textures) { //alternate textures might not match
493 //alt textures might not match, but in the one case we're using this
494 //for on 11/14/94, they do match. So we leave it in.
499 depth = g3_calc_point_depth(pos); //gets 3d depth
501 while (po->simpler_model && depth > cnt++ * Simple_model_threshhold_scale * po->rad)
502 po = &Polygon_models[po->simpler_model-1];
507 for (i=0;i<po->n_textures;i++) {
508 texture_list_index[i] = alt_textures[i];
509 texture_list[i] = &GameBitmaps[alt_textures[i].index];
512 texture_list[i]->bm_handle = texture_list_index[i].index;
518 for (i=0;i<po->n_textures;i++) {
519 texture_list_index[i] = ObjBitmaps[ObjBitmapPtrs[po->first_texture+i]];
520 texture_list[i] = &GameBitmaps[ObjBitmaps[ObjBitmapPtrs[po->first_texture+i]].index];
523 texture_list[i]->bm_handle = texture_list_index[i].index;
528 #ifdef PIGGY_USE_PAGING
529 // Make sure the textures for this object are paged in...
530 piggy_page_flushed = 0;
531 for (i=0;i<po->n_textures;i++)
532 PIGGY_PAGE_IN( texture_list_index[i] );
533 // Hmmm... cache got flushed in the middle of paging all these in,
534 // so we need to reread them all in.
535 if (piggy_page_flushed) {
536 piggy_page_flushed = 0;
537 for (i=0;i<po->n_textures;i++)
538 PIGGY_PAGE_IN( texture_list_index[i] );
540 // Make sure that they can all fit in memory.
541 Assert( piggy_page_flushed == 0 );
544 g3_start_instance_matrix(pos,orient);
546 g3_set_interp_points(robot_points);
549 _3dfx_rendering_poly_obj = 1;
551 PA_DFX(save_light = Lighting_on);
552 PA_DFX(Lighting_on = 0);
554 if (flags == 0) //draw entire object
556 g3_draw_polygon_model(po->model_data,texture_list,anim_angles,light,glow_values);
561 for (i=0;flags;flags>>=1,i++)
565 Assert(i < po->n_models);
567 //if submodel, rotate around its center point, not pivot point
569 vm_vec_avg(&ofs,&po->submodel_mins[i],&po->submodel_maxs[i]);
571 g3_start_instance_matrix(&ofs,NULL);
573 g3_draw_polygon_model(&po->model_data[po->submodel_ptrs[i]],texture_list,anim_angles,light,glow_values);
582 _3dfx_rendering_poly_obj = 0;
585 PA_DFX (Lighting_on = save_light);
590 void free_polygon_models()
594 for (i=0;i<N_polygon_models;i++) {
595 free_model(&Polygon_models[i]);
600 void polyobj_find_min_max(polymodel *pm)
606 vms_vector *big_mn,*big_mx;
611 for (m=0;m<pm->n_models;m++) {
612 vms_vector *mn,*mx,*ofs;
614 mn = &pm->submodel_mins[m];
615 mx = &pm->submodel_maxs[m];
616 ofs= &pm->submodel_offsets[m];
618 data = (ushort *)&pm->model_data[pm->submodel_ptrs[m]];
622 Assert(type == 7 || type == 1);
627 data+=2; //skip start & pad
629 vp = (vms_vector *) data;
631 *mn = *mx = *vp++; nverts--;
634 *big_mn = *big_mx = *mn;
637 if (vp->x > mx->x) mx->x = vp->x;
638 if (vp->y > mx->y) mx->y = vp->y;
639 if (vp->z > mx->z) mx->z = vp->z;
641 if (vp->x < mn->x) mn->x = vp->x;
642 if (vp->y < mn->y) mn->y = vp->y;
643 if (vp->z < mn->z) mn->z = vp->z;
645 if (vp->x+ofs->x > big_mx->x) big_mx->x = vp->x+ofs->x;
646 if (vp->y+ofs->y > big_mx->y) big_mx->y = vp->y+ofs->y;
647 if (vp->z+ofs->z > big_mx->z) big_mx->z = vp->z+ofs->z;
649 if (vp->x+ofs->x < big_mn->x) big_mn->x = vp->x+ofs->x;
650 if (vp->y+ofs->y < big_mn->y) big_mn->y = vp->y+ofs->y;
651 if (vp->z+ofs->z < big_mn->z) big_mn->z = vp->z+ofs->z;
656 // printf("Submodel %d: (%8x,%8x) (%8x,%8x) (%8x,%8x)\n",m,mn->x,mx->x,mn->y,mx->y,mn->z,mx->z);
659 // 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);
663 extern short highest_texture_num; //from the 3d
665 char Pof_names[MAX_POLYGON_MODELS][FILENAME_LEN];
667 //returns the number of this model
669 int load_polygon_model(char *filename,int n_textures,int first_texture,robot_info *r)
671 int load_polygon_model(char *filename,int n_textures,grs_bitmap ***textures)
678 Assert(N_polygon_models < MAX_POLYGON_MODELS);
679 Assert(n_textures < MAX_POLYOBJ_TEXTURES);
681 // MK was real tired of those useless, slow mprintfs...
682 if (N_polygon_models > MAX_POLYGON_MODELS - 10)
683 mprintf(( 0, "Used %d/%d polygon model slots\n", N_polygon_models+1, MAX_POLYGON_MODELS ));
685 Assert(strlen(filename) <= 12);
686 strcpy(Pof_names[N_polygon_models],filename);
688 read_model_file(&Polygon_models[N_polygon_models],filename,r);
690 polyobj_find_min_max(&Polygon_models[N_polygon_models]);
692 g3_init_polygon_model(Polygon_models[N_polygon_models].model_data);
694 if (highest_texture_num+1 != n_textures)
695 Error("Model <%s> references %d textures but specifies %d.",filename,highest_texture_num+1,n_textures);
697 Polygon_models[N_polygon_models].n_textures = n_textures;
698 Polygon_models[N_polygon_models].first_texture = first_texture;
699 Polygon_models[N_polygon_models].simpler_model = 0;
701 // Assert(polygon_models[N_polygon_models]!=NULL);
705 return N_polygon_models-1;
710 void init_polygon_models()
712 N_polygon_models = 0;
714 atexit((void (*)())free_polygon_models);
718 //compare against this size when figuring how far to place eye for picture
719 #define BASE_MODEL_SIZE 0x28000
721 #define DEFAULT_VIEW_DIST 0x60000
723 //draws the given model in the current canvas. The distance is set to
724 //more-or-less fill the canvas. Note that this routine actually renders
725 //into an off-screen canvas that it creates, then copies to the current
727 void draw_model_picture(int mn,vms_angvec *orient_angles)
729 vms_vector temp_pos=ZERO_VECTOR;
730 vms_matrix temp_orient = IDENTITY_MATRIX;
731 grs_canvas *save_canv = grd_curcanv,*temp_canv;
733 Assert(mn>=0 && mn<N_polygon_models);
735 temp_canv = gr_create_canvas(save_canv->cv_bitmap.bm_w,save_canv->cv_bitmap.bm_h);
736 gr_set_current_canvas(temp_canv);
737 gr_clear_canvas( BM_XRGB(0,0,0) );
740 g3_set_view_matrix(&temp_pos,&temp_orient,0x9000);
742 if (Polygon_models[mn].rad != 0)
743 temp_pos.z = fixmuldiv(DEFAULT_VIEW_DIST,Polygon_models[mn].rad,BASE_MODEL_SIZE);
745 temp_pos.z = DEFAULT_VIEW_DIST;
747 vm_angles_2_matrix(&temp_orient, orient_angles);
749 PA_DFX(save_light = Lighting_on);
750 PA_DFX(Lighting_on = 0);
751 draw_polygon_model(&temp_pos,&temp_orient,NULL,mn,0,f1_0,NULL,NULL);
752 PA_DFX (Lighting_on = save_light);
754 gr_set_current_canvas(save_canv);
756 gr_bitmap(0,0,&temp_canv->cv_bitmap);
758 gr_free_canvas(temp_canv);
762 * reads a polymodel structure from a CFILE
764 extern void polymodel_read(polymodel *pm, CFILE *fp)
768 pm->n_models = cfile_read_int(fp);
769 pm->model_data_size = cfile_read_int(fp);
770 pm->model_data = (ubyte *) cfile_read_int(fp);
771 for (i = 0; i < MAX_SUBMODELS; i++)
772 pm->submodel_ptrs[i] = cfile_read_int(fp);
773 for (i = 0; i < MAX_SUBMODELS; i++)
774 cfile_read_vector(&(pm->submodel_offsets[i]), fp);
775 for (i = 0; i < MAX_SUBMODELS; i++)
776 cfile_read_vector(&(pm->submodel_norms[i]), fp);
777 for (i = 0; i < MAX_SUBMODELS; i++)
778 cfile_read_vector(&(pm->submodel_pnts[i]), fp);
779 for (i = 0; i < MAX_SUBMODELS; i++)
780 pm->submodel_rads[i] = cfile_read_fix(fp);
781 cfread(pm->submodel_parents, MAX_SUBMODELS, 1, fp);
782 for (i = 0; i < MAX_SUBMODELS; i++)
783 cfile_read_vector(&(pm->submodel_mins[i]), fp);
784 for (i = 0; i < MAX_SUBMODELS; i++)
785 cfile_read_vector(&(pm->submodel_maxs[i]), fp);
786 cfile_read_vector(&(pm->mins), fp);
787 cfile_read_vector(&(pm->maxs), fp);
788 pm->rad = cfile_read_fix(fp);
789 pm->n_textures = cfile_read_byte(fp);
790 pm->first_texture = cfile_read_short(fp);
791 pm->simpler_model = cfile_read_byte(fp);