PageRenderTime 65ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/CS/migrated/branches/R0_18/libs/csengine/sector.cpp

#
C++ | 1790 lines | 1309 code | 156 blank | 325 comment | 306 complexity | a4192ccb8dd0488277b9a135ba62a68d MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, LGPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. Copyright (C) 1998-2000 by Jorrit Tyberghein
  3. This library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Library General Public
  5. License as published by the Free Software Foundation; either
  6. version 2 of the License, or (at your option) any later version.
  7. This library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Library General Public License for more details.
  11. You should have received a copy of the GNU Library General Public
  12. License along with this library; if not, write to the Free
  13. Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #include "cssysdef.h"
  16. #include "qint.h"
  17. #include "csutil/csstring.h"
  18. #include "csutil/hashmap.h"
  19. #include "csengine/dumper.h"
  20. #include "csengine/sector.h"
  21. #include "csengine/thing.h"
  22. #include "csengine/meshobj.h"
  23. #include "csengine/polygon.h"
  24. #include "csengine/pol2d.h"
  25. #include "csengine/polytext.h"
  26. #include "csengine/polytmap.h"
  27. #include "csengine/light.h"
  28. #include "csengine/camera.h"
  29. #include "csengine/engine.h"
  30. #include "csengine/stats.h"
  31. #include "csengine/csppulse.h"
  32. #include "csengine/cbuffer.h"
  33. #include "csengine/quadtr3d.h"
  34. #include "csengine/covtree.h"
  35. #include "csengine/bspbbox.h"
  36. #include "csengine/terrain.h"
  37. #include "csengine/covcube.h"
  38. #include "csengine/cbufcube.h"
  39. #include "csengine/bsp.h"
  40. #include "csengine/octree.h"
  41. #include "igraph3d.h"
  42. #include "igraph2d.h"
  43. #include "itxtmgr.h"
  44. #include "itexture.h"
  45. #include "ivfs.h"
  46. #include "istlight.h"
  47. // Option variable: render portals?
  48. bool csSector::do_portals = true;
  49. // Option variable: render things?
  50. bool csSector::do_things = true;
  51. // Configuration variable: number of allowed reflections for static lighting.
  52. int csSector::cfg_reflections = 1;
  53. // Option variable: do pseudo radiosity?
  54. bool csSector::do_radiosity = false;
  55. //---------------------------------------------------------------------------
  56. IMPLEMENT_CSOBJTYPE (csSector,csPolygonSet);
  57. IMPLEMENT_IBASE_EXT (csSector)
  58. IMPLEMENTS_EMBEDDED_INTERFACE (iSector)
  59. IMPLEMENT_IBASE_EXT_END
  60. IMPLEMENT_EMBEDDED_IBASE (csSector::eiSector)
  61. IMPLEMENTS_INTERFACE (iSector)
  62. IMPLEMENT_EMBEDDED_IBASE_END
  63. csSector::csSector (csEngine* engine) : csPolygonSet (engine)
  64. {
  65. CONSTRUCT_EMBEDDED_IBASE (scfiSector);
  66. beam_busy = 0;
  67. level_r = level_g = level_b = 0;
  68. static_tree = NULL;
  69. static_thing = NULL;
  70. engine->AddToCurrentRegion (this);
  71. }
  72. csSector::~csSector ()
  73. {
  74. // Meshes, things, and collections are not deleted by the calls below. They
  75. // belong to csEngine.
  76. things.DeleteAll ();
  77. skies.DeleteAll ();
  78. meshes.DeleteAll ();
  79. collections.DeleteAll ();
  80. delete static_tree;
  81. lights.DeleteAll ();
  82. terrains.DeleteAll ();
  83. }
  84. void csSector::Prepare (csSector*)
  85. {
  86. csPolygonSet::Prepare (this);
  87. int i;
  88. for (i = 0 ; i < things.Length () ; i++)
  89. {
  90. csThing* th = (csThing*)things[i];
  91. th->Prepare (this);
  92. }
  93. for (i = 0 ; i < skies.Length () ; i++)
  94. {
  95. csThing* th = (csThing*)skies[i];
  96. th->Prepare (this);
  97. }
  98. }
  99. void csSector::AddLight (csStatLight* light)
  100. {
  101. lights.Push (light);
  102. light->SetSector (this);
  103. }
  104. void csSector::UseStaticTree (int mode, bool /*octree*/)
  105. {
  106. //mode = BSP_BALANCE_AND_SPLITS;
  107. delete static_tree; static_tree = NULL;
  108. if (static_thing) return;
  109. static_thing = new csThing (engine);
  110. static_thing->SetName ("__static__");
  111. // First copy the vector of things locally.
  112. csVector copy_things;
  113. int i;
  114. for (i = 0 ; i < things.Length () ; i++)
  115. copy_things.Push (things[i]);
  116. i = 0;
  117. while (i < copy_things.Length ())
  118. {
  119. csThing* sp = (csThing*)copy_things[i];
  120. if (!sp->flags.Check (CS_ENTITY_MOVEABLE | CS_ENTITY_DETAIL) && !sp->GetFog ().enabled
  121. && sp->GetNumCurves () == 0)
  122. {
  123. static_thing->Merge (sp);
  124. delete sp;
  125. }
  126. i++;
  127. }
  128. static_thing->GetMovable ().SetSector (this);
  129. static_thing->GetMovable ().UpdateMove ();
  130. static_thing->CreateBoundingBox ();
  131. engine->things.Push (static_thing);
  132. csBox3 bbox;
  133. static_thing->GetBoundingBox (bbox);
  134. static_tree = new csOctree (this, bbox.Min (), bbox.Max (), 150/*15*/, mode);
  135. csString str ("vis/octree_");
  136. str += GetName ();
  137. csEngine* w = engine;
  138. bool recalc_octree = true;
  139. if (!csEngine::do_force_revis && w->VFS->Exists ((const char*)str))
  140. {
  141. recalc_octree = false;
  142. CsPrintf (MSG_INITIALIZATION, "Loading bsp/octree...\n");
  143. recalc_octree = !((csOctree*)static_tree)->ReadFromCache (
  144. w->VFS, (const char*)str, static_thing->GetPolygonArray ().GetArray (),
  145. static_thing->GetPolygonArray ().Length ());
  146. if (recalc_octree)
  147. {
  148. delete static_tree;
  149. static_tree = new csOctree (this, bbox.Min (), bbox.Max (), 150/*15*/, mode);
  150. }
  151. }
  152. if (recalc_octree)
  153. {
  154. CsPrintf (MSG_INITIALIZATION, "Calculate bsp/octree...\n");
  155. static_tree->Build (static_thing->GetPolygonArray ());
  156. CsPrintf (MSG_INITIALIZATION, "Caching bsp/octree...\n");
  157. ((csOctree*)static_tree)->Cache (w->VFS, (const char*)str);
  158. }
  159. CsPrintf (MSG_INITIALIZATION, "Compress vertices...\n");
  160. static_thing->CompressVertices ();
  161. CsPrintf (MSG_INITIALIZATION, "Build vertex tables...\n");
  162. ((csOctree*)static_tree)->BuildVertexTables ();
  163. // Everything for PVS.
  164. str = "vis/pvs_";
  165. str += GetName ();
  166. bool recalc_pvs = true;
  167. if ((!csEngine::do_force_revis || csEngine::do_not_force_revis) &&
  168. w->VFS->Exists ((const char*)str))
  169. {
  170. recalc_pvs = false;
  171. CsPrintf (MSG_INITIALIZATION, "Loading PVS...\n");
  172. recalc_pvs = !((csOctree*)static_tree)->ReadFromCachePVS (
  173. w->VFS, (const char*)str);;
  174. }
  175. if (csEngine::do_not_force_revis) recalc_pvs = false;
  176. if (recalc_pvs)
  177. {
  178. # if 0
  179. CsPrintf (MSG_INITIALIZATION, "Build PVS...\n");
  180. ((csOctree*)static_tree)->BuildPVS (static_thing);
  181. # else
  182. //CsPrintf (MSG_INITIALIZATION, "Build Dummy PVS...\n");
  183. //((csOctree*)static_tree)->SetupDummyPVS ();
  184. # endif
  185. CsPrintf (MSG_INITIALIZATION, "Caching PVS...\n");
  186. ((csOctree*)static_tree)->CachePVS (w->VFS, (const char*)str);
  187. }
  188. static_tree->Statistics ();
  189. // Loop through all things and update their bounding box in the
  190. // polygon trees.
  191. for (i = 0 ; i < things.Length () ; i++)
  192. {
  193. csThing* th = (csThing*)things[i];
  194. th->GetMovable ().UpdateMove ();
  195. }
  196. CsPrintf (MSG_INITIALIZATION, "DONE!\n");
  197. }
  198. csPolygon3D* csSector::HitBeam (const csVector3& start, const csVector3& end,
  199. csVector3& isect)
  200. {
  201. csPolygon3D* p = IntersectSegment (start, end, isect);
  202. if (p)
  203. {
  204. csPortal* po = p->GetPortal ();
  205. if (po)
  206. {
  207. draw_busy++;
  208. csVector3 new_start = isect;
  209. p = po->HitBeam (new_start, end, isect);
  210. draw_busy--;
  211. return p;
  212. }
  213. else return p;
  214. }
  215. else return NULL;
  216. }
  217. csObject* csSector::HitBeam (const csVector3& start, const csVector3& end,
  218. csPolygon3D** polygonPtr)
  219. {
  220. float r, best_mesh_r = 10000000000.;
  221. csMeshWrapper* near_mesh = NULL;
  222. csVector3 isect;
  223. // First check all meshes in this sector.
  224. int i;
  225. for (i = 0 ; i < meshes.Length () ; i++)
  226. {
  227. csMeshWrapper* mesh = (csMeshWrapper*)meshes[i];
  228. if (mesh->HitBeam (start, end, isect, &r))
  229. {
  230. if (r < best_mesh_r)
  231. {
  232. best_mesh_r = r;
  233. near_mesh = mesh;
  234. }
  235. }
  236. }
  237. float best_poly_r;
  238. csPolygon3D* p = IntersectSegment (start, end, isect, &best_poly_r);
  239. // We hit a polygon and the polygon is closer than the mesh.
  240. if (p && best_poly_r < best_mesh_r)
  241. {
  242. csPortal* po = p->GetPortal ();
  243. if (po)
  244. {
  245. draw_busy++;
  246. csVector3 new_start = isect;
  247. csObject* obj = po->HitBeam (new_start, end, polygonPtr);
  248. draw_busy--;
  249. return obj;
  250. }
  251. else
  252. {
  253. if (polygonPtr) *polygonPtr = p;
  254. return (csObject*)(p->GetParent ());
  255. }
  256. }
  257. // The mesh is closer (or there is no mesh).
  258. if (polygonPtr) *polygonPtr = NULL;
  259. return (csObject*)near_mesh;
  260. }
  261. void csSector::CreateLightMaps (iGraphics3D* g3d)
  262. {
  263. int i;
  264. for (i = 0 ; i < polygons.Length () ; i++)
  265. {
  266. csPolygon3D* p = polygons.Get (i);
  267. p->CreateLightMaps (g3d);
  268. }
  269. for (i = 0 ; i < things.Length () ; i++)
  270. {
  271. csThing* sp = (csThing*)things[i];
  272. sp->CreateLightMaps (g3d);
  273. }
  274. for (i = 0 ; i < skies.Length () ; i++)
  275. {
  276. csThing* sp = (csThing*)skies[i];
  277. sp->CreateLightMaps (g3d);
  278. }
  279. }
  280. struct ISectData
  281. {
  282. csSegment3 seg;
  283. csVector3 isect;
  284. float r;
  285. };
  286. /*
  287. * @@@
  288. * This function does not yet do anything but it should
  289. * use the PVS as soon as we have that to make csSector::IntersectSegment
  290. * even faster.
  291. */
  292. bool IntersectSegmentCull (csPolygonTree* /*tree*/,
  293. csPolygonTreeNode* node,
  294. const csVector3& /*pos*/, void* data)
  295. {
  296. if (!node) return false;
  297. if (node->Type () != NODE_OCTREE) return true;
  298. ISectData* idata = (ISectData*)data;
  299. csOctreeNode* onode = (csOctreeNode*)node;
  300. csVector3 isect;
  301. if (csIntersect3::BoxSegment (onode->GetBox (), idata->seg, isect))
  302. return true;
  303. // Segment does not intersect with node so we return false here.
  304. return false;
  305. }
  306. void* IntersectSegmentTestPol (csSector*,
  307. csPolygonInt** polygon, int num, bool /*same_plane*/, void* data)
  308. {
  309. ISectData* idata = (ISectData*)data;
  310. int i;
  311. for (i = 0 ; i < num ; i++)
  312. {
  313. // @@@ What about other types of polygons?
  314. if (polygon[i]->GetType () == 1)
  315. {
  316. csPolygon3D* p = (csPolygon3D*)polygon[i];
  317. if (p->IntersectSegment (idata->seg.Start (), idata->seg.End (),
  318. idata->isect, &(idata->r)))
  319. return (void*)p;
  320. }
  321. }
  322. return NULL;
  323. }
  324. csPolygon3D* csSector::IntersectSegment (const csVector3& start,
  325. const csVector3& end, csVector3& isect, float* pr)
  326. {
  327. float r, best_r = 10000000000.;
  328. csVector3 cur_isect;
  329. csPolygon3D* best_p = NULL;
  330. int i;
  331. for (i = 0 ; i < things.Length () ; i++)
  332. {
  333. csThing* sp = (csThing*)things[i];
  334. if (sp != static_thing)
  335. {
  336. r = best_r;
  337. csPolygon3D* p = sp->IntersectSegment (start, end, cur_isect, &r);
  338. if (p && r < best_r)
  339. {
  340. best_r = r;
  341. best_p = p;
  342. isect = cur_isect;
  343. }
  344. }
  345. }
  346. if (static_tree)
  347. {
  348. // Handle the octree.
  349. ISectData idata;
  350. idata.seg.Set (start, end);
  351. void* rc = static_tree->Front2Back (start, IntersectSegmentTestPol,
  352. (void*)&idata, IntersectSegmentCull, (void*)&idata);
  353. if (rc && idata.r < best_r)
  354. {
  355. best_r = idata.r;
  356. best_p = (csPolygon3D*)rc;
  357. isect = idata.isect;
  358. }
  359. }
  360. if (best_p)
  361. {
  362. if (pr) *pr = best_r;
  363. return best_p;
  364. }
  365. return csPolygonSet::IntersectSegment (start, end, isect, pr);
  366. }
  367. csSector* csSector::FollowSegment (csReversibleTransform& t,
  368. csVector3& new_position, bool& mirror)
  369. {
  370. csVector3 isect;
  371. csPolygon3D* p = IntersectSegment (t.GetOrigin (), new_position, isect);
  372. csPortal* po;
  373. if (p)
  374. {
  375. po = p->GetPortal ();
  376. if (po)
  377. {
  378. if (!po->GetSector ()) po->CompleteSector ();
  379. if (po->flags.Check (CS_PORTAL_WARP))
  380. {
  381. po->WarpSpace (t, mirror);
  382. new_position = po->Warp (new_position);
  383. }
  384. csSector* dest_sect = po->GetSector ();
  385. return dest_sect ? dest_sect->FollowSegment (t, new_position, mirror) : (csSector*)NULL;
  386. }
  387. else
  388. new_position = isect;
  389. }
  390. return this;
  391. }
  392. csPolygon3D* csSector::IntersectSphere (csVector3& center, float radius,
  393. float* pr)
  394. {
  395. float d, min_d = radius;
  396. int i;
  397. csPolygon3D* p, * min_p = NULL;
  398. csVector3 hit;
  399. for (i = 0 ; i < polygons.Length () ; i++)
  400. {
  401. p = polygons.Get (i);
  402. const csPolyPlane* pl = p->GetPlane ();
  403. const csPlane3& wpl = pl->GetWorldPlane ();
  404. d = wpl.Distance (center);
  405. if (d < min_d && csMath3::Visible (center, wpl))
  406. {
  407. hit = -center;
  408. hit -= wpl.GetNormal ();
  409. hit *= d;
  410. hit += center;
  411. if (p->IntersectRay (center, hit))
  412. {
  413. csPortal* po = p->GetPortal ();
  414. if (po)
  415. {
  416. if (!po->GetSector ()) po->CompleteSector ();
  417. csSector* dest_sect = po->GetSector ();
  418. p = dest_sect->IntersectSphere (center, min_d, &d);
  419. if (p)
  420. {
  421. min_d = d;
  422. min_p = p;
  423. }
  424. }
  425. else
  426. {
  427. min_d = d;
  428. min_p = p;
  429. }
  430. }
  431. }
  432. }
  433. for (i = 0 ; i < things.Length () ; i++)
  434. {
  435. csThing* sp = (csThing*)things[i];
  436. p = sp->IntersectSphere (center, radius, &d);
  437. if (p && d < min_d)
  438. {
  439. min_d = d;
  440. min_p = p;
  441. }
  442. }
  443. if (pr) *pr = min_d;
  444. return min_p;
  445. }
  446. void* csSector::DrawPolygons (csSector* sector,
  447. csPolygonInt** polygon, int num, bool /*same_plane*/, void* data)
  448. {
  449. csRenderView* d = (csRenderView*)data;
  450. sector->DrawPolygonArray (polygon, num, d, false);
  451. return NULL;
  452. }
  453. csPolygon2DQueue* poly_queue;
  454. void* csSector::TestQueuePolygons (csSector* sector,
  455. csPolygonInt** polygon, int num, bool /*same_plane*/, void* data)
  456. {
  457. csRenderView* d = (csRenderView*)data;
  458. return sector->TestQueuePolygonArray (polygon, num, d, poly_queue,
  459. d->GetEngine ()->IsPVS ());
  460. }
  461. void csSector::DrawPolygonsFromQueue (csPolygon2DQueue* queue,
  462. csRenderView* rview)
  463. {
  464. csPolygon3D* poly3d;
  465. csPolygon2D* poly2d;
  466. csPoly2DPool* render_pool = rview->GetEngine ()->render_pol2d_pool;
  467. while (queue->Pop (&poly3d, &poly2d))
  468. {
  469. poly3d->CamUpdate ();
  470. poly3d->GetPlane ()->WorldToCamera (*rview, poly3d->Vcam (0));
  471. DrawOnePolygon (poly3d, poly2d, rview, false);
  472. render_pool->Free (poly2d);
  473. }
  474. }
  475. int compare_z_thing (const void* p1, const void* p2)
  476. {
  477. csThing* sp1 = *(csThing**)p1;
  478. csThing* sp2 = *(csThing**)p2;
  479. float z1 = sp1->Vcam (sp1->GetCenter ()).z;
  480. float z2 = sp2->Vcam (sp2->GetCenter ()).z;
  481. if (z1 < z2) return -1;
  482. else if (z1 > z2) return 1;
  483. return 0;
  484. }
  485. static int count_cull_node_notvis_behind;
  486. // static int count_cull_node_vis_cutzplane;
  487. static int count_cull_node_notvis_cbuffer;
  488. static int count_cull_node_vis;
  489. // @@@ This routine need to be cleaned up!!! It probably needs to
  490. // be part of the class.
  491. bool CullOctreeNode (csPolygonTree* tree, csPolygonTreeNode* node,
  492. const csVector3& pos, void* data)
  493. {
  494. if (!node) return false;
  495. if (node->Type () != NODE_OCTREE) return true;
  496. int i;
  497. csOctree* otree = (csOctree*)tree;
  498. csOctreeNode* onode = (csOctreeNode*)node;
  499. csCBuffer* c_buffer;
  500. csQuadTree3D* quad3d;
  501. csCoverageMaskTree* covtree;
  502. csRenderView* rview = (csRenderView*)data;
  503. static csPolygon2D persp;
  504. csVector3 array[7];
  505. csEngine* w = rview->GetEngine ();
  506. if (w->IsPVS ())
  507. {
  508. // Test for PVS.
  509. if (!onode->IsVisible ()) return false;
  510. else if (w->IsPVSOnly ()) goto is_vis;
  511. }
  512. c_buffer = w->GetCBuffer ();
  513. covtree = w->GetCovtree ();
  514. quad3d = w->GetQuad3D ();
  515. int num_array;
  516. otree->GetConvexOutline (onode, pos, array, num_array, rview->UseFarPlane ());
  517. if (num_array)
  518. {
  519. int nVert = MIN (6, num_array); // if we use a farplane we could have up to 7 corners,
  520. // but the 7th we'll need not here
  521. if (quad3d)
  522. {
  523. csVector3 test_poly[6];
  524. for (i = 0 ; i < nVert ; i++)
  525. test_poly[i] = array[i]-quad3d->GetCenter ();
  526. csBox3 bbox;
  527. int rc = quad3d->TestPolygon (test_poly, nVert, bbox);
  528. bool visible = (rc != CS_QUAD3D_NOCHANGE);
  529. if (!visible) return false;
  530. goto is_vis;
  531. }
  532. csVector3 cam[7];
  533. // If all vertices are behind z plane then the node is
  534. // not visible. If some vertices are behind z plane then we
  535. // need to clip the polygon.
  536. // We also test the node against the view frustum here.
  537. int num_z_0 = 0;
  538. bool left = true, right = true, top = true, bot = true;
  539. float lx, rx, ty, by;
  540. rview->GetFrustum (lx, rx, ty, by);
  541. for (i = 0 ; i < nVert; i++)
  542. {
  543. cam[i] = rview->Other2This (array[i]);
  544. if (cam[i].z < SMALL_EPSILON) num_z_0++;
  545. if (left && cam[i].x >= cam[i].z * lx) left = false;
  546. if (right && cam[i].x <= cam[i].z * rx) right = false;
  547. if (top && cam[i].y >= cam[i].z * ty) top = false;
  548. if (bot && cam[i].y <= cam[i].z * by) bot = false;
  549. }
  550. if (left || right || top || bot) return false;
  551. if (num_z_0 == nVert)
  552. {
  553. // Node behind camera.
  554. count_cull_node_notvis_behind++;
  555. return false;
  556. }
  557. if (rview->UseFarPlane ())
  558. {
  559. if (num_array == 7) // we havent transformed the 7th yet
  560. cam[6] = rview->Other2This (array[6]);
  561. for (i = 0 ; i < num_array ; i++)
  562. if (rview->GetFarPlane ()->Classify (cam[i]) > SMALL_EPSILON)
  563. break;
  564. if (i == num_array) return false;
  565. }
  566. persp.MakeEmpty ();
  567. if (num_z_0 == 0)
  568. {
  569. // No vertices are behind. Just perspective correct.
  570. for (i = 0 ; i < nVert ; i++)
  571. persp.AddPerspective (cam[i]);
  572. }
  573. else
  574. {
  575. // Some vertices are behind. We need to clip.
  576. csVector3 isect;
  577. int i1 = nVert-1;
  578. for (i = 0 ; i < nVert ; i++)
  579. {
  580. if (cam[i].z < SMALL_EPSILON)
  581. {
  582. if (cam[i1].z < SMALL_EPSILON)
  583. {
  584. // Just skip vertex.
  585. }
  586. else
  587. {
  588. // We need to intersect and add intersection point.
  589. csIntersect3::ZPlane (SMALL_EPSILON, cam[i], cam[i1], isect);
  590. persp.AddPerspective (isect);
  591. }
  592. }
  593. else
  594. {
  595. if (cam[i1].z < SMALL_EPSILON)
  596. {
  597. // We need to intersect and add both intersection point and this point.
  598. csIntersect3::ZPlane (SMALL_EPSILON, cam[i], cam[i1], isect);
  599. persp.AddPerspective (isect);
  600. }
  601. // Just perspective correct and add to the 2D polygon.
  602. persp.AddPerspective (cam[i]);
  603. }
  604. i1 = i;
  605. }
  606. }
  607. if (!persp.ClipAgainst (rview->GetView ())) return false;
  608. // c-buffer test.
  609. bool vis;
  610. if (covtree)
  611. vis = covtree->TestPolygon (persp.GetVertices (),
  612. persp.GetNumVertices (), persp.GetBoundingBox ());
  613. else
  614. vis = c_buffer->TestPolygon (persp.GetVertices (),
  615. persp.GetNumVertices ());
  616. if (!vis)
  617. {
  618. count_cull_node_notvis_cbuffer++;
  619. return false;
  620. }
  621. }
  622. is_vis:
  623. count_cull_node_vis++;
  624. // If a node is visible we check wether or not it has a minibsp.
  625. // If it has a minibsp then we need to transform all vertices used
  626. // by that minibsp to camera space.
  627. csVector3* cam;
  628. int* indices;
  629. int num_indices;
  630. if (onode->GetMiniBspVerts ())
  631. {
  632. // Here we get the polygon set as the static thing from the sector itself.
  633. csPolygonSet* pset = (csPolygonSet*)(otree->GetSector ()->GetStaticThing ());
  634. cam = pset->GetCameraVertices ();
  635. indices = onode->GetMiniBspVerts ();
  636. num_indices = onode->GetMiniBspNumVerts ();
  637. for (i = 0 ; i < num_indices ; i++)
  638. cam[indices[i]] = rview->Other2This (pset->Vwor (indices[i]));
  639. }
  640. return true;
  641. }
  642. // Some notes about drawing here. These notes are the start for
  643. // a rethinking about how rendering objects in one sector actually
  644. // should happen. Note that the current implementation actually
  645. // implements very little of the things discussed here. Currently
  646. // the entities are just rendered one after the other which can cause
  647. // some problems.
  648. //
  649. // There are a few issues here:
  650. //
  651. // 1. Z-buffering/Z-filling.
  652. // Some objects/entities are more efficiently rendered back
  653. // to front using Z-filling instead of Z-buffering. In some cases
  654. // Z-filling is also required because rendering a sector starts
  655. // with an uninitialized Z-buffer (CS normally doesn't clear the
  656. // Z buffer every frame). In some cases it might be more optimal
  657. // to use Z buffering in any case (to avoid sorting back to front)
  658. // (for hardware 3D) so we would like to have the option to clear
  659. // the Z buffer every frame and use Z-buffering.
  660. //
  661. // 2. Alpha transparency.
  662. // Some entities have alpha transparency. Alpha transparent surfaces
  663. // actually need to be sorted back to front to render correctly.
  664. // Also before rendering an alpha surface all objects behind it should
  665. // already be rendered.
  666. //
  667. // 3. Floating portals.
  668. // Floating portals also take some special consideration. First
  669. // of all the assume a new intialize of the Z buffer for the 2D
  670. // area of the portal in question. This is ok if the first entities
  671. // that are rendered through the portal use Z-fill and cover the
  672. // entire portal (this is the case if you use sector walls for
  673. // example). If Z-fill cannot be used for the portal then an
  674. // extra initial pass would have to clear the Z buffer for the portal
  675. // area in 2D. Also geometry needs to be clipped in 3D if you have
  676. // a floating portal. The reason is that the Z buffer information
  677. // outside of the floating portal may actually contain information
  678. // further than the contents of the portal. This would cause entities
  679. // visible inside the portal to be rendered as if they are in the
  680. // parent sector too.
  681. // After rendering through a floating portal, the floating portal
  682. // itself needs to be covered by the Z-buffer. i.e. we need to make
  683. // sure that the Z-buffer thinks the portal is a regular polygon.
  684. // This is to make sure that meshes or other entities rendered
  685. // afterwards will not get rendered INSIDE the portal contents.
  686. //
  687. // Here is a list of all the entities that we can draw in a sector:
  688. //
  689. // 1. Sector walls.
  690. // Sectors are always convex. So sectors walls are ideal for rendering
  691. // first through Z-fill.
  692. //
  693. // 2. Static things in octree.
  694. // In some cases all static things are collected into one big
  695. // octree with mini-bsp trees. This structure ensures that we can
  696. // actually easily sort polygon back to front or front to back if
  697. // needed. This structure can also easily be rendered using Z-fill.
  698. // The c-buffer/coverage mask tree can also be used to detect
  699. // visibility before rendering. This pushes visible polygons into
  700. // a queue. There is the issue here that it should be possible
  701. // to ignore the mini-bsp trees and only use the octree information.
  702. // This can be done on hardware where Z-buffering is fast. This
  703. // of course implies either the use of a Z-filled sector or else
  704. // a clear of the Z buffer every frame.
  705. // A related issue is when there are portals between the polygons.
  706. // Those portals need to be handled as floating portals (i.e. geometry
  707. // needs to be clipped in 3D) because the Z buffer information
  708. // will not be correct. If rendering the visible octree polygons
  709. // back to front then rendering through the portals presents no
  710. // other difficulties.
  711. //
  712. // 3. Terrain triangles.
  713. // The terrain engine generates a set of triangles. These triangles
  714. // can easily be sorted back to front so they are also suitable for
  715. // Z-fill rendering. However, this conflicts with the use of the
  716. // static octree. You cannot use Z-fill for both because that could
  717. // cause wrong rendering. Using Z-buffer for one of them might be
  718. // expensive but the only solution. Here there is also the issue
  719. // if it isn't possible to combine visibility algorithms for landscape
  720. // and octree stuff. i.e. cull octree nodes if occluded by a part
  721. // of the landscape.
  722. //
  723. // 4. 3D Sprites.
  724. // Sprites are entities that need to be rendered using the Z-buffer
  725. // because the triangles cannot easily be sorted.
  726. //
  727. // 5. Dynamic things.
  728. // Things that are not part of the static octree are handled much
  729. // like normal 3D sprites. The most important exception is when
  730. // such a thing has a floating portal. In this case all the normal
  731. // floating portal issues are valid. However, there are is an important
  732. // issue here: if you are rendering a floating portal that is BEHIND
  733. // an already rendered entity then there is a problem. The contents
  734. // of the portal may actually use Z-fill and thus would overrender
  735. // the entity in front. One obvious solution is to sort ALL entities
  736. // to make sure that everything is rendered back to front. That's of
  737. // course not always efficient and easy to do. Also it is not possible
  738. // in all cases to do it 100% correct (i.e. complex sprites with
  739. // skeletal animation and so on). The ideal solution would be to have
  740. // a way to clear the Z-buffer for an invisible polygon but only
  741. // where the polygon itself is visible according to the old Z-buffer
  742. // values. This is possible with software but I'm currently unsure
  743. // about hardware. With such a routine you could draw the floating
  744. // portal at any time you want. First you clear the Z-buffer for the
  745. // visible area. Then you force Z-buffer use for the contents inside
  746. // (i.e. everything normally rendered using Z-fill will use Z-buffer
  747. // instead), then you render. Finally you update the Z-buffer with
  748. // the Z-value of the polygon to make it 'hard'.
  749. //
  750. // If we can treat floating portals this way then we can in fact
  751. // consider them as normal polygons that behave correctly for the
  752. // Z buffer. Aside from the fact that they clip geometry in 3D
  753. // that passes through the portal. Note that 3D sprites don't
  754. // currently support 3D geometry clipping yet.
  755. void csSector::Draw (csRenderView& rview)
  756. {
  757. draw_busy++;
  758. UpdateTransformation (rview);
  759. Stats::polygons_considered += polygons.Length ();
  760. int i;
  761. rview.SetThisSector (this);
  762. G3D_FOGMETHOD fogmethod = G3DFOGMETHOD_NONE;
  763. if (rview.GetCallback ())
  764. {
  765. rview.CallCallback (CALLBACK_SECTOR, (void*)this);
  766. }
  767. else if (HasFog ())
  768. {
  769. if ((fogmethod = rview.GetEngine ()->fogmethod) == G3DFOGMETHOD_VERTEX)
  770. {
  771. csFogInfo* fog_info = new csFogInfo ();
  772. fog_info->next = rview.GetFogInfo ();
  773. if (rview.GetPortalPolygon ())
  774. {
  775. fog_info->incoming_plane = rview.GetPortalPolygon ()->GetPlane ()->
  776. GetCameraPlane ();
  777. fog_info->incoming_plane.Invert ();
  778. fog_info->has_incoming_plane = true;
  779. }
  780. else fog_info->has_incoming_plane = false;
  781. fog_info->fog = &GetFog ();
  782. fog_info->has_outgoing_plane = true;
  783. rview.SetFogInfo (fog_info);
  784. }
  785. else if (fogmethod != G3DFOGMETHOD_NONE)
  786. {
  787. rview.GetG3D ()->OpenFogObject (GetID (), &GetFog ());
  788. }
  789. }
  790. // First draw all 'sky' things using Z-fill.
  791. for (i = 0 ; i < skies.Length () ; i++)
  792. {
  793. csThing* th = (csThing*)skies[i];
  794. th->Draw (rview, false);
  795. }
  796. // In some cases this queue will be filled with all visible
  797. // meshes.
  798. csMeshWrapper** mesh_queue = NULL;
  799. int num_mesh_queue = 0;
  800. // For things we have a similar queue.
  801. csThing** thing_queue = NULL;
  802. int num_thing_queue = 0;
  803. // If the following flag is true the queues are actually used.
  804. bool use_object_queues = false;
  805. int engine_mode = rview.GetEngine ()->GetEngineMode ();
  806. if (engine_mode == CS_ENGINE_FRONT2BACK)
  807. {
  808. //-----
  809. // In this part of the rendering we use the c-buffer or another
  810. // 2D/3D visibility culler.
  811. //-----
  812. // @@@ We should make a pool for queues. The number of queues allocated
  813. // at the same time is bounded by the recursion through portals. So a
  814. // pool would be ideal.
  815. if (static_thing)
  816. {
  817. //-----
  818. // This sector has a static polygon tree (octree).
  819. //-----
  820. // Mark all meshes as invisible and clear the camera transformation
  821. // for their bounding boxes.
  822. if (meshes.Length () > 0)
  823. for (i = 0 ; i < meshes.Length () ; i++)
  824. {
  825. csMeshWrapper* sp = (csMeshWrapper*)meshes[i];
  826. csPolyTreeObject* pt = sp->GetPolyTreeObject ();
  827. if (pt->GetWorldBoundingBox ().In (rview.GetOrigin ()))
  828. sp->MarkVisible ();
  829. else
  830. sp->MarkInvisible ();
  831. sp->VisTestReset ();
  832. }
  833. // Similarly mark all things as invisible and clear the camera
  834. // transformation for their bounding boxes.
  835. for (i = 0 ; i < things.Length () ; i++)
  836. {
  837. csThing* th = (csThing*)things[i];
  838. csPolyTreeObject* pt = th->GetPolyTreeObject ();
  839. if (pt->GetWorldBoundingBox ().In (rview.GetOrigin ()))
  840. th->MarkVisible ();
  841. else
  842. th->MarkInvisible ();
  843. th->VisTestReset ();
  844. }
  845. // Using the PVS, mark all sectors and polygons that are visible
  846. // from the current node.
  847. if (rview.GetEngine ()->IsPVS ())
  848. {
  849. csOctree* otree = (csOctree*)static_tree;
  850. if (rview.GetEngine ()->IsPVSFrozen ())
  851. otree->MarkVisibleFromPVS (rview.GetEngine ()->GetFrozenPosition ());
  852. else
  853. otree->MarkVisibleFromPVS (rview.GetOrigin ());
  854. }
  855. // Initialize a queue on which all visible polygons will be pushed.
  856. // The octree is traversed front to back but we want to render
  857. // back to front. That's one of the reasons for this queue.
  858. poly_queue = new csPolygon2DQueue (polygons.Length ()+
  859. static_thing->GetNumPolygons ());
  860. // Update the transformation for the static tree. This will
  861. // not actually transform all vertices from world to camera but
  862. // it will make sure that when a node (octree node) is visited,
  863. // the transformation will happen at that time.
  864. static_thing->UpdateTransformation ();
  865. // Traverse the tree front to back and push all visible polygons
  866. // on the queue. This traversal will also mark all visible
  867. // meshes and things. They will be put on a queue later.
  868. static_tree->Front2Back (rview.GetOrigin (), &TestQueuePolygons,
  869. &rview, CullOctreeNode, &rview);
  870. // Fill the mesh and thing queues for all meshes and things
  871. // that were visible.
  872. use_object_queues = true;
  873. if (meshes.Length () > 0)
  874. {
  875. // Push all visible meshes in a queue.
  876. // @@@ Avoid memory allocation?
  877. mesh_queue = new csMeshWrapper* [meshes.Length ()];
  878. num_mesh_queue = 0;
  879. for (i = 0 ; i < meshes.Length () ; i++)
  880. {
  881. csMeshWrapper* sp = (csMeshWrapper*)meshes[i];
  882. if (sp->IsVisible ()) mesh_queue[num_mesh_queue++] = sp;
  883. }
  884. }
  885. if (things.Length () > 0)
  886. {
  887. // Push all visible things in a queue.
  888. // @@@ Avoid memory allocation?
  889. thing_queue = new csThing* [things.Length ()];
  890. num_thing_queue = 0;
  891. for (i = 0 ; i < things.Length () ; i++)
  892. {
  893. csThing* th = (csThing*)things[i];
  894. if (th->IsVisible ()) thing_queue[num_thing_queue++] = th;
  895. }
  896. }
  897. }
  898. else
  899. {
  900. // There is no static thing (i.e. octree) in this sector so
  901. // we just make room for the polygons from the sector.
  902. poly_queue = new csPolygon2DQueue (polygons.Length ());
  903. }
  904. // Also add/queue the polygons of the current sector (which are expected
  905. // to be behind all other polygons from entities inside the sector).
  906. csPolygon2DQueue* queue = poly_queue;
  907. TestQueuePolygonArray (polygons.GetArray (), polygons.Length (), &rview,
  908. queue, false);
  909. // Render all polygons that are visible back to front.
  910. DrawPolygonsFromQueue (queue, &rview);
  911. delete queue;
  912. }
  913. else if (engine_mode == CS_ENGINE_BACK2FRONT)
  914. {
  915. //-----
  916. // Here we don't use the c-buffer or 2D culler but just render back
  917. // to front.
  918. //-----
  919. DrawPolygons (this, polygons.GetArray (), polygons.Length (), false, &rview);
  920. if (static_thing)
  921. {
  922. static_thing->UpdateTransformation (rview);
  923. static_tree->Back2Front (rview.GetOrigin (), &DrawPolygons, (void*)&rview);
  924. }
  925. }
  926. else
  927. {
  928. //-----
  929. // Here we render using the Z-buffer.
  930. //-----
  931. DrawPolygonArray (polygons.GetArray (), polygons.Length (), &rview, true);
  932. if (static_thing)
  933. {
  934. static_thing->UpdateTransformation (rview);
  935. csOctree* otree = (csOctree*)static_tree;
  936. csPolygonIntArray& unsplit = otree->GetRoot ()->GetUnsplitPolygons ();
  937. DrawPolygonArray (unsplit.GetPolygons (), unsplit.GetNumPolygons (),
  938. &rview, true);
  939. }
  940. }
  941. if (do_things)
  942. {
  943. // If the queues are not used for things we still fill the queue here
  944. // just to make the code below easier.
  945. if (!use_object_queues)
  946. {
  947. num_thing_queue = 0;
  948. if (things.Length ())
  949. {
  950. thing_queue = new csThing* [things.Length ()];
  951. for (i = 0 ; i < things.Length () ; i++)
  952. {
  953. csThing* th = (csThing*)things[i];
  954. thing_queue[num_thing_queue++] = th;
  955. }
  956. }
  957. else
  958. thing_queue = NULL;
  959. }
  960. // All csThings which are not merged with the static bsp still need to
  961. // be drawn. Unless they are fog objects (or transparent, this is a todo!)
  962. // we just render them using the Z-buffer. Fog or transparent objects
  963. // are z-sorted and rendered back to front.
  964. //
  965. // We should see if there are better alternatives to Z-sort which are
  966. // more accurate in more cases (@@@).
  967. csThing* sort_list[256]; // @@@HARDCODED == BAD == EASY!
  968. int sort_idx = 0;
  969. int i;
  970. // First we do z-sorting for fog objects so that they are rendered
  971. // correctly from back to front. All other objects are drawn using
  972. // the z-buffer.
  973. for (i = 0 ; i < num_thing_queue ; i++)
  974. {
  975. csThing* th = thing_queue[i];
  976. if (th != static_thing)
  977. if (th->GetFog ().enabled) sort_list[sort_idx++] = th;
  978. else th->Draw (rview);
  979. }
  980. if (sort_idx)
  981. {
  982. // Now sort the objects in sort_list.
  983. qsort (sort_list, sort_idx, sizeof (csThing*), compare_z_thing);
  984. // Draw them back to front.
  985. for (i = 0 ; i < sort_idx ; i++)
  986. {
  987. csThing* th = sort_list[i];
  988. if (th->GetFog ().enabled) th->DrawFoggy (rview);
  989. else th->Draw (rview, false);
  990. }
  991. }
  992. delete [] thing_queue;
  993. // Draw meshes.
  994. // To correctly support meshes in multiple sectors we only draw a
  995. // mesh if the mesh is not in the sector we came from. If the
  996. // mesh is also present in the previous sector then we will still
  997. // draw it in any of the following cases:
  998. // - the previous sector has fog
  999. // - the portal we just came through has alpha transparency
  1000. // - the portal is a portal on a thing (i.e. a floating portal)
  1001. // - the portal does space warping
  1002. // In those cases we draw the mesh anyway. @@@ Note that we should
  1003. // draw it clipped (in 3D) to the portal polygon. This is currently not
  1004. // done.
  1005. csSector* previous_sector = rview.GetPreviousSector ();
  1006. int spr_num;
  1007. if (mesh_queue) spr_num = num_mesh_queue;
  1008. else spr_num = meshes.Length ();
  1009. if (rview.AddedFogInfo ())
  1010. rview.GetFogInfo ()->has_outgoing_plane = false;
  1011. for (i = 0 ; i < spr_num ; i++)
  1012. {
  1013. csMeshWrapper* sp;
  1014. if (mesh_queue) sp = mesh_queue[i];
  1015. else sp = (csMeshWrapper*)meshes[i];
  1016. if (!previous_sector || sp->GetMovable ().GetSectors ().Find (previous_sector) == -1)
  1017. {
  1018. // Mesh is not in the previous sector or there is no previous sector.
  1019. sp->Draw (rview);
  1020. }
  1021. else
  1022. {
  1023. if (
  1024. ((csPolygonSet*)rview.GetPortalPolygon ()->GetParent ())->GetType ()
  1025. == csThing::Type ||
  1026. previous_sector->HasFog () ||
  1027. rview.GetPortalPolygon ()->IsTransparent () ||
  1028. rview.GetPortalPolygon ()->GetPortal ()->flags.Check (CS_PORTAL_WARP))
  1029. {
  1030. // @@@ Here we should draw clipped to the portal.
  1031. sp->Draw (rview);
  1032. }
  1033. }
  1034. }
  1035. delete [] mesh_queue;
  1036. }
  1037. // Draw all terrain surfaces.
  1038. if (terrains.Length () > 0)
  1039. {
  1040. for (i = 0 ; i < terrains.Length () ; i++)
  1041. {
  1042. csTerrain* terrain = (csTerrain*)terrains[i];
  1043. terrain->Draw (rview, true);
  1044. }
  1045. }
  1046. // queue all halos in this sector to be drawn.
  1047. if (!rview.GetCallback ())
  1048. for (i = lights.Length () - 1; i >= 0; i--)
  1049. // Tell the engine to try to add this light into the halo queue
  1050. rview.GetEngine ()->AddHalo ((csLight *)lights.Get (i));
  1051. // Handle the fog, if any
  1052. if (fogmethod != G3DFOGMETHOD_NONE)
  1053. {
  1054. G3DPolygonDFP g3dpoly;
  1055. if (fogmethod == G3DFOGMETHOD_ZBUFFER)
  1056. {
  1057. g3dpoly.num = rview.GetView ()->GetNumVertices ();
  1058. csVector2 *clipview = rview.GetView ()->GetClipPoly ();
  1059. memcpy (g3dpoly.vertices, clipview, g3dpoly.num * sizeof (csVector2));
  1060. if (rview.GetSector () == this && draw_busy == 0)
  1061. {
  1062. // Since there is fog in the current camera sector we simulate
  1063. // this by adding the view plane polygon.
  1064. rview.GetG3D ()->DrawFogPolygon (GetID (), g3dpoly, CS_FOG_VIEW);
  1065. }
  1066. else
  1067. {
  1068. // We must add a FRONT fog polygon for the clipper to this sector.
  1069. g3dpoly.normal = rview.GetClipPlane ();
  1070. g3dpoly.normal.Invert ();
  1071. g3dpoly.inv_aspect = rview.GetInvFOV ();
  1072. rview.GetG3D ()->DrawFogPolygon (GetID (), g3dpoly, CS_FOG_FRONT);
  1073. }
  1074. }
  1075. else if (fogmethod == G3DFOGMETHOD_VERTEX && rview.AddedFogInfo ())
  1076. {
  1077. csFogInfo *fog_info = rview.GetFogInfo ();
  1078. rview.SetFogInfo (rview.GetFogInfo ()->next);
  1079. delete fog_info;
  1080. }
  1081. }
  1082. if (rview.GetCallback ()) rview.CallCallback (CALLBACK_SECTOREXIT, (void*)this);
  1083. draw_busy--;
  1084. }
  1085. struct CheckFrustData
  1086. {
  1087. csFrustumView* lview;
  1088. csHashSet visible_things;
  1089. };
  1090. void* csSector::CheckFrustumPolygons (csSector*,
  1091. csPolygonInt** polygon, int num, void* data)
  1092. {
  1093. csPolygon3D* p;
  1094. CheckFrustData* fdata = (CheckFrustData*)data;
  1095. csFrustumView* lview = fdata->lview;
  1096. csVector3& center = lview->light_frustum->GetOrigin ();
  1097. int i, j;
  1098. for (i = 0 ; i < num ; i++)
  1099. {
  1100. p = (csPolygon3D*)polygon[i];
  1101. if (p->GetUnsplitPolygon ()) p = (csPolygon3D*)(p->GetUnsplitPolygon ());
  1102. csVector3 poly[50]; // @@@ HARDCODED! BAD!
  1103. for (j = 0 ; j < p->GetNumVertices () ; j++)
  1104. poly[j] = p->Vwor (j)-center;
  1105. if (p->GetPortal ())
  1106. {
  1107. lview->poly_func ((csObject*)p, lview);
  1108. }
  1109. else
  1110. {
  1111. //@@@ ONLY DO THIS WHEN QUADTREE IS USED!!!
  1112. //csEngine::current_engine->GetQuadcube ()->InsertPolygon (poly, p->GetNumVertices ());
  1113. lview->poly_func ((csObject*)p, lview);
  1114. }
  1115. }
  1116. return NULL;
  1117. }
  1118. //@@@ Needs to be part of sector?
  1119. void CompressShadowFrustums (csFrustumList* list)
  1120. {
  1121. csCBufferCube* cb = csEngine::current_engine->GetCBufCube ();
  1122. csCovcube* cc = csEngine::current_engine->GetCovcube ();
  1123. if (cb) cb->MakeEmpty ();
  1124. else cc->MakeEmpty ();
  1125. csShadowFrustum* sf = list->GetLast ();
  1126. csSector* cur_sector = NULL;
  1127. int cur_draw_busy = 0;
  1128. if (sf)
  1129. {
  1130. cur_sector = sf->sector;
  1131. cur_draw_busy = sf->draw_busy;
  1132. }
  1133. while (sf)
  1134. {
  1135. if (sf->sector != cur_sector || sf->draw_busy != cur_draw_busy)
  1136. break;
  1137. bool vis;
  1138. if (cb)
  1139. vis = cb->InsertPolygon (sf->GetVertices (), sf->GetNumVertices ());
  1140. else
  1141. vis = cc->InsertPolygon (sf->GetVertices (), sf->GetNumVertices ());
  1142. if (!vis)
  1143. {
  1144. csShadowFrustum* sfdel = sf;
  1145. sf = sf->prev;
  1146. list->Unlink (sfdel);
  1147. sfdel->DecRef ();
  1148. }
  1149. else
  1150. sf = sf->prev;
  1151. }
  1152. }
  1153. static int frust_cnt = 50;
  1154. //@@@ Needs to be part of sector?
  1155. void* CheckFrustumPolygonsFB (csSector* sector,
  1156. csPolygonInt** polygon, int num, bool /*same_plane*/, void* data)
  1157. {
  1158. csPolygon3D* p;
  1159. CheckFrustData* fdata = (CheckFrustData*)data;
  1160. csFrustumView* lview = fdata->lview;
  1161. csVector3& center = lview->light_frustum->GetOrigin ();
  1162. csCBufferCube* cb = csEngine::current_engine->GetCBufCube ();
  1163. csCovcube* cc = csEngine::current_engine->GetCovcube ();
  1164. bool cw = true; // @@@ Mirror flag?
  1165. int i, j;
  1166. for (i = 0 ; i < num ; i++)
  1167. {
  1168. csVector3 poly[128]; // @@@ HARDCODED! BAD!
  1169. if (polygon[i]->GetType () == 3)
  1170. {
  1171. // A BSP polygon. Used for testing visibility of things.
  1172. csBspPolygon* bsppol = (csBspPolygon*)polygon[i];
  1173. csObject* obj = bsppol->GetOriginator ();
  1174. if (obj->GetType () == csThing::Type)
  1175. {
  1176. csThing* th = (csThing*)obj;
  1177. if (!fdata->visible_things.In (th))
  1178. {
  1179. csPolyIndexed& pi = bsppol->GetPolygon ();
  1180. csPolyTreeBBox* pi_par = bsppol->GetParent ();
  1181. csVector3Array& verts = pi_par->GetVertices ();
  1182. for (j = 0 ; j < pi.GetNumVertices () ; j++)
  1183. poly[j] = verts[pi[j]]-center;
  1184. bool vis = false;
  1185. if (cb)
  1186. vis = cb->TestPolygon (poly, pi.GetNumVertices ());
  1187. else
  1188. vis = cc->TestPolygon (poly, pi.GetNumVertices ());
  1189. if (vis)
  1190. {
  1191. csFrustumList* shadows;
  1192. if (lview->things_shadow)
  1193. // The thing is visible and we want things to cast
  1194. // shadows. So we add all shadows generated by this
  1195. // thing to the shadow list.
  1196. if (th != sector->GetStaticThing ())
  1197. {
  1198. shadows = th->GetShadows (sector, center);
  1199. lview->shadows.AppendList (shadows);
  1200. delete shadows;
  1201. }
  1202. fdata->visible_things.AddNoTest (th);
  1203. }
  1204. }
  1205. }
  1206. continue;
  1207. }
  1208. if (polygon[i]->GetType () != 1) continue;
  1209. p = (csPolygon3D*)polygon[i];
  1210. for (j = 0 ; j < p->GetNumVertices () ; j++)
  1211. poly[j] = p->Vwor (j)-center;
  1212. bool vis = false;
  1213. float clas = p->GetPlane ()->GetWorldPlane ().Classify (center);
  1214. if (ABS (clas) < EPSILON) continue;
  1215. if ((clas <= 0) != cw) continue;
  1216. if (p->GetPortal ())
  1217. {
  1218. if (cb) vis = cb->TestPolygon (poly, p->GetNumVertices ());
  1219. else vis = cc->TestPolygon (poly, p->GetNumVertices ());
  1220. }
  1221. else
  1222. {
  1223. if (cb) vis = cb->InsertPolygon (poly, p->GetNumVertices ());
  1224. else vis = cc->InsertPolygon (poly, p->GetNumVertices ());
  1225. }
  1226. if (vis)
  1227. {
  1228. lview->poly_func ((csObject*)p, lview);
  1229. csShadowFrustum* frust;
  1230. frust = new csShadowFrustum (center);
  1231. csPlane3 pl = p->GetPlane ()->GetWorldPlane ();
  1232. pl.DD += center * pl.norm;
  1233. pl.Invert ();
  1234. frust->SetBackPlane (pl);
  1235. frust->polygon = p;
  1236. for (j = 0 ; j < p->GetVertices ().GetNumVertices () ; j++)
  1237. frust->AddVertex (p->Vwor (j)-center);
  1238. lview->shadows.AddLast (frust);
  1239. frust_cnt--;
  1240. if (frust_cnt < 0)
  1241. {
  1242. frust_cnt = 200;
  1243. CompressShadowFrustums (&(lview->shadows));
  1244. }
  1245. }
  1246. }
  1247. return NULL;
  1248. }
  1249. static int count_cull_dist;
  1250. static int count_cull_quad;
  1251. static int count_cull_not;
  1252. // @@@ This routine need to be cleaned up!!! It needs to
  1253. // be part of the class.
  1254. // @@@ This function needs to use the PVS. However, this function itself
  1255. // is used for the PVS so we need to take care!
  1256. bool CullOctreeNodeLighting (csPolygonTree* tree, csPolygonTreeNode* node,
  1257. const csVector3& /*pos*/, void* data)
  1258. {
  1259. if (!node) return false;
  1260. if (node->Type () != NODE_OCTREE) return true;
  1261. csOctree* otree = (csOctree*)tree;
  1262. csOctreeNode* onode = (csOctreeNode*)node;
  1263. csFrustumView* lview = (csFrustumView*)data;
  1264. const csVector3& center = lview->light_frustum->GetOrigin ();
  1265. csVector3 bmin = onode->GetMinCorner ()-center;
  1266. csVector3 bmax = onode->GetMaxCorner ()-center;
  1267. // Calculate the distance between (0,0,0) and the box.
  1268. csVector3 result (0,0,0);
  1269. if (bmin.x > 0) result.x = bmin.x;
  1270. else if (bmax.x < 0) result.x = -bmax.x;
  1271. if (bmin.y > 0) result.y = bmin.y;
  1272. else if (bmax.y < 0) result.y = -bmax.y;
  1273. if (bmin.z > 0) result.z = bmin.z;
  1274. else if (bmax.z < 0) result.z = -bmax.z;
  1275. float dist = result.Norm ();
  1276. float radius = lview->radius;
  1277. if (radius < dist)
  1278. {
  1279. count_cull_dist++;
  1280. return false;
  1281. }
  1282. if (ABS (dist) < EPSILON)
  1283. {
  1284. // We are in the node.
  1285. if (lview->node_func) lview->node_func (onode, lview);
  1286. return true;
  1287. }
  1288. // Test node against quad-tree.
  1289. csVector3 outline[6];
  1290. int num_outline;
  1291. otree->GetConvexOutline (onode, center, outline, num_outline);
  1292. if (num_outline > 0)
  1293. {
  1294. int i;
  1295. for (i = 0 ; i < num_outline ; i++)
  1296. outline[i] -= center;
  1297. csCBufferCube* cb = csEngine::current_engine->GetCBufCube ();
  1298. csCovcube* cc = csEngine::current_engine->GetCovcube ();
  1299. if (cb)
  1300. {
  1301. if (!cb->TestPolygon (outline, num_outline))
  1302. {
  1303. count_cull_quad++;
  1304. return false;
  1305. }
  1306. }
  1307. else if (cc && !cc->TestPolygon (outline, num_outline))
  1308. {
  1309. count_cull_quad++;
  1310. return false;
  1311. }
  1312. }
  1313. count_cull_not++;
  1314. if (lview->node_func) lview->node_func (onode, lview);
  1315. return true;
  1316. }
  1317. csThing** csSector::GetVisibleThings (csFrustumView& lview, int& num_things)
  1318. {
  1319. csFrustum* lf = lview.light_frustum;
  1320. bool infinite = lf->IsInfinite ();
  1321. csVector3& center = lf->GetOrigin ();
  1322. csPolygonSetBBox* bbox;
  1323. bool vis;
  1324. int i, i1;
  1325. int j;
  1326. num_things = things.Length ();
  1327. if (!num_things) { return NULL; }
  1328. csThing** visible_things = new csThing* [num_things];
  1329. num_things = 0;
  1330. for (j = 0 ; j < things.Length () ; j++)
  1331. {
  1332. csThing* sp = (csThing*)things[j];
  1333. // If the light frustum is infinite then every thing
  1334. // in this sector is of course visible.
  1335. if (infinite) vis = true;
  1336. else
  1337. {
  1338. bbox = sp->GetBoundingBox ();
  1339. if (bbox)
  1340. {
  1341. // If we have a bounding box then we can do a quick test to
  1342. // see if the bounding box is visible in the frustum. This
  1343. // test is not complete in the sense that it will say that
  1344. // some bounding boxes are visible even if they are not. But
  1345. // it is correct in the sense that if it says a bounding box
  1346. // is invisible, then it certainly is invisible.
  1347. //
  1348. // It works by taking all vertices of the bounding box. If
  1349. // ALL of them are on the outside of the same plane from the
  1350. // frustum then the object is certainly not visible.
  1351. vis = true;
  1352. i1 = lf->GetNumVertices ()-1;
  1353. for (i = 0 ; i < lf->GetNumVertices () ; i1 = i, i++)
  1354. {
  1355. csVector3& v1 = lf->GetVertex (i);
  1356. csVector3& v2 = lf->GetVertex (i1);
  1357. if (csMath3::WhichSide3D (sp->Vwor (bbox->i1)-center, v1, v2) < 0)
  1358. continue;
  1359. if (csMath3::WhichSide3D (sp->Vwor (bbox->i2)-center, v1, v2) < 0)
  1360. continue;
  1361. if (csMath3::WhichSide3D (sp->Vwor (bbox->i3)-center, v1, v2) < 0)
  1362. continue;
  1363. if (csMath3::WhichSide3D (sp->Vwor (bbox->i4)-center, v1, v2) < 0)
  1364. continue;
  1365. if (csMath3::WhichSide3D (sp->Vwor (bbox->i5)-center, v1, v2) < 0)
  1366. continue;
  1367. if (csMath3::WhichSide3D (sp->Vwor (bbox->i6)-center, v1, v2) < 0)
  1368. continue;
  1369. if (csMath3::WhichSide3D (sp->Vwor (bbox->i7)-center, v1, v2) < 0)
  1370. continue;
  1371. if (csMath3::WhichSide3D (sp->Vwor (bbox->i8)-center, v1, v2) < 0)
  1372. continue;
  1373. // Here we have a case of all vertices of the bbox being on the
  1374. // outside of the same plane.
  1375. vis = false;
  1376. break;
  1377. }
  1378. if (vis && lf->GetBackPlane ())
  1379. {
  1380. // If still visible then we can also check the back plane.
  1381. // @@@ NOTE THIS IS UNTESTED CODE. LIGHT_FRUSTUMS CURRENTLY DON'T
  1382. // HAVE A BACK PLANE YET.
  1383. if (!csMath3::Visible (sp->Vwor (bbox->i1)-center, *lf->GetBackPlane ()) &&
  1384. !csMath3::Visible (sp->Vwor (bbox->i2)-center, *lf->GetBackPlane ()) &&
  1385. !csMath3::Visible (sp->Vwor (bbox->i3)-center, *lf->GetBackPlane ()) &&
  1386. !csMath3::Visible (sp->Vwor (bbox->i4)-center, *lf->GetBackPlane ()) &&
  1387. !csMath3::Visible (sp->Vwor (bbox->i5)-center, *lf->GetBackPlane ()) &&
  1388. !csMath3::Visible (sp->Vwor (bbox->i6)-center, *lf->GetBackPlane ()) &&
  1389. !csMath3::Visible (sp->Vwor (bbox->i7)-center, *lf->GetBackPlane ()) &&
  1390. !csMath3::Visible (sp->Vwor (bbox->i8)-center, *lf->GetBackPlane ()))
  1391. vis = false;
  1392. }
  1393. }
  1394. else
  1395. {
  1396. CsPrintf (MSG_WARNING, "Bounding box for thing not found!\n");
  1397. vis = true;
  1398. }
  1399. }
  1400. if (vis) visible_things[num_things++] = sp;
  1401. }
  1402. return visible_things;
  1403. }
  1404. void csSector::CheckFrustum (csFrustumView& lview)
  1405. {
  1406. csCBufferCube* cb = engine->GetCBufCube ();
  1407. csCovcube* cc = engine->GetCovcube ();
  1408. if (cb) cb->MakeEmpty ();
  1409. else cc->MakeEmpty ();
  1410. RealCheckFrustum (lview);
  1411. }
  1412. void csSector::RealCheckFrustum (csFrustumView& lview)
  1413. {
  1414. if (draw_busy > cfg_reflections) return;
  1415. draw_busy++;
  1416. int i;
  1417. csThing* sp;
  1418. // Translate this sector so that it is oriented around
  1419. // the position of the light (position of the light becomes
  1420. // the new origin).
  1421. csVector3& center = lview.light_frustum->GetOrigin ();
  1422. // Check if gouraud shading needs to be updated.
  1423. if (light_frame_number != current_light_frame_number)
  1424. {
  1425. light_frame_number = current_light_frame_number;
  1426. lview.gouraud_color_reset = true;
  1427. }
  1428. else lview.gouraud_color_reset = false;
  1429. // Data for the polygon traversal routines that are called below.
  1430. CheckFrustData fdata;
  1431. fdata.lview = &lview;
  1432. // Remember the previous last shadow so that we can remove all
  1433. // shadows that are added in this routine.
  1434. csShadowFrustum* previous_last = lview.shadows.GetLast ();
  1435. // When doing lighting there are two big cases: either we
  1436. // have a static tree (octree) or not.
  1437. if (static_tree)
  1438. {
  1439. // If there is a static tree (BSP and/or octree) then we
  1440. // go front to back and add shadows to the list while we are doing
  1441. // that. In future I would like to add some extra culling stage
  1442. // here using a quad-tree or something similar (for example six
  1443. // quad-trees arranged in a cube around the light).
  1444. // All visible things will cause shadows to be added to 'lview'.
  1445. // Later on we'll restore these shadows.
  1446. count_cull_dist = 0;
  1447. count_cull_quad = 0;
  1448. count_cull_not = 0;
  1449. static_thing->UpdateTransformation (center);
  1450. frust_cnt = 50;
  1451. static_tree->Front2Back (center, CheckFrustumPolygonsFB, (void*)&fdata,
  1452. CullOctreeNodeLighting, (void*)&lview);
  1453. frust_cnt = 50;
  1454. CheckFrustumPolygonsFB (this, polygons.GetArray (),
  1455. polygons.Length (), false, (void*)&fdata);
  1456. // Calculate lighting for all things in this sector.
  1457. // The 'visible_things' hashset that is in fdata will contain
  1458. // all things that are found visible while traversing the octree.
  1459. // This queue is filled while traversing the octree
  1460. // (CheckFrustumPolygonsFB).
  1461. csHashIterator* it = fdata.visible_things.GetIterator ();
  1462. while (it->HasNext ())
  1463. {
  1464. sp = (csThing*)(it->Next ());
  1465. if (sp != static_thing)
  1466. sp->RealCheckFrustum (lview);
  1467. }
  1468. }
  1469. else
  1470. {
  1471. // Here we have no octree so we know the sector polygons are
  1472. // convex. First find all things that are visible in the frustum.
  1473. int num_visible_things;
  1474. csThing** visible_things = GetVisibleThings (lview, num_visible_things);
  1475. // Append the shadows for these things to the shadow list.
  1476. // This list is appended to the one given in 'lview'. After
  1477. // returning, the list in '…

Large files files are truncated, but you can click here to view the full file