/ucf/ucfDxRenderImpl.cpp
C++ | 457 lines | 350 code | 93 blank | 14 comment | 35 complexity | bc00194eb7a1107b05fbc9a8df27d72a MD5 | raw file
- #include "ucfDxRenderImpl.h"
- #include "ucfDxTextureImpl.h"
-
- #include "ucfWinAppImpl.h"
-
- IDirect3DDevice9Ptr g_device;
-
- // ----------------------------------------------------------------------------
- // ucfRenderImpl
-
- ucfRenderImpl::ucfRenderImpl() : frameDelay(0), isDrawing(false)
- {
- }
-
- ucfRenderImpl::~ucfRenderImpl()
- {
- }
-
- void ucfRenderImpl::createD3D()
- {
- if (d3d9 != NULL || g_appImpl->hwnd == NULL)
- return; // already initialised, or not initialised enough.
-
- if( NULL == ( d3d9 = Direct3DCreate9( D3D_SDK_VERSION ) ) )
- throw "Direct3DCreate9 failed";
-
- D3DPRESENT_PARAMETERS d3dpp;
- ZeroMemory( &d3dpp, sizeof(d3dpp) );
- d3dpp.Windowed = screenMode != RenderFullscreen ? TRUE : FALSE;
- d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
- d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
- d3dpp.EnableAutoDepthStencil = TRUE;
- d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
-
- g_appImpl->resizeWindow(screenSize);
-
- DX_THROW(d3d9->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_appImpl->hwnd,
- D3DCREATE_HARDWARE_VERTEXPROCESSING,
- &d3dpp, &device));
-
- DX_THROW(D3DXCreateMatrixStack(0, &matrixStack));
-
- D3DXMATRIX projMat;
- D3DXMatrixOrthoOffCenterLH(&projMat, 0, float(screenSize.x), float(screenSize.y), 0, 0.0f, 1.0f);
- device->SetTransform(D3DTS_PROJECTION, &projMat);
-
- device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
-
- device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
- device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
- device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
-
- device->SetRenderState(D3DRS_LIGHTING, FALSE);
-
- device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
- device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
- device->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_TEXTURE);
-
- preDraw();
-
- g_device = device; // handy global, probably a bad idea long term.
- }
-
- void ucfRenderImpl::destroyD3D()
- {
- if (device)
- device.Release();
- if (d3d9)
- d3d9.Release();
- }
-
- void ucfRenderImpl::postSetup()
- {
- if (isDrawing)
- postDraw();
- else
- createD3D();
- }
-
- void ucfRenderImpl::postShutdown()
- {
- destroyD3D();
- }
-
- void ucfRenderImpl::preDraw()
- {
- frameStartTime = clock();
-
- // FIXME: doesn't deal with stack leaks
- // Each frame starts with the identity matrix.
- matrixStack->LoadIdentity();
-
- DX_THROW(device->BeginScene());
-
- isDrawing = true;
- }
-
- void ucfRenderImpl::postDraw()
- {
- isDrawing = false;
-
- DX_THROW(device->EndScene());
-
- // Frame delay logic. FIXME: Not particularly accurate wrt wall clock time.
- clock_t endTime = clock();
- double elapsed = double(endTime - frameStartTime) / CLOCKS_PER_SEC;
- double required = frameDelay / 1000.f;
- int delay = int((required - elapsed) * 1000);
- if (delay > 0)
- Sleep(delay);
-
- DX_THROW(device->Present( NULL, NULL, NULL, NULL ));
- }
-
- // ----------------------------------------------------------------------------
- // API Support.
-
- void ucfRenderImpl::size(const TVec<int>& sz, ucfRenderMode mode)
- {
- screenSize = sz;
- screenMode = mode;
-
- createD3D();
- }
-
- void ucfRenderImpl::clear(const ucfColor& c)
- {
- DX_THROW(device->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOL(c), 1.0f, 0 ));
- }
-
- struct CUSTOMVERTEX
- {
- CUSTOMVERTEX() { }
- CUSTOMVERTEX(float _x, float _y, float _z, DWORD _col) : x(_x), y(_y), z(_z), color(_col) { }
- CUSTOMVERTEX(const Vec &v, const ucfColor &col) : x(v.x), y(v.y), z(v.z), color(D3DCOL(col)) { }
-
- FLOAT x, y, z; // The position for the vertex.
- DWORD color; // The vertex color.
- };
-
- #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)
-
- struct CUSTOMVERTEX_UV
- {
- CUSTOMVERTEX_UV() { }
- 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) { }
- 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) { }
-
- FLOAT x, y, z; // The position for the vertex.
- DWORD color; // The vertex color.
- FLOAT u, v; // Gosh! What could these be?
- };
-
- #define D3DFVF_CUSTOMVERTEX_UV (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
-
- void ucfRenderImpl::point(const Vec& pt, const ucfColor& c)
- {
- DX_THROW(device->SetTransform(D3DTS_WORLDMATRIX(0), matrixStack->GetTop()));
-
- CUSTOMVERTEX vtx(pt, c);
- DX_THROW(device->SetFVF( D3DFVF_CUSTOMVERTEX ));
- DX_THROW(device->DrawPrimitiveUP(D3DPT_POINTLIST, 1, &vtx, sizeof(CUSTOMVERTEX)));
- }
-
- static inline Vec calcWidthVec(const Vec * const vts, const int nVts, bool loop, const int i)
- {
- int i0 = i-1;
- int i1 = i;
- int i2 = i+1;
- bool mitre = true;
- if (i == 0)
- {
- if (loop)
- {
- i0 = nVts-1;
- i1 = 0;
- i2 = 1;
- }
- else
- {
- i0 = 0;
- i1 = 1;
- mitre = false;
- }
- }
- else if (i == nVts-1)
- {
- if (loop)
- {
- i0 = nVts-2;
- i1 = nVts-1;
- i2 = 0;
- }
- else
- {
- i0 = nVts-2;
- i1 = nVts-1;
- mitre = false;
- }
- }
-
- Vec v1 = (vts[i1] - vts[i0]).norm();
- Vec p(0, 0, 1);
- Vec n = v1.cross(p);
-
- if (mitre)
- {
- Vec v2 = (vts[i2] - vts[i1]).norm();
- Vec m = (v1 - v2) / 2.f;
-
- float md = 1.f / n.dot(m);
-
- return m * md;
- }
- else
- {
- return n;
- }
- }
-
- void ucfRenderImpl::lineStrip(const Vec * const vts, const int nVts, const ucfColor &c, float width, bool loop)
- {
- assert(nVts > 1);
-
- int nTriVerts = nVts*2 + (loop ? 2 : 0);
- CUSTOMVERTEX *vertices = new CUSTOMVERTEX [nTriVerts];
- int vIndex = 0;
- for (int i = 0 ; i < nVts ; ++i)
- {
- Vec n = calcWidthVec(vts, nVts, loop, i);
- Vec r = n * (width/2);
-
- vertices[vIndex++] = CUSTOMVERTEX(vts[i] - r, c);
- vertices[vIndex++] = CUSTOMVERTEX(vts[i] + r, c);
- }
- if (loop)
- {
- Vec n = calcWidthVec(vts, nVts, loop, 0);
- Vec r = n * (width/2);
-
- vertices[vIndex++] = CUSTOMVERTEX(vts[0] - r, c);
- vertices[vIndex++] = CUSTOMVERTEX(vts[0] + r, c);
- }
-
- DX_THROW(device->SetTransform(D3DTS_WORLDMATRIX(0), matrixStack->GetTop()));
- DX_THROW(device->SetFVF( D3DFVF_CUSTOMVERTEX ));
- DX_THROW(device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, nTriVerts-2, vertices, sizeof(CUSTOMVERTEX)));
-
- delete vertices;
- }
-
- void ucfRenderImpl::poly(const Vec * const vts, const int nVts, bool joinUp, const ucfColor &fillCol, const ucfColor &strokeCol, float strokeWidth)
- {
- if (fillCol.a > 0)
- {
- int extra = joinUp ? 1 : 0;
- CUSTOMVERTEX *vertices = new CUSTOMVERTEX [nVts + 1];
- int i;
- for (i = 0 ; i < nVts ; ++i)
- {
- vertices[i] = CUSTOMVERTEX(vts[i], fillCol);
- }
- vertices[i] = CUSTOMVERTEX(vts[0], fillCol);
-
- DX_THROW(device->SetTransform(D3DTS_WORLDMATRIX(0), matrixStack->GetTop()));
- DX_THROW(device->SetFVF( D3DFVF_CUSTOMVERTEX ));
-
- // create a stencil for the areas of the possibly convex poly we're drawing.
- DX_THROW(device->SetRenderState(D3DRS_STENCILENABLE, TRUE));
- DX_THROW(device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS));
- DX_THROW(device->SetRenderState(D3DRS_STENCILMASK, 1));
- DX_THROW(device->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INVERT));
- DX_THROW(device->SetRenderState(D3DRS_COLORWRITEENABLE, 0));
- DX_THROW(device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE));
- //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?
- DX_THROW(device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, nVts+1-2, vertices, sizeof(CUSTOMVERTEX)));
-
- // use the stencil to draw to the convex poly. clear the stencil at the same time.
- DX_THROW(device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL));
- DX_THROW(device->SetRenderState(D3DRS_STENCILREF, 1));
- DX_THROW(device->SetRenderState(D3DRS_STENCILMASK, 1));
- DX_THROW(device->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_ZERO)); // clear while drawing.
- DX_THROW(device->SetRenderState(D3DRS_COLORWRITEENABLE, -1));
- DX_THROW(device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE));
-
- DX_THROW(device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, nVts+1-2, vertices, sizeof(CUSTOMVERTEX)));
-
- DX_THROW(device->SetRenderState(D3DRS_STENCILENABLE, FALSE));
-
- delete vertices;
- }
-
- if (strokeCol.a > 0)
- {
- lineStrip(vts, nVts, strokeCol, strokeWidth, joinUp);
- }
- }
-
- void ucfRenderImpl::triStrip(const Vec *const vts, const int nVts, const ucfColor &fillCol, const ucfColor &strokeCol)
- {
- DX_THROW(device->SetFVF(D3DFVF_CUSTOMVERTEX));
-
- DX_THROW(device->SetTransform(D3DTS_WORLDMATRIX(0), matrixStack->GetTop()));
-
- if (fillCol.a > 0)
- {
- CUSTOMVERTEX *vertices = new CUSTOMVERTEX [nVts];
- D3DCOLOR col = D3DCOL(fillCol);
-
- for (int i = 0 ; i < nVts ; ++i)
- {
- vertices[i] = CUSTOMVERTEX(vts[i], fillCol);
- }
- DX_THROW(device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, nVts-2, vertices, sizeof(CUSTOMVERTEX)));
-
- delete vertices;
- }
-
- if (strokeCol.a > 0)
- {
- int nTris = nVts - 2;
- int nLines = (nTris * 2) + 1;
- CUSTOMVERTEX *lineVerts = new CUSTOMVERTEX [nLines * 2];
- D3DCOLOR col = D3DCOL(strokeCol);
-
- int lineI = 0;
- for (int i = 2, lineI = 0 ; i < nVts ; ++i, lineI += 4)
- {
- CUSTOMVERTEX v1(vts[i], strokeCol);
- CUSTOMVERTEX v2(vts[i-1], strokeCol);
- CUSTOMVERTEX v3(vts[i-2], strokeCol);
- lineVerts[lineI + 0] = v1;
- lineVerts[lineI + 1] = v2;
- lineVerts[lineI + 2] = v1;
- lineVerts[lineI + 3] = v3;
- }
- {
- int i = 0;
- CUSTOMVERTEX v1(vts[i], strokeCol);
- CUSTOMVERTEX v2(vts[i+1], strokeCol);
- lineVerts[lineI + 0] = v1;
- lineVerts[lineI + 1] = v2;
- }
- // FIXME: Actually need to use custom line drawing.
- DX_THROW(device->DrawPrimitiveUP(D3DPT_LINELIST, nLines, lineVerts, sizeof(CUSTOMVERTEX)));
-
- delete lineVerts;
- }
- }
-
- void ucfRenderImpl::setTexture(const Vec& pos, ucfTextureImpl &tex)
- {
- if (tex.locked) tex.unlock();
-
- IDirect3DSurface9Ptr backSurface;
- DX_THROW(device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backSurface));
-
- RECT r;
- SetRect(&r, int(pos.x), int(pos.y), int(pos.x) + tex.width, int(pos.y) + tex.height);
-
- RECT sr;
- SetRect(&sr, 0, 0, tex.width, tex.height);
- if (r.top < 0) { sr.top -= r.top; r.top = 0; }
- if (r.left < 0) { sr.left -= r.left; r.left = 0; }
- if (r.right > int(screenSize.x)) { int diff = r.right - screenSize.x; sr.right -= diff; r.right -= diff; }
- if (r.bottom > int(screenSize.y)) { int diff = r.bottom - screenSize.y; sr.bottom -= diff; r.bottom -= diff; }
-
- DX_THROW(device->StretchRect(tex.surf, &sr, backSurface, &r, D3DTEXF_NONE));
- }
-
- void ucfRenderImpl::image(ucfTextureImpl &tex, const Vec &pos, const Vec &size, const ucfColor &tint)
- {
- if (tex.locked) tex.unlock();
-
- D3DCOLOR diffuse = D3DCOL(tint);
-
- // FIXME: pixel shader which does tint etc.
- CUSTOMVERTEX_UV vtx[4];
- vtx[0] = CUSTOMVERTEX_UV(pos.x, pos.y, 0.f, diffuse, 0.f, 0.f);
- vtx[1] = CUSTOMVERTEX_UV(pos.x+size.x, pos.y, 0.f, diffuse, 1.f, 0.f);
- vtx[2] = CUSTOMVERTEX_UV(pos.x, pos.y+size.y, 0.f, diffuse, 0.f, 1.f);
- vtx[3] = CUSTOMVERTEX_UV(pos.x+size.x, pos.y+size.y, 0.f, diffuse, 1.f, 1.f);
-
- DX_THROW(device->SetTransform(D3DTS_WORLDMATRIX(0), matrixStack->GetTop()));
-
- IDirect3DTexture9Ptr texture;
- DX_THROW(device->SetFVF(D3DFVF_CUSTOMVERTEX_UV));
- DX_THROW(tex.surf->GetContainer(IID_IDirect3DTexture9, (void**)&texture));
- DX_THROW(device->SetTexture(0, texture));
- DX_THROW(device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, vtx, sizeof(CUSTOMVERTEX_UV)));
- }
-
- void ucfRenderImpl::loadPixels(ucfTextureImpl &tex)
- {
- IDirect3DSurface9Ptr backSurface;
- DX_THROW(device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backSurface));
-
- D3DSURFACE_DESC desc;
- DX_THROW(backSurface->GetDesc(&desc));
-
- IDirect3DTexture9Ptr loadTex;
- DX_THROW(device->CreateTexture(desc.Width, desc.Height, 1, D3DUSAGE_DYNAMIC, desc.Format, D3DPOOL_SYSTEMMEM, &loadTex, NULL));
-
- IDirect3DSurface9Ptr loadSurface;
- DX_THROW(loadTex->GetSurfaceLevel(0, &loadSurface));
-
- DX_THROW(device->GetRenderTargetData(backSurface, loadSurface));
-
- tex.surf = loadSurface;
- tex.update();
- }
-
- void ucfRenderImpl::updatePixels(ucfTextureImpl &tex)
- {
- IDirect3DSurface9Ptr backSurface;
-
- if (tex.locked)
- tex.unlock();
-
- DX_THROW(device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backSurface));
- DX_THROW(device->UpdateSurface(tex.surf, NULL, backSurface, NULL));
- tex.surf.Release();
- tex.update();
- }
-
- void ucfRenderImpl::frameRate(u32 rate)
- {
- float frameTime = 1.f / rate;
- // subtract the refresh rate from the frame time to ensure we end up in the right refresh
- // cycle. FIXME: Use the actual refresh rate.
- frameDelay = u32((frameTime - (1.f / 60.f)) * 1000);
- }
-
- void ucfRenderImpl::pushMatrix()
- {
- matrixStack->Push();
- }
-
- void ucfRenderImpl::popMatrix()
- {
- matrixStack->Pop();
- }
-
- void ucfRenderImpl::translate(const Vec &translate)
- {
- matrixStack->TranslateLocal(translate.x, translate.y, translate.z);
- }
-
- void ucfRenderImpl::eulerRotate(const Vec &rotate)
- {
- matrixStack->RotateYawPitchRollLocal(rotate.x, rotate.y, rotate.z);
- }
-
- void ucfRenderImpl::scale(const Vec &scale)
- {
- matrixStack->ScaleLocal(scale.x, scale.y, scale.z);
- }