/****************************************************************************/ /* FILE: PathPt.c */ /****************************************************************************/ #define WIN32_LEAN_AND_MEAN #include // PathPt kind of does a naughty thing. It digs directly into the world, to get the entities needed // to make a path. This is ok, UNTIL the game stuff gets put into a dll. Then we'll need to make // an interface to all the genesis API's needed to access the world. ALSO, NOTE that this stuff will // still only happen on the server side... #include #include #include #include "PathPt.h" #include "_Bot.h" #include "Track.h" static geBoolean PathPoint_Frame2(geWorld *World, const geXForm3d *XForm, geFloat DeltaTime); static geBoolean PathPoint_Frame3(geWorld *World, const geXForm3d *XForm, geFloat DeltaTime); static geBitmap *PathPointTexture; #define SetRGB(t,rv,gv,bv) ((t).r = (float)(rv), (t).g = (float)(gv), (t).b = (float)(bv)) static void DrawLine3d( geWorld * World, const geXForm3d * M, const geVec3d * p1, const geVec3d * p2, int r, int g, int b, int r1, int g1, int b1 ) { GE_LVertex v[4]; int i; geVec3d perp; geVec3d in; v[0].u = 0.0f; v[0].v = 0.0f; v[1].u = 1.0f; v[1].v = 0.0f; v[2].u = 1.0f; v[2].v = 1.0f; v[3].u = 0.0f; v[3].v = 1.0f; for (i = 0; i < 4; i++) { v[i].r = (geFloat)r; v[i].g = (geFloat)g; v[i].b = (geFloat)b; v[i].a = 255.0f; } geVec3d_Subtract(p1, p2, &perp); geXForm3d_GetIn(M, &in); geVec3d_CrossProduct(&perp, &in, &perp); geVec3d_Normalize(&perp); // geVec3d_Scale(&perp, 4.0f / 2.0f, &perp); geVec3d_Scale(&perp, 2.0f / 2.0f, &perp); v[0].X = p2->X - perp.X; v[0].Y = p2->Y - perp.Y; v[0].Z = p2->Z - perp.Z; v[1].X = p2->X + perp.X; v[1].Y = p2->Y + perp.Y; v[1].Z = p2->Z + perp.Z; v[2].X = p1->X + perp.X; v[2].Y = p1->Y + perp.Y; v[2].Z = p1->Z + perp.Z; v[3].X = p1->X - perp.X; v[3].Y = p1->Y - perp.Y; v[3].Z = p1->Z - perp.Z; SetRGB(v[0], r1, g1, b1); SetRGB(v[1], r1, g1, b1); SetRGB(v[2], r, g, b); SetRGB(v[3], r, g, b); geWorld_AddPolyOnce(World, v, 4, NULL, GE_GOURAUD_POLY, GE_RENDER_DO_NOT_OCCLUDE_OTHERS, 1.0f); } geBoolean PathPt_Reset(geWorld *World) { if (!World) return GE_TRUE; memset(TrackList,0,sizeof(TrackList[0])*MAX_TRACKS); TrackCount = 0; return GE_TRUE; } static geBoolean PathPoint_SetTexture(geWorld *World, geVFile *MainFS) { geEntity_EntitySet *Set; geBitmap *ABitmap; ABitmap = NULL; if (World == NULL) return GE_TRUE; Set = geWorld_GetEntitySet(World, "PathPoint"); if (Set == NULL) return GE_TRUE; PathPointTexture = geBitmap_CreateFromFileName(MainFS, "Bmp\\Corona.Bmp"); if (!PathPointTexture) { goto ExitWithError; } ABitmap = geBitmap_CreateFromFileName(MainFS, "Bmp\\Corona.Bmp"); if (!ABitmap) { goto ExitWithError; } if (!geBitmap_SetAlpha(PathPointTexture, ABitmap)) { goto ExitWithError; } geBitmap_Destroy(&ABitmap); ABitmap = NULL; if (!geWorld_AddBitmap(World, PathPointTexture)) { goto ExitWithError; } return GE_TRUE; // Error clean up ExitWithError: { if (PathPointTexture) { geBitmap_Destroy(&PathPointTexture); PathPointTexture = NULL; } if (ABitmap) { geBitmap_Destroy(&ABitmap); ABitmap = NULL; } return GE_FALSE; } } geBoolean PathPt_Startup(geWorld *World, geVFile *Fs) { void *ClassData; geEntity_EntitySet *ClassSet; geEntity *Entity; PathPoint *Point; int pointnum=0; TrackPt *track_pt; if (!World) return GE_TRUE; PathPt_Reset(World); // Look for the class name in the world ClassSet = geWorld_GetEntitySet(World, "PathPoint"); if (!ClassSet) return GE_TRUE; Entity = NULL; while (1) { Entity = geEntity_EntitySetGetNextEntity(ClassSet, Entity); if (!Entity) break; ClassData = geEntity_GetUserData(Entity); Point = (PathPoint*)ClassData; assert(Point); // initialize translated position Point->Pos = Point->origin; if (Point->PathType <= 0) continue; //save off header info TrackList[TrackCount].Type = Point->PathType; pointnum = 0; //move through points setting up the list do { //save off point info track_pt = &TrackList[TrackCount].PointList[pointnum]; // initialize translated position Point->Pos = Point->origin; track_pt->Pos = &Point->Pos; if (Point->WatchPoint) track_pt->WatchPos = &Point->WatchPoint->origin; track_pt->Action = Point->ActionType; track_pt->Time = Point->Time; track_pt->ActionDir = Point->Direction; track_pt->Dist = Point->Dist; track_pt->VelocityScale = Point->VelocityScale; // automatic setup for doors if (TrackList[TrackCount].Type == TRACK_TYPE_TRAVERSE_DOOR) { if (pointnum == 0) { track_pt->ActionDir = 1; track_pt->Action = POINT_TYPE_WAIT_POINT_VISIBLE; track_pt->WatchPos = &Point->Next->origin; } else if (pointnum == 1) { track_pt->ActionDir = -1; track_pt->Action = POINT_TYPE_WAIT_POINT_VISIBLE; track_pt->WatchPos = (track_pt-1)->Pos; } } pointnum++; TrackList[TrackCount].PointCount = pointnum; assert(pointnum < MAX_TRACK_POINTS); Point = Point->Next; // Found a type if (Point && Point->PathType >= 0) { track_pt = &TrackList[TrackCount].PointList[pointnum]; SET(track_pt->Flags, BIT(0)); } }while(Point && Point != (PathPoint*)ClassData); TrackCount++; assert(TrackCount < MAX_TRACKS); } Entity = NULL; { void Track_LinkTracks(geWorld *World); Track_LinkTracks(World); } if (Fs) { if (!PathPoint_SetTexture(World, Fs)) return GE_FALSE; } return GE_TRUE; } geBoolean PathPt_Shutdown(void) { if (PathPointTexture) { // NOTE - We really should remove it from the world, but when the world is destroyed // it removes all leftover bitmaps, so we are free to just let that happen... geBitmap_Destroy(&PathPointTexture); PathPointTexture = NULL; } return GE_TRUE; } geBoolean PathPt_Frame(geWorld *World, const geXForm3d *XForm, geFloat DeltaTime) { geEntity_EntitySet * Set; geEntity * Entity; PathPoint * P; geVec3d Pos; geVec3d Center; extern geBoolean PathLight; extern geBoolean MultiPathLight; if (!World) return GE_TRUE; Set = geWorld_GetEntitySet(World, "PathPoint"); if (Set == NULL) return GE_TRUE; Entity = NULL; while (1) { Entity = geEntity_EntitySetGetNextEntity(Set, Entity); if (!Entity) break; P = geEntity_GetUserData(Entity); if (P->MoveWithModel) { geXForm3d XForm; geWorld_GetModelXForm(World, P->MoveWithModel, &XForm); Pos = P->origin; geWorld_GetModelRotationalCenter(World, P->MoveWithModel, &Center); geVec3d_Subtract(&Pos, &Center, &Pos); geXForm3d_Transform(&XForm, &Pos, &Pos); geVec3d_Add(&Pos, &Center, &P->Pos); } } if (XForm) { if (PathLight) PathPoint_Frame2(World, XForm, DeltaTime); if (MultiPathLight) PathPoint_Frame3(World, XForm, DeltaTime); } return GE_TRUE; } static geBoolean PathPoint_Frame2(geWorld *World, const geXForm3d *XForm, geFloat DeltaTime) { GE_Collision Collision; int i; geBoolean Visible; geFloat DistanceToCorona; geVec3d Delta; if (!World) return GE_TRUE; // Now walk the track list, drawing lines to connect them all. Draw red // lines to things that are being watched. for (i = 0; i < TrackCount; i++) { int j; Track * T; T = &TrackList[i]; assert(T->PointCount > 0); for (j = 0; j < T->PointCount; j++) { GE_LVertex Vert; float Radius; DistanceToCorona = geVec3d_Length(&Delta); if (!geWorld_Collision(World, NULL, NULL, T->PointList[j].Pos, &XForm->Translation, GE_CONTENTS_CANNOT_OCCUPY, GE_COLLIDE_MODELS, 0xffffffff, NULL, NULL, &Collision) && (DistanceToCorona < 2000.0f))//C->MaxVisibleDistance)) { Visible = GE_TRUE; } else { Visible = GE_FALSE; } if (Visible) { Vert.X = T->PointList[j].Pos->X; Vert.Y = T->PointList[j].Pos->Y; Vert.Z = T->PointList[j].Pos->Z; if (j != 0 && TEST(T->PointList[j].Flags, BIT(0))) { Vert.g = 0.0f; Vert.b = 0.0f; Radius = 5.0f; } else { Vert.g = 255.0f; Vert.b = 255.0f; Radius = 1.0f; } Vert.r = 255.0f; Vert.a = 255.0f; Vert.u = Vert.v = 0.0f; geWorld_AddPolyOnce(World, &Vert, 1, PathPointTexture, GE_TEXTURED_POINT, GE_RENDER_DO_NOT_OCCLUDE_OTHERS | GE_RENDER_DO_NOT_OCCLUDE_SELF, Radius); } if (j < T->PointCount - 1) { DrawLine3d(World, XForm, T->PointList[j].Pos, T->PointList[j + 1].Pos, 255, 255, 255, 0, 255, 0); } if (T->PointList[j].WatchPos) { DrawLine3d(World, XForm, T->PointList[j].Pos, T->PointList[j].WatchPos, 255, 255, 255, 255, 0, 0); } } } return GE_TRUE; } static geBoolean PathPoint_Frame3(geWorld *World, const geXForm3d *XForm, geFloat DeltaTime) { int i,v; geVec3d *sp, *ep, *ep2, *sp2; if (!World) return GE_TRUE; // Now walk the track list, drawing lines to connect them all. Draw red // lines to things that are being watched. for (i = 0; i < TrackCount; i++) { Track * T; T = &TrackList[i]; assert(T->PointCount > 0); sp = T->PointList[0].Pos; ep = T->PointList[T->PointCount - 1].Pos; for (v = 0; T->Vis[v]; v++) { sp2 = T->Vis[v]->PointList[0].Pos; ep2 = T->Vis[v]->PointList[T->Vis[v]->PointCount - 1].Pos; switch(T->VisFlag[v]) { case 1: DrawLine3d(World, XForm, sp, sp2, 255, 255, 255, 0, 0, 255); break; case 2: DrawLine3d(World, XForm, sp, ep2, 255, 255, 255, 0, 0, 255); break; case 3: DrawLine3d(World, XForm, ep, ep2, 255, 255, 255, 0, 0, 255); break; case 4: DrawLine3d(World, XForm, ep, sp2, 255, 255, 255, 0, 0, 255); break; } } } return GE_TRUE; }