OcclusionBuffer.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907
  1. //
  2. // Copyright (c) 2008-2013 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "Precompiled.h"
  23. #include "Camera.h"
  24. #include "Log.h"
  25. #include "OcclusionBuffer.h"
  26. #include <cstring>
  27. #include "DebugNew.h"
  28. namespace Urho3D
  29. {
  30. static const unsigned CLIPMASK_X_POS = 0x1;
  31. static const unsigned CLIPMASK_X_NEG = 0x2;
  32. static const unsigned CLIPMASK_Y_POS = 0x4;
  33. static const unsigned CLIPMASK_Y_NEG = 0x8;
  34. static const unsigned CLIPMASK_Z_POS = 0x10;
  35. static const unsigned CLIPMASK_Z_NEG = 0x20;
  36. OcclusionBuffer::OcclusionBuffer(Context* context) :
  37. Object(context),
  38. buffer_(0),
  39. width_(0),
  40. height_(0),
  41. numTriangles_(0),
  42. maxTriangles_(OCCLUSION_DEFAULT_MAX_TRIANGLES),
  43. cullMode_(CULL_CCW),
  44. depthHierarchyDirty_(true),
  45. nearClip_(0.0f),
  46. farClip_(0.0f)
  47. {
  48. }
  49. OcclusionBuffer::~OcclusionBuffer()
  50. {
  51. }
  52. bool OcclusionBuffer::SetSize(int width, int height)
  53. {
  54. // Force the height to an even amount of pixels for better mip generation
  55. if (height & 1)
  56. ++height;
  57. if (width == width_ && height == height_)
  58. return true;
  59. if (width <= 0 || height <= 0)
  60. return false;
  61. if (!IsPowerOfTwo(width))
  62. {
  63. LOGERROR("Width is not a power of two");
  64. return false;
  65. }
  66. width_ = width;
  67. height_ = height;
  68. // Reserve extra memory in case 3D clipping is not exact
  69. fullBuffer_ = new int[width * (height + 2) + 2];
  70. buffer_ = fullBuffer_.Get() + width + 1;
  71. mipBuffers_.Clear();
  72. // Build buffers for mip levels
  73. for (;;)
  74. {
  75. width = (width + 1) / 2;
  76. height = (height + 1) / 2;
  77. mipBuffers_.Push(SharedArrayPtr<DepthValue>(new DepthValue[width * height]));
  78. if (width <= OCCLUSION_MIN_SIZE && height <= OCCLUSION_MIN_SIZE)
  79. break;
  80. }
  81. LOGDEBUG("Set occlusion buffer size " + String(width_) + "x" + String(height_) + " with " +
  82. String(mipBuffers_.Size()) + " mip levels");
  83. CalculateViewport();
  84. return true;
  85. }
  86. void OcclusionBuffer::SetView(Camera* camera)
  87. {
  88. if (!camera)
  89. return;
  90. view_ = camera->GetView();
  91. projection_ = camera->GetProjection(false);
  92. viewProj_ = projection_ * view_;
  93. nearClip_ = camera->GetNearClip();
  94. farClip_ = camera->GetFarClip();
  95. CalculateViewport();
  96. }
  97. void OcclusionBuffer::SetMaxTriangles(unsigned triangles)
  98. {
  99. maxTriangles_ = triangles;
  100. }
  101. void OcclusionBuffer::SetCullMode(CullMode mode)
  102. {
  103. cullMode_ = mode;
  104. }
  105. void OcclusionBuffer::Reset()
  106. {
  107. numTriangles_ = 0;
  108. }
  109. void OcclusionBuffer::Clear()
  110. {
  111. if (!buffer_)
  112. return;
  113. Reset();
  114. int* dest = buffer_;
  115. int count = width_ * height_;
  116. while (count--)
  117. *dest++ = 0x7fffffff;
  118. depthHierarchyDirty_ = true;
  119. }
  120. bool OcclusionBuffer::Draw(const Matrix3x4& model, const void* vertexData, unsigned vertexSize, unsigned vertexStart, unsigned vertexCount)
  121. {
  122. const unsigned char* srcData = ((const unsigned char*)vertexData) + vertexStart * vertexSize;
  123. Matrix4 modelViewProj = viewProj_ * model;
  124. depthHierarchyDirty_ = true;
  125. // Theoretical max. amount of vertices if each of the 6 clipping planes doubles the triangle count
  126. Vector4 vertices[64 * 3];
  127. // 16-bit indices
  128. unsigned index = 0;
  129. while (index + 2 < vertexCount)
  130. {
  131. if (numTriangles_ >= maxTriangles_)
  132. return false;
  133. const Vector3& v0 = *((const Vector3*)(&srcData[index * vertexSize]));
  134. const Vector3& v1 = *((const Vector3*)(&srcData[(index + 1) * vertexSize]));
  135. const Vector3& v2 = *((const Vector3*)(&srcData[(index + 2) * vertexSize]));
  136. vertices[0] = ModelTransform(modelViewProj, v0);
  137. vertices[1] = ModelTransform(modelViewProj, v1);
  138. vertices[2] = ModelTransform(modelViewProj, v2);
  139. DrawTriangle(vertices);
  140. index += 3;
  141. }
  142. return true;
  143. }
  144. bool OcclusionBuffer::Draw(const Matrix3x4& model, const void* vertexData, unsigned vertexSize, const void* indexData,
  145. unsigned indexSize, unsigned indexStart, unsigned indexCount)
  146. {
  147. const unsigned char* srcData = (const unsigned char*)vertexData;
  148. Matrix4 modelViewProj = viewProj_ * model;
  149. depthHierarchyDirty_ = true;
  150. // Theoretical max. amount of vertices if each of the 6 clipping planes doubles the triangle count
  151. Vector4 vertices[64 * 3];
  152. // 16-bit indices
  153. if (indexSize == sizeof(unsigned short))
  154. {
  155. const unsigned short* indices = ((const unsigned short*)indexData) + indexStart;
  156. const unsigned short* indicesEnd = indices + indexCount;
  157. while (indices < indicesEnd)
  158. {
  159. if (numTriangles_ >= maxTriangles_)
  160. return false;
  161. const Vector3& v0 = *((const Vector3*)(&srcData[indices[0] * vertexSize]));
  162. const Vector3& v1 = *((const Vector3*)(&srcData[indices[1] * vertexSize]));
  163. const Vector3& v2 = *((const Vector3*)(&srcData[indices[2] * vertexSize]));
  164. vertices[0] = ModelTransform(modelViewProj, v0);
  165. vertices[1] = ModelTransform(modelViewProj, v1);
  166. vertices[2] = ModelTransform(modelViewProj, v2);
  167. DrawTriangle(vertices);
  168. indices += 3;
  169. }
  170. }
  171. else
  172. {
  173. const unsigned* indices = ((const unsigned*)indexData) + indexStart;
  174. const unsigned* indicesEnd = indices + indexCount;
  175. while (indices < indicesEnd)
  176. {
  177. if (numTriangles_ >= maxTriangles_)
  178. return false;
  179. const Vector3& v0 = *((const Vector3*)(&srcData[indices[0] * vertexSize]));
  180. const Vector3& v1 = *((const Vector3*)(&srcData[indices[1] * vertexSize]));
  181. const Vector3& v2 = *((const Vector3*)(&srcData[indices[2] * vertexSize]));
  182. vertices[0] = ModelTransform(modelViewProj, v0);
  183. vertices[1] = ModelTransform(modelViewProj, v1);
  184. vertices[2] = ModelTransform(modelViewProj, v2);
  185. DrawTriangle(vertices);
  186. indices += 3;
  187. }
  188. }
  189. return true;
  190. }
  191. void OcclusionBuffer::BuildDepthHierarchy()
  192. {
  193. if (!buffer_)
  194. return;
  195. // Build the first mip level from the pixel-level data
  196. int width = (width_ + 1) / 2;
  197. int height = (height_ + 1) / 2;
  198. if (mipBuffers_.Size())
  199. {
  200. for (int y = 0; y < height; ++y)
  201. {
  202. int* src = buffer_ + (y * 2) * width_;
  203. DepthValue* dest = mipBuffers_[0].Get() + y * width;
  204. DepthValue* end = dest + width;
  205. if (y * 2 + 1 < height_)
  206. {
  207. int* src2 = src + width_;
  208. while (dest < end)
  209. {
  210. int minUpper = Min(src[0], src[1]);
  211. int minLower = Min(src2[0], src2[1]);
  212. dest->min_ = Min(minUpper, minLower);
  213. int maxUpper = Max(src[0], src[1]);
  214. int maxLower = Max(src2[0], src2[1]);
  215. dest->max_ = Max(maxUpper, maxLower);
  216. src += 2;
  217. src2 += 2;
  218. ++dest;
  219. }
  220. }
  221. else
  222. {
  223. while (dest < end)
  224. {
  225. dest->min_ = Min(src[0], src[1]);
  226. dest->max_ = Max(src[0], src[1]);
  227. src += 2;
  228. ++dest;
  229. }
  230. }
  231. }
  232. }
  233. // Build the rest of the mip levels
  234. for (unsigned i = 1; i < mipBuffers_.Size(); ++i)
  235. {
  236. int prevWidth = width;
  237. int prevHeight = height;
  238. width = (width + 1) / 2;
  239. height = (height + 1) / 2;
  240. for (int y = 0; y < height; ++y)
  241. {
  242. DepthValue* src = mipBuffers_[i - 1].Get() + (y * 2) * prevWidth;
  243. DepthValue* dest = mipBuffers_[i].Get() + y * width;
  244. DepthValue* end = dest + width;
  245. if (y * 2 + 1 < prevHeight)
  246. {
  247. DepthValue* src2 = src + prevWidth;
  248. while (dest < end)
  249. {
  250. int minUpper = Min(src[0].min_, src[1].min_);
  251. int minLower = Min(src2[0].min_, src2[1].min_);
  252. dest->min_ = Min(minUpper, minLower);
  253. int maxUpper = Max(src[0].max_, src[1].max_);
  254. int maxLower = Max(src2[0].max_, src2[1].max_);
  255. dest->max_ = Max(maxUpper, maxLower);
  256. src += 2;
  257. src2 += 2;
  258. ++dest;
  259. }
  260. }
  261. else
  262. {
  263. while (dest < end)
  264. {
  265. dest->min_ = Min(src[0].min_, src[1].min_);
  266. dest->max_ = Max(src[0].max_, src[1].max_);
  267. src += 2;
  268. ++dest;
  269. }
  270. }
  271. }
  272. }
  273. depthHierarchyDirty_ = false;
  274. }
  275. void OcclusionBuffer::ResetUseTimer()
  276. {
  277. useTimer_.Reset();
  278. }
  279. bool OcclusionBuffer::IsVisible(const BoundingBox& worldSpaceBox) const
  280. {
  281. if (!buffer_)
  282. return true;
  283. // Transform corners to projection space
  284. Vector4 vertices[8];
  285. vertices[0] = ModelTransform(viewProj_, worldSpaceBox.min_);
  286. vertices[1] = ModelTransform(viewProj_, Vector3(worldSpaceBox.max_.x_, worldSpaceBox.min_.y_, worldSpaceBox.min_.z_));
  287. vertices[2] = ModelTransform(viewProj_, Vector3(worldSpaceBox.min_.x_, worldSpaceBox.max_.y_, worldSpaceBox.min_.z_));
  288. vertices[3] = ModelTransform(viewProj_, Vector3(worldSpaceBox.max_.x_, worldSpaceBox.max_.y_, worldSpaceBox.min_.z_));
  289. vertices[4] = ModelTransform(viewProj_, Vector3(worldSpaceBox.min_.x_, worldSpaceBox.min_.y_, worldSpaceBox.max_.z_));
  290. vertices[5] = ModelTransform(viewProj_, Vector3(worldSpaceBox.max_.x_, worldSpaceBox.min_.y_, worldSpaceBox.max_.z_));
  291. vertices[6] = ModelTransform(viewProj_, Vector3(worldSpaceBox.min_.x_, worldSpaceBox.max_.y_, worldSpaceBox.max_.z_));
  292. vertices[7] = ModelTransform(viewProj_, worldSpaceBox.max_);
  293. // Apply a far clip relative bias
  294. for (unsigned i = 0; i < 8; ++i)
  295. vertices[i].z_ -= OCCLUSION_RELATIVE_BIAS;
  296. // Transform to screen space. If any of the corners cross the near plane, assume visible
  297. float minX, maxX, minY, maxY, minZ;
  298. if (vertices[0].z_ <= 0.0f)
  299. return true;
  300. Vector3 projected = ViewportTransform(vertices[0]);
  301. minX = maxX = projected.x_;
  302. minY = maxY = projected.y_;
  303. minZ = projected.z_;
  304. // Project the rest
  305. for (unsigned i = 1; i < 8; ++i)
  306. {
  307. if (vertices[i].z_ <= 0.0f)
  308. return true;
  309. projected = ViewportTransform(vertices[i]);
  310. if (projected.x_ < minX) minX = projected.x_;
  311. if (projected.x_ > maxX) maxX = projected.x_;
  312. if (projected.y_ < minY) minY = projected.y_;
  313. if (projected.y_ > maxY) maxY = projected.y_;
  314. if (projected.z_ < minZ) minZ = projected.z_;
  315. }
  316. // Expand the bounding box 1 pixel in each direction to be conservative and correct rasterization offset
  317. IntRect rect(
  318. (int)(minX - 1.5f), (int)(minY - 1.5f),
  319. (int)(maxX + 0.5f), (int)(maxY + 0.5f)
  320. );
  321. // If the rect is outside, let frustum culling handle
  322. if (rect.right_ < 0 || rect.bottom_ < 0)
  323. return true;
  324. if (rect.left_ >= width_ || rect.top_ >= height_)
  325. return true;
  326. // Clipping of rect
  327. if (rect.left_ < 0)
  328. rect.left_ = 0;
  329. if (rect.top_ < 0)
  330. rect.top_ = 0;
  331. if (rect.right_ >= width_)
  332. rect.right_ = width_ - 1;
  333. if (rect.bottom_ >= height_)
  334. rect.bottom_ = height_ - 1;
  335. // Convert depth to integer and apply final bias
  336. int z = (int)(minZ + 0.5f) - OCCLUSION_FIXED_BIAS;
  337. if (!depthHierarchyDirty_)
  338. {
  339. // Start from lowest mip level and check if a conclusive result can be found
  340. for (int i = mipBuffers_.Size() - 1; i >= 0; --i)
  341. {
  342. int shift = i + 1;
  343. int width = width_ >> shift;
  344. int left = rect.left_ >> shift;
  345. int right = rect.right_ >> shift;
  346. DepthValue* buffer = mipBuffers_[i].Get();
  347. DepthValue* row = buffer + (rect.top_ >> shift) * width;
  348. DepthValue* endRow = buffer + (rect.bottom_ >> shift) * width;
  349. bool allOccluded = true;
  350. while (row <= endRow)
  351. {
  352. DepthValue* src = row + left;
  353. DepthValue* end = row + right;
  354. while (src <= end)
  355. {
  356. if (z <= src->min_)
  357. return true;
  358. if (z <= src->max_)
  359. allOccluded = false;
  360. ++src;
  361. }
  362. row += width;
  363. }
  364. if (allOccluded)
  365. return false;
  366. }
  367. }
  368. // If no conclusive result, finally check the pixel-level data
  369. int* row = buffer_ + rect.top_ * width_;
  370. int* endRow = buffer_ + rect.bottom_ * width_;
  371. while (row <= endRow)
  372. {
  373. int* src = row + rect.left_;
  374. int* end = row + rect.right_;
  375. while (src <= end)
  376. {
  377. if (z <= *src)
  378. return true;
  379. ++src;
  380. }
  381. row += width_;
  382. }
  383. return false;
  384. }
  385. unsigned OcclusionBuffer::GetUseTimer()
  386. {
  387. return useTimer_.GetMSec(false);
  388. }
  389. inline Vector4 OcclusionBuffer::ModelTransform(const Matrix4& transform, const Vector3& vertex) const
  390. {
  391. return Vector4(
  392. transform.m00_ * vertex.x_ + transform.m01_ * vertex.y_ + transform.m02_ * vertex.z_ + transform.m03_,
  393. transform.m10_ * vertex.x_ + transform.m11_ * vertex.y_ + transform.m12_ * vertex.z_ + transform.m13_,
  394. transform.m20_ * vertex.x_ + transform.m21_ * vertex.y_ + transform.m22_ * vertex.z_ + transform.m23_,
  395. transform.m30_ * vertex.x_ + transform.m31_ * vertex.y_ + transform.m32_ * vertex.z_ + transform.m33_
  396. );
  397. }
  398. inline Vector3 OcclusionBuffer::ViewportTransform(const Vector4& vertex) const
  399. {
  400. float invW = 1.0f / vertex.w_;
  401. return Vector3(
  402. invW * vertex.x_ * scaleX_ + offsetX_,
  403. invW * vertex.y_ * scaleY_ + offsetY_,
  404. invW * vertex.z_ * OCCLUSION_Z_SCALE
  405. );
  406. }
  407. inline Vector4 OcclusionBuffer::ClipEdge(const Vector4& v0, const Vector4& v1, float d0, float d1) const
  408. {
  409. float t = d0 / (d0 - d1);
  410. return v0 + t * (v1 - v0);
  411. }
  412. inline bool OcclusionBuffer::CheckFacing(const Vector3& v0, const Vector3& v1, const Vector3& v2) const
  413. {
  414. if (cullMode_ == CULL_NONE)
  415. return true;
  416. float aX = v0.x_ - v1.x_;
  417. float aY = v0.y_ - v1.y_;
  418. float bX = v2.x_ - v1.x_;
  419. float bY = v2.y_ - v1.y_;
  420. float signedArea = aX * bY - aY * bX;
  421. if (cullMode_ == CULL_CCW)
  422. return signedArea < 0.0f;
  423. else
  424. return signedArea > 0.0f;
  425. }
  426. void OcclusionBuffer::CalculateViewport()
  427. {
  428. // Add half pixel offset due to 3D frustum culling
  429. scaleX_ = 0.5f * width_;
  430. scaleY_ = -0.5f * height_;
  431. offsetX_ = 0.5f * width_ + 0.5f;
  432. offsetY_ = 0.5f * height_ + 0.5f;
  433. projOffsetScaleX_ = projection_.m00_ * scaleX_;
  434. projOffsetScaleY_ = projection_.m11_ * scaleY_;
  435. }
  436. void OcclusionBuffer::DrawTriangle(Vector4* vertices)
  437. {
  438. unsigned clipMask = 0;
  439. unsigned andClipMask = 0;
  440. bool drawOk = false;
  441. Vector3 projected[3];
  442. // Build the clip plane mask for the triangle
  443. for (unsigned i = 0; i < 3; ++i)
  444. {
  445. unsigned vertexClipMask = 0;
  446. if (vertices[i].x_ > vertices[i].w_)
  447. vertexClipMask |= CLIPMASK_X_POS;
  448. if (vertices[i].x_ < -vertices[i].w_)
  449. vertexClipMask |= CLIPMASK_X_NEG;
  450. if (vertices[i].y_ > vertices[i].w_)
  451. vertexClipMask |= CLIPMASK_Y_POS;
  452. if (vertices[i].y_ < -vertices[i].w_)
  453. vertexClipMask |= CLIPMASK_Y_NEG;
  454. if (vertices[i].z_ > vertices[i].w_)
  455. vertexClipMask |= CLIPMASK_Z_POS;
  456. if (vertices[i].z_ < 0.0f)
  457. vertexClipMask |= CLIPMASK_Z_NEG;
  458. clipMask |= vertexClipMask;
  459. if (!i)
  460. andClipMask = vertexClipMask;
  461. else
  462. andClipMask &= vertexClipMask;
  463. }
  464. // If triangle is fully behind any clip plane, can reject quickly
  465. if (andClipMask)
  466. return;
  467. // Check if triangle is fully inside
  468. if (!clipMask)
  469. {
  470. projected[0] = ViewportTransform(vertices[0]);
  471. projected[1] = ViewportTransform(vertices[1]);
  472. projected[2] = ViewportTransform(vertices[2]);
  473. if (CheckFacing(projected[0], projected[1], projected[2]))
  474. {
  475. DrawTriangle2D(projected);
  476. drawOk = true;
  477. }
  478. }
  479. else
  480. {
  481. bool triangles[64];
  482. // Initial triangle
  483. triangles[0] = true;
  484. unsigned numTriangles = 1;
  485. if (clipMask & CLIPMASK_X_POS)
  486. ClipVertices(Vector4(-1.0f, 0.0f, 0.0f, 1.0f), vertices, triangles, numTriangles);
  487. if (clipMask & CLIPMASK_X_NEG)
  488. ClipVertices(Vector4(1.0f, 0.0f, 0.0f, 1.0f), vertices, triangles, numTriangles);
  489. if (clipMask & CLIPMASK_Y_POS)
  490. ClipVertices(Vector4(0.0f, -1.0f, 0.0f, 1.0f), vertices, triangles, numTriangles);
  491. if (clipMask & CLIPMASK_Y_NEG)
  492. ClipVertices(Vector4(0.0f, 1.0f, 0.0f, 1.0f), vertices, triangles, numTriangles);
  493. if (clipMask & CLIPMASK_Z_POS)
  494. ClipVertices(Vector4(0.0f, 0.0f, -1.0f, 1.0f), vertices, triangles, numTriangles);
  495. if (clipMask & CLIPMASK_Z_NEG)
  496. ClipVertices(Vector4(0.0f, 0.0f, 1.0f, 0.0f), vertices, triangles, numTriangles);
  497. // Draw each accepted triangle
  498. for (unsigned i = 0; i < numTriangles; ++i)
  499. {
  500. if (triangles[i])
  501. {
  502. unsigned index = i * 3;
  503. projected[0] = ViewportTransform(vertices[index]);
  504. projected[1] = ViewportTransform(vertices[index + 1]);
  505. projected[2] = ViewportTransform(vertices[index + 2]);
  506. if (CheckFacing(projected[0], projected[1], projected[2]))
  507. {
  508. DrawTriangle2D(projected);
  509. drawOk = true;
  510. }
  511. }
  512. }
  513. }
  514. if (drawOk)
  515. ++numTriangles_;
  516. }
  517. void OcclusionBuffer::ClipVertices(const Vector4& plane, Vector4* vertices, bool* triangles, unsigned& numTriangles)
  518. {
  519. unsigned num = numTriangles;
  520. for (unsigned i = 0; i < num; ++i)
  521. {
  522. if (triangles[i])
  523. {
  524. unsigned index = i * 3;
  525. float d0 = plane.DotProduct(vertices[index]);
  526. float d1 = plane.DotProduct(vertices[index + 1]);
  527. float d2 = plane.DotProduct(vertices[index + 2]);
  528. // If all vertices behind the plane, reject triangle
  529. if (d0 < 0.0f && d1 < 0.0f && d2 < 0.0f)
  530. {
  531. triangles[i] = false;
  532. continue;
  533. }
  534. // If 2 vertices behind the plane, create a new triangle in-place
  535. else if (d0 < 0.0f && d1 < 0.0f)
  536. {
  537. vertices[index] = ClipEdge(vertices[index], vertices[index + 2], d0, d2);
  538. vertices[index + 1] = ClipEdge(vertices[index + 1], vertices[index + 2], d1, d2);
  539. }
  540. else if (d0 < 0.0f && d2 < 0.0f)
  541. {
  542. vertices[index] = ClipEdge(vertices[index], vertices[index + 1], d0, d1);
  543. vertices[index + 2] = ClipEdge(vertices[index + 2], vertices[index + 1], d2, d1);
  544. }
  545. else if (d1 < 0.0f && d2 < 0.0f)
  546. {
  547. vertices[index + 1] = ClipEdge(vertices[index + 1], vertices[index], d1, d0);
  548. vertices[index + 2] = ClipEdge(vertices[index + 2], vertices[index], d2, d0);
  549. }
  550. // 1 vertex behind the plane: create one new triangle, and modify one in-place
  551. else if (d0 < 0.0f)
  552. {
  553. unsigned newIdx = numTriangles * 3;
  554. triangles[numTriangles] = true;
  555. ++numTriangles;
  556. vertices[newIdx] = ClipEdge(vertices[index], vertices[index + 2], d0, d2);
  557. vertices[newIdx + 1] = vertices[index] = ClipEdge(vertices[index], vertices[index + 1], d0, d1);
  558. vertices[newIdx + 2] = vertices[index + 2];
  559. }
  560. else if (d1 < 0.0f)
  561. {
  562. unsigned newIdx = numTriangles * 3;
  563. triangles[numTriangles] = true;
  564. ++numTriangles;
  565. vertices[newIdx + 1] = ClipEdge(vertices[index + 1], vertices[index], d1, d0);
  566. vertices[newIdx + 2] = vertices[index + 1] = ClipEdge(vertices[index + 1], vertices[index + 2], d1, d2);
  567. vertices[newIdx] = vertices[index];
  568. }
  569. else if (d2 < 0.0f)
  570. {
  571. unsigned newIdx = numTriangles * 3;
  572. triangles[numTriangles] = true;
  573. ++numTriangles;
  574. vertices[newIdx + 2] = ClipEdge(vertices[index + 2], vertices[index + 1], d2, d1);
  575. vertices[newIdx] = vertices[index + 2] = ClipEdge(vertices[index + 2], vertices[index], d2, d0);
  576. vertices[newIdx + 1] = vertices[index + 1];
  577. }
  578. }
  579. }
  580. }
  581. // Code based on Chris Hecker's Perspective Texture Mapping series in the Game Developer magazine
  582. // Also available online at http://chrishecker.com/Miscellaneous_Technical_Articles
  583. /// %Gradients of a software rasterized triangle.
  584. struct Gradients
  585. {
  586. /// Construct from vertices.
  587. Gradients(const Vector3* vertices)
  588. {
  589. float invdX = 1.0f / (((vertices[1].x_ - vertices[2].x_) *
  590. (vertices[0].y_ - vertices[2].y_)) -
  591. ((vertices[0].x_ - vertices[2].x_) *
  592. (vertices[1].y_ - vertices[2].y_)));
  593. float invdY = -invdX;
  594. dInvZdX_ = invdX * (((vertices[1].z_ - vertices[2].z_) * (vertices[0].y_ - vertices[2].y_)) -
  595. ((vertices[0].z_ - vertices[2].z_) * (vertices[1].y_ - vertices[2].y_)));
  596. dInvZdY_ = invdY * (((vertices[1].z_ - vertices[2].z_) * (vertices[0].x_ - vertices[2].x_)) -
  597. ((vertices[0].z_ - vertices[2].z_) * (vertices[1].x_ - vertices[2].x_)));
  598. dInvZdXInt_ = (int)dInvZdX_;
  599. }
  600. /// Integer horizontal gradient.
  601. int dInvZdXInt_;
  602. /// Horizontal gradient.
  603. float dInvZdX_;
  604. /// Vertical gradient.
  605. float dInvZdY_;
  606. };
  607. /// %Edge of a software rasterized triangle.
  608. struct Edge
  609. {
  610. /// Construct from gradients and top & bottom vertices.
  611. Edge(const Gradients& gradients, const Vector3& top, const Vector3& bottom, int topY)
  612. {
  613. float slope = (bottom.x_ - top.x_) / (bottom.y_ - top.y_);
  614. float yPreStep = (float)(topY + 1) - top.y_;
  615. float xPreStep = slope * yPreStep;
  616. x_ = (int)((xPreStep + top.x_) * OCCLUSION_X_SCALE + 0.5f);
  617. xStep_ = (int)(slope * OCCLUSION_X_SCALE + 0.5f);
  618. invZ_ = (int)(top.z_ + xPreStep * gradients.dInvZdX_ + yPreStep * gradients.dInvZdY_ + 0.5f);
  619. invZStep_ = (int)(slope * gradients.dInvZdX_ + gradients.dInvZdY_ + 0.5f);
  620. }
  621. /// X coordinate.
  622. int x_;
  623. /// X coordinate step.
  624. int xStep_;
  625. /// Inverse Z.
  626. int invZ_;
  627. /// Inverse Z step.
  628. int invZStep_;
  629. };
  630. void OcclusionBuffer::DrawTriangle2D(const Vector3* vertices)
  631. {
  632. int top, middle, bottom;
  633. bool middleIsRight;
  634. // Sort vertices in Y-direction
  635. if (vertices[0].y_ < vertices[1].y_)
  636. {
  637. if (vertices[2].y_ < vertices[0].y_)
  638. {
  639. top = 2; middle = 0; bottom = 1;
  640. middleIsRight = true;
  641. }
  642. else
  643. {
  644. top = 0;
  645. if (vertices[1].y_ < vertices[2].y_)
  646. {
  647. middle = 1; bottom = 2;
  648. middleIsRight = true;
  649. }
  650. else
  651. {
  652. middle = 2; bottom = 1;
  653. middleIsRight = false;
  654. }
  655. }
  656. }
  657. else
  658. {
  659. if (vertices[2].y_ < vertices[1].y_)
  660. {
  661. top = 2; middle = 1; bottom = 0;
  662. middleIsRight = false;
  663. }
  664. else
  665. {
  666. top = 1;
  667. if (vertices[0].y_ < vertices[2].y_)
  668. {
  669. middle = 0; bottom = 2;
  670. middleIsRight = false;
  671. }
  672. else
  673. {
  674. middle = 2; bottom = 0;
  675. middleIsRight = true;
  676. }
  677. }
  678. }
  679. int topY = (int)vertices[top].y_;
  680. int middleY = (int)vertices[middle].y_;
  681. int bottomY = (int)vertices[bottom].y_;
  682. // Check for degenerate triangle
  683. if (topY == bottomY)
  684. return;
  685. Gradients gradients(vertices);
  686. Edge topToMiddle(gradients, vertices[top], vertices[middle], topY);
  687. Edge topToBottom(gradients, vertices[top], vertices[bottom], topY);
  688. Edge middleToBottom(gradients, vertices[middle], vertices[bottom], middleY);
  689. // The triangle is clockwise, so if bottom > middle then middle is right
  690. if (middleIsRight)
  691. {
  692. // Top half
  693. int* row = buffer_ + topY * width_;
  694. int* endRow = buffer_ + middleY * width_;
  695. while (row < endRow)
  696. {
  697. int invZ = topToBottom.invZ_;
  698. int* dest = row + (topToBottom.x_ >> 16);
  699. int* end = row + (topToMiddle.x_ >> 16);
  700. while (dest < end)
  701. {
  702. if (invZ < *dest)
  703. *dest = invZ;
  704. invZ += gradients.dInvZdXInt_;
  705. ++dest;
  706. }
  707. topToBottom.x_ += topToBottom.xStep_;
  708. topToBottom.invZ_ += topToBottom.invZStep_;
  709. topToMiddle.x_ += topToMiddle.xStep_;
  710. row += width_;
  711. }
  712. // Bottom half
  713. row = buffer_ + middleY * width_;
  714. endRow = buffer_ + bottomY * width_;
  715. while (row < endRow)
  716. {
  717. int invZ = topToBottom.invZ_;
  718. int* dest = row + (topToBottom.x_ >> 16);
  719. int* end = row + (middleToBottom.x_ >> 16);
  720. while (dest < end)
  721. {
  722. if (invZ < *dest)
  723. *dest = invZ;
  724. invZ += gradients.dInvZdXInt_;
  725. ++dest;
  726. }
  727. topToBottom.x_ += topToBottom.xStep_;
  728. topToBottom.invZ_ += topToBottom.invZStep_;
  729. middleToBottom.x_ += middleToBottom.xStep_;
  730. row += width_;
  731. }
  732. }
  733. else
  734. {
  735. // Top half
  736. int* row = buffer_ + topY * width_;
  737. int* endRow = buffer_ + middleY * width_;
  738. while (row < endRow)
  739. {
  740. int invZ = topToMiddle.invZ_;
  741. int* dest = row + (topToMiddle.x_ >> 16);
  742. int* end = row + (topToBottom.x_ >> 16);
  743. while (dest < end)
  744. {
  745. if (invZ < *dest)
  746. *dest = invZ;
  747. invZ += gradients.dInvZdXInt_;
  748. ++dest;
  749. }
  750. topToMiddle.x_ += topToMiddle.xStep_;
  751. topToMiddle.invZ_ += topToMiddle.invZStep_;
  752. topToBottom.x_ += topToBottom.xStep_;
  753. row += width_;
  754. }
  755. // Bottom half
  756. row = buffer_ + middleY * width_;
  757. endRow = buffer_ + bottomY * width_;
  758. while (row < endRow)
  759. {
  760. int invZ = middleToBottom.invZ_;
  761. int* dest = row + (middleToBottom.x_ >> 16);
  762. int* end = row + (topToBottom.x_ >> 16);
  763. while (dest < end)
  764. {
  765. if (invZ < *dest)
  766. *dest = invZ;
  767. invZ += gradients.dInvZdXInt_;
  768. ++dest;
  769. }
  770. middleToBottom.x_ += middleToBottom.xStep_;
  771. middleToBottom.invZ_ += middleToBottom.invZStep_;
  772. topToBottom.x_ += topToBottom.xStep_;
  773. row += width_;
  774. }
  775. }
  776. }
  777. }