#include "pch.h" ////////////////////////////////////////////////////////////////////////////// // // Plane // ////////////////////////////////////////////////////////////////////////////// float Plane::Distance(const HVector& vec) const { return vec.X() * m_hvec.X() + vec.Y() * m_hvec.Y() + vec.Z() * m_hvec.Z() + vec.W() * m_hvec.W(); } float Plane::Intersect(const HVector& v0, const HVector& v1) const { HVector vd = v1 - v0; float a = m_hvec * v0; float b = m_hvec * vd; float alpha = -a / b; return bound(alpha, 0.0f, 1.0f); } ////////////////////////////////////////////////////////////////////////////// // // State // ////////////////////////////////////////////////////////////////////////////// class StateChangeBase {}; typedef TBitMask StateChange; class StateChangeMatrix : public StateChange { public: StateChangeMatrix () : StateChange(0x000001) {} }; class StateChangePerspectiveMatrix : public StateChange { public: StateChangePerspectiveMatrix () : StateChange(0x000002) {} }; class StateChangeMaterial : public StateChange { public: StateChangeMaterial () : StateChange(0x000004) {} }; class StateChangeTexture : public StateChange { public: StateChangeTexture () : StateChange(0x000008) {} }; class StateChangeShadeMode : public StateChange { public: StateChangeShadeMode () : StateChange(0x000010) {} }; class StateChangeBlendMode : public StateChange { public: StateChangeBlendMode () : StateChange(0x000020) {} }; class StateChangeZTest : public StateChange { public: StateChangeZTest () : StateChange(0x000040) {} }; class StateChangeZWrite : public StateChange { public: StateChangeZWrite () : StateChange(0x000080) {} }; class StateChangeLinearFilter : public StateChange { public: StateChangeLinearFilter () : StateChange(0x000100) {} }; class StateChangePerspectiveCorrection : public StateChange { public: StateChangePerspectiveCorrection() : StateChange(0x000200) {} }; class StateChangeDither : public StateChange { public: StateChangeDither () : StateChange(0x000400) {} }; class StateChangeWrapMode : public StateChange { public: StateChangeWrapMode () : StateChange(0x000800) {} }; class StateChangeCullMode : public StateChange { public: StateChangeCullMode () : StateChange(0x001000) {} }; class StateChangeClipRect : public StateChange { public: StateChangeClipRect () : StateChange(0x002000) {} }; class StateChangeClipPlanes : public StateChange { public: StateChangeClipPlanes () : StateChange(0x004000) {} }; class StateChangeColor : public StateChange { public: StateChangeColor () : StateChange(0x008000) {} }; class StateChangeAmbientLevel : public StateChange { public: StateChangeAmbientLevel () : StateChange(0x010000) {} }; class StateChangeLineWidth : public StateChange { public: StateChangeLineWidth () : StateChange(0x020000) {} }; class StateChangeColorKey : public StateChange { public: StateChangeColorKey () : StateChange(0x040000) {} }; class StateChangeDeformation : public StateChange { public: StateChangeDeformation () : StateChange(0x080000) {} }; class StateChangeAll : public StateChange { public: StateChangeAll () : StateChange(0xffffff) {} }; const StateChange stCommon = StateChangeMatrix() | StateChangeMaterial() | StateChangeTexture(); const StateChange stUncommon = StateChangeAll().Clear(stCommon); class State : public IObjectSingle { public: TRef m_pnext; TRef m_pmaterial; TRef m_psurfaceTexture; TRef m_pdeform; Matrix m_mat; Matrix m_matPerspective; Rect m_rectClip; int m_countClipPlanes; bool m_bZTest; bool m_bZWrite; bool m_bDither; bool m_bColorKey; bool m_bLinearFilter; bool m_bPerspectiveCorrection; ShadeMode m_shadeMode; BlendMode m_blendMode; WrapMode m_wrapMode; CullMode m_cullMode; Color m_color; float m_ambientLevel; float m_lineWidth; StateChange m_maskChanges; StateChange m_maskOverride; State() { } State(State* pstate) : m_pnext(pstate), m_maskChanges(), m_maskOverride() { } }; ////////////////////////////////////////////////////////////////////////////// // // Drawing Context // ////////////////////////////////////////////////////////////////////////////// class ContextImpl : public PrivateContext { private: ////////////////////////////////////////////////////////////////////////////// // // types // ////////////////////////////////////////////////////////////////////////////// class WhiteSurfaceSite : public SurfaceSite { public: void UpdateSurface(Surface* psurface) { psurface->FillSurface(Color::White()); } }; ////////////////////////////////////////////////////////////////////////////// // // members // ////////////////////////////////////////////////////////////////////////////// TRef m_pdevice3D; TRef m_pstate; TRef m_pstateDevice; PrivateSurface* m_psurface; // // Vertex buffers // Vertex* m_pvertexBuffer; int m_countVertexBuffer; MeshIndex* m_pindexBuffer; int m_countIndexBuffer; // // What mode is the device in? // bool m_bRendering; bool m_bIn3DLayer; bool m_bInScene; bool m_bRenderingCallbacks; // // Culling // float m_focus; float m_near; float m_far; float m_aspect; float m_rxscale; float m_ryscale; float m_yscale; // // Level of detail // float m_lod; ////////////////////////////////////////////////////////////////////////////// // // Decal Data // ////////////////////////////////////////////////////////////////////////////// class Decal { public: Vector m_position; Color m_color; float m_scale; float m_angle; Vector m_forward; Vector m_right; bool GetVertices(VertexL* pvertex) const { Vector v0; Vector v1; Vector v2; Vector v3; if (m_forward.IsZero()) { float c = cos(m_angle) * m_scale; float s = sin(m_angle) * m_scale; float dx = c - s; float dy = c + s; float x = m_position.X(); float y = m_position.Y(); float z = m_position.Z(); v0 = Vector(x - dy, y + dx, z); v1 = Vector(x - dx, y - dy, z); v2 = Vector(x + dy, y - dx, z); v3 = Vector(x + dx, y + dy, z); } else { v0 = m_position - m_forward - m_right; v1 = m_position + m_forward - m_right; v2 = m_position + m_forward + m_right; v3 = m_position - m_forward + m_right; } float r = m_color.R(); float g = m_color.G(); float b = m_color.B(); float a = m_color.A(); pvertex[0] = VertexL(v0.X(), v0.Y(), v0.Z(), r, g, b, a, 0, 1); pvertex[1] = VertexL(v1.X(), v1.Y(), v1.Z(), r, g, b, a, 0, 0); pvertex[2] = VertexL(v2.X(), v2.Y(), v2.Z(), r, g, b, a, 1, 0); pvertex[3] = VertexL(v3.X(), v3.Y(), v3.Z(), r, g, b, a, 1, 1); return true; } }; ////////////////////////////////////////////////////////////////////////////// // // Decal Sets // ////////////////////////////////////////////////////////////////////////////// class DecalSet { public: TRef m_psurface; TVector m_vdecal; }; TVector m_vdecalSet; TVector m_vdecalSetOpaque; // // Delayed 3D Rendering // class GeoCallbackData { public: TRef m_pgeoCallback; Matrix m_mat; float m_distance; }; class CompareDistance { public: bool operator () (const GeoCallbackData& value1, const GeoCallbackData& value2) { return value1.m_distance < value2.m_distance; } }; typedef TList GeoCallbackDataList; GeoCallbackDataList m_listGeoCallbacks; GeoCallbackDataList m_listGeoCallbacksSorted; // // Counters // #ifdef EnablePerformanceCounters int m_countDrawString; int m_countDrawStringChars; #endif public: ////////////////////////////////////////////////////////////////////////////// // // Constructor // ////////////////////////////////////////////////////////////////////////////// ContextImpl(PrivateSurface* psurface) : #ifdef EnablePerformanceCounters m_countDrawString(0), m_countDrawStringChars(0), #endif m_pvertexBuffer(NULL), m_countVertexBuffer(0), m_pindexBuffer(NULL), m_countIndexBuffer(0), m_psurface(psurface), m_bRendering(false), m_bIn3DLayer(false), m_bInScene(false), m_bRenderingCallbacks(false) { // // Create a rasterizer and a 3D device // if (psurface->GetSurfaceType().Test(SurfaceType3D())) { TRef pengine = psurface->GetEngine(); TRef prasterizer; bool bAlwaysUseD3D = false; if ( bAlwaysUseD3D || ( pengine->GetUsing3DAcceleration() && psurface->GetSurfaceType().Test(SurfaceTypeVideo()) ) ) { prasterizer = CreateD3DRasterizer(m_psurface); } else { prasterizer = CreateSoftwareRasterizer(m_psurface); } if (prasterizer == NULL) { return; } m_pdevice3D = CreateDevice3D(prasterizer); } // // Setup the initial state // m_pstateDevice = new State(); m_pstateDevice->m_mat.SetIdentity(); m_pstateDevice->m_matPerspective.SetIdentity(); m_pstateDevice->m_pmaterial = NULL; m_pstateDevice->m_bZTest = false; m_pstateDevice->m_bZWrite = false; m_pstateDevice->m_bPerspectiveCorrection = false; m_pstateDevice->m_bDither = true; m_pstateDevice->m_bColorKey = true; m_pstateDevice->m_bLinearFilter = true; m_pstateDevice->m_shadeMode = ShadeModeGouraud; m_pstateDevice->m_blendMode = BlendModeSource; m_pstateDevice->m_wrapMode = WrapModeNone; m_pstateDevice->m_cullMode = CullModeCCW; m_pstateDevice->m_maskChanges = StateChangeAll(); m_pstateDevice->m_maskOverride = StateChange(); m_pstateDevice->m_countClipPlanes = 0; m_pstateDevice->m_rectClip = Rect( Point(0, 0), Point::Cast(m_psurface->GetSize()) ); m_pstateDevice->m_color = Color::White(); m_pstateDevice->m_lineWidth = 1; } bool IsValid() { return m_pdevice3D != NULL && m_pdevice3D->IsValid(); } ////////////////////////////////////////////////////////////////////////////// // // Destructor // ////////////////////////////////////////////////////////////////////////////// ~ContextImpl() { if (m_pvertexBuffer) { free(m_pvertexBuffer); } if (m_pindexBuffer) { free(m_pindexBuffer); } } ////////////////////////////////////////////////////////////////////////////// // // Capabilities // ////////////////////////////////////////////////////////////////////////////// bool Has3DAcceleration() { return m_pdevice3D->Has3DAcceleration(); } ////////////////////////////////////////////////////////////////////////////// // // Rendering Initialization // ////////////////////////////////////////////////////////////////////////////// void BeginRendering() { ZAssert(!m_bRendering); ZAssert(!m_bInScene); ZAssert(!m_bIn3DLayer); m_bRendering = true; PushState(); } void EndRendering() { ZAssert(m_bRendering); PopState(); if (m_bIn3DLayer) { End3DLayer(); } EndScene(); m_bRendering = false; } PrivateSurface* GetSurface() { return m_psurface; } ////////////////////////////////////////////////////////////////////////////// // // Attributes // ////////////////////////////////////////////////////////////////////////////// bool GetClipping() { return m_pdevice3D->GetClipping(); } void SetClipping(bool bClip) { m_pdevice3D->SetClipping(bClip); } bool IsCulled( const Vector& vecOrigin, float radius, bool& bNotClipped ) { // , this code assumes there are no non-uniform scales // actualy it doesn't handle scales at all since radius isn't // scaled. Vector vecEye = TransformLocalToEye(vecOrigin); float x = vecEye.X(); float y = vecEye.Y(); float z = vecEye.Z(); float back = z - m_far; float front = m_near - z; float rx; float ry; float left; float right; float bottom; float top; if (m_focus == 0) { rx = radius; ry = radius; left = x - 1; right = -x - 1; bottom = y - 1; top = -y - 1; } else { rx = radius * m_rxscale; ry = radius * m_ryscale; left = m_focus * x - z; right = -m_focus * x - z; bottom = m_yscale * y - z; top = -m_yscale * y - z; } // // Is the sphere completely outside the frustum? // if ( left < -rx || right < -rx || bottom < -ry || top < -ry || back < -radius || front < -radius ) { bNotClipped = false; return true; } // // Is the sphere completely inside the frustum? // if ( left > rx && right > rx && bottom > ry && top > ry && back > radius && front > radius ) { bNotClipped = true; return false; } // // The sphere intersects the frustum's boundary. // bNotClipped = false; return false; } ////////////////////////////////////////////////////////////////////////////// // // 2D Image Rendering // ////////////////////////////////////////////////////////////////////////////// void DrawImage( Surface* psurface, const Rect& rectSource, bool bCentered, const Point& point ) { // !!! should really look at the device mode and the current transform // !!! this uses upper left as (0, 0) on psurface and DrawImage3D() uses lower left as (0, 0) // !!! this doesn't scale or rotate the image ZAssert(!m_bIn3DLayer); ZAssert(m_pstateDevice->m_matPerspective.GetType() < TransformRotate); DD2D(); Point pointImage; if (TransformLocalToImage(Vector(point.X(), point.Y(), 0), pointImage)) { WinPoint pointScreen = TransformImageToSurface(pointImage); if (bCentered) { pointScreen.SetX(pointScreen.X() - (int)(rectSource.XSize() / 2.0f)); pointScreen.SetY(pointScreen.Y() - (int)(rectSource.YSize() / 2.0f)); } else { pointScreen.SetY(pointScreen.Y() - (int)rectSource.YSize()); } m_psurface->BitBlt( pointScreen, psurface, WinRect::Cast(rectSource) ); }; } void DrawImage( Surface* psurface, bool bCentered, const Point& point ) { DrawImage( psurface, WinRect( WinPoint(0, 0), psurface->GetSize() ), bCentered, point ); } ////////////////////////////////////////////////////////////////////////////// // // 3D Image Rendering // ////////////////////////////////////////////////////////////////////////////// void DrawImage3D( Surface* psurface, const Rect& rectSource, const Color& color, bool bCentered, const Point& point ) { ZAssert(m_bRendering); if (!m_bInScene) { Texture2D(); } Point sizeSource(Point::Cast(psurface->GetSize())); float xOffset = point.X() - (bCentered ? rectSource.XSize() / 2 : 0); float yOffset = point.Y() - (bCentered ? rectSource.YSize() / 2 : 0); float xmin = xOffset ; float xmax = xOffset + rectSource.XSize(); float ymin = yOffset; float ymax = yOffset + rectSource.YSize(); float xt; float yt; //if (psurface->GetSurfaceType().Test(SurfaceTypeTile())) { xt = 1.0f / sizeSource.X(); yt = 1.0f / sizeSource.Y(); //} else { // // , this is broken if the texture size is smaller that the surface size // Point pointTextureSize(Point::Cast(psurface->GetTextureRect().Size())); // // xt = 1.0f / pointTextureSize.X(); // yt = 1.0f / pointTextureSize.Y(); //} float xtmin = xt * rectSource.XMin(); float xtmax = xt * rectSource.XMax(); float ytmin = yt * (sizeSource.Y() - rectSource.YMin()); float ytmax = yt * (sizeSource.Y() - rectSource.YMax()); static MeshIndex indices[6] = { 0, 2, 1, 0, 3, 2 }; UpdateState(); m_pdevice3D->SetTexture(psurface); switch (GetShadeMode()) { case ShadeModeCopy: { Vertex vertices[4] = { Vertex(xmin, ymax, 0, 0, 0, 1, xtmin, ytmax), Vertex(xmin, ymin, 0, 0, 0, 1, xtmin, ytmin), Vertex(xmax, ymin, 0, 0, 0, 1, xtmax, ytmin), Vertex(xmax, ymax, 0, 0, 0, 1, xtmax, ytmax) }; m_pdevice3D->DrawTriangles(vertices, 4, indices, 6); } break; case ShadeModeFlat: case ShadeModeGouraud: { float r = color.R(); float g = color.G(); float b = color.B(); float a = color.A(); VertexL vertices[4] = { VertexL(xmin, ymax, 0, r, g, b, a, xtmin, ytmax), VertexL(xmin, ymin, 0, r, g, b, a, xtmin, ytmin), VertexL(xmax, ymin, 0, r, g, b, a, xtmax, ytmin), VertexL(xmax, ymax, 0, r, g, b, a, xtmax, ytmax) }; m_pdevice3D->SetShadeMode(ShadeModeFlat); m_pdevice3D->DrawTriangles(vertices, 4, indices, 6); m_pdevice3D->SetShadeMode(m_pstateDevice->m_shadeMode); } break; default: ZError("Invalid shade mode"); break; } m_pdevice3D->SetTexture(m_pstateDevice->m_psurfaceTexture); } void DrawImage3D( Surface* psurface, const Color& color, bool bCentered, const Point& point ) { DrawImage3D( psurface, Rect( Point(0, 0), Point::Cast(psurface->GetSize()) ), color, bCentered, point ); } ////////////////////////////////////////////////////////////////////////////// // // Text Rendering // ////////////////////////////////////////////////////////////////////////////// void DrawString( IEngineFont* pfont, const Color& color, const Point& point, const ZString& str ) { #ifdef EnablePerformanceCounters m_countDrawString++; m_countDrawStringChars += str.GetLength(); #endif DD2D(); Point pointImage; if (TransformLocalToImage(Vector(point.X(), point.Y(), 0), pointImage)) { WinPoint pointScreen = TransformImageToSurface(pointImage); WinPoint size = pfont->GetTextExtent(str); pointScreen.SetY(pointScreen.Y() - size.Y()); m_psurface->DrawString(pfont, color, pointScreen, str); }; } void DrawRectangle(const Rect& rect, const Color& color) { Texture2D(); static MeshIndex indices[8] = { 0, 1, 1, 2, 2, 3, 3, 0 }; float xmin = rect.XMin(); float xmax = rect.XMax(); float ymin = rect.YMin(); float ymax = rect.YMax(); float r = color.R(); float g = color.G(); float b = color.B(); float a = color.A(); VertexL vertices[4] = { VertexL(xmin, ymax, 0, r, g, b, a, 0, 0), VertexL(xmin, ymin, 0, r, g, b, a, 0, 0), VertexL(xmax, ymin, 0, r, g, b, a, 0, 0), VertexL(xmax, ymax, 0, r, g, b, a, 0, 0) }; m_pdevice3D->DrawLines(vertices, 4, indices, 8); } void FillRect(const Rect& rect, const Color& color) { Texture2D(); static MeshIndex indices[6] = { 0, 2, 1, 0, 3, 2 }; float xmin = rect.XMin(); float xmax = rect.XMax(); float ymin = rect.YMin(); float ymax = rect.YMax(); float r = color.R(); float g = color.G(); float b = color.B(); float a = color.A(); VertexL vertices[4] = { VertexL(xmin, ymax, 0, r, g, b, a, 0, 1), VertexL(xmin, ymin, 0, r, g, b, a, 0, 0), VertexL(xmax, ymin, 0, r, g, b, a, 1, 0), VertexL(xmax, ymax, 0, r, g, b, a, 1, 1) }; UpdateState(); m_pdevice3D->SetShadeMode(ShadeModeFlat); m_pdevice3D->DrawTriangles(vertices, 4, indices, 6); m_pdevice3D->SetShadeMode(m_pstateDevice->m_shadeMode); } void FillInfinite(const Color& color) { DD2D(); m_psurface->FillSurface(color); } ////////////////////////////////////////////////////////////////////////////// // // 3D Layers // ////////////////////////////////////////////////////////////////////////////// void Begin3DLayer(Camera* pcamera, bool bZBuffer) { ZEnter("Context::Begin3DLayer"); ZAssert(m_bRendering); ZAssert(!m_bIn3DLayer); // // Push the state so we can undo all the state changes // PushState(); // // Integrate the 2D transforms up until this point with the 3D transform // pcamera->Update(); SetPerspectiveMatrix(pcamera->GetPerspectiveMatrix()); // // Change this flag after we change the prespective matrix // m_bIn3DLayer = true; // // Apply the camera's transform // SetTransform(pcamera->GetModelMatrix()); // // start the 3D Layer // BeginScene(); // // Save some information needed for culling // WinPoint point = m_psurface->GetSize(); m_focus = pcamera->GetFocus(); m_near = pcamera->GetNear(); m_far = pcamera->GetFar(); m_aspect = float(point.Y()) / float(point.X()); m_yscale = m_focus / m_aspect; m_rxscale = sqrt(m_focus * m_focus + 1.0f); m_ryscale = sqrt(m_yscale * m_yscale + 1.0f); // // Default to being frustum clipped // SetClipping(true); // // Initialize state // m_lod = FLT_MAX; // // Clear the ZBuffer // if (bZBuffer) { ZTrace("Clearing ZBuffer"); UpdateState(); m_pdevice3D->ClearZBuffer(); SetZWrite(true, false); SetZTest(true, false); } else { // // turn off zbuffering for any future drawing // SetZWrite(false, false); SetZTest(false, false); } PushState(); } void RenderCallbackGeos(GeoCallbackDataList& list) { GeoCallbackDataList::Iterator iter(list); while (!iter.End()) { GeoCallbackData& data = iter.Value(); PushState(); SetTransform(data.m_mat); data.m_pgeoCallback->RenderCallback(this); PopState(); iter.Next(); } list.SetEmpty(); } void End3DLayer() { ZExit("Context::Begin3DLayer"); ZAssert(m_bRendering); ZAssert(m_bIn3DLayer); ZAssert(m_bInScene); // // Restore the original state // PopState(); // // Render any GeoCallbacks // m_bRenderingCallbacks = true; RenderCallbackGeos(m_listGeoCallbacksSorted); RenderCallbackGeos(m_listGeoCallbacks); m_bRenderingCallbacks = false; // // Draw decals // DrawCachedDecals(); // // End the 3D layer // PopState(); m_bIn3DLayer = false; } void BeginScene() { if (!m_bInScene) { m_pdevice3D->BeginScene(); m_bInScene = true; } } void EndScene() { if (m_bInScene) { m_pdevice3D->EndScene(); m_bInScene = false; } } ////////////////////////////////////////////////////////////////////////////// // // Level of detail // ////////////////////////////////////////////////////////////////////////////// void SetLOD(float lod) { m_lod = lod; } float GetLOD() { return m_lod; } ////////////////////////////////////////////////////////////////////////////// // // Get State // ////////////////////////////////////////////////////////////////////////////// const Color& GetGlobalColor() const { return m_pstateDevice->m_color ; } bool GetZTest() const { return m_pstateDevice->m_bZTest ; } bool GetZWrite() const { return m_pstateDevice->m_bZWrite ; } bool GetPerspectiveCorrection() const { return m_pstateDevice->m_bPerspectiveCorrection; } bool GetDither() const { return m_pstateDevice->m_bDither ; } bool GetColorKey() const { return m_pstateDevice->m_bColorKey ; } bool GetLinearFilter() const { return m_pstateDevice->m_bLinearFilter ; } ShadeMode GetShadeMode() const { return m_pstateDevice->m_shadeMode ; } BlendMode GetBlendMode() const { return m_pstateDevice->m_blendMode ; } WrapMode GetWrapMode() const { return m_pstateDevice->m_wrapMode ; } CullMode GetCullMode() const { return m_pstateDevice->m_cullMode ; } Surface* GetTexture() const { return m_pstateDevice->m_psurfaceTexture ; } Material* GetMaterial() const { return m_pstateDevice->m_pmaterial ; } Deformation* GetDeformation() const { return m_pstateDevice->m_pdeform ; } ////////////////////////////////////////////////////////////////////////////// // // Efficient State Changes // ////////////////////////////////////////////////////////////////////////////// template void DoSetState( const ValueType& value, ValueType& valueDevice, ValueType& valueState, bool bOverride, const StateChange& st ) { if (!m_pstateDevice->m_maskOverride.Test(st)) { if (value != valueDevice) { if (!m_pstate->m_maskChanges.Test(st)) { valueState = valueDevice; m_pstate->m_maskChanges.Set(st); } valueDevice = value; m_pstateDevice->m_maskChanges.Set(st); } if (bOverride) { m_pstate->m_maskOverride.Set(st); m_pstateDevice->m_maskOverride.Set(st); } } } ////////////////////////////////////////////////////////////////////////////// // // Efficient State Changes // ////////////////////////////////////////////////////////////////////////////// void SetGlobalColor(const Color& color, bool bOverride) { DoSetState( color, m_pstateDevice->m_color, m_pstate->m_color, bOverride, StateChangeColor() ); } void SetLinearFilter(bool b, bool bOverride) { DoSetState( b, m_pstateDevice->m_bLinearFilter, m_pstate->m_bLinearFilter, bOverride, StateChangeLinearFilter() ); } void SetPerspectiveCorrection(bool b, bool bOverride) { DoSetState( b, m_pstateDevice->m_bPerspectiveCorrection, m_pstate->m_bPerspectiveCorrection, bOverride, StateChangePerspectiveCorrection() ); } void SetDither(bool b, bool bOverride) { DoSetState( b, m_pstateDevice->m_bDither, m_pstate->m_bDither, bOverride, StateChangeDither() ); } void SetColorKey(bool b, bool bOverride) { DoSetState( b, m_pstateDevice->m_bColorKey, m_pstate->m_bColorKey, bOverride, StateChangeColorKey() ); } void SetZTest(bool b, bool bOverride) { DoSetState( b, m_pstateDevice->m_bZTest, m_pstate->m_bZTest, bOverride, StateChangeZTest() ); } void SetZWrite(bool b, bool bOverride) { DoSetState( b, m_pstateDevice->m_bZWrite, m_pstate->m_bZWrite, bOverride, StateChangeZWrite() ); } void SetShadeMode(ShadeMode shadeMode, bool bOverride) { DoSetState( shadeMode, m_pstateDevice->m_shadeMode, m_pstate->m_shadeMode, bOverride, StateChangeShadeMode() ); } void SetBlendMode(BlendMode blendMode, bool bOverride) { DoSetState( blendMode, m_pstateDevice->m_blendMode, m_pstate->m_blendMode, bOverride, StateChangeBlendMode() ); } void SetWrapMode(WrapMode wrapMode, bool bOverride) { DoSetState( wrapMode, m_pstateDevice->m_wrapMode, m_pstate->m_wrapMode, bOverride, StateChangeWrapMode() ); } void SetCullMode(CullMode cullMode, bool bOverride) { DoSetState( cullMode, m_pstateDevice->m_cullMode, m_pstate->m_cullMode, bOverride, StateChangeCullMode() ); } void SetMaterial(Material* pmaterial, bool bOverride) { DoSetState( TRef(pmaterial), m_pstateDevice->m_pmaterial, m_pstate->m_pmaterial, bOverride, StateChangeMaterial() ); } void SetTexture(Surface* psurface, bool bOverride) { DoSetState( TRef(psurface), m_pstateDevice->m_psurfaceTexture, m_pstate->m_psurfaceTexture, bOverride, StateChangeTexture() ); } void SetDeformation(Deformation* pdeform, bool bOverride) { DoSetState( TRef(pdeform), m_pstateDevice->m_pdeform, m_pstate->m_pdeform, bOverride, StateChangeDeformation() ); } void SetLineWidth(float width, bool bOverride = false) { DoSetState( width, m_pstateDevice->m_lineWidth, m_pstate->m_lineWidth, bOverride, StateChangeLineWidth() ); } ////////////////////////////////////////////////////////////////////////////// // // Update the device states // ////////////////////////////////////////////////////////////////////////////// void UpdateState() { const StateChange& maskChanges = m_pstateDevice->m_maskChanges; if (maskChanges.Test(stCommon)) { if (maskChanges.Test(StateChangeMatrix())) { m_pdevice3D->SetMatrix(m_pstateDevice->m_mat); } if (maskChanges.Test(StateChangeMaterial())) { m_pdevice3D->SetMaterial(m_pstateDevice->m_pmaterial); } if (maskChanges.Test(StateChangeTexture())) { m_pdevice3D->SetTexture(m_pstateDevice->m_psurfaceTexture); } } if (maskChanges.Test(stUncommon)) { if (maskChanges.Test(StateChangeDeformation())) { m_pdevice3D->SetDeformation(m_pstateDevice->m_pdeform); } if (maskChanges.Test(StateChangePerspectiveMatrix())) { m_pdevice3D->SetPerspectiveMatrix(m_pstateDevice->m_matPerspective); } if (maskChanges.Test(StateChangeColor())) { m_pdevice3D->SetGlobalColor(m_pstateDevice->m_color); } if (maskChanges.Test(StateChangeClipRect())) { m_pdevice3D->SetClipRect(m_pstateDevice->m_rectClip); } if (maskChanges.Test(StateChangeShadeMode())) { m_pdevice3D->SetShadeMode(m_pstateDevice->m_shadeMode); } if (maskChanges.Test(StateChangeBlendMode())) { m_pdevice3D->SetBlendMode(m_pstateDevice->m_blendMode); } if (maskChanges.Test(StateChangeWrapMode())) { m_pdevice3D->SetWrapMode(m_pstateDevice->m_wrapMode); } if (maskChanges.Test(StateChangeCullMode())) { m_pdevice3D->SetCullMode(m_pstateDevice->m_cullMode); } if (maskChanges.Test(StateChangeZTest())) { m_pdevice3D->SetZTest(m_pstateDevice->m_bZTest); } if (maskChanges.Test(StateChangeZWrite())) { m_pdevice3D->SetZWrite(m_pstateDevice->m_bZWrite); } if (maskChanges.Test(StateChangeLinearFilter())) { m_pdevice3D->SetLinearFilter(m_pstateDevice->m_bLinearFilter); } if (maskChanges.Test(StateChangePerspectiveCorrection())) { m_pdevice3D->SetPerspectiveCorrection(m_pstateDevice->m_bPerspectiveCorrection); } if (maskChanges.Test(StateChangeDither())) { m_pdevice3D->SetDither(m_pstateDevice->m_bDither); } if (maskChanges.Test(StateChangeColorKey())) { m_pdevice3D->SetColorKey(m_pstateDevice->m_bColorKey); } if (maskChanges.Test(StateChangeLineWidth())) { m_pdevice3D->SetLineWidth(m_pstateDevice->m_lineWidth); } } m_pstateDevice->m_maskChanges.Clear(StateChangeAll()); } ////////////////////////////////////////////////////////////////////////////// // // Push and Pop // ////////////////////////////////////////////////////////////////////////////// void PushState() { m_pstate = new State(m_pstate); } void PopState() { const StateChange& maskChanges = m_pstate->m_maskChanges; if (maskChanges.Test(stCommon)) { if (maskChanges.Test(StateChangeMatrix())) { m_pstateDevice->m_mat = m_pstate->m_mat; } if (maskChanges.Test(StateChangeMaterial())) { m_pstateDevice->m_pmaterial = m_pstate->m_pmaterial; } if (maskChanges.Test(StateChangeTexture())) { m_pstateDevice->m_psurfaceTexture = m_pstate->m_psurfaceTexture; } } if (maskChanges.Test(stUncommon)) { if (maskChanges.Test(StateChangeDeformation())) { m_pstateDevice->m_pdeform = m_pstate->m_pdeform; } if (maskChanges.Test(StateChangeClipPlanes())) { while (m_pstateDevice->m_countClipPlanes > m_pstate->m_countClipPlanes) { m_pdevice3D->RemoveClipPlane(0); m_pstateDevice->m_countClipPlanes--; } } if (maskChanges.Test(StateChangeColor())) { m_pstateDevice->m_color = m_pstate->m_color; } if (maskChanges.Test(StateChangeClipRect())) { m_pstateDevice->m_rectClip = m_pstate->m_rectClip; } if (maskChanges.Test(StateChangePerspectiveMatrix())) { m_pstateDevice->m_matPerspective = m_pstate->m_matPerspective; } if (maskChanges.Test(StateChangeShadeMode())) { m_pstateDevice->m_shadeMode = m_pstate->m_shadeMode; } if (maskChanges.Test(StateChangeBlendMode())) { m_pstateDevice->m_blendMode = m_pstate->m_blendMode; } if (maskChanges.Test(StateChangeWrapMode())) { m_pstateDevice->m_wrapMode = m_pstate->m_wrapMode; } if (maskChanges.Test(StateChangeCullMode())) { m_pstateDevice->m_cullMode = m_pstate->m_cullMode; } if (maskChanges.Test(StateChangeZTest())) { m_pstateDevice->m_bZTest = m_pstate->m_bZTest; } if (maskChanges.Test(StateChangeZWrite())) { m_pstateDevice->m_bZWrite = m_pstate->m_bZWrite; } if (maskChanges.Test(StateChangeLinearFilter())) { m_pstateDevice->m_bLinearFilter = m_pstate->m_bLinearFilter; } if (maskChanges.Test(StateChangePerspectiveCorrection())) { m_pstateDevice->m_bPerspectiveCorrection = m_pstate->m_bPerspectiveCorrection; } if (maskChanges.Test(StateChangeDither())) { m_pstateDevice->m_bDither = m_pstate->m_bDither; } if (maskChanges.Test(StateChangeColorKey())) { m_pstateDevice->m_bColorKey = m_pstate->m_bColorKey; } if (maskChanges.Test(StateChangeLineWidth())) { m_pstateDevice->m_lineWidth = m_pstate->m_lineWidth; } } m_pstateDevice->m_maskChanges.Set(m_pstate->m_maskChanges); m_pstateDevice->m_maskOverride.Clear(m_pstate->m_maskOverride); m_pstate = m_pstate->m_pnext; } ////////////////////////////////////////////////////////////////////////////// // // Clipping Rect // ////////////////////////////////////////////////////////////////////////////// Point Transform2D(const Point& point) { Point pointImage; ZVerify(TransformLocalToImage(Vector(point.X(), point.Y(), 0), pointImage)); return pointImage; } WinRect GetSurfaceClipRect() { return WinRect( int(m_pstateDevice->m_rectClip.XMin()), m_psurface->GetSize().Y() - int(m_pstateDevice->m_rectClip.YMax()), int(m_pstateDevice->m_rectClip.XMax()), m_psurface->GetSize().Y() - int(m_pstateDevice->m_rectClip.YMin()) ); } void Clip(const Rect& rect) { ZAssert(!m_bIn3DLayer); if (!m_pstate->m_maskChanges.Test(StateChangeClipRect())) { m_pstate->m_rectClip = m_pstateDevice->m_rectClip; m_pstate->m_maskChanges.Set(StateChangeClipRect()); } m_pstateDevice->m_rectClip.Intersect( Rect( Transform2D(rect.Min()), Transform2D(rect.Max()) ) ); m_pstateDevice->m_maskChanges.Set(StateChangeClipRect()); } ////////////////////////////////////////////////////////////////////////////// // // Clipping planes // ////////////////////////////////////////////////////////////////////////////// void AddClipPlane(const Plane& plane) { if (!m_pstate->m_maskChanges.Test(StateChangeClipPlanes())) { m_pstate->m_countClipPlanes = m_pstateDevice->m_countClipPlanes; m_pstate->m_maskChanges.Set(StateChangeClipPlanes()); } UpdateState(); m_pdevice3D->AddClipPlane(plane); m_pstateDevice->m_countClipPlanes++; } ////////////////////////////////////////////////////////////////////////////// // // 3D Modeling Transforms // ////////////////////////////////////////////////////////////////////////////// void PreMatrixChanged() { ZAssert(m_bIn3DLayer); if (!m_pstate->m_maskChanges.Test(StateChangeMatrix())) { m_pstate->m_mat = m_pstateDevice->m_mat; m_pstate->m_maskChanges.Set(StateChangeMatrix()); } m_pstateDevice->m_maskChanges.Set(StateChangeMatrix()); } void SetTransform(const Matrix& mat) { PreMatrixChanged(); m_pstateDevice->m_mat = mat; } void Multiply(const Matrix& mat) { PreMatrixChanged(); m_pstateDevice->m_mat.PreMultiply(mat); } void Rotate(const Vector& vec, float angle) { PreMatrixChanged(); m_pstateDevice->m_mat.PreRotate(vec, angle); } void Translate(const Vector& vec) { PreMatrixChanged(); m_pstateDevice->m_mat.PreTranslate(vec); } void Scale(const Vector& vec) { PreMatrixChanged(); m_pstateDevice->m_mat.PreScale(vec); } void Scale3(float scale) { PreMatrixChanged(); m_pstateDevice->m_mat.PreScale(scale); } ////////////////////////////////////////////////////////////////////////////// // // 2D Modeling Transforms // ////////////////////////////////////////////////////////////////////////////// void PrePerspectiveMatrixChanged() { ZAssert(!m_bIn3DLayer); if (!m_pstate->m_maskChanges.Test(StateChangePerspectiveMatrix())) { m_pstate->m_matPerspective = m_pstateDevice->m_matPerspective; m_pstate->m_maskChanges.Set(StateChangePerspectiveMatrix()); } m_pstateDevice->m_maskChanges.Set(StateChangePerspectiveMatrix()); } void SetMatrix(const Matrix2& mat) { PrePerspectiveMatrixChanged(); m_pstateDevice->m_matPerspective = mat; } void Multiply(const Matrix2& mat) { PrePerspectiveMatrixChanged(); m_pstateDevice->m_matPerspective.PreMultiply(mat); } void Rotate(float angle) { PrePerspectiveMatrixChanged(); m_pstateDevice->m_matPerspective.PreRotate(Vector(0, 0, 1), angle); } void Translate(const Point& point) { PrePerspectiveMatrixChanged(); m_pstateDevice->m_matPerspective.PreTranslate(Vector(point.X(), point.Y(), 0)); } void Scale(const Point& point) { PrePerspectiveMatrixChanged(); m_pstateDevice->m_matPerspective.PreScale(Vector(point.X(), point.Y(), 0)); } void Scale2(float scale) { PrePerspectiveMatrixChanged(); m_pstateDevice->m_matPerspective.PreScale(Vector(scale, scale, 1)); } void SetPerspectiveMatrix(const Matrix& mat) { PrePerspectiveMatrixChanged(); m_pstateDevice->m_matPerspective.PreMultiply(mat); } ////////////////////////////////////////////////////////////////////////////// // // Transform Operations // ////////////////////////////////////////////////////////////////////////////// const Matrix& GetLocalToEyeMatrix() { return m_pstateDevice->m_mat; } const Matrix& GetEyeToLocalMatrix() { UpdateState(); return m_pdevice3D->GetInverseModelMatrix(); } Vector TransformEyeToLocal(const Vector& vec) { return GetEyeToLocalMatrix().Transform(vec); } Vector TransformLocalToEye(const Vector& vec) { return GetLocalToEyeMatrix().Transform(vec); } Vector TransformDirectionToEye(const Vector& vec) { HVector hvec = m_pstateDevice->m_mat.Transform(HVector(vec.X(), vec.Y(), vec.Z(), 0)); return Vector(hvec.X(), hvec.Y(), hvec.Z()); } bool TransformEyeToImage(const Vector& vecEye, Point& point) { HVector hvecImage = m_pstateDevice->m_matPerspective.Transform(HVector(vecEye)); if (hvecImage.W() < 0) { return false; } float rhw = 1.0f / hvecImage.W(); point = Point( rhw * hvecImage.X(), rhw * hvecImage.Y() ); return true; } bool TransformDirectionToImage(const Vector& vec, Point& point) { return TransformEyeToImage(TransformDirectionToEye(vec), point); } bool TransformLocalToImage(const Vector& vec, Point& point) { return TransformEyeToImage(TransformLocalToEye(vec), point); } WinPoint TransformImageToSurface(const Point& point) { const WinPoint& size = m_psurface->GetSize(); return WinPoint( MakeInt(point.X()), size.Y() - MakeInt(point.Y()) ); } float GetImageRadius(const Vector& vec, float radius) { Vector vecEye = TransformLocalToEye(vec); Point point; if (TransformEyeToImage(vecEye, point)) { Point pointRadius; if (TransformEyeToImage(vecEye + Vector(radius, 0, 0), pointRadius)) { return pointRadius.X() - point.X(); } } return radius; } ////////////////////////////////////////////////////////////////////////////// // // Lighting // ////////////////////////////////////////////////////////////////////////////// void DirectionalLight(const Vector& vec, const Color& color) { UpdateState(); m_pdevice3D->DirectionalLight(vec, color); } void BidirectionalLight(const Vector& direction, const Color& color, const Color& colorAlt) { UpdateState(); m_pdevice3D->BidirectionalLight(direction, color, colorAlt); } void SetAmbientLevel(float ambientLevel) { // , this should be on the state stack m_pdevice3D->SetAmbientLevel(ambientLevel); } ////////////////////////////////////////////////////////////////////////////// // // Callbacks // ////////////////////////////////////////////////////////////////////////////// void DrawCallbackGeo(IGeoCallback* pgeoCallback, bool bSortObject) { if (m_bIn3DLayer) { if (m_bRenderingCallbacks) { PushState(); pgeoCallback->RenderCallback(this); PopState(); } else { if (bSortObject) { GeoCallbackData dataNew; dataNew.m_mat = m_pstateDevice->m_mat; dataNew.m_pgeoCallback = pgeoCallback; dataNew.m_distance = m_pstateDevice->m_mat.GetTranslate().LengthSquared(); m_listGeoCallbacksSorted.InsertSorted(dataNew); } else { m_listGeoCallbacks.PushFront(); GeoCallbackData& data = m_listGeoCallbacks.GetFront(); data.m_mat = m_pstateDevice->m_mat; data.m_pgeoCallback = pgeoCallback; } } } else { // // Drawing a geo in 2D. Draw it now even though it is a callback geo // pgeoCallback->RenderCallback(this); } } ////////////////////////////////////////////////////////////////////////////// // // Buffers // ////////////////////////////////////////////////////////////////////////////// void SizeVertexBuffer(int count) { if (m_countVertexBuffer < count) { m_countVertexBuffer = count; m_pvertexBuffer = (Vertex*)realloc(m_pvertexBuffer, sizeof(Vertex) * count); } } void SizeIndexBuffer(int count) { if (m_countIndexBuffer < count) { m_countIndexBuffer = count; m_pindexBuffer = (MeshIndex*)realloc(m_pindexBuffer, sizeof(MeshIndex) * count); } } Vertex* GetVertexBuffer(int count) { SizeVertexBuffer(count); return m_pvertexBuffer; } MeshIndex* GetIndexBuffer(int count) { SizeIndexBuffer(count); return m_pindexBuffer; } ////////////////////////////////////////////////////////////////////////////// // // Buffers implemented by Device3D // ////////////////////////////////////////////////////////////////////////////// VertexL* GetVertexLBuffer(int count) { return m_pdevice3D->GetVertexLBuffer(count); } VertexScreen* GetVertexScreenBuffer(int count) { return m_pdevice3D->GetVertexScreenBuffer(count); } ////////////////////////////////////////////////////////////////////////////// // // Context Drawing modes // ////////////////////////////////////////////////////////////////////////////// void DD2D() { ZAssert(m_bRendering); ZAssert(!m_bIn3DLayer); EndScene(); UpdateState(); } void Texture2D() { ZAssert(m_bRendering); ZAssert(!m_bIn3DLayer); BeginScene(); UpdateState(); } void Mode3D() { ZAssert(m_bRendering); if (!m_bIn3DLayer) { Texture2D(); } else { ZAssert(m_bInScene); UpdateState(); } } ////////////////////////////////////////////////////////////////////////////// // // External Rendering Calls // ////////////////////////////////////////////////////////////////////////////// void DrawTriangles(const Vertex* pvertex, int vcount, const MeshIndex* pindex, int icount) { if (icount != 0) { Mode3D(); m_pdevice3D->DrawTriangles(pvertex, vcount, pindex, icount); } } void DrawTriangles(const VertexL* pvertex, int vcount, const MeshIndex* pindex, int icount) { if (icount != 0) { Mode3D(); m_pdevice3D->DrawTriangles(pvertex, vcount, pindex, icount); } } void DrawTriangles(const VertexScreen* pvertex, int vcount, const MeshIndex* pindex, int icount) { if (icount != 0) { Mode3D(); m_pdevice3D->DrawTriangles(pvertex, vcount, pindex, icount); } } void DrawTriangles(const D3DVertex* pvertex, int vcount, const MeshIndex* pindex, int icount) { Mode3D(); m_pdevice3D->DrawTriangles(pvertex, vcount, pindex, icount); } void DrawLineStrip(const Vertex* pvertex, int vcount) { int icount = (vcount - 1) * 2; MeshIndex* pindex = GetIndexBuffer(icount); for (int index = 0; index < vcount - 1; index++) { pindex[index * 2 ] = index; pindex[index * 2 + 1] = index + 1; } DrawLines(pvertex, vcount, pindex, icount); } void DrawLineStrip(const VertexL* pvertex, int vcount) { int icount = (vcount - 1) * 2; MeshIndex* pindex = GetIndexBuffer(icount); for (int index = 0; index < vcount - 1; index++) { pindex[index * 2 ] = index; pindex[index * 2 + 1] = index + 1; } DrawLines(pvertex, vcount, pindex, icount); } void DrawLineStrip(const VertexScreen* pvertex, int vcount) { int icount = (vcount - 1) * 2; MeshIndex* pindex = GetIndexBuffer(icount); for (int index = 0; index < vcount - 1; index++) { pindex[index * 2 ] = index; pindex[index * 2 + 1] = index + 1; } DrawLines(pvertex, vcount, pindex, icount); } void DrawLineStrip(const D3DVertex* pvertex, int vcount) { int icount = (vcount - 1) * 2; MeshIndex* pindex = GetIndexBuffer(icount); for (int index = 0; index < vcount - 1; index++) { pindex[index * 2 ] = index; pindex[index * 2 + 1] = index + 1; } DrawLines(pvertex, vcount, pindex, icount); } void DrawLines(const Vertex* pvertex, int vcount, const MeshIndex* pindex, int icount) { if (icount != 0) { Mode3D(); m_pdevice3D->DrawLines(pvertex, vcount, pindex, icount); } } void DrawLines(const VertexL* pvertex, int vcount, const MeshIndex* pindex, int icount) { if (icount != 0) { Mode3D(); m_pdevice3D->DrawLines(pvertex, vcount, pindex, icount); } } void DrawLines(const VertexScreen* pvertex, int vcount, const MeshIndex* pindex, int icount) { if (icount != 0) { Mode3D(); m_pdevice3D->DrawLines(pvertex, vcount, pindex, icount); } } void DrawLines(const D3DVertex* pvertex, int vcount, const MeshIndex* pindex, int icount) { Mode3D(); m_pdevice3D->DrawLines(pvertex, vcount, pindex, icount); } void DrawPoints(const Vertex* pvertex, int vcount) { if (vcount != 0) { Mode3D(); m_pdevice3D->DrawPoints(pvertex, vcount); } } void DrawPoints(const VertexL* pvertex, int vcount) { if (vcount != 0) { Mode3D(); m_pdevice3D->DrawPoints(pvertex, vcount); } } void DrawPoints(const VertexScreen* pvertex, int vcount) { if (vcount != 0) { Mode3D(); m_pdevice3D->DrawPoints(pvertex, vcount); } } void DrawPoints(const D3DVertex* pvertex, int vcount) { Mode3D(); m_pdevice3D->DrawPoints(pvertex, vcount); } ////////////////////////////////////////////////////////////////////////////// // // Vector Rendering Calls // ////////////////////////////////////////////////////////////////////////////// void DrawTriangles(const TVector& vertices, const TVector& indices) { DrawTriangles(&(vertices[0]), vertices.GetCount(), &(indices[0]), indices.GetCount()); } void DrawTriangles(const TVector& vertices, const TVector& indices) { DrawTriangles(&(vertices[0]), vertices.GetCount(), &(indices[0]), indices.GetCount()); } void DrawTriangles(const TVector& vertices, const TVector& indices) { DrawTriangles(&(vertices[0]), vertices.GetCount(), &(indices[0]), indices.GetCount()); } void DrawLines(const TVector& vertices, const TVector& indices) { DrawLines(&(vertices[0]), vertices.GetCount(), &(indices[0]), indices.GetCount()); } void DrawLines(const TVector& vertices, const TVector& indices) { DrawLines(&(vertices[0]), vertices.GetCount(), &(indices[0]), indices.GetCount()); } void DrawLines(const TVector& vertices, const TVector& indices) { DrawLines(&(vertices[0]), vertices.GetCount(), &(indices[0]), indices.GetCount()); } void DrawPoints(const TVector& vertices) { DrawPoints(&(vertices[0]), vertices.GetCount()); } void DrawPoints(const TVector& vertices) { DrawPoints(&(vertices[0]), vertices.GetCount()); } void DrawPoints(const TVector& vertices) { DrawPoints(&(vertices[0]), vertices.GetCount()); } ////////////////////////////////////////////////////////////////////////////// // // Add a new Decal // ////////////////////////////////////////////////////////////////////////////// Decal& AddDecal(TVector& vdecalSet, Surface* psurface) { // // find the associated decal set // int countDecalSets = vdecalSet.GetCount(); for(int indexSet = 0; indexSet < countDecalSets; indexSet++) { const DecalSet& set = vdecalSet[indexSet]; if (psurface == set.m_psurface) { break; } } // // Add a new decal set // if (indexSet == countDecalSets) { vdecalSet.PushEnd(); vdecalSet.Get(indexSet).m_psurface = psurface; } DecalSet& set = vdecalSet.Get(indexSet); // // Return a reference to the newly created decal // set.m_vdecal.PushEnd(); return set.m_vdecal.Get(set.m_vdecal.GetCount() - 1); } ////////////////////////////////////////////////////////////////////////////// // // Draw a Decal so that it faces the eye point and lies along a direction vector // ////////////////////////////////////////////////////////////////////////////// float DrawDecal( Surface* psurface, const Color& color, const Vector& positionLocal, const Vector& forwardLocal, const Vector& rightLocal, float scale, float angle, BlendMode blendMode ) { ZAssert( blendMode == BlendModeSource || blendMode == BlendModeAdd ); const Matrix& mat = GetLocalToEyeMatrix(); Vector position = mat.Transform(positionLocal); if (position.Z() < 0) { Decal& decal = AddDecal( blendMode == BlendModeSource ? m_vdecalSetOpaque : m_vdecalSet, psurface ); float sizeScale = 4.0f / (position.Z() * position.Z()); float scaleMat = mat.GetScale(); decal.m_position = position; decal.m_color = color; decal.m_angle = angle; decal.m_scale = scaleMat * scale; if (forwardLocal.IsZero()) { decal.m_forward = Vector(0, 0, 0); return sizeScale * decal.m_scale * decal.m_scale; } else { decal.m_forward = scaleMat * mat.TransformDirection(forwardLocal); if (rightLocal.IsZero()) { Vector right = decal.m_forward.GetOrthogonalVector(); float lengthForward = forwardLocal.Length(); float lengthRight = decal.m_scale * lengthForward; decal.m_right = lengthRight * right.Normalize(); return sizeScale * lengthForward * lengthRight; } else { decal.m_right = scaleMat * mat.TransformDirection(rightLocal); return sizeScale * decal.m_right.Length() * decal.m_forward.Length(); } } } return 0; } ////////////////////////////////////////////////////////////////////////////// // // Decal Drawing // ////////////////////////////////////////////////////////////////////////////// void DrawVDecalSet(TVector& vdecalSet) { // // Iterate through the decal sets // int countDecalSets = vdecalSet.GetCount(); for(int indexSet = 0; indexSet < countDecalSets; indexSet++) { DecalSet& set = vdecalSet.Get(indexSet); int countDecal = set.m_vdecal.GetCount(); if (countDecal > 0) { SetTexture(set.m_psurface, false); VertexL* pvertex = GetVertexLBuffer(countDecal * 4); MeshIndex* pindex = GetIndexBuffer(countDecal * 6); for (int index = 0; index < countDecal; index++) { set.m_vdecal[index].GetVertices(pvertex + index * 4); pindex[index * 6 + 0] = index * 4 + 0; pindex[index * 6 + 1] = index * 4 + 2; pindex[index * 6 + 2] = index * 4 + 1; pindex[index * 6 + 3] = index * 4 + 0; pindex[index * 6 + 4] = index * 4 + 3; pindex[index * 6 + 5] = index * 4 + 2; } UpdateState(); m_pdevice3D->DrawTriangles( &pvertex[0], index * 4, &pindex[0], index * 6 ); set.m_vdecal.SetCount(0); } } } void DrawCachedDecals() { // // Render States // SetCullMode(CullModeNone, false); SetShadeMode(ShadeModeFlat, false); SetTransform(Matrix::GetIdentity()); // // Opaque decals first // SetBlendMode(BlendModeSource, false); SetZWrite(true, false); DrawVDecalSet(m_vdecalSetOpaque); // // Emissive Transparent decals // SetBlendMode(BlendModeAdd, false); SetZWrite(false, false); DrawVDecalSet(m_vdecalSet); } ////////////////////////////////////////////////////////////////////////////// // // Performance Counters // ////////////////////////////////////////////////////////////////////////////// #ifdef EnablePerformanceCounters int GetPerformanceCounter(Counter counter) { if (counter == CounterDrawStrings) return m_countDrawString; else if (counter == CounterDrawStringChars) return m_countDrawStringChars; return m_pdevice3D->GetPerformanceCounter(counter); } void ResetPerformanceCounters() { m_countDrawString = 0; m_countDrawStringChars = 0; m_pdevice3D->ResetPerformanceCounters(); } #endif }; ////////////////////////////////////////////////////////////////////////////// // // Constructor // ////////////////////////////////////////////////////////////////////////////// TRef CreateContextImpl(PrivateSurface* psurface) { return new ContextImpl(psurface); }