/* * $Logfile: /DescentIII/Main/model/newstyle.cpp $ * $Revision: 122 $ * $Date: 3/20/00 12:28p $ * $Author: Matt $ * * Polygon model code * * $Log: /DescentIII/Main/model/newstyle.cpp $ * * 122 3/20/00 12:28p Matt * Merge of Duane's post-1.3 changes. * Check for NULL pointer. * * 121 7/08/99 5:47p Jason * changes for new bumpmapping system in 1.1 update patch * * 120 6/08/99 1:00p Jason * changes for bumpmapping * * 119 5/18/99 10:31a Jason * polymodel stuff wasn't getting paged in before drawing * * 118 5/14/99 2:03p Jason * added polymodel errors to catch bugs * * 117 5/14/99 12:02a Jason * more speedups for g3_DrawPoly * * 116 5/13/99 8:33p Matt * Consolidated Mac & Windows code. * * 115 5/13/99 5:07p Ardussi * changes for compiling on the Mac * * 114 5/04/99 4:34p Jason * changes for bumpmapping * * 113 4/22/99 8:29p Kevin * made psrand.h come after stdlib.h * * 112 4/21/99 11:05a Kevin * new ps_rand and ps_srand to replace rand & srand * * 111 4/16/99 5:32p Jason * fixed smooth specularity with objects * * 110 4/14/99 1:36a Jeff * fixed case mismatched #includes * * 109 4/09/99 12:06p Jason * made model setup code faster * * 108 3/31/99 12:26p Jason * fixed some issues related to non wbuffer cards * * 107 3/24/99 10:22a Matt * Fixed null-pointer bug * */ #include "pserror.h" #include "pstypes.h" #include "3d.h" #include "vecmat.h" #include "grdefs.h" #include "polymodel.h" #include "gametexture.h" #include "BYTESWAP.H" #include "renderer.h" #include "lighting.h" #include "game.h" #include "render.h" #include "fireball.h" #include "lightmap_info.h" #include "lightmap.h" #include "lighting.h" #include "findintersection.h" #include #include #include #include "psrand.h" static float face_depth[MAX_POLYGON_VECS]; static ubyte triangulated_faces[MAX_FACES_PER_ROOM]; static ubyte FacingPass=0; static int Multicolor_texture=-1; static vector Fog_plane; static float Fog_distance,Fog_eye_distance; static vector Fog_view_pos,Specular_view_pos,Bump_view_pos; static matrix Unscaled_bumpmap_matrix; static int ModelFaceSortFunc(const short *a, const short *b) { float az,bz; az = face_depth[*a]; bz = face_depth[*b]; if (az < bz) return -1; else if (az > bz) return 1; else return 0; } #ifdef _DEBUG void model_draw_outline(int nverts,g3Point **pointlist) { int i; for (i=0;ifaces[facenum]; int modelnum=sm-pm->submodel; texture *texp=NULL; int t; int custom=0; g3Codes face_cc; int triface=0; face_cc.cc_and=0xff; face_cc.cc_or=0; triangulated_faces[facenum]=0; if (sm->flags & SOF_CUSTOM) custom=1; // Setup texturing if (fp->texnum!=-1) texp=&GameTextures[pm->textures[fp->texnum]]; if (texp && custom && Polymodel_use_effect && (Polymodel_effect.type & PEF_CUSTOM_TEXTURE)) texp=&GameTextures[Polymodel_effect.custom_texture]; // Set radiosity lightmaps if needed if (Polymodel_light_type==POLYMODEL_LIGHTING_LIGHTMAP) { rend_SetOverlayMap (LightmapInfo[Polylighting_lightmap_object->lightmap_faces[modelnum][facenum].lmi_handle].lm_handle); } // Do bump mapping if ((Polymodel_effect.type & PEF_BUMPMAPPED) &&texp && texp->bumpmap!=-1 && Polymodel_light_type==POLYMODEL_LIGHTING_GOURAUD ) { rend_SetOverlayType (OT_NONE); rend_SetBumpmapReadyState(1,texp->bumpmap); if ((GameTextures[fp->texnum].flags & TF_SMOOTH_SPECULAR)) smooth=1; } float uchange=0,vchange=0; // Figure out if there is any texture sliding if (texp && texp->slide_u!=0) { int int_time=Gametime/texp->slide_u; float norm_time=Gametime-(int_time*texp->slide_u); norm_time/=texp->slide_u; uchange=norm_time; } if (texp && texp->slide_v!=0) { int int_time=Gametime/texp->slide_v; float norm_time=Gametime-(int_time*texp->slide_v); norm_time/=texp->slide_v; vchange=norm_time; } ASSERT (fp->nverts<100); // Setup the points for this face for (t=0;tnverts;t++) { g3Point *p = &Robot_points[fp->vertnums[t]]; pointlist[t] = p; if (texp) { p->p3_uvl.u = fp->u[t]+uchange; p->p3_uvl.v = fp->v[t]+vchange; p->p3_uvl.a = sm->alpha[fp->vertnums[t]]; p->p3_flags |=PF_UV+PF_RGBA+PF_L; // Assign bump mapping coords if ((Polymodel_effect.type & PEF_BUMPMAPPED) && texp->bumpmap!=-1 && Polymodel_light_type==POLYMODEL_LIGHTING_GOURAUD ) { p->p3_flags|=PF_UV2; vector vert=sm->verts[fp->vertnums[t]]; vector vertnorm; if (smooth) vertnorm=sm->vertnorms[fp->vertnums[t]]; else vertnorm=fp->normal; vector subvec=Bump_view_pos-vert; vm_NormalizeVectorFast (&subvec); vector incident_norm=vert-Polymodel_bump_pos; vm_NormalizeVectorFast (&incident_norm); float d=incident_norm * vertnorm; vector upvec=d * vertnorm; incident_norm-=(2*upvec); float dotp=(subvec * incident_norm); if (dotp<0) dotp=0; if (dotp>1) dotp=1; float val=dotp*.5; p->p3_uvl.u2=val; p->p3_uvl.v2=val; } } if (Polymodel_light_type==POLYMODEL_LIGHTING_LIGHTMAP) { p->p3_flags |=PF_UV2; p->p3_uvl.u2=Polylighting_lightmap_object->lightmap_faces[modelnum][facenum].u2[t]; p->p3_uvl.v2=Polylighting_lightmap_object->lightmap_faces[modelnum][facenum].v2[t]; } face_cc.cc_or|=p->p3_codes; face_cc.cc_and&=p->p3_codes; } if (face_cc.cc_or && Polymodel_use_effect && (Polymodel_effect.type & (PEF_FOGGED_MODEL|PEF_SPECULAR_MODEL|PEF_SPECULAR_FACES))) { triface=1; triangulated_faces[facenum]=1; } // If there is a texture, set it up if (texp) { bm_handle=GetTextureBitmap(texp-GameTextures,0); rend_SetTextureType (TT_LINEAR); if (Polymodel_light_type==POLYMODEL_LIGHTING_GOURAUD) rend_SetLighting (LS_GOURAUD); // If this is a light texture, make the texture full bright if (texp->flags & TF_LIGHT) { rend_SetLighting (LS_FLAT_GOURAUD); rend_SetFlatColor (GR_RGB(255,255,255)); } // Setup custom color if there is one if (Polymodel_use_effect && (Polymodel_effect.type & PEF_CUSTOM_COLOR) && (texp-GameTextures)==Multicolor_texture) { int r,g,b; rend_SetLighting (LS_FLAT_GOURAUD); r=GR_COLOR_RED (Polymodel_effect.custom_color); g=GR_COLOR_GREEN (Polymodel_effect.custom_color); b=GR_COLOR_BLUE (Polymodel_effect.custom_color); if (Polymodel_light_type==POLYMODEL_LIGHTING_GOURAUD) { if (Polymodel_use_effect && Polymodel_effect.type & PEF_COLOR) { r=Polymodel_effect.r*(float)r*Polylighting_static_red; g=Polymodel_effect.g*(float)g*Polylighting_static_green; b=Polymodel_effect.b*(float)b*Polylighting_static_blue; } else { r=(float)r*Polylighting_static_red; g=(float)g*Polylighting_static_green; b=(float)b*Polylighting_static_blue; } } rend_SetFlatColor(GR_RGB(r,g,b)); } if (Polymodel_use_effect && (Polymodel_effect.type & PEF_ALPHA)) rend_SetAlphaValue (texp->alpha * Polymodel_effect.alpha * 255 ); else rend_SetAlphaValue (texp->alpha*255); if (texp->flags & TF_SATURATE) rend_SetAlphaType (AT_SATURATE_CONSTANT_VERTEX); else { if ((texp->flags & TF_ALPHA) || (Polymodel_use_effect && (Polymodel_effect.type & PEF_ALPHA))) rend_SetAlphaType (ATF_CONSTANT+ATF_VERTEX); else rend_SetAlphaType (ATF_TEXTURE+ATF_VERTEX); } } else { rend_SetAlphaType (ATF_CONSTANT+ATF_VERTEX); if (Polymodel_use_effect && (Polymodel_effect.type & PEF_ALPHA)) rend_SetAlphaValue (Polymodel_effect.alpha * 255 ); else rend_SetAlphaValue (255); rend_SetLighting(LS_NONE); rend_SetTextureType (TT_FLAT); int r,g,b; r=GR_COLOR_RED (fp->color); g=GR_COLOR_GREEN (fp->color); b=GR_COLOR_BLUE (fp->color); if (Polymodel_light_type==POLYMODEL_LIGHTING_GOURAUD) { if (Polymodel_use_effect && Polymodel_effect.type & PEF_COLOR) { r=Polymodel_effect.r*(float)r*Polylighting_static_red; g=Polymodel_effect.g*(float)g*Polylighting_static_green; b=Polymodel_effect.b*(float)b*Polylighting_static_blue; } else { r=(float)r*Polylighting_static_red; g=(float)g*Polylighting_static_green; b=(float)b*Polylighting_static_blue; } } rend_SetFlatColor(GR_RGB(r,g,b)); bm_handle=0; } if (triface) g3_SetTriangulationTest(1); g3_DrawPoly(fp->nverts,pointlist,bm_handle,MAP_TYPE_BITMAP,&face_cc); if (triface) g3_SetTriangulationTest(0); if (texp && (Polymodel_effect.type & PEF_BUMPMAPPED) && texp->bumpmap!=-1 && Polymodel_light_type==POLYMODEL_LIGHTING_GOURAUD ) { rend_SetBumpmapReadyState(0,0); } #ifdef _DEBUG if (Polymodel_outline_mode) DrawSubmodelFaceOutline (fp->nverts,pointlist); /* if (Lightmap_debug_model==(pm-Poly_models) && Polymodel_light_type==POLYMODEL_LIGHTING_LIGHTMAP && Lightmap_debug_subnum==modelnum && Lightmap_debug_facenum==facenum) { int lmi_handle=Polylighting_lightmap_object->lightmap_faces[modelnum][facenum].lmi_handle; lightmap_object_face *lfp=&Polylighting_lightmap_object->lightmap_faces[modelnum][facenum]; lightmap_info *lmi_ptr=&LightmapInfo[lmi_handle]; int w=lmi_w (lmi_handle); int h=lmi_h (lmi_handle); vector rvec=lfp->rvec*lmi_ptr->xspacing; vector uvec=lfp->uvec*lmi_ptr->yspacing; ushort *src_data=(ushort *)lm_data(lmi_ptr->lm_handle); for (int i=0;iupper_left-(y*uvec)+(x*rvec); g3_RotatePoint(&epoints[0],&evec[0]); pointlist[0] = &epoints[0]; evec[1]=lmi_ptr->upper_left-(y*uvec)+((x+1)*rvec); g3_RotatePoint(&epoints[1],&evec[1]); pointlist[1] = &epoints[1]; evec[2]=lmi_ptr->upper_left-((y+1)*uvec)+((x+1)*rvec); g3_RotatePoint(&epoints[2],&evec[2]); pointlist[2] = &epoints[2]; evec[3]=lmi_ptr->upper_left-((y+1)*uvec)+(x*rvec); g3_RotatePoint(&epoints[3],&evec[3]); pointlist[3] = &epoints[3]; if (!(src_data[y*w+x] & OPAQUE_FLAG)) { for (t=0;t<4;t++) g3_DrawLine(GR_RGB(255,0,255),pointlist[t],pointlist[(t+1)%4]); } else { for (t=0;t<4;t++) g3_DrawLine(GR_RGB(255,255,255),pointlist[t],pointlist[(t+1)%4]); } } // Draw red cross where upper left is ubyte c0; g3Point p0; p0.p3_flags=0; c0 = g3_RotatePoint(&p0,&LightmapInfo[lmi_handle].upper_left); if (! c0) { //Draw a little cross at the current vert g3_ProjectPoint(&p0); //make sure projected rend_SetFlatColor(GR_RGB(255,0,0)); rend_DrawLine(p0.p3_sx-CROSS_WIDTH,p0.p3_sy,p0.p3_sx,p0.p3_sy-CROSS_WIDTH); rend_DrawLine(p0.p3_sx,p0.p3_sy-CROSS_WIDTH,p0.p3_sx+CROSS_WIDTH,p0.p3_sy); rend_DrawLine(p0.p3_sx+CROSS_WIDTH,p0.p3_sy,p0.p3_sx,p0.p3_sy+CROSS_WIDTH); rend_DrawLine(p0.p3_sx,p0.p3_sy+CROSS_WIDTH,p0.p3_sx-CROSS_WIDTH,p0.p3_sy); } }*/ #endif } inline void RenderSubmodelLightmapFace (poly_model *pm,bsp_info *sm,int facenum) { g3Point *pointlist[100]; polyface *fp=&sm->faces[facenum]; int modelnum=sm-pm->submodel; int t; int lm_handle=LightmapInfo[Polylighting_lightmap_object->lightmap_faces[modelnum][facenum].lmi_handle].lm_handle; float xscalar=(float)GameLightmaps[lm_handle].width/(float)GameLightmaps[lm_handle].square_res; float yscalar=(float)GameLightmaps[lm_handle].height/(float)GameLightmaps[lm_handle].square_res; ASSERT (fp->nverts<100); // Setup the points for this face for (t=0;tnverts;t++) { g3Point *p = &Robot_points[fp->vertnums[t]]; pointlist[t] = p; p->p3_uvl.u = Polylighting_lightmap_object->lightmap_faces[modelnum][facenum].u2[t]*xscalar; p->p3_uvl.v = Polylighting_lightmap_object->lightmap_faces[modelnum][facenum].v2[t]*yscalar; p->p3_uvl.l = 1.0; p->p3_flags |=PF_UV2+PF_RGBA+PF_L; } if (triangulated_faces[facenum]) g3_SetTriangulationTest (1); g3_DrawPoly(fp->nverts,pointlist,lm_handle,MAP_TYPE_LIGHTMAP); if (triangulated_faces[facenum]) g3_SetTriangulationTest (0); } inline void RenderSubmodelFaceFogged (poly_model *pm,bsp_info *sm,int facenum) { g3Point *pointlist[100]; polyface *fp=&sm->faces[facenum]; int modelnum=sm-pm->submodel; int t; for (t=0;tnverts;t++) { g3Point *p = &Robot_points[fp->vertnums[t]]; pointlist[t] = p; float mag; if (Polymodel_effect.fog_plane_check==1) { mag = vm_DotProduct(&Fog_plane,&sm->verts[fp->vertnums[t]])+Fog_distance; } else { vector *vec=&sm->verts[fp->vertnums[t]]; // Now we must generate the split point. This is simply // an equation in the form Origin + t*Direction float dist = (*vec*Polymodel_fog_plane)+ Fog_distance; vector subvec=*vec-Fog_view_pos; float t = Fog_eye_distance / (Fog_eye_distance - dist); vector portal_point=Fog_view_pos+(t*subvec); float eye_distance=-(vm_DotProduct (&Fog_plane,&portal_point)); mag = vm_DotProduct(&Fog_plane,vec)+eye_distance; } float scalar=mag/Polymodel_effect.fog_depth; if (scalar>1) scalar=1; if (scalar<0) scalar=0; p->p3_a=scalar; p->p3_flags |= PF_RGBA; } if (triangulated_faces[facenum]) g3_SetTriangulationTest (1); g3_DrawPoly(fp->nverts,pointlist,0); if (triangulated_faces[facenum]) g3_SetTriangulationTest (0); } inline void RenderSubmodelFaceSpecular (poly_model *pm,bsp_info *sm,int facenum) { g3Point *pointlist[100]; polyface *fp=&sm->faces[facenum]; int modelnum=sm-pm->submodel; int t; bool smooth=0; if ((Polymodel_effect.type & PEF_SPECULAR_FACES) && (GameTextures[fp->texnum].flags & TF_SMOOTH_SPECULAR)) smooth=1; for (t=0;tnverts;t++) { g3Point *p = &Robot_points[fp->vertnums[t]]; vector vert=sm->verts[fp->vertnums[t]]; vector vertnorm; if (smooth) vertnorm=sm->vertnorms[fp->vertnums[t]]; else vertnorm=fp->normal; pointlist[t] = p; p->p3_flags |= PF_RGBA; p->p3_a=0.0; vector subvec=Specular_view_pos-vert; vm_NormalizeVectorFast (&subvec); vector incident_norm=vert-Polymodel_specular_pos; vm_NormalizeVectorFast (&incident_norm); float d=incident_norm * vertnorm; vector upvec=d * vertnorm; incident_norm-=(2*upvec); float dotp=subvec * incident_norm; if (dotp<0) continue; if (dotp>1) dotp=1; if (dotp>0) { int index=((float)(MAX_SPECULAR_INCREMENTS-1)*dotp); float val=Specular_tables[2][index]; p->p3_a=val*Polymodel_effect.spec_scalar; } } if (triangulated_faces[facenum]) g3_SetTriangulationTest (1); g3_DrawPoly(fp->nverts,pointlist,0); if (triangulated_faces[facenum]) g3_SetTriangulationTest (0); } #define MAX_PARTS 100 // Draws a glowing cone of light that represents thrusters void DrawThrusterEffect (vector *pos,float r,float g,float b,vector *norm,float size,float length) { vector cur_pos=*pos; float cur_length=0; vector glow_pos[MAX_PARTS]; float glow_size[MAX_PARTS]; int total_parts=0; if (length<.1) return; int num_divs=length*3; if (num_divs>MAX_PARTS) num_divs=MAX_PARTS; float size_change=size/num_divs; float pos_change=length/num_divs; if (!UseHardware) return; // No software stuff here! rend_SetZBufferWriteMask (0); rend_SetAlphaType (AT_SATURATE_TEXTURE); rend_SetAlphaValue (.3*255); rend_SetLighting (LS_GOURAUD); rend_SetColorModel (CM_RGB); ddgr_color color=GR_RGB(r*255,g*255,b*255); int bm_handle=Fireballs[GRADIENT_BALL_INDEX].bm_handle; int t; // We must draw the small ones first, but we're starting the iteration from the // large one. Consequently, we must store our variables so we can draw in reverse order for (t=0;t.05;t++) { glow_pos[t]=cur_pos; glow_size[t]=size; size-=size_change; cur_pos+=((*norm)*pos_change); total_parts++; } for (t=total_parts-1;t>=0;t--) { rend_SetZBias (-glow_size[t]); g3_DrawBitmap (&glow_pos[t],glow_size[t],(glow_size[t]*bm_h(bm_handle,0))/bm_w(bm_handle,0),bm_handle,color); } rend_SetZBias (0.0); rend_SetZBufferWriteMask (1); } // Draws a glowing cone of light void DrawGlowEffect (vector *pos,float r,float g,float b,vector *norm,float size) { if (!UseHardware) return; // No software stuff here! if (Polymodel_use_effect && Polymodel_effect.type & PEF_NO_GLOWS) return; rend_SetZBufferWriteMask (0); rend_SetAlphaType (AT_SATURATE_TEXTURE); rend_SetAlphaValue (.8*255); rend_SetLighting (LS_GOURAUD); rend_SetColorModel (CM_RGB); ddgr_color color=GR_RGB(r*255,g*255,b*255); int bm_handle=Fireballs[GRADIENT_BALL_INDEX].bm_handle; rend_SetZBias (-size); g3_DrawBitmap (pos,size,(size*bm_h(bm_handle,0))/bm_w(bm_handle,0),bm_handle,color); rend_SetZBias (0.0); rend_SetZBufferWriteMask (1); } void RenderSubmodelFacesSorted (poly_model *pm,bsp_info *sm) { int i,t; int rcount; int model_render_order[MAX_POLYGON_VECS]; int modelnum=sm-pm->submodel; ASSERT (sm->nvertsnum_faces;i++) { polyface *fp = &sm->faces[i]; //check for visible face if (g3_CheckNormalFacing(&sm->verts[fp->vertnums[0]],&fp->normal)) { face_depth[i] = 0; for (t=0;tnverts;t++) face_depth[i] += Robot_points[fp->vertnums[t]].p3_z; face_depth[i] /= fp->nverts; //initialize order list model_render_order[rcount] = i; rcount++; ASSERT (rcount=0;i--) { int facenum=model_render_order[i]; RenderSubmodelFace (pm,sm,facenum); } } void RenderSubmodelFacesUnsorted (poly_model *pm,bsp_info *sm) { int i; int modelnum=sm-pm->submodel; short alpha_faces[MAX_FACES_PER_ROOM],num_alpha_faces=0; int rcount=0; vector view_pos; g3_GetViewPosition (&view_pos); g3_GetUnscaledMatrix (&Unscaled_bumpmap_matrix); Specular_view_pos=view_pos; Bump_view_pos=view_pos; if (modelnum<0 || modelnum>=pm->n_models) { Error ("Got bad model number %d from polymodel %s!",modelnum,pm->name); return; } if (sm->flags & SOF_CUSTOM) rend_SetZBias (-.5); for (i=0;inum_faces;i++) { vector tempv; polyface *fp=&sm->faces[i]; texture *texp; // Check to see if this face even faces us! tempv = view_pos - sm->verts[fp->vertnums[0]]; if ((tempv * fp->normal)<0) continue; if (fp->texnum!=-1) { texp=&GameTextures[pm->textures[fp->texnum]]; if (texp->flags & TF_ALPHA || texp->flags & TF_SATURATE) { alpha_faces[num_alpha_faces++] = i; continue; } } if (StateLimited) { State_elements[rcount].facenum=i; State_elements[rcount].sort_key=pm->textures[fp->texnum]; rcount++; } else RenderSubmodelFace (pm,sm,i); } if (StateLimited) { SortStates (State_elements,rcount); for (i=rcount-1;i>=0;i--) { int facenum=State_elements[i].facenum; RenderSubmodelFace (pm,sm,facenum); } if (!NoLightmaps) { if (!UseMultitexture && Polymodel_light_type==POLYMODEL_LIGHTING_LIGHTMAP) { rend_SetAlphaType(AT_LIGHTMAP_BLEND); rend_SetLighting (LS_GOURAUD); rend_SetColorModel (CM_MONO); rend_SetOverlayType (OT_NONE); rend_SetTextureType(TT_PERSPECTIVE); rend_SetWrapType (WT_CLAMP); rend_SetMipState (0); for (i=rcount-1;i>=0;i--) { int facenum=State_elements[i].facenum; RenderSubmodelLightmapFace (pm,sm,facenum); } rend_SetWrapType (WT_WRAP); rend_SetMipState (1); } } } // Now render all alpha faces //rend_SetZBufferWriteMask (0); for (i=0;iflags & SOF_CUSTOM) rend_SetZBias (0); // Draw specular faces if needed if (Polymodel_use_effect && Polymodel_effect.type & (PEF_SPECULAR_MODEL|PEF_SPECULAR_FACES)) { rend_SetOverlayType (OT_NONE); rend_SetTextureType (TT_FLAT); rend_SetLighting (LS_NONE); rend_SetColorModel (CM_MONO); rend_SetAlphaType (AT_SATURATE_VERTEX); rend_SetAlphaValue (255); rend_SetZBufferWriteMask (0); rend_SetFlatColor (GR_RGB((int)(Polymodel_effect.spec_r*255.0),(int)(Polymodel_effect.spec_g*255.0),(int)(Polymodel_effect.spec_b*255.0))); for (i=0;inum_faces;i++) { polyface *fp=&sm->faces[i]; if (!g3_CheckNormalFacing(&sm->verts[fp->vertnums[0]],&fp->normal)) continue; /* vector subvec=sm->verts[fp->vertnums[0]]-Polymodel_specular_pos; if ((fp->normal * subvec)> 0) continue;*/ if ((Polymodel_effect.type & PEF_SPECULAR_MODEL) || (fp->texnum!=-1 && GameTextures[pm->textures[fp->texnum]].flags & TF_SPECULAR)) RenderSubmodelFaceSpecular (pm,sm,i); } rend_SetZBufferWriteMask (1); } // Draw fog if need be if (Polymodel_use_effect && Polymodel_effect.type & PEF_FOGGED_MODEL) { matrix mat; g3_GetUnscaledMatrix (&mat); g3_GetViewPosition (&Fog_view_pos); Fog_plane=mat.fvec; if (Polymodel_effect.fog_plane_check==1) Fog_distance=-(vm_DotProduct (&Fog_plane,&Fog_view_pos)); else { Fog_distance=-(vm_DotProduct (&Polymodel_fog_plane,&Polymodel_fog_portal_vert)); Fog_eye_distance = (Fog_view_pos*Polymodel_fog_plane)+ Fog_distance; } rend_SetOverlayType (OT_NONE); rend_SetTextureType (TT_FLAT); rend_SetLighting (LS_NONE); rend_SetColorModel (CM_MONO); rend_SetAlphaType (AT_VERTEX); rend_SetAlphaValue (255); rend_SetZBufferWriteMask (0); rend_SetCoplanarPolygonOffset(1); rend_SetFlatColor (GR_RGB((int)(Polymodel_effect.fog_r*255.0),(int)(Polymodel_effect.fog_g*255.0),(int)(Polymodel_effect.fog_b*255.0))); for (i=0;inum_faces;i++) { polyface *fp=&sm->faces[i]; if (!g3_CheckNormalFacing(&sm->verts[fp->vertnums[0]],&fp->normal)) continue; RenderSubmodelFaceFogged (pm,sm,i); } rend_SetCoplanarPolygonOffset(0); rend_SetZBufferWriteMask (1); } } void BuildModelAngleMatrix( matrix *mat, angle ang,vector *axis); void StartLightInstance (vector *,matrix *); void DoneLightInstance(); // Rotates all of the points of a submodel, plus supplies color info void RotateModelPoints (poly_model *pm,bsp_info *sm) { // Figure out lighting if (Polymodel_light_type==POLYMODEL_LIGHTING_STATIC) { if ((Polymodel_use_effect && (Polymodel_effect.type & PEF_DEFORM)) || (sm->flags & SOF_JITTER)) { for (int i=0;inverts;i++) { vector vec=sm->verts[i]; float val=((ps_rand()%1000)-500.0)/500.0; vec*=1.0+(Polymodel_effect.deform_range*val); g3_RotatePoint(&Robot_points[i],&vec); } } else { for (int i=0;inverts;i++) g3_RotatePoint(&Robot_points[i],&sm->verts[i]); } } else if (Polymodel_light_type==POLYMODEL_LIGHTING_LIGHTMAP) { if ((Polymodel_use_effect && (Polymodel_effect.type & PEF_DEFORM)) || (sm->flags & SOF_JITTER)) { for (int i=0;inverts;i++) { vector vec=sm->verts[i]; float val=((ps_rand()%1000)-500.0)/500.0; vec*=1.0+(Polymodel_effect.deform_range*val); g3_RotatePoint(&Robot_points[i],&vec); Robot_points[i].p3_r=1.0; Robot_points[i].p3_g=1.0; Robot_points[i].p3_b=1.0; } } else { for (int i=0;inverts;i++) { g3_RotatePoint(&Robot_points[i],&sm->verts[i]); Robot_points[i].p3_r=1.0; Robot_points[i].p3_g=1.0; Robot_points[i].p3_b=1.0; } } } else if (Polymodel_light_type==POLYMODEL_LIGHTING_GOURAUD) { if (Polymodel_use_effect && Polymodel_effect.type & PEF_COLOR) { if ((Polymodel_use_effect && (Polymodel_effect.type & PEF_DEFORM)) || (sm->flags & SOF_JITTER)) { for (int i=0;inverts;i++) { vector vec=sm->verts[i]; float val=((ps_rand()%1000)-500.0)/500.0; vec*=1.0+(Polymodel_effect.deform_range*val); g3_RotatePoint(&Robot_points[i],&vec); vector normvec=sm->vertnorms[i]; val=(-vm_DotProduct (Polymodel_light_direction,&normvec)+1.0)/2; Robot_points[i].p3_r=Polymodel_effect.r*val*Polylighting_static_red; Robot_points[i].p3_g=Polymodel_effect.g*val*Polylighting_static_green; Robot_points[i].p3_b=Polymodel_effect.b*val*Polylighting_static_blue; } } else { if ((Polymodel_use_effect && (Polymodel_effect.type & PEF_DEFORM)) || (sm->flags & SOF_JITTER)) { for (int i=0;inverts;i++) { vector vec=sm->verts[i]; float val=((ps_rand()%1000)-500.0)/500.0; vec*=1.0+(Polymodel_effect.deform_range*val); g3_RotatePoint(&Robot_points[i],&vec); vector normvec=sm->vertnorms[i]; val=(-vm_DotProduct (Polymodel_light_direction,&normvec)+1.0)/2; Robot_points[i].p3_r=Polymodel_effect.r*val*Polylighting_static_red; Robot_points[i].p3_g=Polymodel_effect.g*val*Polylighting_static_green; Robot_points[i].p3_b=Polymodel_effect.b*val*Polylighting_static_blue; } } else { for (int i=0;inverts;i++) { g3_RotatePoint(&Robot_points[i],&sm->verts[i]); vector normvec=sm->vertnorms[i]; float val=(-vm_DotProduct (Polymodel_light_direction,&normvec)+1.0)/2; Robot_points[i].p3_r=Polymodel_effect.r*val*Polylighting_static_red; Robot_points[i].p3_g=Polymodel_effect.g*val*Polylighting_static_green; Robot_points[i].p3_b=Polymodel_effect.b*val*Polylighting_static_blue; } } } } else { if ((Polymodel_use_effect && (Polymodel_effect.type & PEF_DEFORM)) || (sm->flags & SOF_JITTER)) { for (int i=0;inverts;i++) { vector vec=sm->verts[i]; float val=((ps_rand()%1000)-500.0)/500.0; vec*=1.0+(Polymodel_effect.deform_range*val); g3_RotatePoint(&Robot_points[i],&vec); vector normvec=sm->vertnorms[i]; val=(-vm_DotProduct (Polymodel_light_direction,&normvec)+1.0)/2; Robot_points[i].p3_r=val*Polylighting_static_red; Robot_points[i].p3_g=val*Polylighting_static_green; Robot_points[i].p3_b=val*Polylighting_static_blue; } } else { for (int i=0;inverts;i++) { g3_RotatePoint(&Robot_points[i],&sm->verts[i]); vector normvec=sm->vertnorms[i]; float val=(-vm_DotProduct (Polymodel_light_direction,&normvec)+1.0)/2; Robot_points[i].p3_r=val*Polylighting_static_red; Robot_points[i].p3_g=val*Polylighting_static_green; Robot_points[i].p3_b=val*Polylighting_static_blue; } } } } #ifndef RELEASE if (!UseHardware) { for (int i=0;inverts;i++) Robot_points[i].p3_l=Robot_points[i].p3_g; rend_SetColorModel (CM_MONO); } #endif } void RenderSubmodel (poly_model *pm,bsp_info *sm, uint f_render_sub) { int i; matrix lightmatrix; // Don't render door housings if (IsNonRenderableSubmodel (pm,sm-pm->submodel)) return; if (Polymodel_light_type!=POLYMODEL_LIGHTING_LIGHTMAP) { // Turn off bumpmapping if not needed rend_SetBumpmapReadyState(0,0); } else { if (!StateLimited || UseMultitexture) rend_SetOverlayType (OT_BLEND); } if (Multicolor_texture==-1 && Polymodel_use_effect && (Polymodel_effect.type & PEF_CUSTOM_COLOR)) Multicolor_texture=FindTextureName ("MultiColor"); rend_SetColorModel (CM_RGB); StartPolyModelPosInstance(&sm->mod_pos); vector temp_vec=sm->mod_pos+sm->offset; g3_StartInstanceAngles(&temp_vec,&sm->angs ); vm_AnglesToMatrix (&lightmatrix,sm->angs.p,sm->angs.h,sm->angs.b); StartLightInstance(&temp_vec,&lightmatrix); // Check my bit to see if I get drawn if(f_render_sub & (0x00000001 << (sm - pm->submodel))) { if (sm->flags & SOF_CUSTOM) { if (!(Polymodel_effect.type & PEF_CUSTOM_TEXTURE)) goto pop_lighting; } // Check to draw glow faces if (sm->flags & (SOF_GLOW | SOF_THRUSTER)) { if (!FacingPass) goto pop_lighting; vector zero_pos={0,0,0}; rend_SetOverlayType (OT_NONE); if (Polymodel_use_effect && Polymodel_effect.type & PEF_GLOW_SCALAR) { if (Polymodel_effect.type & PEF_CUSTOM_GLOW) DrawThrusterEffect (&zero_pos,Polymodel_effect.glow_r,Polymodel_effect.glow_g,Polymodel_effect.glow_b,&sm->glow_info->normal,sm->glow_info->glow_size*Polymodel_effect.glow_size_scalar,3*Polymodel_effect.glow_length_scalar); else DrawThrusterEffect (&zero_pos,sm->glow_info->glow_r,sm->glow_info->glow_g,sm->glow_info->glow_b,&sm->glow_info->normal,sm->glow_info->glow_size*Polymodel_effect.glow_size_scalar,3*Polymodel_effect.glow_length_scalar); } else { if (Polymodel_use_effect && Polymodel_effect.type & PEF_CUSTOM_GLOW) DrawGlowEffect (&zero_pos,Polymodel_effect.glow_r,Polymodel_effect.glow_g,Polymodel_effect.glow_b,&sm->glow_info->normal,sm->glow_info->glow_size); else DrawGlowEffect (&zero_pos,sm->glow_info->glow_r,sm->glow_info->glow_g,sm->glow_info->glow_b,&sm->glow_info->normal,sm->glow_info->glow_size); } goto pop_lighting; } else if (sm->flags & SOF_FACING) { if (!FacingPass) goto pop_lighting; vector pos; rend_SetLighting (LS_NONE); rend_SetColorModel (CM_MONO); rend_SetOverlayType (OT_NONE); int bm_handle=GetTextureBitmap(pm->textures[sm->faces[0].texnum],0); rend_SetAlphaValue (GameTextures[pm->textures[sm->faces[0].texnum]].alpha*255); vm_MakeZero (&pos); if (GameTextures[pm->textures[sm->faces[0].texnum]].flags & TF_SATURATE) rend_SetAlphaType (AT_SATURATE_TEXTURE); else rend_SetAlphaType (ATF_CONSTANT+ATF_TEXTURE); rend_SetZBufferWriteMask (0); g3_DrawBitmap (&pos,sm->rad,(sm->rad*bm_h(bm_handle,0))/bm_w(bm_handle,0),bm_handle); rend_SetZBufferWriteMask (1); goto pop_lighting; } else { if (FacingPass) goto pop_lighting; } RotateModelPoints (pm,sm); if (!UseHardware) RenderSubmodelFacesSorted (pm, sm); else RenderSubmodelFacesUnsorted (pm, sm); } pop_lighting: for (i=0;inum_children;i++) { RenderSubmodel(pm,&pm->submodel[sm->children[i]], f_render_sub); } g3_DoneInstance(); DonePolyModelPosInstance(); DoneLightInstance(); } int RenderPolygonModel(poly_model * pm, uint f_render_sub) { ASSERT (pm->new_style==1); int i=0; rend_SetAlphaType (ATF_CONSTANT+ATF_VERTEX); rend_SetWrapType (WT_WRAP); FacingPass=0; for (i=0;in_models;i++) { bsp_info *sm=&pm->submodel[i]; if (sm->parent==-1) RenderSubmodel (pm,sm, f_render_sub); } // Now render any facing submodels if (pm->flags & PMF_FACING) { // Don't render if we have it set for no glows FacingPass=1; rend_SetOverlayType (OT_NONE); for (i=0;in_models;i++) { bsp_info *sm=&pm->submodel[i]; if (sm->parent==-1) RenderSubmodel (pm,sm, f_render_sub); } } FacingPass=0; return 1; } float ComputeDefaultSizeFunc(int handle, float *size_ptr, vector *offset_ptr, bool f_use_all_frames) { poly_model *pm; matrix m; float normalized_time[MAX_SUBOBJECTS]; int i, j, n; float cur_dist; float size = 0.0; int start_frame = 0; int end_frame = 0; vector geometric_center = Zero_vector; // Chris: Come see me when you are ready to deal with the paging problem - JL pm = GetPolymodelPointer(handle); ASSERT(start_frame <= end_frame); ASSERT(end_frame <= pm->frame_max); if(f_use_all_frames) { end_frame = pm->frame_max; } if(offset_ptr) { vector min_xyz; vector max_xyz; for(n = start_frame; n <= end_frame; n++) { // Because size changes with animation, we need the worst case point -- so, check every keyframe // NOTE: This code does not currently account for all $turret and $rotate positions SetNormalizedTimeAnim(n, normalized_time, pm); SetModelAnglesAndPos (pm,normalized_time); for (i = 0;i < pm->n_models; i++) { bsp_info *sm=&pm->submodel[i]; // For every vertex for(j = 0; j < sm->nverts; j++) { vector pnt; int mn; // Get the point and its current sub-object pnt = sm->verts[j]; mn = i; // Instance up the tree while (mn != -1) { vector tpnt; vm_AnglesToMatrix(&m, pm->submodel[mn].angs.p,pm->submodel[mn].angs.h, pm->submodel[mn].angs.b); vm_TransposeMatrix(&m); tpnt = pnt * m; pnt = tpnt + pm->submodel[mn].offset + pm->submodel[mn].mod_pos; mn = pm->submodel[mn].parent; } // Maybe use for other code -- Accounts for world coordinates // m = obj->orient; // vm_TransposeMatrix(&m); // // pnt = pnt * m; // // *gun_point += obj->pos; // Find the min_xyz and max_xyz if(n == start_frame && i == 0 && j == 0) { min_xyz = max_xyz = pnt; } else { if(pnt.x < min_xyz.x) min_xyz.x = pnt.x; else if(pnt.x > max_xyz.x) max_xyz.x = pnt.x; if(pnt.y < min_xyz.y) min_xyz.y = pnt.y; else if(pnt.y > max_xyz.y) max_xyz.y = pnt.y; if(pnt.z < min_xyz.z) min_xyz.z = pnt.z; else if(pnt.z > max_xyz.z) max_xyz.z = pnt.z; } } } } geometric_center = (max_xyz + min_xyz)/2.0; *offset_ptr = geometric_center; } for(n = start_frame; n <= end_frame; n++) { // Because size changes with animation, we need the worst case point -- so, check every keyframe // NOTE: This code does not currently account for all $turret and $rotate positions SetNormalizedTimeAnim(n, normalized_time, pm); SetModelAnglesAndPos (pm,normalized_time); for (i = 0;i < pm->n_models; i++) { bsp_info *sm=&pm->submodel[i]; // For every vertex for(j = 0; j < sm->nverts; j++) { vector pnt; int mn; // Get the point and its current sub-object pnt = sm->verts[j]; mn = i; // Instance up the tree while (mn != -1) { vector tpnt; vm_AnglesToMatrix(&m, pm->submodel[mn].angs.p,pm->submodel[mn].angs.h, pm->submodel[mn].angs.b); vm_TransposeMatrix(&m); tpnt = pnt * m; pnt = tpnt + pm->submodel[mn].offset + pm->submodel[mn].mod_pos; mn = pm->submodel[mn].parent; } // Maybe use for other code -- Accounts for world coordinates // m = obj->orient; // vm_TransposeMatrix(&m); // // pnt = pnt * m; // // *gun_point += obj->pos; cur_dist = vm_VectorDistance(&geometric_center, &pnt); if(cur_dist > size) size = cur_dist; } } } // This is a arbitary value. It allows for some turret and rotations to be caught size = size + 0.01f; if(size_ptr) //DAJ *size_ptr = size; return size; } float ComputeDefaultSize(int type, int handle, float *size_ptr) { float size = ComputeDefaultSizeFunc(handle, size_ptr, NULL, true); if(type != OBJ_WEAPON && type != OBJ_DEBRIS && type != OBJ_POWERUP) { ComputeDefaultSizeFunc(handle, &Poly_models[handle].wall_size, &Poly_models[handle].wall_size_offset, false); ComputeDefaultSizeFunc(handle, &Poly_models[handle].anim_size, &Poly_models[handle].anim_size_offset, true); if (type == OBJ_PLAYER) { Poly_models[handle].anim_size *= PLAYER_SIZE_SCALAR; Poly_models[handle].anim_size_offset = Zero_vector; } } else { if(type == OBJ_POWERUP) { size *= 2.0f; *size_ptr *= 2.0f; } Poly_models[handle].wall_size = size; Poly_models[handle].wall_size_offset = Zero_vector; Poly_models[handle].anim_size = size; Poly_models[handle].anim_size_offset = Zero_vector; } Poly_models[handle].flags |= PMF_SIZE_COMPUTED; return size; }