- build system has to use 32bit (the code is not 64bit safe)
[genesis3d.git] / GBSPLib / RAD.CPP
1 /****************************************************************************************/\r
2 /*  Rad.cpp                                                                             */\r
3 /*                                                                                      */\r
4 /*  Author: John Pollard                                                                */\r
5 /*  Description: Cacluates radiosity for a BSP.                                         */\r
6 /*                                                                                      */\r
7 /*  The contents of this file are subject to the Genesis3D Public License               */\r
8 /*  Version 1.01 (the "License"); you may not use this file except in                   */\r
9 /*  compliance with the License. You may obtain a copy of the License at                */\r
10 /*  http://www.genesis3d.com                                                            */\r
11 /*                                                                                      */\r
12 /*  Software distributed under the License is distributed on an "AS IS"                 */\r
13 /*  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See                */\r
14 /*  the License for the specific language governing rights and limitations              */\r
15 /*  under the License.                                                                  */\r
16 /*                                                                                      */\r
17 /*  The Original Code is Genesis3D, released March 25, 1999.                            */\r
18 /*Genesis3D Version 1.1 released November 15, 1999                            */\r
19 /*  Copyright (C) 1999 WildTangent, Inc. All Rights Reserved           */\r
20 /*                                                                                      */\r
21 /****************************************************************************************/\r
22 #include <Windows.h>\r
23 #include <Stdio.h>\r
24 \r
25 #include "DCommon.h"\r
26 #include "BSP.h"\r
27 #include "GBSPFile.h"\r
28 #include "Math.h"\r
29 #include "MathLib.h"\r
30 #include "Poly.h"\r
31 #include "Light.h"\r
32 #include "Texture.h"\r
33 \r
34 #include "Ram.h"\r
35 \r
36 pRAD_Patch      *FacePatches;\r
37 pRAD_Patch      *PatchList;\r
38 geFloat         *RecAmount;\r
39 \r
40 int32           NumPatches;\r
41 int32           NumReceivers;\r
42 \r
43 geBoolean BuildPatch(int32 Face);\r
44 geBoolean FinalizePatches(void);\r
45 RAD_Patch *AllocPatch(void);\r
46 void FreePatch(RAD_Patch *Patch);\r
47 void CalcPatchReflectivity(int32 Face, RAD_Patch *Patch);\r
48 void GetFaceMinsMaxs(int32 Face, geVec3d *Mins, geVec3d *Maxs);\r
49 \r
50 geBoolean SaveReceiverFile(char *FileName);\r
51 geBoolean LoadReceiverFile(char *FileName);\r
52 \r
53 //====================================================================================\r
54 //      BuildPatches\r
55 //====================================================================================\r
56 geBoolean BuildPatches(void)\r
57 {\r
58         int32           i;\r
59 \r
60         GHook.Printf("--- Build Patches --- \n");\r
61 \r
62         NumPatches = NumGFXFaces;\r
63 \r
64         FacePatches = GE_RAM_ALLOCATE_ARRAY(pRAD_Patch,NumGFXFaces);\r
65 \r
66         if (!FacePatches)\r
67         {\r
68                 GHook.Error("BuilkdPatches:  Not enough memory for patches.\n");\r
69                 return GE_FALSE;\r
70         }\r
71 \r
72         for (i=0; i< NumGFXFaces; i++)\r
73         {\r
74                 FacePatches[i] = NULL;\r
75 \r
76                 //if (GFXTexInfo[GFXFaces[i].TexInfo].Flags & TEXINFO_NO_LIGHTMAP)\r
77                 //      continue;\r
78 \r
79                 if (!BuildPatch(i))\r
80                         return GE_FALSE;\r
81         }\r
82 \r
83         NumPatches = 0;\r
84         if (!FinalizePatches())\r
85         {\r
86                 GHook.Error("BuildPatches:  Could not finalize face patches.\n");\r
87                 return GE_FALSE;\r
88         }\r
89 \r
90         if (LVerbose)\r
91                 GHook.Printf("Num Patches          : %5i\n", NumPatches);\r
92 \r
93         return GE_TRUE;\r
94 }\r
95 \r
96 //====================================================================================\r
97 //      CalcPatchInfo\r
98 //====================================================================================\r
99 geBoolean CalcPatchInfo(RAD_Patch *Patch)\r
100 {\r
101         int32           i, k;\r
102         GBSP_Poly       *Poly;\r
103 \r
104         ClearBounds(&Patch->Mins, &Patch->Maxs);\r
105 \r
106         Poly = Patch->Poly;\r
107 \r
108         if (!Poly)\r
109         {\r
110                 GHook.Error("CalcPatchInfo:  No Poly!\n");\r
111                 return GE_FALSE;\r
112         }\r
113 \r
114         for (i=0; i< Poly->NumVerts; i++)\r
115         {\r
116                 for (k=0; k< 3; k++)\r
117                 {\r
118                         if (VectorToSUB(Poly->Verts[i], k) < VectorToSUB(Patch->Mins, k))\r
119                                 VectorToSUB(Patch->Mins, k) = VectorToSUB(Poly->Verts[i], k);\r
120                         if (VectorToSUB(Poly->Verts[i], k) > VectorToSUB(Patch->Maxs, k))\r
121                                 VectorToSUB(Patch->Maxs, k) = VectorToSUB(Poly->Verts[i], k);\r
122                 }\r
123         }\r
124 \r
125         return GE_TRUE;\r
126 }\r
127 \r
128 //====================================================================================\r
129 //      GBSPPolyFromGFXFace\r
130 //====================================================================================\r
131 GBSP_Poly *GBSPPolyFromGFXFace(GFX_Face *Face)\r
132 {\r
133         GBSP_Poly       *NewPoly;\r
134         int32           i, Index;\r
135 \r
136         NewPoly = AllocPoly(Face->NumVerts);\r
137 \r
138         for (i=0; i< Face->NumVerts; i++)\r
139         {\r
140                 Index = GFXVertIndexList[i + Face->FirstVert];\r
141 \r
142                 NewPoly->Verts[i].X = (geFloat)GFXVerts[Index].X;\r
143                 NewPoly->Verts[i].Y = (geFloat)GFXVerts[Index].Y;\r
144                 NewPoly->Verts[i].Z = (geFloat)GFXVerts[Index].Z;\r
145         }\r
146 \r
147         RemoveDegenerateEdges(NewPoly);\r
148         \r
149         return NewPoly;\r
150 }\r
151 \r
152 //====================================================================================\r
153 //      PatchNeedsSplit\r
154 //====================================================================================\r
155 geBoolean PatchNeedsSplit(RAD_Patch *Patch, GBSP_Plane *Plane)\r
156 {\r
157         int32           i;\r
158 \r
159         \r
160         if (NumPatches >= MAX_PATCHES-2)                // Do not cut any more if max patches exceeded!!!\r
161                 return GE_FALSE;\r
162 \r
163 if (FastPatch)\r
164 {\r
165         geFloat Dist;\r
166 \r
167         for (i=0; i<3; i++)\r
168         {\r
169                 Dist = VectorToSUB(Patch->Maxs, i) - VectorToSUB(Patch->Mins, i);\r
170 \r
171                 if (Dist > PatchSize)\r
172                 {\r
173                         // Cut it right through the center...\r
174                         geVec3d_Clear(&Plane->Normal);\r
175                         VectorToSUB(Plane->Normal, i) = (geFloat)1;\r
176                         Plane->Dist = (VectorToSUB(Patch->Maxs, i) + VectorToSUB(Patch->Mins, i))/2.0f;\r
177                         Plane->Type = PLANE_ANY;\r
178                         return GE_TRUE;\r
179                 }\r
180         }\r
181 }\r
182 else\r
183 {\r
184         geFloat Min, Max;\r
185 \r
186         for (i=0 ; i<3 ; i++)\r
187         {\r
188                 Min = VectorToSUB(Patch->Mins,i)+1.0f;\r
189                 Max = VectorToSUB(Patch->Maxs,i)-1.0f;\r
190                 if (floor(Min/PatchSize) < floor(Max/PatchSize))\r
191                 {\r
192                         geVec3d_Clear(&Plane->Normal);\r
193                         VectorToSUB(Plane->Normal, i) = (geFloat)1;\r
194                         Plane->Dist = PatchSize*(1.0f+(geFloat)floor(Min/PatchSize));\r
195                         Plane->Type = PLANE_ANY;\r
196                         return GE_TRUE;         \r
197                 }\r
198         }\r
199 }\r
200         return GE_FALSE;\r
201 }\r
202 \r
203 //====================================================================================\r
204 //      SubdivideFacePatches\r
205 //====================================================================================\r
206 RAD_Patch *SubdivideFacePatches(RAD_Patch *Patch)\r
207 {\r
208         RAD_Patch       *CPatch, *NewPatch, *NextPatch;\r
209         GBSP_Poly       *Poly, *FPoly, *BPoly;\r
210         GBSP_Plane      Plane;\r
211 \r
212         for (CPatch = Patch; CPatch; CPatch = NextPatch)\r
213         {\r
214                 NextPatch = CPatch->Next;\r
215 \r
216                 if (PatchNeedsSplit(CPatch, &Plane))\r
217                 {\r
218                         NumPatches++;\r
219 \r
220                         Poly = CPatch->Poly;\r
221                         if (!SplitPoly(Poly, &Plane, &FPoly, &BPoly, GE_FALSE))\r
222                                 return GE_FALSE;\r
223                         \r
224                         if (!FPoly || !BPoly)\r
225                         {\r
226                                 GHook.Error("SubdivideFacePatches:  Patch was not split.\n");\r
227                                 return NULL;\r
228                         }\r
229                         \r
230                         NewPatch = AllocPatch();\r
231                         if (!NewPatch)\r
232                         {\r
233                                 GHook.Error("SubdivideFacePatches:  Out of memory for new patch.\n");\r
234                                 return NULL;\r
235                         }\r
236 \r
237                         *NewPatch = *CPatch;                    // Make it take on all the attributes of it's parent\r
238 \r
239                         NewPatch->Next = NextPatch;\r
240                         NewPatch->Poly = FPoly;\r
241                         if (!CalcPatchInfo(NewPatch))\r
242                         {\r
243                                 GHook.Error("SubdivideFacePatches:  Could not calculate patch info.\n");\r
244                                 return NULL;\r
245                         }\r
246 \r
247                         // Re-use the first patch\r
248                         CPatch->Next = NewPatch;\r
249                         CPatch->Poly = BPoly;\r
250 \r
251                         if (!CalcPatchInfo(CPatch))\r
252                         {\r
253                                 GHook.Error("SubdivideFacePatches:  Could not calculate patch info.\n");\r
254                                 return NULL;\r
255                         }\r
256 \r
257                         NextPatch = CPatch;     // Keep working from here till satisfied...\r
258                 }\r
259         }\r
260 \r
261         return Patch;\r
262 }\r
263 \r
264 //====================================================================================\r
265 //      FinalizePatchInfo\r
266 //====================================================================================\r
267 geBoolean FinalizePatchInfo(int32 Face, RAD_Patch *Patch)\r
268 {\r
269         GBSP_Poly       *Poly;\r
270         int32           i;\r
271 \r
272         Poly = Patch->Poly;\r
273 \r
274         if (!Poly)\r
275         {\r
276                 GHook.Error("FinalizePatchInfo:  No Poly!\n");\r
277                 return GE_FALSE;\r
278         }\r
279 \r
280         geVec3d_Clear(&Patch->Origin);\r
281 \r
282         for (i=0; i< Poly->NumVerts; i++)\r
283         {\r
284                 geVec3d_Add(&Patch->Origin, &Poly->Verts[i], &Patch->Origin);\r
285         }\r
286 \r
287         for (i=0; i<3; i++)\r
288                 VectorToSUB(Patch->Origin, i) /= Poly->NumVerts;\r
289 \r
290         Patch->Plane.Normal.X = (geFloat)GFXPlanes[GFXFaces[Face].PlaneNum].Normal.X;\r
291         Patch->Plane.Normal.Y = (geFloat)GFXPlanes[GFXFaces[Face].PlaneNum].Normal.Y;\r
292         Patch->Plane.Normal.Z = (geFloat)GFXPlanes[GFXFaces[Face].PlaneNum].Normal.Z;\r
293 \r
294         Patch->Plane.Dist = (geFloat)GFXPlanes[GFXFaces[Face].PlaneNum].Dist;\r
295         Patch->Plane.Type = PLANE_ANY;\r
296 \r
297         if (GFXFaces[Face].PlaneSide)\r
298         {\r
299                 geVec3d_Inverse(&Patch->Plane.Normal);\r
300                 Patch->Plane.Dist = -Patch->Plane.Dist;\r
301         }\r
302 \r
303         geVec3d_AddScaled(&Patch->Origin, &Patch->Plane.Normal, 2.0f, &Patch->Origin);\r
304 \r
305         Patch->Leaf = FindGFXLeaf(0, &Patch->Origin);\r
306 \r
307         Patch->Area = PolyArea(Patch->Poly);\r
308         if (Patch->Area < 1.0f)\r
309                 Patch->Area = 1.0f;\r
310 \r
311         FreePoly(Patch->Poly);          // Don't need this anymore\r
312         Patch->Poly = NULL;\r
313 \r
314         return GE_TRUE;\r
315 }\r
316 \r
317 //====================================================================================\r
318 //      FinalizePatches\r
319 //====================================================================================\r
320 geBoolean FinalizePatches(void)\r
321 {\r
322         RAD_Patch       *Patch;\r
323         int32           i, k;\r
324 \r
325         for (i=0; i< NumGFXFaces; i++)\r
326         for (Patch = FacePatches[i]; Patch; Patch = Patch->Next)\r
327         {\r
328                 FinalizePatchInfo(i, Patch);\r
329                 NumPatches++;\r
330         }\r
331 \r
332         PatchList = GE_RAM_ALLOCATE_ARRAY(pRAD_Patch,NumPatches);\r
333 \r
334         if (!PatchList)\r
335         {\r
336                 GHook.Error("FinalizePatches:  Out of memory for patch list.\n");\r
337                 return GE_FALSE;\r
338         }\r
339         \r
340         // Build the patch list, so we can use indexing, instead of pointers (for receivers)...\r
341         k = 0;\r
342         for (i=0; i< NumGFXFaces; i++)\r
343         for (Patch = FacePatches[i]; Patch; Patch = Patch->Next)\r
344         {\r
345                 PatchList[k] = Patch;\r
346                 k++;\r
347         }\r
348 \r
349         return GE_TRUE;\r
350 }\r
351 \r
352 //====================================================================================\r
353 //      FreePatches\r
354 //====================================================================================\r
355 void FreePatches(void)\r
356 {\r
357         int32           i;\r
358 \r
359         for (i=0; i< NumPatches; i++)\r
360         {\r
361                 geRam_Free(PatchList[i]);\r
362         }\r
363 \r
364         NumPatches = 0;\r
365 \r
366         if (PatchList)\r
367                 geRam_Free(PatchList);\r
368         if (FacePatches)        \r
369                 geRam_Free(FacePatches);\r
370 \r
371         PatchList = NULL;\r
372         FacePatches = NULL;\r
373 }\r
374 \r
375 \r
376 geFloat BestPatchSize(int32 Face)\r
377 {\r
378         GBSP_Poly       *Poly;\r
379         int32           i;\r
380         int32           Axis;\r
381         geFloat         Mins, Maxs, Size, BestSize, v;\r
382         geVec3d         *Verts;\r
383         GFX_TexInfo     *Tex;\r
384 \r
385         Poly = FacePatches[Face]->Poly;\r
386 \r
387         // Special (nonsurface cached) faces don't need subdivision\r
388         Tex = &TexInfo[GFXFaces[Face].TexInfo];\r
389 \r
390         BestSize = -MIN_MAX_BOUNDS2;\r
391 \r
392         for (Axis = 0 ; Axis < 2 ; Axis++)\r
393         {\r
394                 Mins =  MIN_MAX_BOUNDS;\r
395                 Maxs = -MIN_MAX_BOUNDS;\r
396                         \r
397                 Verts = Poly->Verts;\r
398                 for (i=0 ; i< Poly->NumVerts ; i++)\r
399                 {\r
400                         v = geVec3d_DotProduct(&Verts[i], &Tex->Vecs[Axis]);\r
401                         if (v < Mins)\r
402                                 Mins = v;\r
403                         if (v > Maxs)\r
404                                 Maxs = v;\r
405                 }\r
406                 \r
407                 Size = Maxs - Mins;\r
408                 if (Size > BestSize)\r
409                         BestSize = Size;\r
410         }\r
411 \r
412         return (BestSize/4);\r
413 \r
414 }\r
415 //====================================================================================\r
416 //      BuildPatch\r
417 //====================================================================================\r
418 void ApplyLightmapToPatches(int32 Face);\r
419 \r
420 geBoolean BuildPatch(int32 Face)\r
421 {\r
422 \r
423         //int32         Texture;\r
424         //Texture = GFXTexInfo[GFXFaces[Face].TexInfo].Texture;\r
425 \r
426         FacePatches[Face] = AllocPatch();\r
427         if (!FacePatches[Face])\r
428         {\r
429                 GHook.Error("BuildPatch:  Could not allocate patch.\n");\r
430                 return GE_FALSE;\r
431         }\r
432 \r
433         CalcPatchReflectivity(Face, FacePatches[Face]);\r
434         \r
435         FacePatches[Face]->Poly = GBSPPolyFromGFXFace(&GFXFaces[Face]);\r
436 \r
437         if (!CalcPatchInfo(FacePatches[Face]))\r
438         {\r
439                 GHook.Error("BuildPatch:  Could not calculate patch info.\n");\r
440                 return GE_FALSE;\r
441         }\r
442 \r
443         FacePatches[Face] = SubdivideFacePatches(FacePatches[Face]);\r
444 \r
445         if (!FacePatches[Face])\r
446         {\r
447                 GHook.Error("BuildPatch:  Could not subdivide patch.\n");\r
448                 return GE_FALSE;\r
449         }\r
450 \r
451         return GE_TRUE;\r
452 }\r
453 \r
454 //====================================================================================\r
455 //      AllocPatch\r
456 //====================================================================================\r
457 RAD_Patch *AllocPatch(void)\r
458 {\r
459         RAD_Patch *Patch;\r
460 \r
461         Patch = GE_RAM_ALLOCATE_STRUCT(RAD_Patch);\r
462 \r
463         if (!Patch)\r
464         {\r
465                 GHook.Error("AllocPatch:  Not enough memory.\n");\r
466                 return NULL;\r
467         }\r
468 \r
469         memset(Patch, 0, sizeof(RAD_Patch));\r
470 \r
471         return Patch;\r
472 }\r
473 \r
474 //====================================================================================\r
475 //      FreePatch\r
476 //====================================================================================\r
477 void FreePatch(RAD_Patch *Patch)\r
478 {\r
479         if (!Patch)\r
480         {\r
481                 GHook.Printf("*WARNING* FreePatch:  Nothing to free!\n");\r
482                 return;\r
483         }\r
484 \r
485         if (Patch->Poly)\r
486                 FreePoly(Patch->Poly);\r
487 \r
488         Patch->Poly = NULL;\r
489 \r
490         geRam_Free(Patch);\r
491 }\r
492 \r
493 //====================================================================================\r
494 //      AllocReceiver\r
495 //====================================================================================\r
496 RAD_Receiver *AllocReceiver(void)\r
497 {\r
498         RAD_Receiver *Receiver;\r
499 \r
500         Receiver = GE_RAM_ALLOCATE_STRUCT(RAD_Receiver);\r
501 \r
502         if (!Receiver)\r
503         {\r
504                 GHook.Error("AllocReceiver:  Not enough memory.\f");\r
505                 return NULL;\r
506         }\r
507 \r
508         memset(Receiver, 0, sizeof(RAD_Receiver));\r
509 \r
510         return Receiver;\r
511 }\r
512 \r
513 //====================================================================================\r
514 //      FreeReceiver\r
515 //====================================================================================\r
516 void FreeReceiver(RAD_Receiver *Rec)\r
517 {\r
518         if (!Rec)\r
519         {\r
520                 GHook.Printf("*WARNING* FreeReceiver:  Nothing to free!\n");\r
521                 return;\r
522         }\r
523         geRam_Free(Rec);\r
524 }\r
525 \r
526 //====================================================================================\r
527 //      FindPatchReceivers\r
528 //      PreCalculate who can see who, and how much they emit\r
529 //====================================================================================\r
530 geBoolean FindPatchReceivers(RAD_Patch *Patch)\r
531 {\r
532         RAD_Patch               *Patch2;\r
533         uint8                   *VisData;\r
534         geBoolean                       VisInfo;\r
535         geFloat                 Dist;\r
536         geFloat                 Amount;\r
537         geFloat                 Total, Scale;\r
538         int32                   i, Cluster;\r
539         geVec3d                 Vect, Normal;\r
540         RAD_Receiver    *Receiver;\r
541         GFX_Leaf                *pLeaf;\r
542         int32                   Area;\r
543 \r
544         pLeaf = &GFXLeafs[Patch->Leaf];\r
545         Cluster = pLeaf->Cluster;\r
546         Area = pLeaf->Area;\r
547 \r
548         if (Cluster >= 0 && GFXClusters[Cluster].VisOfs >= 0)\r
549         {\r
550                 VisData = &GFXVisData[GFXClusters[Cluster].VisOfs];\r
551                 VisInfo = GE_TRUE;\r
552         }\r
553         else\r
554                 VisInfo = GE_FALSE;\r
555 \r
556         Total = 0.0f;\r
557 \r
558         Normal = Patch->Plane.Normal;\r
559 \r
560         // For each face, go through all it's patches\r
561         for (i=0; i< NumPatches; i++)\r
562         {\r
563                 if (CancelRequest)\r
564                 {\r
565                         GHook.Printf("Cancel requested...\n");\r
566                         return GE_FALSE;\r
567                 }\r
568 \r
569                 Patch2 = PatchList[i];\r
570                 \r
571                 RecAmount[i] = 0.0f;\r
572 \r
573                 if (Patch2 == Patch)\r
574                         continue;\r
575 \r
576                 pLeaf = &GFXLeafs[Patch2->Leaf];\r
577 \r
578                 if (pLeaf->Area != Area)                        // Radiosity only bounces in it's original area\r
579                         continue;\r
580 \r
581                 if (VisInfo)\r
582                 {\r
583                         Cluster = pLeaf->Cluster;\r
584                         if (Cluster >= 0 && !(VisData[Cluster>>3] &(1<<(Cluster&7))) )\r
585                                 continue;\r
586 \r
587                 }\r
588 \r
589                 geVec3d_Subtract(&Patch2->Origin, &Patch->Origin, &Vect);\r
590         \r
591                 Dist = geVec3d_Normalize(&Vect);\r
592 \r
593                 //if (Dist > PatchSize)\r
594                 if (!Dist)\r
595                         continue;       // Error\r
596                 \r
597                 Scale =   geVec3d_DotProduct(&Vect, &Normal);\r
598                 Scale *= -geVec3d_DotProduct(&Vect, &Patch2->Plane.Normal);\r
599 \r
600                 if (Scale <= 0)\r
601                         continue;\r
602 \r
603                 if (RayCollision(&Patch->Origin, &Patch2->Origin, NULL))\r
604                         continue;               // Blocked by somthing in the world\r
605 \r
606                 Amount = Scale * Patch2->Area / (Dist*Dist);\r
607 \r
608                 if (Amount <= 0.0f)\r
609                         continue;\r
610 \r
611                 RecAmount[i] = Amount;\r
612 \r
613                 // Add the receiver\r
614                 Total += Amount;\r
615                 NumReceivers++;\r
616                 Patch->NumReceivers++;\r
617         }\r
618 \r
619         Patch->Receivers = GE_RAM_ALLOCATE_ARRAY(RAD_Receiver,Patch->NumReceivers);\r
620 \r
621         if (!Patch->Receivers)\r
622         {\r
623                 GHook.Error("CalcReceivers:  Out of memory for receiver.\n");\r
624                 return GE_FALSE;\r
625         }\r
626 \r
627         Receiver = Patch->Receivers;\r
628 \r
629         for (i=0; i< NumPatches; i++)\r
630         {\r
631                 if (!RecAmount[i])\r
632                         continue;\r
633 \r
634                 Receiver->Patch = (uint16)i;\r
635                 Receiver->Amount = (uint16)(RecAmount[i]*0x10000 / Total);\r
636                 Receiver++;\r
637         }\r
638 \r
639         return GE_TRUE;\r
640 }\r
641 \r
642 //====================================================================================\r
643 //      CalcReceivers\r
644 //====================================================================================\r
645 geBoolean CalcReceivers(char *FileName)\r
646 {\r
647         int32           i;\r
648         RAD_Patch       *Patch;\r
649         int32           Perc;\r
650         geFloat         Megs;\r
651 \r
652         NumReceivers = 0;\r
653 \r
654         // Try to load the receiver file first!!!\r
655         if (LoadReceiverFile(FileName))\r
656         {\r
657                 GHook.Printf("--- Found receiver file ---\n");\r
658                 return GE_TRUE;\r
659         }\r
660 \r
661         GHook.Printf(" --- Calculating receivers from scratch ---\n");\r
662 \r
663         RecAmount = GE_RAM_ALLOCATE_ARRAY(geFloat,NumPatches);\r
664 \r
665         if (!RecAmount)\r
666         {\r
667                 GHook.Error("CalcReceivers:  Out of memory for RecAmount.\n");\r
668                 return GE_FALSE;\r
669         }\r
670 \r
671         Perc = (NumPatches/20);\r
672         for (i=0; i< NumPatches; i++)\r
673         {\r
674                 if (Perc)\r
675                 {\r
676                         if (!(i%Perc) && (i/Perc)<=20)\r
677                                 GHook.Printf(".%i", (i/Perc));\r
678                 }\r
679                 \r
680                 Patch = PatchList[i];\r
681 \r
682                 if (!FindPatchReceivers(Patch))\r
683                 {\r
684                         GHook.Error("CalcReceivers:  There was an error calculating receivers.\n");\r
685                         return GE_FALSE;\r
686                 }\r
687         }\r
688         GHook.Printf("\n");\r
689 \r
690 \r
691         geRam_Free(RecAmount);\r
692         RecAmount = NULL;\r
693 \r
694         Megs = (geFloat)NumReceivers * sizeof(RAD_Receiver) / (1024*1024);\r
695         GHook.Printf("Num Receivers        : %5i, Megs %2.2f\n", NumReceivers, Megs);\r
696 \r
697         // Save receiver file for later retreival\r
698         if (!SaveReceiverFile(FileName))\r
699         {\r
700                 GHook.Error("CalcReceivers:  Failed to save receiver file...\n");\r
701                 return GE_FALSE;\r
702         }\r
703 \r
704         return GE_TRUE;\r
705 }\r
706 \r
707 //====================================================================================\r
708 //      FreeReceivers\r
709 //====================================================================================\r
710 void FreeReceivers(void)\r
711 {\r
712         int32                   i;\r
713         RAD_Patch               *Patch;\r
714 \r
715         NumReceivers = 0;\r
716 \r
717         for (i=0; i< NumPatches; i++)\r
718         {\r
719                 Patch = PatchList[i];\r
720 \r
721                 if (Patch->NumReceivers)\r
722                         geRam_Free(Patch->Receivers);\r
723 \r
724                 Patch->Receivers = NULL;\r
725         }\r
726 }\r
727 \r
728 //====================================================================================\r
729 //      CheckPatch\r
730 //====================================================================================\r
731 geBoolean CheckPatch(RAD_Patch *Patch)\r
732 {\r
733         int32   i;\r
734 \r
735         for (i=0; i<3; i++)\r
736         {\r
737                 if (VectorToSUB(Patch->RadFinal, i) < 0.0f)\r
738                 {\r
739                         GHook.Error("CheckPatch:  Bad final radiosity Color in patch.\n");\r
740                         return GE_FALSE;\r
741                 }\r
742         }\r
743 \r
744         return GE_TRUE;\r
745 }\r
746 \r
747 //====================================================================================\r
748 //      CollectPatchLight\r
749 //====================================================================================\r
750 geFloat CollectPatchLight(void)\r
751 {\r
752         int                     i, j;\r
753         RAD_Patch       *Patch;\r
754         geFloat         Total;\r
755 \r
756         Total = 0.0f;\r
757         \r
758         for (i=0; i< NumPatches; i++)\r
759         {\r
760                 Patch = PatchList[i];\r
761                 \r
762                 for (j=0 ; j<3 ; j++)\r
763                 {\r
764                         // Add receive amount to Final amount\r
765                         VectorToSUB(Patch->RadFinal, j) +=\r
766                                 VectorToSUB(Patch->RadReceive, j) / Patch->Area;\r
767 \r
768                         VectorToSUB(Patch->RadSend, j) = \r
769                                 VectorToSUB(Patch->RadReceive, j) * VectorToSUB(Patch->Reflectivity, j);\r
770                         \r
771                         Total += VectorToSUB(Patch->RadSend, j);\r
772                 }\r
773 \r
774                 geVec3d_Clear(&Patch->RadReceive);\r
775         }\r
776 \r
777         return Total;\r
778 }\r
779 \r
780 \r
781 //====================================================================================\r
782 //      SendPatch\r
783 //====================================================================================\r
784 void SendPatch(RAD_Patch *Patch)\r
785 {\r
786         geVec3d                 Send;\r
787         RAD_Patch               *RPatch;\r
788         int32                   k;\r
789         RAD_Receiver    *Receiver;\r
790 \r
791         for (k=0; k<3; k++)\r
792                 VectorToSUB(Send, k) = VectorToSUB(Patch->RadSend, k) / (geFloat)0x10000;\r
793                 //VectorToSUB(Send, k) = VectorToSUB(Patch->RadSend, k);\r
794 \r
795         // Send light out to each pre-computed receiver\r
796         Receiver = Patch->Receivers;\r
797         for (k=0; k< Patch->NumReceivers; k++, Receiver++)\r
798         {\r
799                 RPatch = PatchList[Receiver->Patch];\r
800 \r
801                 geVec3d_AddScaled(&RPatch->RadReceive, &Send, (geFloat)Receiver->Amount, &RPatch->RadReceive);\r
802                 //geVec3d_AddScaled(&RPatch->RadReceive, &Send, .0005f, &RPatch->RadReceive);\r
803         }\r
804 }\r
805 \r
806 //====================================================================================\r
807 //      BouncePatches\r
808 //====================================================================================\r
809 geBoolean BouncePatches(void)\r
810 {\r
811         int32           i, j;\r
812         RAD_Patch       *Patch;\r
813         geFloat         Total;\r
814 \r
815         GHook.Printf("--- Bounce Patches --- \n");\r
816         \r
817         for (i=0 ; i< NumPatches; i++)\r
818         {\r
819                 // Set each patches first pass send amount with what was obtained\r
820                 // from their lightmaps... \r
821                 Patch = PatchList[i];\r
822                 for (j=0 ; j<3 ; j++)\r
823                 {\r
824                         VectorToSUB(Patch->RadSend, j) = VectorToSUB(Patch->RadStart, j) *\r
825                                 VectorToSUB(Patch->Reflectivity, j) * Patch->Area;\r
826                 }\r
827 \r
828                 //geVec3d_Clear(&Patch->RadFinal);\r
829         }\r
830 \r
831         for (i=0 ; i<NumBounce ; i++)\r
832         {\r
833                 if (LVerbose)\r
834                         GHook.Printf("Bounce: %3i, ", i+1);\r
835                 \r
836                 if (CancelRequest)\r
837                 {\r
838                         GHook.Printf("Cancel requested...\n");\r
839                         return GE_FALSE;\r
840                 }\r
841 \r
842                 // For each patch, send it's energy to each pre-computed receiver\r
843                 for (j=0 ; j< NumPatches; j++)\r
844                 {\r
845                         Patch = PatchList[j];\r
846                         SendPatch(Patch);\r
847                 }\r
848 \r
849                 // For each patch, collect any light it might have received\r
850                 // and throw into patch RadFinal\r
851                 Total = CollectPatchLight();\r
852 \r
853                 if (LVerbose)\r
854                         GHook.Printf("Energy: %2.2f\n", Total);\r
855         }\r
856         \r
857         for (j=0 ; j< NumPatches; j++)\r
858         {\r
859                 Patch = PatchList[j];\r
860                 if (!CheckPatch(Patch))\r
861                         return GE_FALSE;\r
862         }\r
863 \r
864         return GE_TRUE;\r
865 }\r
866 \r
867 typedef struct _PlaneFace\r
868 {\r
869         _PlaneFace      *Next;\r
870         int32           GFXFace;\r
871 } PlaneFace, *pPlaneFace;\r
872 \r
873 pPlaneFace *PlaneFaces;\r
874 \r
875 //====================================================================================\r
876 //      LinkPlaneFaces\r
877 //====================================================================================\r
878 void LinkPlaneFaces(void)\r
879 {\r
880         PlaneFace       *PFace;\r
881         int32           i, PlaneNum;\r
882 \r
883         PlaneFaces = GE_RAM_ALLOCATE_ARRAY(pPlaneFace,NumGFXPlanes);\r
884 \r
885         for (i=0; i< NumGFXPlanes; i++)\r
886                 PlaneFaces[i] = NULL;\r
887                 \r
888         for (i=0; i< NumGFXFaces; i++)\r
889         {\r
890                 PFace = GE_RAM_ALLOCATE_STRUCT(PlaneFace);\r
891                 memset(PFace, 0, sizeof(PlaneFace));\r
892 \r
893                 PlaneNum = GFXFaces[i].PlaneNum;\r
894                 PFace->GFXFace = i;\r
895                 PFace->Next = PlaneFaces[PlaneNum];\r
896                 PlaneFaces[PlaneNum] = PFace;\r
897         }\r
898 }\r
899 \r
900 //====================================================================================\r
901 //      FreePlaneFaces\r
902 //====================================================================================\r
903 void FreePlaneFaces(void)\r
904 {\r
905         int32           i;\r
906         PlaneFace       *PFace, *Next;\r
907 \r
908         for (i=0; i< NumGFXPlanes; i++)\r
909         {\r
910                 for (PFace = PlaneFaces[i]; PFace; PFace = Next)\r
911                 {\r
912                         Next = PFace->Next;\r
913                         geRam_Free(PFace);\r
914                 }\r
915         }\r
916 \r
917         geRam_Free(PlaneFaces);\r
918 }\r
919 \r
920 //====================================================================================\r
921 //      GetFaceMinsMaxs\r
922 //====================================================================================\r
923 void GetFaceMinsMaxs(int32 Face, geVec3d *Mins, geVec3d *Maxs)\r
924 {\r
925         int32   i, k, Index;\r
926         geFloat t;\r
927 \r
928         ClearBounds(Mins, Maxs);\r
929 \r
930         for (i=0; i< GFXFaces[Face].NumVerts; i++)\r
931         {\r
932                 Index = GFXVertIndexList[GFXFaces[Face].FirstVert+i];\r
933                 for (k=0; k<3; k++)\r
934                 {\r
935                         t = VectorToSUB(GFXVerts[Index], k);\r
936 \r
937                         if (t < VectorToSUB(*Mins, k))\r
938                                 VectorToSUB(*Mins, k) = t;\r
939                         if (t > VectorToSUB(*Maxs, k))\r
940                                 VectorToSUB(*Maxs, k) = t;\r
941                 }\r
942         }\r
943 }\r
944 \r
945 //====================================================================================\r
946 // MakeCornerPatches\r
947 //====================================================================================\r
948 RAD_Patch *MakeCornerPatches(int32 Face, Tri_Patch *Tri)\r
949 {\r
950         RAD_Patch       *PatchList, *NewPatch;\r
951         int32           i, Width, Height, u, v;\r
952         geFloat         StartU, StartV, CurU, CurV, EndU, EndV;\r
953         FInfo           *Fi;\r
954         LInfo           *Li;\r
955 \r
956         PatchList = NULL;\r
957 \r
958         Fi = &FaceInfo[Face];\r
959         Li = &Lightmaps[Face];\r
960 \r
961         Width = Li->LSize[0]+1;\r
962         Height = Li->LSize[1]+1;\r
963         StartU = ((geFloat)Li->LMins[0]) * (geFloat)LGRID_SIZE;\r
964         StartV = ((geFloat)Li->LMins[1]) * (geFloat)LGRID_SIZE;\r
965 \r
966         EndU = ((geFloat)Li->LMaxs[0]) * (geFloat)LGRID_SIZE;\r
967         EndV = ((geFloat)Li->LMaxs[1]) * (geFloat)LGRID_SIZE;\r
968 \r
969         for (v=0; v < 2; v++)\r
970         {\r
971                 for (u=0; u < 2; u++)\r
972                 {\r
973                         if (u == 0)\r
974                                 CurU = StartU;\r
975                         else\r
976                                 CurU = EndU;\r
977                         \r
978                         if (v == 0)\r
979                                 CurV = StartV;\r
980                         else\r
981                                 CurV = EndV;\r
982 \r
983                         NewPatch = AllocPatch();\r
984                         if (!NewPatch)\r
985                         {\r
986                                 GHook.Error("CreateCornerPatches:  Could not create patch.\n");\r
987                                 return NULL;\r
988                         }\r
989 \r
990                         for (i=0; i< 3; i++)\r
991                                 VectorToSUB(NewPatch->Origin, i) = VectorToSUB(Fi->TexOrg,i) + \r
992                                         VectorToSUB(Fi->T2WVecs[0], i) * CurU + \r
993                                         VectorToSUB(Fi->T2WVecs[1], i) * CurV;\r
994                         \r
995                         if (!FindClosestTriPoint(&NewPatch->Origin, Tri, &NewPatch->RadFinal))\r
996                         {\r
997                                 GHook.Error("MakeCornerPatches:  Could not find patch for Color.\n");\r
998                                 return GE_FALSE;\r
999                         }\r
1000                         \r
1001                         //NewPatch->RadFinal.X = 0.0f;\r
1002                         //NewPatch->RadFinal.Y = 255.0f;\r
1003                         //NewPatch->RadFinal.Z = 0.0f;\r
1004                         // Insert it into the beginning of the list\r
1005                         NewPatch->Next = PatchList;\r
1006                         PatchList = NewPatch;\r
1007                 }\r
1008         }\r
1009         return PatchList;\r
1010 }\r
1011 \r
1012 //====================================================================================\r
1013 // FreePatchList\r
1014 //====================================================================================\r
1015 void FreePatchList(RAD_Patch *Patches)\r
1016 {\r
1017         RAD_Patch       *Patch, *Next;\r
1018 \r
1019         for (Patch = Patches; Patch; Patch = Next)\r
1020         {\r
1021                 Next = Patch->Next;\r
1022                 FreePatch(Patch);\r
1023         }\r
1024 }\r
1025 \r
1026 //====================================================================================\r
1027 //      AbsorbPatches\r
1028 //====================================================================================\r
1029 geBoolean AbsorbPatches(void)\r
1030 {\r
1031         Tri_Patch               *Tri;\r
1032         GBSP_Plane              Plane;\r
1033         geVec3d                 Add, *pPoint, *pRGB;\r
1034         int32                   i, k, PNum, FNum, PSide;\r
1035         RAD_Patch               *Patch, *OPatch, *TempPatches;\r
1036         PlaneFace               *PFace;\r
1037         geVec3d                 FMins, FMaxs;\r
1038 \r
1039         LinkPlaneFaces();       // We need all the faces that belong to each Plane\r
1040 \r
1041         for (i=0; i< NumGFXFaces; i++)\r
1042         {\r
1043                 int32           Flags;\r
1044                 GFX_Face        *pGFXFace;\r
1045 \r
1046                 pGFXFace = &GFXFaces[i];\r
1047 \r
1048                 if (CancelRequest)\r
1049                 {\r
1050                         GHook.Printf("Cancel requested...\n");\r
1051                         return GE_FALSE;\r
1052                 }\r
1053 \r
1054                 pPoint = FaceInfo[i].Points;\r
1055                 pRGB = Lightmaps[i].RGBLData[0];\r
1056 \r
1057                 Flags = GFXTexInfo[GFXFaces[i].TexInfo].Flags;\r
1058 \r
1059                 if ((Flags & TEXINFO_NO_LIGHTMAP) && !(Flags & TEXINFO_GOURAUD))\r
1060                         continue;\r
1061 \r
1062                 //if (!pRGB)\r
1063                 //      continue;\r
1064 \r
1065                 Plane.Normal.X = (geFloat)GFXPlanes[GFXFaces[i].PlaneNum].Normal.X;\r
1066                 Plane.Normal.Y = (geFloat)GFXPlanes[GFXFaces[i].PlaneNum].Normal.Y;\r
1067                 Plane.Normal.Z = (geFloat)GFXPlanes[GFXFaces[i].PlaneNum].Normal.Z;\r
1068                 Plane.Dist = (geFloat)GFXPlanes[GFXFaces[i].PlaneNum].Dist;\r
1069                 Plane.Type = PLANE_ANY;\r
1070                 /*\r
1071                 if(GFXFaces[i].PlaneSide)\r
1072                 {\r
1073                         geVec3d_Inverse(&Plane.Normal);\r
1074                         Plane.Dist = -Plane.Dist;\r
1075                 }\r
1076                 */\r
1077 \r
1078                 Tri = Tri_PatchCreate(&Plane);\r
1079                 if (!Tri)\r
1080                 {\r
1081                         GHook.Error("AbsorbPatches:  Tri_PatchCreate failed.\n");\r
1082                         return GE_FALSE;\r
1083                 }\r
1084                 \r
1085                 PNum = GFXFaces[i].PlaneNum;\r
1086                 PSide = GFXFaces[i].PlaneSide;\r
1087                 \r
1088                 OPatch = FacePatches[i];\r
1089 \r
1090                 GetFaceMinsMaxs(i, &FMins, &FMaxs);\r
1091                 \r
1092                 for (PFace = PlaneFaces[PNum]; PFace; PFace = PFace->Next)\r
1093                 {\r
1094                         FNum = PFace->GFXFace;\r
1095 \r
1096                         if (GFXFaces[FNum].PlaneSide != PSide)\r
1097                                 continue;\r
1098 \r
1099                         for (Patch = FacePatches[FNum]; Patch; Patch = Patch->Next)\r
1100                         {\r
1101                                 for (k=0 ; k < 3 ; k++)\r
1102                                 {\r
1103                                         if (VectorToSUB(Patch->Origin, k) < VectorToSUB(FMins,k) - (PatchSize*2))\r
1104                                                 break;\r
1105 \r
1106                                         if (VectorToSUB(Patch->Origin, k) > VectorToSUB(FMaxs,k) + (PatchSize*2))\r
1107                                                 break;\r
1108                                 }\r
1109                                 if (k != 3)\r
1110                                         continue;\r
1111                                 \r
1112                                 // Don't include patches that might cross through walls or floors, or\r
1113                                 // it will cause false light bleeds from patch to patch\r
1114                                 //if (OPatch != Patch)\r
1115                                 //if (RayCollision(&OPatch->Origin, &Patch->Origin, NULL))\r
1116                                 //      continue;\r
1117                                 \r
1118                                 if (!AddPointToTriangulation (Patch, Tri))\r
1119                                 {\r
1120                                         GHook.Error("AbsorbPatches:  Could not add patch to triangulation.\n");\r
1121                                         return GE_FALSE;\r
1122                                 }\r
1123                                 \r
1124                         }\r
1125                 }\r
1126                 /*\r
1127                 TempPatches = NULL;\r
1128                 \r
1129                 TempPatches = MakeCornerPatches(i, Tri);\r
1130                 if (!TempPatches)\r
1131                 {\r
1132                         GHook.Error("AbsorbPatches:  Could not create corner temp patches.\n");\r
1133                         return GE_FALSE;\r
1134                 }\r
1135 \r
1136                 for (Patch = TempPatches; Patch; Patch = Patch->Next)\r
1137                 {\r
1138                         if (!AddPointToTriangulation (Patch, Tri))\r
1139                         {\r
1140                                 GHook.Error("AbsorbPatches:  Could not add temp patch to triangulation.\n");\r
1141                                 return GE_FALSE;\r
1142                         }\r
1143                 }\r
1144                 */\r
1145                 if (!TriangulatePoints (Tri))\r
1146                 {\r
1147                         GHook.Error("AbsorbPatches:  Could not triangulate patches.\n");\r
1148                         return GE_FALSE;\r
1149                 }\r
1150                 \r
1151                 if (Flags & TEXINFO_GOURAUD)\r
1152                 {\r
1153                         for (k=0; k< pGFXFace->NumVerts; k++)\r
1154                         {\r
1155                                 int32           vn;\r
1156 \r
1157                                 vn = pGFXFace->FirstVert+k;\r
1158 \r
1159                                 pPoint = &GFXVerts[GFXVertIndexList[vn]];\r
1160 \r
1161                                 SampleTriangulation (pPoint, Tri, &Add);\r
1162 \r
1163                                 geVec3d_Add(&GFXRGBVerts[vn], &Add, &GFXRGBVerts[vn]);\r
1164                         }\r
1165                 }\r
1166                 else\r
1167                 {\r
1168 \r
1169                         geBoolean Created = (pRGB != NULL);\r
1170                 \r
1171                         for (k=0; k< FaceInfo[i].NumPoints; k++, pRGB++, pPoint++)\r
1172                         {\r
1173                                 if (!SampleTriangulation (pPoint, Tri, &Add))\r
1174                                 {\r
1175                                         GHook.Error("AbsorbPatches:  Could not sample from patch triangles.\n");\r
1176                                         continue;\r
1177                                 }\r
1178 \r
1179                                 if (!Created)\r
1180                                 {\r
1181                                         if (Add.X > 0 || Add.Y > 0 || Add.Z > 0)\r
1182                                         {\r
1183                                                 if (Lightmaps[i].NumLTypes > MAX_LTYPES)\r
1184                                                 {\r
1185                                                         GHook.Error("AbsorbPatches:  Too many Light Types on Face.\n");\r
1186                                                         return GE_FALSE;\r
1187                                                 }\r
1188 \r
1189                                                 Lightmaps[i].RGBLData[0] = GE_RAM_ALLOCATE_ARRAY(geVec3d,FaceInfo[i].NumPoints);\r
1190                                                 if (!Lightmaps[i].RGBLData[0])\r
1191                                                 {\r
1192                                                         GHook.Error("AbsorbPAtches:  Out of memory for lightmap.\n");\r
1193                                                         return GE_FALSE;\r
1194                                                 }\r
1195                                                 Lightmaps[i].NumLTypes++;\r
1196                                                 pRGB = Lightmaps[i].RGBLData[0];\r
1197                                                 memset(pRGB, 0, FaceInfo[i].NumPoints*sizeof(geVec3d));\r
1198                                                 pRGB = &pRGB[k];\r
1199                                                 Created = GE_TRUE;\r
1200                                         }\r
1201                                 }\r
1202                                 if (Created)\r
1203                                         geVec3d_Add(pRGB, &Add, pRGB);\r
1204 \r
1205                         }\r
1206                 }\r
1207 \r
1208                 Tri_PatchDestroy(Tri);\r
1209                 //FreePatchList(TempPatches);\r
1210                 TempPatches = NULL;\r
1211         }\r
1212 \r
1213         FreePlaneFaces();\r
1214 \r
1215         return GE_TRUE;\r
1216 }\r
1217 \r
1218 //====================================================================================\r
1219 //      Tri_PatchCreate\r
1220 //====================================================================================\r
1221 Tri_Patch *Tri_PatchCreate(GBSP_Plane *Plane)\r
1222 {\r
1223         Tri_Patch       *Patch;\r
1224 \r
1225         Patch = GE_RAM_ALLOCATE_STRUCT(Tri_Patch);\r
1226         if (!Patch)\r
1227         {\r
1228                 GHook.Error("Tri_PatchCreate: Out of memory.\n");\r
1229                 return NULL;\r
1230         }\r
1231 \r
1232         Patch->NumPoints = 0;\r
1233         Patch->NumEdges = 0;\r
1234         Patch->NumTris = 0;\r
1235 \r
1236         Patch->Plane = Plane;\r
1237 \r
1238         return Patch;\r
1239 }\r
1240 \r
1241 //====================================================================================\r
1242 //      Tri_PatchDestroy\r
1243 //====================================================================================\r
1244 void Tri_PatchDestroy(Tri_Patch *tr)\r
1245 {\r
1246         geRam_Free(tr);\r
1247 }\r
1248 \r
1249 \r
1250 //====================================================================================\r
1251 //      FindEdge\r
1252 //====================================================================================\r
1253 Tri_Edge *FindEdge(Tri_Patch *TriPatch, int p0, int p1)\r
1254 {\r
1255         Tri_Edge        *e, *be;\r
1256         geVec3d         v1;\r
1257         geVec3d         normal;\r
1258         geFloat         dist;\r
1259 \r
1260         if (TriPatch->EdgeMatrix[p0][p1])\r
1261                 return TriPatch->EdgeMatrix[p0][p1];\r
1262 \r
1263         if (TriPatch->NumEdges > MAX_TRI_EDGES-2)\r
1264         {\r
1265                 GHook.Error ("TriPatch->NumEdges > MAX_TRI_EDGES-2");\r
1266                 return NULL;\r
1267         }\r
1268 \r
1269         geVec3d_Subtract (&TriPatch->Points[p1]->Origin, &TriPatch->Points[p0]->Origin, &v1);\r
1270         geVec3d_Normalize (&v1);\r
1271         geVec3d_CrossProduct (&v1, &TriPatch->Plane->Normal, &normal);\r
1272         dist = geVec3d_DotProduct (&TriPatch->Points[p0]->Origin, &normal);\r
1273 \r
1274         e = &TriPatch->Edges[TriPatch->NumEdges];\r
1275         e->p0 = p0;\r
1276         e->p1 = p1;\r
1277         e->tri = NULL;\r
1278         geVec3d_Copy(&normal, &e->normal);\r
1279         e->dist = dist;\r
1280         TriPatch->NumEdges++;\r
1281         TriPatch->EdgeMatrix[p0][p1] = e;\r
1282 \r
1283         // Go ahead and make the reverse edge ahead of time\r
1284         be = &TriPatch->Edges[TriPatch->NumEdges];\r
1285         be->p0 = p1;\r
1286         be->p1 = p0;\r
1287         be->tri = NULL;\r
1288         geVec3d_Copy(&normal, &be->normal);\r
1289         geVec3d_Inverse(&be->normal);\r
1290         be->dist = -dist;\r
1291         TriPatch->NumEdges++;\r
1292         TriPatch->EdgeMatrix[p1][p0] = be;\r
1293 \r
1294         return e;\r
1295 }\r
1296 \r
1297 //====================================================================================\r
1298 //      AllocTriangle\r
1299 //====================================================================================\r
1300 Tri     *AllocTriangle(Tri_Patch *TriPatch)\r
1301 {\r
1302         Tri     *t;\r
1303 \r
1304         if (TriPatch->NumTris >= MAX_TRI_TRIS)\r
1305         {\r
1306                 GHook.Error ("TriPatch->NumTris >= MAX_TRI_TRIS");\r
1307                 return NULL;\r
1308         }\r
1309 \r
1310         t = &TriPatch->TriList[TriPatch->NumTris];\r
1311         TriPatch->NumTris++;\r
1312 \r
1313         return t;\r
1314 }\r
1315 \r
1316 //====================================================================================\r
1317 //      Tri_Edge_r\r
1318 //====================================================================================\r
1319 geBoolean Tri_Edge_r (Tri_Patch *TriPatch, Tri_Edge *e)\r
1320 {\r
1321         int                     i, bestp;\r
1322         geVec3d         v1, v2;\r
1323         geVec3d         *p0, *p1, *p;\r
1324         geFloat         best, ang;\r
1325         Tri                     *nt;\r
1326         Tri_Edge        *e2;\r
1327 \r
1328         if (e->tri)\r
1329                 return GE_TRUE;         \r
1330 \r
1331         p0 = &TriPatch->Points[e->p0]->Origin;\r
1332         p1 = &TriPatch->Points[e->p1]->Origin;\r
1333         best = 1.1f;\r
1334         for (i=0 ; i< TriPatch->NumPoints ; i++)\r
1335         {\r
1336                 p = &TriPatch->Points[i]->Origin;\r
1337 \r
1338                 if (geVec3d_DotProduct(p, &e->normal) - e->dist < 0)\r
1339                         continue;       \r
1340                 \r
1341                 geVec3d_Subtract(p0, p, &v1);\r
1342                 geVec3d_Subtract(p1, p, &v2);\r
1343                 \r
1344                 if (!geVec3d_Normalize(&v1))\r
1345                         continue;\r
1346                 if (!geVec3d_Normalize(&v2))\r
1347                         continue;\r
1348 \r
1349                 ang = geVec3d_DotProduct (&v1, &v2);\r
1350                 if (ang < best)\r
1351                 {\r
1352                         best = ang;\r
1353                         bestp = i;\r
1354                 }\r
1355         }\r
1356         if (best >= 1)\r
1357                 return GE_TRUE;         \r
1358         \r
1359         nt = AllocTriangle (TriPatch);\r
1360         if (!nt)\r
1361         {\r
1362                 GHook.Error("Tri_Edge_r:  Could not allocate triangle.\n");\r
1363                 return GE_FALSE;\r
1364         }\r
1365         nt->Edges[0] = e;\r
1366         if (!nt->Edges[0])\r
1367         {\r
1368                 GHook.Error("Tri_Edge_r:  There was an error finding an edge.\n");\r
1369                 return GE_FALSE;\r
1370         }\r
1371         nt->Edges[1] = FindEdge (TriPatch, e->p1, bestp);\r
1372         if (!nt->Edges[1])\r
1373         {\r
1374                 GHook.Error("Tri_Edge_r:  There was an error finding an edge.\n");\r
1375                 return GE_FALSE;\r
1376         }\r
1377         nt->Edges[2] = FindEdge (TriPatch, bestp, e->p0);\r
1378         if (!nt->Edges[2])\r
1379         {\r
1380                 GHook.Error("Tri_Edge_r:  There was an error finding an edge.\n");\r
1381                 return GE_FALSE;\r
1382         }\r
1383         for (i=0 ; i<3 ; i++)\r
1384                 nt->Edges[i]->tri = nt;\r
1385 \r
1386         e2 = FindEdge (TriPatch, bestp, e->p1);\r
1387         if (!e2)\r
1388         {\r
1389                 GHook.Error("Tri_Edge_r:  There was an error finding an edge.\n");\r
1390                 return GE_FALSE;\r
1391         }\r
1392         if (!Tri_Edge_r (TriPatch, e2))\r
1393                 return GE_FALSE;\r
1394         \r
1395         e2 = FindEdge (TriPatch, e->p0, bestp);\r
1396         if (!e2)\r
1397         {\r
1398                 GHook.Error("Tri_Edge_r:  There was an error finding an edge.\n");\r
1399                 return GE_FALSE;\r
1400         }\r
1401         if (!Tri_Edge_r (TriPatch, e2))\r
1402                 return GE_FALSE;\r
1403 \r
1404         return GE_TRUE;\r
1405 }\r
1406 \r
1407 //====================================================================================\r
1408 //      TriangulatePoints\r
1409 //====================================================================================\r
1410 geBoolean TriangulatePoints(Tri_Patch *TriPatch)\r
1411 {\r
1412         geFloat         d, bestd;\r
1413         geVec3d         v1;\r
1414         int                     bp1, bp2, i, j;\r
1415         geVec3d         *p1, *p2;\r
1416         Tri_Edge        *e, *e2;\r
1417 \r
1418         for (i=0; i<TriPatch->NumPoints; i++)\r
1419                 memset(TriPatch->EdgeMatrix[i], 0, TriPatch->NumPoints*sizeof(TriPatch->EdgeMatrix[0][0]) );\r
1420 \r
1421         if (TriPatch->NumPoints < 2)\r
1422                 return GE_TRUE;\r
1423 \r
1424         // Find the two closest Points\r
1425         bestd = MIN_MAX_BOUNDS2;\r
1426         for (i=0 ; i<TriPatch->NumPoints ; i++)\r
1427         {\r
1428                 p1 = &TriPatch->Points[i]->Origin;\r
1429                 for (j=i+1 ; j<TriPatch->NumPoints ; j++)\r
1430                 {\r
1431                         p2 = &TriPatch->Points[j]->Origin;\r
1432                         geVec3d_Subtract(p2, p1, &v1);\r
1433                         d = geVec3d_Length(&v1);\r
1434                         if (d < bestd && d > .05f)\r
1435                         {\r
1436                                 bestd = d;\r
1437                                 bp1 = i;\r
1438                                 bp2 = j;\r
1439                         }\r
1440                 }\r
1441         }\r
1442 \r
1443         e = FindEdge (TriPatch, bp1, bp2);\r
1444         if (!e)\r
1445         {\r
1446                 GHook.Error("There was an error finding an edge.\n");\r
1447                 return GE_FALSE;\r
1448         }\r
1449         e2 = FindEdge (TriPatch, bp2, bp1);\r
1450         if (!e2)\r
1451         {\r
1452                 GHook.Error("There was an error finding an edge.\n");\r
1453                 return GE_FALSE;\r
1454         }\r
1455         if (!Tri_Edge_r (TriPatch, e))\r
1456                 return GE_FALSE;\r
1457         if (!Tri_Edge_r (TriPatch, e2))\r
1458                 return GE_FALSE;\r
1459 \r
1460         return GE_TRUE;\r
1461 }\r
1462 \r
1463 //====================================================================================\r
1464 //      AddPointToTriangulation\r
1465 //====================================================================================\r
1466 geBoolean AddPointToTriangulation(RAD_Patch *patch, Tri_Patch *TriPatch)\r
1467 {\r
1468         int                     pnum;\r
1469 \r
1470         pnum = TriPatch->NumPoints;\r
1471         if (pnum == MAX_TRI_POINTS)\r
1472         {\r
1473                 GHook.Error ("TriPatch->NumPoints == MAX_TRI_POINTS");\r
1474                 return GE_FALSE;\r
1475         }\r
1476         TriPatch->Points[pnum] = patch;\r
1477         TriPatch->NumPoints++;\r
1478 \r
1479         return GE_TRUE;\r
1480 }\r
1481 \r
1482 //====================================================================================\r
1483 //      LerpTriangle\r
1484 //====================================================================================\r
1485 void LerpTriangle(Tri_Patch *TriPatch, Tri *t, geVec3d *Point, geVec3d *Color)\r
1486 {\r
1487         RAD_Patch       *p1, *p2, *p3;\r
1488         geVec3d         base, d1, d2;\r
1489         geFloat         x, y, x1, y1, x2, y2;\r
1490 \r
1491         p1 = TriPatch->Points[t->Edges[0]->p0];\r
1492         p2 = TriPatch->Points[t->Edges[1]->p0];\r
1493         p3 = TriPatch->Points[t->Edges[2]->p0];\r
1494 \r
1495         geVec3d_Copy(&p1->RadFinal, &base);\r
1496         geVec3d_Subtract(&p2->RadFinal, &base, &d1);\r
1497         geVec3d_Subtract(&p3->RadFinal, &base, &d2);\r
1498 \r
1499         x = geVec3d_DotProduct(Point, &t->Edges[0]->normal) - t->Edges[0]->dist;\r
1500         y = geVec3d_DotProduct(Point, &t->Edges[2]->normal) - t->Edges[2]->dist;\r
1501 \r
1502         x1 = 0.0f;\r
1503         y1 = geVec3d_DotProduct(&p2->Origin, &t->Edges[2]->normal) - t->Edges[2]->dist;\r
1504 \r
1505         x2 = geVec3d_DotProduct(&p3->Origin, &t->Edges[0]->normal) - t->Edges[0]->dist;\r
1506         y2 = 0.0f;\r
1507 \r
1508         if (fabs(y1)<ON_EPSILON || fabs(x2)<ON_EPSILON)\r
1509         {\r
1510                 geVec3d_Copy(&base, Color);\r
1511                 return;\r
1512         }\r
1513 \r
1514         geVec3d_AddScaled(&base, &d2, x/x2, Color);\r
1515         geVec3d_AddScaled(Color, &d1, y/y1, Color);\r
1516 }\r
1517 \r
1518 //====================================================================================\r
1519 //      Tri_PointInside\r
1520 //====================================================================================\r
1521 geBoolean Tri_PointInside(Tri *Tri, geVec3d *Point)\r
1522 {\r
1523         int                     i;\r
1524 \r
1525         for (i=0 ; i<3 ; i++)\r
1526         {\r
1527                 geFloat         Dist;\r
1528                 Tri_Edge        *pEdge;\r
1529 \r
1530                 pEdge = Tri->Edges[i];\r
1531 \r
1532                 Dist = geVec3d_DotProduct(&pEdge->normal, Point) - pEdge->dist;\r
1533 \r
1534                 if (Dist < 0.0f)\r
1535                         return GE_FALSE;        \r
1536         }\r
1537 \r
1538         return GE_TRUE;\r
1539 }\r
1540 \r
1541 //====================================================================================\r
1542 //      SampleTriangulation\r
1543 //====================================================================================\r
1544 geBoolean SampleTriangulation(geVec3d *Point, Tri_Patch *TriPatch, geVec3d *Color)\r
1545 {\r
1546         Tri                     *t;\r
1547         Tri_Edge        *e;\r
1548         geFloat         d;\r
1549         RAD_Patch       *p0, *p1;\r
1550         geVec3d         v1, v2;\r
1551         int                     i, j;\r
1552 \r
1553         if (TriPatch->NumPoints == 0)\r
1554         {\r
1555                 geVec3d_Clear(Color);\r
1556                 return GE_TRUE;\r
1557         }\r
1558         if (TriPatch->NumPoints == 1)\r
1559         {\r
1560                 geVec3d_Copy(&TriPatch->Points[0]->RadFinal, Color);\r
1561                 return GE_TRUE;\r
1562         }\r
1563         \r
1564         // See of the Point is inside a tri in the patch\r
1565         for (t = TriPatch->TriList, j=0 ; j < TriPatch->NumTris ; t++, j++)\r
1566         {\r
1567                 if (!Tri_PointInside (t, Point))\r
1568                         continue;\r
1569 \r
1570                 LerpTriangle (TriPatch, t, Point, Color);\r
1571 \r
1572                 return GE_TRUE;\r
1573         }\r
1574         \r
1575         for (e=TriPatch->Edges, j=0 ; j< TriPatch->NumEdges ; e++, j++)\r
1576         {\r
1577                 if (e->tri)\r
1578                         continue;               // not an exterior edge\r
1579 \r
1580                 d = geVec3d_DotProduct(Point, &e->normal) - e->dist;\r
1581                 if (d < 0)\r
1582                         continue;       // not in front of edge\r
1583 \r
1584                 p0 = TriPatch->Points[e->p0];\r
1585                 p1 = TriPatch->Points[e->p1];\r
1586         \r
1587                 geVec3d_Subtract(&p1->Origin, &p0->Origin, &v1);\r
1588                 geVec3d_Normalize (&v1);\r
1589                 \r
1590                 geVec3d_Subtract(Point, &p0->Origin, &v2);\r
1591                 d = geVec3d_DotProduct(&v2, &v1);\r
1592 \r
1593                 if (d < 0)\r
1594                         continue;\r
1595                 if (d > 1)\r
1596                         continue;\r
1597                 \r
1598                 for (i=0 ; i<3 ; i++)\r
1599                         VectorToSUB(*Color,i) = VectorToSUB(p0->RadFinal,i) + d * (VectorToSUB(p1->RadFinal,i) - VectorToSUB(p0->RadFinal,i));\r
1600                 return GE_TRUE;\r
1601         }\r
1602         \r
1603         if (!FindClosestTriPoint(Point, TriPatch, Color))\r
1604         {\r
1605                 GHook.Error("SampleTriangulation:  Could not find closest Color.\n");\r
1606                 return GE_FALSE;\r
1607         }\r
1608 \r
1609         return GE_TRUE;\r
1610 }\r
1611 \r
1612 //========================================================================================\r
1613 //      FindClosestTriPoint\r
1614 //========================================================================================\r
1615 geBoolean FindClosestTriPoint(geVec3d *Point, Tri_Patch *Tri, geVec3d *Color)\r
1616 {\r
1617         int32           i;\r
1618         RAD_Patch       *p0, *BestPatch;\r
1619         geFloat         BestDist, d;\r
1620         geVec3d         v1;\r
1621 \r
1622         // Search for nearest Point\r
1623         BestDist = MIN_MAX_BOUNDS2;\r
1624         BestPatch = NULL;\r
1625 \r
1626         for (i=0 ; i<Tri->NumPoints ; i++)\r
1627         {\r
1628                 p0 = Tri->Points[i];\r
1629                 geVec3d_Subtract(Point, &p0->Origin, &v1);\r
1630                 d = geVec3d_Length(&v1);\r
1631                 if (d < BestDist)\r
1632                 {\r
1633                         BestDist = d;\r
1634                         BestPatch = p0;\r
1635                 }\r
1636         }\r
1637 \r
1638         if (!BestPatch)\r
1639         {\r
1640                 GHook.Error ("FindClosestTriPoint: No Points.\n");\r
1641                 return GE_FALSE;\r
1642         }\r
1643 \r
1644         geVec3d_Copy(&BestPatch->RadFinal, Color);\r
1645 \r
1646         return GE_TRUE;\r
1647 }\r
1648 \r
1649 //========================================================================================\r
1650 //      CalcPatchReflectivity\r
1651 //========================================================================================\r
1652 void CalcPatchReflectivity(int32 Face, RAD_Patch *Patch)\r
1653 {\r
1654         GFX_Texture             *pTexture;\r
1655         geVec3d                 Color;\r
1656         int32                           i, Size;\r
1657         uint8                   *pGFXTexData;\r
1658         DRV_Palette             *Palette;\r
1659         GFX_TexInfo             *pTexInfo;\r
1660         geFloat                 Scale;\r
1661         \r
1662         pTexInfo = &GFXTexInfo[GFXFaces[Face].TexInfo];\r
1663         pTexture = &GFXTextures[pTexInfo->Texture];\r
1664 \r
1665         geVec3d_Clear(&Color);\r
1666         \r
1667         pGFXTexData = &GFXTexData[pTexture->Offset];\r
1668         Size = pTexture->Width*pTexture->Height;\r
1669 \r
1670         Palette = &GFXPalettes[pTexture->PaletteIndex];\r
1671 \r
1672         for (i=0; i< Size; i++, pGFXTexData++)\r
1673         {\r
1674                 DRV_RGB *       RGB;\r
1675 \r
1676                 RGB = &(*Palette)[*pGFXTexData];\r
1677                 Color.X += (geFloat)RGB->r;\r
1678                 Color.Y += (geFloat)RGB->g;\r
1679                 Color.Z += (geFloat)RGB->b;\r
1680         }\r
1681 \r
1682         geVec3d_Scale(&Color, 1.0f/(geFloat)Size, &Color);\r
1683         geVec3d_Scale(&Color, 1.0f/255.0f, &Color);\r
1684 \r
1685         Scale = ColorNormalize(&Color, &Patch->Reflectivity);\r
1686         \r
1687         if (Scale < 0.5f)\r
1688         {\r
1689                 Scale *= 2;\r
1690                 geVec3d_Scale(&Patch->Reflectivity, Scale, &Patch->Reflectivity);\r
1691         }\r
1692 \r
1693         geVec3d_Scale(&Patch->Reflectivity, ReflectiveScale*pTexInfo->ReflectiveScale, &Patch->Reflectivity);\r
1694 }\r
1695 \r
1696 typedef struct\r
1697 {\r
1698         int32           Version;\r
1699         SYSTEMTIME      BSPTime;\r
1700         int32           NumPatches;\r
1701 } Rec_Header;\r
1702 \r
1703 Rec_Header      RecHeader;      \r
1704 \r
1705 //========================================================================================\r
1706 //      SaveReceiverFile\r
1707 //========================================================================================\r
1708 geBoolean SaveReceiverFile(char *FileName)\r
1709 {\r
1710         FILE            *f;\r
1711         int32           i;\r
1712 \r
1713         GHook.Printf("--- Save Receiver File --- \n");\r
1714 \r
1715         f = fopen(FileName, "wb");\r
1716 \r
1717         if (!f)\r
1718         {\r
1719                 GHook.Error("SaveReceiverFile:  Could not open receiver file for writing...\n");\r
1720                 return GE_FALSE;\r
1721         }\r
1722 \r
1723         RecHeader.Version = GBSPHeader.Version;\r
1724         RecHeader.BSPTime = GBSPHeader.BSPTime;\r
1725         RecHeader.NumPatches = NumPatches;\r
1726 \r
1727         // Save header\r
1728         if (fwrite(&RecHeader, sizeof(Rec_Header), 1, f) != 1)\r
1729         {\r
1730                 GHook.Printf("*WARNING* SaveReceiverFile:  Could not save header info...\n");\r
1731                 fclose(f);\r
1732                 return GE_TRUE;\r
1733         }\r
1734 \r
1735         // Patches\r
1736         for (i=0; i< NumPatches; i++)\r
1737         {\r
1738                 int32 NumReceivers = PatchList[i]->NumReceivers;\r
1739 \r
1740                 // Write out the number of receivers for this patch\r
1741                 if (fwrite(&NumReceivers, sizeof(int32), 1, f) != 1)\r
1742                 {\r
1743                         GHook.Printf("*WARNING* SaveReceiverFile:  Could not save num receivers...\n");\r
1744                         fclose(f);\r
1745                         return GE_TRUE;\r
1746                 }\r
1747                 \r
1748                 // Write out the actual receivers\r
1749                 if (fwrite(PatchList[i]->Receivers, sizeof(RAD_Receiver), NumReceivers, f) != (uint32)NumReceivers)\r
1750                 {\r
1751                         GHook.Printf("*WARNING* SaveReceiverFile:  Could not save receivers...\n");\r
1752                         fclose(f);\r
1753                         return GE_TRUE;\r
1754                 }\r
1755         }\r
1756 \r
1757         return GE_TRUE;\r
1758 }\r
1759 \r
1760 //========================================================================================\r
1761 //      LoadReceiverFile\r
1762 //========================================================================================\r
1763 geBoolean LoadReceiverFile(char *FileName)\r
1764 {\r
1765         FILE            *f;\r
1766         int32           i;\r
1767         uint8           *pTime1, *pTime2;\r
1768 \r
1769         f = fopen(FileName, "rb");\r
1770 \r
1771         if (!f)         \r
1772                 return GE_FALSE;\r
1773 \r
1774         // Load header\r
1775         if (fread(&RecHeader, sizeof(Rec_Header), 1, f) != 1)\r
1776         {\r
1777                 GHook.Error("LoadReceiverFile:  Could not load header info...\n");\r
1778                 fclose(f);\r
1779                 return GE_FALSE;\r
1780         }\r
1781 \r
1782         pTime1 = (uint8*)&(RecHeader.BSPTime);\r
1783         pTime2 = (uint8*)&(GBSPHeader.BSPTime);\r
1784 \r
1785         if (RecHeader.Version != GBSPHeader.Version)\r
1786         {\r
1787                 GHook.Printf("*WARNING*  LoadReceiverFile:  Versions do not match, skipping...\n");\r
1788                 fclose(f);\r
1789                 return GE_FALSE;\r
1790         }\r
1791         \r
1792         // Make sure internal time matches...\r
1793         for (i=0; i< sizeof(SYSTEMTIME); i++)\r
1794         {\r
1795                 if (*pTime1 != *pTime2)\r
1796                 {\r
1797                         fclose(f);\r
1798                         return GE_FALSE;\r
1799                 }\r
1800 \r
1801                 pTime1++;\r
1802                 pTime2++;\r
1803         }\r
1804 \r
1805         // Make sure the number of patches in the receiver file, matches the number loaded\r
1806         // for this BSP\r
1807         if (RecHeader.NumPatches != NumPatches)\r
1808         {\r
1809                 GHook.Printf("*WARNING*  LoadReceiverFile:  NumPatches do not match, skipping...\n");\r
1810                 fclose(f);\r
1811                 return GE_FALSE;\r
1812         }\r
1813 \r
1814         // Load Patche receivers\r
1815         for (i=0; i< NumPatches; i++)\r
1816         {\r
1817                 int32 NumReceivers;\r
1818 \r
1819                 // Load the number of receivers for this patch\r
1820                 if (fread(&NumReceivers, sizeof(int32), 1, f) != 1)\r
1821                 {\r
1822                         GHook.Error("LoadReceiverFile:  Could not load num receivers...\n");\r
1823                         fclose(f);\r
1824                         return GE_FALSE;\r
1825                 }\r
1826                 \r
1827                 PatchList[i]->Receivers = GE_RAM_ALLOCATE_ARRAY(RAD_Receiver,NumReceivers);\r
1828 \r
1829                 if (!PatchList[i]->Receivers)\r
1830                 {\r
1831                         GHook.Error("LoadReceiverFile:  Out of memory for receivers.\n");\r
1832                         FreeReceivers();\r
1833                         return GE_FALSE;\r
1834                 }\r
1835 \r
1836                 PatchList[i]->NumReceivers = (uint16)NumReceivers;\r
1837 \r
1838                 // Load the actual receivers\r
1839                 if (fread(PatchList[i]->Receivers, sizeof(RAD_Receiver), NumReceivers, f) != (uint32)NumReceivers)\r
1840                 {\r
1841                         GHook.Error("SaveReceiverFile:  Could not save receivers...\n");\r
1842                         fclose(f);\r
1843                         return GE_FALSE;\r
1844                 }\r
1845         }\r
1846 \r
1847         return GE_TRUE;\r
1848 }\r