OcclusionBuffer.cpp 30 KB

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