pipeline.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2016 RWS Inc, All Rights Reserved
  4. //
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of version 2 of the GNU General Public License as published by
  7. // the Free Software Foundation
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License along
  15. // with this program; if not, write to the Free Software Foundation, Inc.,
  16. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. //
  18. #include "System.h"
  19. #ifdef PATHS_IN_INCLUDES
  20. #include "GREEN/3D/pipeline.h"
  21. #else
  22. #include "pipeline.h"
  23. #endif
  24. ///////////////////////////////////////////////////////////////
  25. // This is the highest level considered actually part of the 3d engine.
  26. // It is the highest level control -> it decides how 3d pts map to 2d.
  27. // You can customize 3d efects by instantiating your own versions of the 3d pipeline!
  28. ///////////////////////////////////////////////////////////////
  29. // PIPELINE - History
  30. ///////////////////////////////////////////////////////////////
  31. //
  32. // 07/23/97 JRD Added support for generating shadows
  33. //
  34. ///////////////////////////////////////////////////////////////
  35. long RPipeLine::ms_lNumPts = 0;
  36. long RPipeLine::ms_lNumPipes = 0;
  37. RP3d* RPipeLine::ms_pPts = NULL;
  38. RPipeLine::RPipeLine()
  39. {
  40. ms_lNumPipes++; // Track for deletion purposes!
  41. Init();
  42. }
  43. void RPipeLine::Init()
  44. {
  45. m_pimClipBuf = NULL;
  46. m_pimShadowBuf = NULL;
  47. m_pZB = NULL;
  48. m_sUseBoundingRect = FALSE;
  49. m_dShadowScale = 1.0;
  50. m_tScreen.Make1();
  51. m_tView.Make1();
  52. m_tShadow.Make1();
  53. }
  54. // assume the clip rect is identical situation to zBUF:
  55. //
  56. short RPipeLine::Create(long lNum,short sW)
  57. {
  58. if (sW)
  59. {
  60. // Will only overwrite memory if it needs MORE!
  61. if ((m_pZB != NULL) && (sW > m_pZB->m_sW))
  62. {
  63. delete m_pZB;
  64. delete m_pimClipBuf;
  65. m_pimClipBuf = NULL;
  66. m_pZB = NULL;
  67. }
  68. if (m_pZB == NULL)
  69. {
  70. m_pZB = new RZBuffer(sW,sW); // no need to clear it yet!
  71. m_pimClipBuf = new RImage;
  72. // clear it when appropriate:
  73. m_pimClipBuf->CreateImage(sW,sW,RImage::BMP8);
  74. }
  75. }
  76. //----------
  77. if (!lNum) return 0;
  78. if ((ms_pPts != NULL) && (lNum > ms_lNumPts))
  79. {
  80. free(ms_pPts);
  81. ms_pPts = NULL;
  82. }
  83. if (ms_pPts == NULL)
  84. {
  85. ms_pPts = (RP3d*) malloc(sizeof(RP3d) * lNum);
  86. }
  87. return 0;
  88. }
  89. short RPipeLine::CreateShadow(short sAngleY,
  90. double dTanDeclension,short sBufSize)
  91. {
  92. ASSERT( (sAngleY >=0 ) && (sAngleY < 360) );
  93. ASSERT(dTanDeclension > 0.0);
  94. // Create the shadow transform:
  95. m_tShadow.Make1();
  96. m_dShadowScale = dTanDeclension;
  97. m_tShadow.T[1 + ROW0] = m_dShadowScale * rspCos(sAngleY);
  98. m_tShadow.T[1 + ROW1] = 0.0;
  99. m_tShadow.T[1 + ROW2] = m_dShadowScale * rspSin(sAngleY);
  100. // Allocate the buffer, if applicable:
  101. if (sBufSize <= 0) // default case:
  102. {
  103. if (m_pimShadowBuf == NULL) // do a default allocation
  104. {
  105. if (m_pimClipBuf) // use as reference:
  106. {
  107. m_pimShadowBuf = new RImage;
  108. m_pimShadowBuf->CreateImage(
  109. m_pimClipBuf->m_sWidth * 2,
  110. m_pimClipBuf->m_sWidth * 2,
  111. RImage::BMP8);
  112. return SUCCESS;
  113. }
  114. TRACE("RPipeLine::CreateShadow: warning - no buffer set!\n");
  115. return SUCCESS;
  116. }
  117. else
  118. {
  119. // No allocatione needed
  120. return SUCCESS;
  121. }
  122. }
  123. else // specified buffer size:
  124. {
  125. if (m_pimShadowBuf)
  126. {
  127. if (m_pimShadowBuf->m_sWidth >= sBufSize)
  128. {
  129. return SUCCESS; // don't need to expand it
  130. }
  131. else
  132. {
  133. delete m_pimShadowBuf;
  134. m_pimShadowBuf = NULL;
  135. }
  136. }
  137. m_pimShadowBuf = new RImage;
  138. m_pimShadowBuf->CreateImage(sBufSize,sBufSize,RImage::BMP8);
  139. }
  140. return SUCCESS;
  141. }
  142. void RPipeLine::Destroy()
  143. {
  144. if (m_pZB) delete m_pZB;
  145. if (m_pimClipBuf) delete m_pimClipBuf;
  146. if (m_pimShadowBuf) delete m_pimShadowBuf;
  147. }
  148. RPipeLine::~RPipeLine()
  149. {
  150. Destroy();
  151. ms_lNumPipes--; // prepare for full death:
  152. if (!ms_lNumPipes) // free ms_pPts
  153. {
  154. if (ms_pPts) free(ms_pPts);
  155. ms_lNumPts = 0;
  156. ms_pPts = NULL;
  157. }
  158. }
  159. void RPipeLine::Transform(RSop* pPts,RTransform& tObj)
  160. {
  161. RTransform tFull;
  162. long i;
  163. // Use to stretch to z-buffer!
  164. tFull.Make1();
  165. tFull.Mul(m_tView.T,tObj.T);
  166. // If there were inhomogeneous transforms, you would need to
  167. // trasnform each pt by two transforms separately!
  168. tFull.PreMulBy(m_tScreen.T);
  169. for (i = 0; i < pPts->m_lNum; i++)
  170. {
  171. tFull.TransformInto(pPts->m_pArray[i],ms_pPts[i]);
  172. // Note that you can now use RP3d directly with the renderers!
  173. }
  174. }
  175. // Need to create a slightly more complex pipe:
  176. void RPipeLine::TransformShadow(RSop* pPts,RTransform& tObj,
  177. short sHeight,short *psOffX,short *psOffY)
  178. {
  179. ASSERT(m_pimShadowBuf);
  180. RTransform tFull;
  181. long i;
  182. // Use to stretch to z-buffer!
  183. tFull.Make1();
  184. // 1) Create Shadow
  185. tFull.Mul(m_tShadow.T,tObj.T);
  186. // 2) Add in normal view
  187. tFull.PreMulBy(m_tView.T);
  188. // If there were inhomogeneous transforms, you would need to
  189. // trasnform each pt by two transforms separately!
  190. if (psOffX || psOffY) // calculate shadow offset
  191. {
  192. // (1) convert to 3d shadow point:
  193. RP3d pOffset = {0.0,static_cast<float>(sHeight),0.0,};
  194. double dOffX = sHeight * m_tShadow.T[ROW0 + 1];
  195. double dOffY = 0.0;
  196. double dOffZ = sHeight * m_tShadow.T[ROW2 + 1]; // y is height here
  197. // (2) partially project
  198. m_tShadow.Transform(pOffset);
  199. m_tView.Transform(pOffset);
  200. // Undo randy slide:
  201. RP3d pTemp = {m_tView.T[3 + ROW0],m_tView.T[3 + ROW1],
  202. m_tView.T[3 + ROW2]};
  203. rspSub(pOffset,pTemp);
  204. // Just use screen for scale:
  205. pOffset.x *= m_tScreen.T[0 + ROW0];
  206. pOffset.y *= m_tScreen.T[1 + ROW1];
  207. // store result
  208. *psOffX = short (pOffset.x);
  209. *psOffY = short (pOffset.y);
  210. }
  211. // 3) Project to the "screen"
  212. tFull.PreMulBy(m_tScreen.T);
  213. // 4) Adjust the screen transform to keep scaling and mirroring
  214. // from normal screen transform, but adjust size for shadow buffer
  215. // This is hard coded to the postal coordinate system
  216. tFull.Trans(0.0,m_pimShadowBuf->m_sHeight-m_tScreen.T[3 + ROW1],0.0);
  217. for (i = 0; i < pPts->m_lNum; i++)
  218. {
  219. tFull.TransformInto(pPts->m_pArray[i],ms_pPts[i]);
  220. // Note that you can now use RP3d directly with the renderers!
  221. }
  222. }
  223. // returns 0 if pts are ClockWise! (Hidden)
  224. // (to be used AFTER the view or screen transformation)
  225. short RPipeLine::NotCulled(RP3d *p1,RP3d *p2,RP3d *p3)
  226. {
  227. REAL ax,ay,bx,by;
  228. ax = p2->x - p1->x;
  229. ay = p2->y - p1->y;
  230. bx = p3->x - p1->x;
  231. by = p3->y - p1->y;
  232. if ( (ax*by - ay*bx) >= 0) return 0;
  233. else return 1;
  234. }
  235. // Currently (sDstX,sDstY) allgns with the upper left half of the z-buffer
  236. // Uses the static transformed point buffer.
  237. //
  238. void RPipeLine::Render(RImage* pimDst,short sDstX,short sDstY,
  239. RMesh* pMesh,UCHAR ucColor) // wire!
  240. {
  241. long i;
  242. long v1,v2,v3;
  243. USHORT *psVertex = pMesh->m_pArray;
  244. long lNumHidden = 0;
  245. for (i=0;i < pMesh->m_sNum; i++)
  246. {
  247. v1 = *psVertex++;
  248. v2 = *psVertex++;
  249. v3 = *psVertex++;
  250. if (NotCulled(ms_pPts+v1,ms_pPts+v2,ms_pPts+v3))
  251. {
  252. // Render the sucker!
  253. DrawTri_wire(pimDst,sDstX,sDstY,
  254. ms_pPts+v1,ms_pPts+v2,ms_pPts+v3,ucColor);
  255. }
  256. else
  257. {
  258. lNumHidden++; // cull debug
  259. }
  260. }
  261. //TRACE("Number culled was %ld\n",lNumHidden);
  262. }
  263. // Currently (sDstX,sDstY) allgns with the upper left half of the z-buffer
  264. // Uses the static transformed point buffer.
  265. //
  266. void RPipeLine::RenderShadow(RImage* pimDst,RMesh* pMesh,UCHAR ucColor)
  267. {
  268. long i;
  269. long v1,v2,v3;
  270. USHORT *psVertex = pMesh->m_pArray;
  271. for (i=0;i < pMesh->m_sNum; i++)
  272. {
  273. v1 = *psVertex++;
  274. v2 = *psVertex++;
  275. v3 = *psVertex++;
  276. if (NotCulled(ms_pPts+v1,ms_pPts+v2,ms_pPts+v3))
  277. {
  278. // Render the sucker!
  279. DrawTri(pimDst->m_pData,pimDst->m_lPitch,
  280. ms_pPts+v1,ms_pPts+v2,ms_pPts+v3,ucColor);
  281. }
  282. }
  283. }
  284. // YOU clear the z-buffer before this if you so desire!!!
  285. // Currently (sDstX,sDstY) allgns with the upper left half of the z-buffer
  286. // Uses the static transformed point buffer.
  287. //
  288. void RPipeLine::Render(RImage* pimDst,short sDstX,short sDstY,
  289. RMesh* pMesh,RZBuffer* pZB,RTexture* pTexColors,
  290. short sFogOffset,RAlpha* pAlpha,
  291. short sOffsetX/* = 0*/, // In: 2D offset for pimDst and pZB.
  292. short sOffsetY/* = 0*/) // In: 2D offset for pimDst and pZB.
  293. {
  294. long i;
  295. long v1,v2,v3;
  296. USHORT *psVertex = pMesh->m_pArray;
  297. UCHAR *pColor = pTexColors->m_pIndices;
  298. long lDstP = pimDst->m_lPitch;
  299. UCHAR* pDst = pimDst->m_pData + (sDstX + sOffsetX) + lDstP * (sDstY + sOffsetY);
  300. for (i=0;i < pMesh->m_sNum; i++,pColor++)
  301. {
  302. v1 = *psVertex++;
  303. v2 = *psVertex++;
  304. v3 = *psVertex++;
  305. if (1)//NotCulled(ms_pPts+v1,ms_pPts+v2,ms_pPts+v3))
  306. {
  307. // Render the sucker!
  308. DrawTri_ZColorFog(pDst,lDstP,
  309. ms_pPts+v1,ms_pPts+v2,ms_pPts+v3,pZB,
  310. pAlpha->m_pAlphas[*pColor] + sFogOffset,
  311. sOffsetX, // In: 2D offset for pZB.
  312. sOffsetY); // In: 2D offset for pZB.
  313. }
  314. }
  315. }
  316. // YOU clear the z-buffer before this if you so desire!!!
  317. // Currently (sDstX,sDstY) allgns with the upper left half of the z-buffer
  318. // FLAT SHADE MODE
  319. //
  320. void RPipeLine::Render(RImage* pimDst,short sDstX,short sDstY,
  321. RMesh* pMesh,RZBuffer* pZB,RTexture* pTexColors,
  322. short sOffsetX/* = 0*/, // In: 2D offset for pimDst and pZB.
  323. short sOffsetY/* = 0*/) // In: 2D offset for pimDst and pZB.
  324. {
  325. long i;
  326. long v1,v2,v3;
  327. USHORT *psVertex = pMesh->m_pArray;
  328. UCHAR *pColor = pTexColors->m_pIndices;
  329. long lDstP = pimDst->m_lPitch;
  330. UCHAR* pDst = pimDst->m_pData + (sDstX + sOffsetX) + lDstP * (sDstY + sOffsetY);
  331. for (i=0;i < pMesh->m_sNum; i++,pColor++)
  332. {
  333. v1 = *psVertex++;
  334. v2 = *psVertex++;
  335. v3 = *psVertex++;
  336. if (NotCulled(ms_pPts+v1,ms_pPts+v2,ms_pPts+v3))
  337. {
  338. // Render the sucker!
  339. DrawTri_ZColor(pDst,lDstP,
  340. ms_pPts+v1,ms_pPts+v2,ms_pPts+v3,pZB,
  341. *pColor,
  342. sOffsetX, // In: 2D offset for pZB.
  343. sOffsetY); // In: 2D offset for pZB.
  344. }
  345. }
  346. }
  347. // THIS IS HACKED! WILL NOT WORK WITH DISTORTED GUYS!
  348. //
  349. void RPipeLine::BoundingSphereToScreen(RP3d& ptCenter, RP3d& ptRadius,
  350. RTransform& tObj)
  351. {
  352. // THIS IS HARD WIRED TO WORK WITH OUR CURRENT STYLE OF
  353. // PROJECTION:
  354. RTransform tFull;
  355. tFull.Make1();
  356. tFull.Mul(m_tView.T,tObj.T); // hold off on screen -> get raw distance:
  357. tFull.PreMulBy(m_tScreen.T);
  358. // THIS IS IN UNSCALED OBJECT VIEW
  359. double dModelRadius = sqrt(
  360. SQR(ptCenter.x - ptRadius.x) +
  361. SQR(ptCenter.y - ptRadius.y) +
  362. SQR(ptCenter.z - ptRadius.z) ); // Randy Units
  363. // Convert from Model To Screen...
  364. double dScreenRadius = dModelRadius * m_tScreen.T[0];
  365. // Project the center onto the screen:
  366. RP3d ptCen/*,ptEnd*/;
  367. tFull.TransformInto(ptCenter,ptCen); // z is now distorted
  368. // store in pieline variables...(ALL OF THEM)
  369. m_sCenX = short(ptCen.x);
  370. m_sCenY = short(ptCen.y);
  371. m_sCenZ = short(ptCen.z / 256.0); // Scale Z's by 256 for lighting later
  372. short sScreenRadius = short(dScreenRadius+1);
  373. m_sX = m_sCenX - sScreenRadius;
  374. m_sY = m_sCenY - sScreenRadius;
  375. m_sZ = m_sCenZ - sScreenRadius;
  376. m_sW = m_sH = (sScreenRadius * 2.);
  377. m_sD = (sScreenRadius * 2.);
  378. m_sUseBoundingRect = TRUE;
  379. }
  380. void RPipeLine::ClearClipBuffer()
  381. {
  382. if (m_pimClipBuf == NULL) return;
  383. rspRect(ULONG(0),m_pimClipBuf,0,0,
  384. m_pimClipBuf->m_sWidth,m_pimClipBuf->m_sHeight);
  385. }
  386. void RPipeLine::ClearShadowBuffer()
  387. {
  388. if (m_pimShadowBuf == NULL) return;
  389. rspRect(ULONG(0),m_pimShadowBuf,0,0,
  390. m_pimShadowBuf->m_sWidth,m_pimShadowBuf->m_sHeight);
  391. }