PageRenderTime 51ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/ucf/ucfDxRenderImpl.cpp

https://bitbucket.org/xg/ucf
C++ | 457 lines | 350 code | 93 blank | 14 comment | 35 complexity | bc00194eb7a1107b05fbc9a8df27d72a MD5 | raw file
  1. #include "ucfDxRenderImpl.h"
  2. #include "ucfDxTextureImpl.h"
  3. #include "ucfWinAppImpl.h"
  4. IDirect3DDevice9Ptr g_device;
  5. // ----------------------------------------------------------------------------
  6. // ucfRenderImpl
  7. ucfRenderImpl::ucfRenderImpl() : frameDelay(0), isDrawing(false)
  8. {
  9. }
  10. ucfRenderImpl::~ucfRenderImpl()
  11. {
  12. }
  13. void ucfRenderImpl::createD3D()
  14. {
  15. if (d3d9 != NULL || g_appImpl->hwnd == NULL)
  16. return; // already initialised, or not initialised enough.
  17. if( NULL == ( d3d9 = Direct3DCreate9( D3D_SDK_VERSION ) ) )
  18. throw "Direct3DCreate9 failed";
  19. D3DPRESENT_PARAMETERS d3dpp;
  20. ZeroMemory( &d3dpp, sizeof(d3dpp) );
  21. d3dpp.Windowed = screenMode != RenderFullscreen ? TRUE : FALSE;
  22. d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
  23. d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
  24. d3dpp.EnableAutoDepthStencil = TRUE;
  25. d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
  26. g_appImpl->resizeWindow(screenSize);
  27. DX_THROW(d3d9->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_appImpl->hwnd,
  28. D3DCREATE_HARDWARE_VERTEXPROCESSING,
  29. &d3dpp, &device));
  30. DX_THROW(D3DXCreateMatrixStack(0, &matrixStack));
  31. D3DXMATRIX projMat;
  32. D3DXMatrixOrthoOffCenterLH(&projMat, 0, float(screenSize.x), float(screenSize.y), 0, 0.0f, 1.0f);
  33. device->SetTransform(D3DTS_PROJECTION, &projMat);
  34. device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
  35. device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
  36. device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
  37. device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
  38. device->SetRenderState(D3DRS_LIGHTING, FALSE);
  39. device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
  40. device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
  41. device->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_TEXTURE);
  42. preDraw();
  43. g_device = device; // handy global, probably a bad idea long term.
  44. }
  45. void ucfRenderImpl::destroyD3D()
  46. {
  47. if (device)
  48. device.Release();
  49. if (d3d9)
  50. d3d9.Release();
  51. }
  52. void ucfRenderImpl::postSetup()
  53. {
  54. if (isDrawing)
  55. postDraw();
  56. else
  57. createD3D();
  58. }
  59. void ucfRenderImpl::postShutdown()
  60. {
  61. destroyD3D();
  62. }
  63. void ucfRenderImpl::preDraw()
  64. {
  65. frameStartTime = clock();
  66. // FIXME: doesn't deal with stack leaks
  67. // Each frame starts with the identity matrix.
  68. matrixStack->LoadIdentity();
  69. DX_THROW(device->BeginScene());
  70. isDrawing = true;
  71. }
  72. void ucfRenderImpl::postDraw()
  73. {
  74. isDrawing = false;
  75. DX_THROW(device->EndScene());
  76. // Frame delay logic. FIXME: Not particularly accurate wrt wall clock time.
  77. clock_t endTime = clock();
  78. double elapsed = double(endTime - frameStartTime) / CLOCKS_PER_SEC;
  79. double required = frameDelay / 1000.f;
  80. int delay = int((required - elapsed) * 1000);
  81. if (delay > 0)
  82. Sleep(delay);
  83. DX_THROW(device->Present( NULL, NULL, NULL, NULL ));
  84. }
  85. // ----------------------------------------------------------------------------
  86. // API Support.
  87. void ucfRenderImpl::size(const TVec<int>& sz, ucfRenderMode mode)
  88. {
  89. screenSize = sz;
  90. screenMode = mode;
  91. createD3D();
  92. }
  93. void ucfRenderImpl::clear(const ucfColor& c)
  94. {
  95. DX_THROW(device->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOL(c), 1.0f, 0 ));
  96. }
  97. struct CUSTOMVERTEX
  98. {
  99. CUSTOMVERTEX() { }
  100. CUSTOMVERTEX(float _x, float _y, float _z, DWORD _col) : x(_x), y(_y), z(_z), color(_col) { }
  101. CUSTOMVERTEX(const Vec &v, const ucfColor &col) : x(v.x), y(v.y), z(v.z), color(D3DCOL(col)) { }
  102. FLOAT x, y, z; // The position for the vertex.
  103. DWORD color; // The vertex color.
  104. };
  105. #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)
  106. struct CUSTOMVERTEX_UV
  107. {
  108. CUSTOMVERTEX_UV() { }
  109. CUSTOMVERTEX_UV(float _x, float _y, float _z, DWORD _col, float _u, float _v) : x(_x), y(_y), z(_z), color(_col), u(_u), v(_v) { }
  110. CUSTOMVERTEX_UV(const Vec &v, const ucfColor &col, const Vec &uv) : x(v.x), y(v.y), z(v.z), color(D3DCOL(col)), u(uv.x), v(uv.y) { }
  111. FLOAT x, y, z; // The position for the vertex.
  112. DWORD color; // The vertex color.
  113. FLOAT u, v; // Gosh! What could these be?
  114. };
  115. #define D3DFVF_CUSTOMVERTEX_UV (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
  116. void ucfRenderImpl::point(const Vec& pt, const ucfColor& c)
  117. {
  118. DX_THROW(device->SetTransform(D3DTS_WORLDMATRIX(0), matrixStack->GetTop()));
  119. CUSTOMVERTEX vtx(pt, c);
  120. DX_THROW(device->SetFVF( D3DFVF_CUSTOMVERTEX ));
  121. DX_THROW(device->DrawPrimitiveUP(D3DPT_POINTLIST, 1, &vtx, sizeof(CUSTOMVERTEX)));
  122. }
  123. static inline Vec calcWidthVec(const Vec * const vts, const int nVts, bool loop, const int i)
  124. {
  125. int i0 = i-1;
  126. int i1 = i;
  127. int i2 = i+1;
  128. bool mitre = true;
  129. if (i == 0)
  130. {
  131. if (loop)
  132. {
  133. i0 = nVts-1;
  134. i1 = 0;
  135. i2 = 1;
  136. }
  137. else
  138. {
  139. i0 = 0;
  140. i1 = 1;
  141. mitre = false;
  142. }
  143. }
  144. else if (i == nVts-1)
  145. {
  146. if (loop)
  147. {
  148. i0 = nVts-2;
  149. i1 = nVts-1;
  150. i2 = 0;
  151. }
  152. else
  153. {
  154. i0 = nVts-2;
  155. i1 = nVts-1;
  156. mitre = false;
  157. }
  158. }
  159. Vec v1 = (vts[i1] - vts[i0]).norm();
  160. Vec p(0, 0, 1);
  161. Vec n = v1.cross(p);
  162. if (mitre)
  163. {
  164. Vec v2 = (vts[i2] - vts[i1]).norm();
  165. Vec m = (v1 - v2) / 2.f;
  166. float md = 1.f / n.dot(m);
  167. return m * md;
  168. }
  169. else
  170. {
  171. return n;
  172. }
  173. }
  174. void ucfRenderImpl::lineStrip(const Vec * const vts, const int nVts, const ucfColor &c, float width, bool loop)
  175. {
  176. assert(nVts > 1);
  177. int nTriVerts = nVts*2 + (loop ? 2 : 0);
  178. CUSTOMVERTEX *vertices = new CUSTOMVERTEX [nTriVerts];
  179. int vIndex = 0;
  180. for (int i = 0 ; i < nVts ; ++i)
  181. {
  182. Vec n = calcWidthVec(vts, nVts, loop, i);
  183. Vec r = n * (width/2);
  184. vertices[vIndex++] = CUSTOMVERTEX(vts[i] - r, c);
  185. vertices[vIndex++] = CUSTOMVERTEX(vts[i] + r, c);
  186. }
  187. if (loop)
  188. {
  189. Vec n = calcWidthVec(vts, nVts, loop, 0);
  190. Vec r = n * (width/2);
  191. vertices[vIndex++] = CUSTOMVERTEX(vts[0] - r, c);
  192. vertices[vIndex++] = CUSTOMVERTEX(vts[0] + r, c);
  193. }
  194. DX_THROW(device->SetTransform(D3DTS_WORLDMATRIX(0), matrixStack->GetTop()));
  195. DX_THROW(device->SetFVF( D3DFVF_CUSTOMVERTEX ));
  196. DX_THROW(device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, nTriVerts-2, vertices, sizeof(CUSTOMVERTEX)));
  197. delete vertices;
  198. }
  199. void ucfRenderImpl::poly(const Vec * const vts, const int nVts, bool joinUp, const ucfColor &fillCol, const ucfColor &strokeCol, float strokeWidth)
  200. {
  201. if (fillCol.a > 0)
  202. {
  203. int extra = joinUp ? 1 : 0;
  204. CUSTOMVERTEX *vertices = new CUSTOMVERTEX [nVts + 1];
  205. int i;
  206. for (i = 0 ; i < nVts ; ++i)
  207. {
  208. vertices[i] = CUSTOMVERTEX(vts[i], fillCol);
  209. }
  210. vertices[i] = CUSTOMVERTEX(vts[0], fillCol);
  211. DX_THROW(device->SetTransform(D3DTS_WORLDMATRIX(0), matrixStack->GetTop()));
  212. DX_THROW(device->SetFVF( D3DFVF_CUSTOMVERTEX ));
  213. // create a stencil for the areas of the possibly convex poly we're drawing.
  214. DX_THROW(device->SetRenderState(D3DRS_STENCILENABLE, TRUE));
  215. DX_THROW(device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS));
  216. DX_THROW(device->SetRenderState(D3DRS_STENCILMASK, 1));
  217. DX_THROW(device->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INVERT));
  218. DX_THROW(device->SetRenderState(D3DRS_COLORWRITEENABLE, 0));
  219. DX_THROW(device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE));
  220. //DX_THROW(device->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 0, 0)); // at the moment, clearing isn't necessary, as it's done during other calls. this is a hack?
  221. DX_THROW(device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, nVts+1-2, vertices, sizeof(CUSTOMVERTEX)));
  222. // use the stencil to draw to the convex poly. clear the stencil at the same time.
  223. DX_THROW(device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL));
  224. DX_THROW(device->SetRenderState(D3DRS_STENCILREF, 1));
  225. DX_THROW(device->SetRenderState(D3DRS_STENCILMASK, 1));
  226. DX_THROW(device->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_ZERO)); // clear while drawing.
  227. DX_THROW(device->SetRenderState(D3DRS_COLORWRITEENABLE, -1));
  228. DX_THROW(device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE));
  229. DX_THROW(device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, nVts+1-2, vertices, sizeof(CUSTOMVERTEX)));
  230. DX_THROW(device->SetRenderState(D3DRS_STENCILENABLE, FALSE));
  231. delete vertices;
  232. }
  233. if (strokeCol.a > 0)
  234. {
  235. lineStrip(vts, nVts, strokeCol, strokeWidth, joinUp);
  236. }
  237. }
  238. void ucfRenderImpl::triStrip(const Vec *const vts, const int nVts, const ucfColor &fillCol, const ucfColor &strokeCol)
  239. {
  240. DX_THROW(device->SetFVF(D3DFVF_CUSTOMVERTEX));
  241. DX_THROW(device->SetTransform(D3DTS_WORLDMATRIX(0), matrixStack->GetTop()));
  242. if (fillCol.a > 0)
  243. {
  244. CUSTOMVERTEX *vertices = new CUSTOMVERTEX [nVts];
  245. D3DCOLOR col = D3DCOL(fillCol);
  246. for (int i = 0 ; i < nVts ; ++i)
  247. {
  248. vertices[i] = CUSTOMVERTEX(vts[i], fillCol);
  249. }
  250. DX_THROW(device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, nVts-2, vertices, sizeof(CUSTOMVERTEX)));
  251. delete vertices;
  252. }
  253. if (strokeCol.a > 0)
  254. {
  255. int nTris = nVts - 2;
  256. int nLines = (nTris * 2) + 1;
  257. CUSTOMVERTEX *lineVerts = new CUSTOMVERTEX [nLines * 2];
  258. D3DCOLOR col = D3DCOL(strokeCol);
  259. int lineI = 0;
  260. for (int i = 2, lineI = 0 ; i < nVts ; ++i, lineI += 4)
  261. {
  262. CUSTOMVERTEX v1(vts[i], strokeCol);
  263. CUSTOMVERTEX v2(vts[i-1], strokeCol);
  264. CUSTOMVERTEX v3(vts[i-2], strokeCol);
  265. lineVerts[lineI + 0] = v1;
  266. lineVerts[lineI + 1] = v2;
  267. lineVerts[lineI + 2] = v1;
  268. lineVerts[lineI + 3] = v3;
  269. }
  270. {
  271. int i = 0;
  272. CUSTOMVERTEX v1(vts[i], strokeCol);
  273. CUSTOMVERTEX v2(vts[i+1], strokeCol);
  274. lineVerts[lineI + 0] = v1;
  275. lineVerts[lineI + 1] = v2;
  276. }
  277. // FIXME: Actually need to use custom line drawing.
  278. DX_THROW(device->DrawPrimitiveUP(D3DPT_LINELIST, nLines, lineVerts, sizeof(CUSTOMVERTEX)));
  279. delete lineVerts;
  280. }
  281. }
  282. void ucfRenderImpl::setTexture(const Vec& pos, ucfTextureImpl &tex)
  283. {
  284. if (tex.locked) tex.unlock();
  285. IDirect3DSurface9Ptr backSurface;
  286. DX_THROW(device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backSurface));
  287. RECT r;
  288. SetRect(&r, int(pos.x), int(pos.y), int(pos.x) + tex.width, int(pos.y) + tex.height);
  289. RECT sr;
  290. SetRect(&sr, 0, 0, tex.width, tex.height);
  291. if (r.top < 0) { sr.top -= r.top; r.top = 0; }
  292. if (r.left < 0) { sr.left -= r.left; r.left = 0; }
  293. if (r.right > int(screenSize.x)) { int diff = r.right - screenSize.x; sr.right -= diff; r.right -= diff; }
  294. if (r.bottom > int(screenSize.y)) { int diff = r.bottom - screenSize.y; sr.bottom -= diff; r.bottom -= diff; }
  295. DX_THROW(device->StretchRect(tex.surf, &sr, backSurface, &r, D3DTEXF_NONE));
  296. }
  297. void ucfRenderImpl::image(ucfTextureImpl &tex, const Vec &pos, const Vec &size, const ucfColor &tint)
  298. {
  299. if (tex.locked) tex.unlock();
  300. D3DCOLOR diffuse = D3DCOL(tint);
  301. // FIXME: pixel shader which does tint etc.
  302. CUSTOMVERTEX_UV vtx[4];
  303. vtx[0] = CUSTOMVERTEX_UV(pos.x, pos.y, 0.f, diffuse, 0.f, 0.f);
  304. vtx[1] = CUSTOMVERTEX_UV(pos.x+size.x, pos.y, 0.f, diffuse, 1.f, 0.f);
  305. vtx[2] = CUSTOMVERTEX_UV(pos.x, pos.y+size.y, 0.f, diffuse, 0.f, 1.f);
  306. vtx[3] = CUSTOMVERTEX_UV(pos.x+size.x, pos.y+size.y, 0.f, diffuse, 1.f, 1.f);
  307. DX_THROW(device->SetTransform(D3DTS_WORLDMATRIX(0), matrixStack->GetTop()));
  308. IDirect3DTexture9Ptr texture;
  309. DX_THROW(device->SetFVF(D3DFVF_CUSTOMVERTEX_UV));
  310. DX_THROW(tex.surf->GetContainer(IID_IDirect3DTexture9, (void**)&texture));
  311. DX_THROW(device->SetTexture(0, texture));
  312. DX_THROW(device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, vtx, sizeof(CUSTOMVERTEX_UV)));
  313. }
  314. void ucfRenderImpl::loadPixels(ucfTextureImpl &tex)
  315. {
  316. IDirect3DSurface9Ptr backSurface;
  317. DX_THROW(device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backSurface));
  318. D3DSURFACE_DESC desc;
  319. DX_THROW(backSurface->GetDesc(&desc));
  320. IDirect3DTexture9Ptr loadTex;
  321. DX_THROW(device->CreateTexture(desc.Width, desc.Height, 1, D3DUSAGE_DYNAMIC, desc.Format, D3DPOOL_SYSTEMMEM, &loadTex, NULL));
  322. IDirect3DSurface9Ptr loadSurface;
  323. DX_THROW(loadTex->GetSurfaceLevel(0, &loadSurface));
  324. DX_THROW(device->GetRenderTargetData(backSurface, loadSurface));
  325. tex.surf = loadSurface;
  326. tex.update();
  327. }
  328. void ucfRenderImpl::updatePixels(ucfTextureImpl &tex)
  329. {
  330. IDirect3DSurface9Ptr backSurface;
  331. if (tex.locked)
  332. tex.unlock();
  333. DX_THROW(device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backSurface));
  334. DX_THROW(device->UpdateSurface(tex.surf, NULL, backSurface, NULL));
  335. tex.surf.Release();
  336. tex.update();
  337. }
  338. void ucfRenderImpl::frameRate(u32 rate)
  339. {
  340. float frameTime = 1.f / rate;
  341. // subtract the refresh rate from the frame time to ensure we end up in the right refresh
  342. // cycle. FIXME: Use the actual refresh rate.
  343. frameDelay = u32((frameTime - (1.f / 60.f)) * 1000);
  344. }
  345. void ucfRenderImpl::pushMatrix()
  346. {
  347. matrixStack->Push();
  348. }
  349. void ucfRenderImpl::popMatrix()
  350. {
  351. matrixStack->Pop();
  352. }
  353. void ucfRenderImpl::translate(const Vec &translate)
  354. {
  355. matrixStack->TranslateLocal(translate.x, translate.y, translate.z);
  356. }
  357. void ucfRenderImpl::eulerRotate(const Vec &rotate)
  358. {
  359. matrixStack->RotateYawPitchRollLocal(rotate.x, rotate.y, rotate.z);
  360. }
  361. void ucfRenderImpl::scale(const Vec &scale)
  362. {
  363. matrixStack->ScaleLocal(scale.x, scale.y, scale.z);
  364. }