#include "pch.h" ////////////////////////////////////////////////////////////////////////////// // // Optimize this file for speed // ////////////////////////////////////////////////////////////////////////////// // /Oa assume no aliasing // /Ow assume aliasing across function calls // /Og global optimization // /Ot fast code sequences // #ifndef _DEBUG #pragma optimize("t", on) #pragma inline_depth(255) //#pragma inline_recursion(off) #endif ////////////////////////////////////////////////////////////////////////////// // // Fast floating point routines // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // Reinterpret casts // ////////////////////////////////////////////////////////////////////////////// __forceinline float& AsFloat(DWORD& value) { return *(float *)(&value); } __forceinline float& AsFloat(int& value) { return *(float *)(&value); } __forceinline int& AsInt (float& value) { return *(int *)(&value); } __forceinline DWORD& AsDWORD(float& value) { return *(DWORD *)(&value); } // VS.Net 2003 port #if _MSC_VER >= 1300 __forceinline void swap(float& x, float& y) #else __forceinline void swap(float& x, float& y) #endif { DWORD temp(AsDWORD(x)); AsDWORD(x) = AsDWORD(y); AsDWORD(y) = temp; } ////////////////////////////////////////////////////////////////////////////// // // FPU Control word functions // ////////////////////////////////////////////////////////////////////////////// class ControlWordBase {}; typedef TBitMask ControlWord; class ControlWordExceptions : public ControlWord { public: ControlWordExceptions () : ControlWord(0x003f) {} }; class ControlWordPrecision : public ControlWord { public: ControlWordPrecision () : ControlWord(0x0300) {} }; class ControlWordRounding : public ControlWord { public: ControlWordRounding () : ControlWord(0x0c00) {} }; __forceinline ControlWord GetControlWord() { WORD w; __asm { fstcw w } ControlWord cw; cw.SetWord(w); return cw; } __forceinline void SetControlWord(const ControlWord& cw) { WORD w = cw.GetWord(); __asm { // fnclex // safe? fldcw w } } void AssertChopRound() { ZAssert(GetControlWord().Test(ControlWordRounding())); } void AssertRound() { ZAssert(!GetControlWord().Test(ControlWordRounding())); } ControlWord g_cw; void InitializeControlWord() { g_cw = GetControlWord(); ControlWord cw = g_cw; cw.Clear(ControlWordRounding()); cw.Clear(ControlWordPrecision()); SetControlWord(cw); } void RestoreControlWord() { SetControlWord(g_cw); } ////////////////////////////////////////////////////////////////////////////// // // Approximate tranesdental functions // ////////////////////////////////////////////////////////////////////////////// #define INT32_FLOAT_ONE 0x3f800000 #define FLOAT_EXPSCALE ((float)0x00800000) __forceinline float ApproximateLN(float f) { return (float)(AsInt(f) - INT32_FLOAT_ONE) * float(1.0 / (double)FLOAT_EXPSCALE); } __forceinline float ApproximatePow2(float f) { INT32 i = (INT32)(f * FLOAT_EXPSCALE) + INT32_FLOAT_ONE; return AsFloat(i); } __forceinline float ApproximateInv(float f) { INT32 i = (INT32_FLOAT_ONE << 1) - AsInt(f); return AsFloat(i); } __forceinline float ApproximateSqrt(float f) { INT32 i = (AsInt(f) >> 1) + (INT32_FLOAT_ONE >> 1); return AsFloat(i); } /* !!! alternate version what's the difference __forceinline float ApproximateSqrt(float f) { INT32 i = INT32_float_ONE + (INT32_float_ONE >> 1) - (AsInt(f) >> 1); return ASfloat(i); } */ __forceinline float ApproximatePow(float f, float exp) { INT32 i = (INT32)(exp * (AsInt(f) - INT32_FLOAT_ONE)) + INT32_FLOAT_ONE; return AsFloat(i); } /* !!! such a thing exists look at math.asm float ApproximateInvSqrt(float value) { } */ ////////////////////////////////////////////////////////////////////////////// // // Fast floating point // ////////////////////////////////////////////////////////////////////////////// __forceinline DWORD MakeDWORD(float value) { return DWORD(value); } __forceinline float Abs(float f) { DWORD i = AsDWORD(f) & 0x7fffffff; return AsFloat(i); } __forceinline float Negate(float f) { DWORD i = AsDWORD(f) ^ 0x80000000; return AsFloat(i); } ////////////////////////////////////////////////////////////////////////////// // // Overlapped Divide // ////////////////////////////////////////////////////////////////////////////// __forceinline void StartDivide(float numerator, float denominator) { _asm { fld numerator fdiv denominator } } __forceinline void StartDivide(float numerator, int denominator) { _asm { fld numerator fidiv denominator } } __forceinline float EndDivide() { float result; _asm { fstp result } return result; } ////////////////////////////////////////////////////////////////////////////// // // Comparison // ////////////////////////////////////////////////////////////////////////////// __forceinline bool GPositiveGreater (float a, float b) { return AsInt(a) > AsInt(b); } __forceinline bool GPositiveLess (float a, float b) { return AsInt(a) < AsInt(b); } __forceinline bool GPositiveEqual (float a, float b) { return AsInt(a) == AsInt(b); } __forceinline bool GPositiveGreateEqual(float a, float b) { return AsInt(a) >= AsInt(b); } __forceinline bool GPositiveLessEqual (float a, float b) { return AsInt(a) <= AsInt(b); } __forceinline bool GPositiveNotEqual (float a, float b) { return AsInt(a) != AsInt(b); } __forceinline bool GreaterZero (float a) { return AsInt(a) > 0; } __forceinline bool LessZero (float a) { return AsDWORD(a) > 0x80000000; } __forceinline bool GreaterEqualZero(float a) { return AsDWORD(a) <= 0x80000000; } __forceinline bool LessEqualZero (float a) { return AsInt(a) <= 0; } __forceinline bool EqualZero (float a) { return (AsDWORD(a) & 0x7fffffff) == 0; } __forceinline bool NotEqualZero (float a) { return (AsDWORD(a) & 0x7fffffff) != 0; } ////////////////////////////////////////////////////////////////////////////// // // Constants // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // Fixed Point Template // ////////////////////////////////////////////////////////////////////////////// template class TFixed { private: Type m_value; public: ////////////////////////////////////////////////////////////////////////////// // // Static functions // ////////////////////////////////////////////////////////////////////////////// __forceinline static Type MaxValue() { if (t_bSigned) { return int(PowerOf2(t_integerBits - 1)) - 1; } else { return PowerOf2(t_integerBits) - 1; } } __forceinline static Type MinValue() { if (t_bSigned) { return -int(PowerOf2(t_integerBits - 1)); } else { return 0; } } __forceinline static int FractionBits() { return 32 - t_integerBits; } __forceinline static float Scale() { return float(PowerOf2(FractionBits())); } ////////////////////////////////////////////////////////////////////////////// // // Constructors // ////////////////////////////////////////////////////////////////////////////// __forceinline TFixed() { } __forceinline TFixed(const TFixed& x) : m_value(x.m_value) { } __forceinline TFixed(float x) { if (t_bAssert) { ZAssert(x <= float(MaxValue())); ZAssert(x >= float(MinValue())); } if (t_bSigned) { m_value = MakeInt(x * Scale()); } else { m_value = MakeDWORD(x * Scale()); } } __forceinline TFixed(Type x) { if (t_bAssert) { ZAssert(x <= MaxValue()); } if (t_bSigned) { ZAssert(x >= MinValue()); } m_value = x << FractionBits(); } __forceinline TFixed(Type x, int shift) { int bits = shift + FractionBits(); if (bits == 0) { m_value = x; } else if (bits > 0) { m_value = x << bits ; } else { m_value = x >> (-bits); } } ////////////////////////////////////////////////////////////////////////////// // // Conversions // ////////////////////////////////////////////////////////////////////////////// __forceinline float GetFloat() const { return float(m_value) / Scale(); } __forceinline Type GetInteger(int shift = 0, bool bAlwaysRight = false) const { int bits = shift - FractionBits(); if (bAlwaysRight || (bits < 0)) { return m_value >> (-bits); } else if (bits == 0) { return m_value; } else { return m_value << bits ; } } __forceinline const Type& GetFixed() const { return m_value; } ////////////////////////////////////////////////////////////////////////////// // // Operators // ////////////////////////////////////////////////////////////////////////////// __forceinline TFixed& operator+=(const TFixed& x) { m_value += x.GetFixed(); return *this; } __forceinline TFixed& operator+=(const TFixed& x) { m_value += x.GetFixed(); return *this; } __forceinline TFixed& operator-=(const TFixed& x) { m_value -= x.m_value; return *this; } __forceinline friend TFixed operator+(const TFixed& x, const TFixed& y) { return TFixed(x.m_value + y.m_value, -FractionBits()); } __forceinline friend TFixed operator-(const TFixed& x, const TFixed& y) { return TFixed(x.m_value - y.m_value, -FractionBits()); } __forceinline friend TFixed operator*(const TFixed& x, const TFixed& y) { return TFixed(x.m_value * y.m_value, -2 * FractionBits()); } __forceinline friend TFixed operator*(const TFixed& x, Type y) { return TFixed(x.m_value * y, -FractionBits()); } __forceinline friend TFixed operator<<(const TFixed& x, int shift) { return TFixed(x.m_value, shift - FractionBits()); } __forceinline friend TFixed operator>>(const TFixed& x, int shift) { return TFixed(x.m_value, FractionBits() - shift); } }; ////////////////////////////////////////////////////////////////////////////// // // Fixed Point Macros // ////////////////////////////////////////////////////////////////////////////// typedef TFixed Fixed; typedef TFixed FixedZ; typedef TFixed FixedDZ; typedef TFixed Fixed1616; typedef TFixed FixedD1616; typedef TFixed Fixed131; typedef TFixed FixedD131; ////////////////////////////////////////////////////////////////////////////// // // Colors // ////////////////////////////////////////////////////////////////////////////// /* Color555 10-14 0x00007c00 5 Red 5- 9 0x000003e0 5 Green 0- 4 0x0000001f 5 Blue Color565 11-15 0x0000f800 5 Red 5-10 0x000007e0 6 Green 0- 4 0x0000001f 5 Blue ColorE 30-31 0xa0000000 2 Unused 20-29 0x3ff00000 5.5 Red 10-19 0x000ffa00 5.5 Green 0- 9 0x000003ff 5.5 Blue */ #define Color555RMask 0x7c00 #define Color555GMask 0x03e0 #define Color555BMask 0x001f #define Color555RShift 15 #define Color555GShift 10 #define Color555BShift 5 #define Color565RMask 0xf800 #define Color565GMask 0x07e0 #define Color565BMask 0x001f #define Color565RShift 16 #define Color565GShift 11 #define Color565BShift 5 #define ColorERMask 0x3fe00000 #define ColorEGMask 0x000ff800 #define ColorEBMask 0x000003ff #define ColorERShift 30 #define ColorEGShift 20 #define ColorEBShift 10 #define ColorERSaturationMask 0xc0000000 #define ColorEGSaturationMask 0x00100000 #define ColorEBSaturationMask 0x00000400 #define ColorESaturationMask (ColorERSaturationMask | ColorEGSaturationMask | ColorEBSaturationMask) typedef WORD Color555; typedef WORD Color565; typedef DWORD ColorE; const float g_componentFloatToIntScale = 255.0f / 256.0f; ////////////////////////////////////////////////////////////////////////////// // // Fixed1616 functions // ////////////////////////////////////////////////////////////////////////////// template __forceinline Type ShiftLeft(Type value, int shift) { if (shift >= 0) { return value << shift; } else { return value >> (-shift); } } ////////////////////////////////////////////////////////////////////////////// // // Color565 Helpers // ////////////////////////////////////////////////////////////////////////////// __forceinline Fixed1616 GetR(const Color565& color) { return Fixed1616(color & Color565RMask, -Color565RShift); } __forceinline Fixed1616 GetG(const Color565& color) { return Fixed1616(color & Color565GMask, -Color565GShift); } __forceinline Fixed1616 GetB(const Color565& color) { return Fixed1616(color & Color565BMask, -Color565BShift); } __forceinline Color565 MakeColor565(const Fixed1616& r, const Fixed1616& g, const Fixed1616& b) { DWORD r565 = r.GetInteger(Color565RShift) & Color565RMask; DWORD g565 = g.GetInteger(Color565GShift) & Color565GMask; DWORD b565 = b.GetInteger(Color565BShift) & Color565BMask; return Color565(r565 | g565 | b565); } __forceinline Color565 operator*(Color565 color, const Fixed1616& i) { /* return MakeColor565( (GetR(color) * i1616), (GetG(color) * i1616), (GetB(color) * i1616) ); */ DWORD r565 = ((GetR(color).GetFixed() * i.GetFixed()) >> 32 - Color565RShift) & Color565RMask; DWORD g565 = ((GetG(color).GetFixed() * i.GetFixed()) >> 32 - Color565GShift) & Color565GMask; DWORD b565 = ((GetB(color).GetFixed() * i.GetFixed()) >> 32 - Color565BShift) & Color565BMask; return Color565(r565 | g565 | b565); } __forceinline Color565 operator*(Color565 color, const Fixed131& i) { return color * Fixed1616(i.GetFixed(), -i.FractionBits()); } ////////////////////////////////////////////////////////////////////////////// // // ColorE Helpers // ////////////////////////////////////////////////////////////////////////////// __forceinline Fixed1616 GetR(const ColorE& color) { return Fixed1616(color & ColorERMask, -ColorERShift); } __forceinline Fixed1616 GetG(const ColorE& color) { return Fixed1616(color & ColorEGMask, -ColorEGShift); } __forceinline Fixed1616 GetB(const ColorE& color) { return Fixed1616(color & ColorEBMask, -ColorEBShift); } __forceinline ColorE MakeColorE(const Fixed1616& r, const Fixed1616& g, const Fixed1616& b) { return (r.GetInteger(ColorERShift) & ColorERMask) | (g.GetInteger(ColorEGShift) & ColorEGMask) | (b.GetInteger(ColorEBShift) & ColorEBMask); } __forceinline ColorE Color555ToColorE(Color555 color) { DWORD dw = color; return ColorE( ShiftLeft(dw & Color555RMask, ColorERShift - Color555RShift) | ShiftLeft(dw & Color555GMask, ColorEGShift - Color555GShift) | ShiftLeft(dw & Color555BMask, ColorEBShift - Color555BShift) ); } __forceinline Color555 ColorEToColor555(ColorE color) { DWORD dw = color; return Color555( (ShiftLeft(dw, Color555RShift - ColorERShift) & Color555RMask) | (ShiftLeft(dw, Color555GShift - ColorEGShift) & Color555GMask) | (ShiftLeft(dw, Color555BShift - ColorEBShift) & Color555BMask) ); } __forceinline ColorE Color565ToColorE(Color565 color) { DWORD dw = color; return ColorE( ShiftLeft(dw & Color565RMask, ColorERShift - Color565RShift) | ShiftLeft(dw & Color565GMask, ColorEGShift - Color565GShift) | ShiftLeft(dw & Color565BMask, ColorEBShift - Color565BShift) ); } __forceinline Color565 ColorEToColor565(ColorE color) { DWORD dw = color; return Color565( (ShiftLeft(dw, Color565RShift - ColorERShift) & Color565RMask) | (ShiftLeft(dw, Color565GShift - ColorEGShift) & Color565GMask) | (ShiftLeft(dw, Color565BShift - ColorEBShift) & Color565BMask) ); } __forceinline ColorE operator*(ColorE colorE, const Fixed1616& i) { /* return MakeColorE( GetR(colorE) * i, GetG(colorE) * i, GetB(colorE) * i ); */ DWORD r = ((GetR(colorE).GetFixed() * i.GetFixed()) >> 32 - ColorERShift) & ColorERMask; DWORD g = ((GetG(colorE).GetFixed() * i.GetFixed()) >> 32 - ColorEGShift) & ColorEGMask; DWORD b = ((GetB(colorE).GetFixed() * i.GetFixed()) >> 32 - ColorEBShift) & ColorEBMask; return ColorE(r | g | b); } __forceinline ColorE operator*(ColorE colorE, const Fixed131& i) { return colorE * Fixed1616(i.GetFixed(), -i.FractionBits()); } ////////////////////////////////////////////////////////////////////////////// // // Constants // ////////////////////////////////////////////////////////////////////////////// #define ChunkSize 16 #define MaxChunkPasses 10 ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// class SoftwareRasterizer : public Rasterizer { private: ////////////////////////////////////////////////////////////////////////////// // // Types // ////////////////////////////////////////////////////////////////////////////// typedef void (SoftwareRasterizer::*PFNDrawTriangle)( const VertexScreen* pva, const VertexScreen* pvb, const VertexScreen* pvc ); typedef void (SoftwareRasterizer::*PFNDrawLine)( const VertexScreen* pva, const VertexScreen* pvb ); typedef void (SoftwareRasterizer::*PFNDrawPoint)( const VertexScreen* pva ); typedef void (SoftwareRasterizer::*PFNFillSubTriangle)( const int ymin, const int ymax ); typedef void (SoftwareRasterizer::*PFNFillChunk)(); ////////////////////////////////////////////////////////////////////////////// // // Pipeline // ////////////////////////////////////////////////////////////////////////////// bool m_bUpdatePointers; bool m_bColorKeyOn; PFNDrawTriangle m_pfnDrawTriangle; PFNDrawLine m_pfnDrawLine; PFNDrawPoint m_pfnDrawPoint; PFNFillSubTriangle m_pfnFillSubTriangle; ////////////////////////////////////////////////////////////////////////////// // // Plane deltas // ////////////////////////////////////////////////////////////////////////////// float m_floatdudx; float m_floatdudy; float m_floatdvdx; float m_floatdvdy; float m_floatdidx; float m_floatdidy; float m_floatdzdx; float m_floatdzdy; Fixed m_dudx; Fixed m_dvdx; FixedD131 m_didx; FixedDZ m_dzdx; ////////////////////////////////////////////////////////////////////////////// // // Edge deltas // ////////////////////////////////////////////////////////////////////////////// int m_xmin ; int m_dxmindyLittle; int m_dxmindyBig ; float m_xminFrac ; float m_dxmindyFrac ; int m_xmax ; int m_dxmaxdyLittle; int m_dxmaxdyBig ; float m_xmaxFrac ; float m_dxmaxdyFrac ; Fixed m_u ; Fixed m_dudyLittle ; Fixed m_dudyBig ; Fixed m_v ; Fixed m_dvdyLittle ; Fixed m_dvdyBig ; Fixed131 m_i ; FixedD131 m_didyLittle ; FixedD131 m_didyBig ; FixedZ m_z ; FixedDZ m_dzdyLittle ; FixedDZ m_dzdyBig ; ////////////////////////////////////////////////////////////////////////////// // // Performance // ////////////////////////////////////////////////////////////////////////////// float m_pixels; ////////////////////////////////////////////////////////////////////////////// // // Render state // ////////////////////////////////////////////////////////////////////////////// bool m_bZTest; bool m_bZWrite; bool m_bDither; bool m_bLinearFilter; bool m_bPerspectiveCorrection; bool m_bColorKeyEnabled; ShadeMode m_shadeMode; BlendMode m_blendMode; WrapMode m_wrapMode; CullMode m_cullMode; Rect m_rectClip; ColorE m_colorE; Fixed1616 m_colorR; Fixed1616 m_colorG; Fixed1616 m_colorB; Fixed1616 m_colorA; Fixed1616 m_colorInvA; ////////////////////////////////////////////////////////////////////////////// // // Surface // ////////////////////////////////////////////////////////////////////////////// Surface* m_psurface; BYTE* m_pbSurface; DWORD m_pitchSurface; WinPoint m_sizeSurface; bool m_b565; ////////////////////////////////////////////////////////////////////////////// // // ZBuffer // ////////////////////////////////////////////////////////////////////////////// BYTE* m_pbZBuffer; DWORD m_pitchZBuffer; ////////////////////////////////////////////////////////////////////////////// // // Texture // ////////////////////////////////////////////////////////////////////////////// TRef m_psurfaceTexture; BYTE* m_pbTexture; DWORD m_pitchTexture; WinPoint m_sizeTexture; float m_uscale; float m_vscale; DWORD m_ushift; DWORD m_vshift; DWORD m_umask; DWORD m_vmask; bool m_bColorKey; ////////////////////////////////////////////////////////////////////////////// // // Members // ////////////////////////////////////////////////////////////////////////////// bool m_bInScene; public: ////////////////////////////////////////////////////////////////////////////// // // Constructor // ////////////////////////////////////////////////////////////////////////////// SoftwareRasterizer(PrivateSurface* psurface) : m_psurface(psurface), m_pixels(0), m_bInScene(false), m_bUpdatePointers(true), m_bZTest(false), m_bZWrite(false), m_bDither(false), m_bLinearFilter(false), m_bPerspectiveCorrection(false), m_bColorKeyEnabled(false), m_shadeMode(ShadeModeCopy), m_blendMode(BlendModeSource), m_wrapMode(WrapModeNone), m_cullMode(CullModeNone), m_pbSurface(NULL), m_pbZBuffer(NULL), m_pbTexture(NULL), m_pitchZBuffer(0) { PixelFormat* ppf = m_psurface->GetPixelFormat(); ZAssert(ppf->RedSize() == 0x1f); ZAssert(ppf->BlueSize() == 0x1f); if (ppf->GreenSize() == 0x1f) { m_b565 = false; } else { ZAssert(ppf->GreenSize() == 0x3f); m_b565 = true; } } ~SoftwareRasterizer() { if (m_pbZBuffer) { delete m_pbZBuffer; } } bool IsValid() { return true; } ////////////////////////////////////////////////////////////////////////////// // // Termination // ////////////////////////////////////////////////////////////////////////////// void Terminate() { } ////////////////////////////////////////////////////////////////////////////// // // Scene // ////////////////////////////////////////////////////////////////////////////// void BeginScene() { m_bInScene = true; m_pbSurface = m_psurface->GetWritablePointer(); m_pitchSurface = m_psurface->GetPitch(); m_sizeSurface = m_psurface->GetSize(); UpdateZBuffer(); UpdateTextureInfo(); m_bUpdatePointers = true; } void EndScene() { m_bInScene = false; m_psurface->ReleasePointer(); if (m_psurfaceTexture) { m_psurfaceTexture->ReleasePointer(); } } ////////////////////////////////////////////////////////////////////////////// // // Viewport // ////////////////////////////////////////////////////////////////////////////// void SetClipRect(const Rect& rectClip) { m_rectClip = rectClip; } void ClearZBuffer() { if (m_pbZBuffer) { memset( m_pbZBuffer, 0xff, m_pitchSurface * m_sizeSurface.Y() ); } } ////////////////////////////////////////////////////////////////////////////// // // Attributes // ////////////////////////////////////////////////////////////////////////////// bool Has3DAcceleration() { return false; } Point GetSurfaceSize() { return Point::Cast(m_psurface->GetSize()); } ////////////////////////////////////////////////////////////////////////////// // // State // ////////////////////////////////////////////////////////////////////////////// void SetTexture(Surface* psurfaceTextureArg) { if (m_bInScene && m_psurfaceTexture) { m_psurfaceTexture->ReleasePointer(); } CastTo(m_psurfaceTexture, psurfaceTextureArg); if (m_bInScene) { UpdateTextureInfo(); } m_bUpdatePointers = true; } void SetShadeMode(ShadeMode shadeMode) { m_shadeMode = shadeMode; m_bUpdatePointers = true; } void SetBlendMode(BlendMode blendMode) { m_blendMode = blendMode; m_bUpdatePointers = true; } void SetWrapMode(WrapMode wrapMode) { m_wrapMode = wrapMode; m_bUpdatePointers = true; } void SetCullMode(CullMode cullMode) { m_cullMode = cullMode; m_bUpdatePointers = true; } void SetZTest(bool bZTest) { m_bZTest = bZTest; m_bUpdatePointers = true; } void SetZWrite(bool bZWrite) { m_bZWrite = bZWrite; m_bUpdatePointers = true; } void SetLinearFilter(bool bLinearFilter) { m_bLinearFilter = bLinearFilter; m_bUpdatePointers = true; } void SetPerspectiveCorrection(bool bPerspectiveCorrection) { m_bPerspectiveCorrection = bPerspectiveCorrection; m_bUpdatePointers = true; } void SetDither(bool bDither) { m_bDither = bDither; m_bUpdatePointers = true; } void SetColorKey(bool bColorKey) { m_bColorKeyEnabled = bColorKey; m_bUpdatePointers = true; } void SetColor(const D3DCOLOR& color) { m_colorA = Fixed1616(color & 0xff000000, -32); m_colorR = Fixed1616(color & 0x00ff0000, -24); m_colorG = Fixed1616(color & 0x0000ff00, -16); m_colorB = Fixed1616(color & 0x000000ff, - 8); m_colorInvA = Fixed1616(255 - (color >> 24), - 8); m_colorE = MakeColorE(m_colorR, m_colorG, m_colorB); } void SetColor(const Color& color) { m_colorR = Fixed1616(color.GetRed () * g_componentFloatToIntScale); m_colorG = Fixed1616(color.GetGreen() * g_componentFloatToIntScale); m_colorB = Fixed1616(color.GetBlue () * g_componentFloatToIntScale); m_colorA = Fixed1616(color.GetAlpha() * g_componentFloatToIntScale); m_colorInvA = Fixed1616(1.0f - color.GetAlpha()); m_colorE = MakeColorE(m_colorR, m_colorG, m_colorB); } ////////////////////////////////////////////////////////////////////////////// // // Chunk Pass Members // ////////////////////////////////////////////////////////////////////////////// PFNFillChunk m_ppfnFillChunk[MaxChunkPasses]; int m_passCount; WORD m_wZBufferMask; int m_count; ColorE m_pcolorEChunk[ChunkSize]; ColorE m_pcolorEDest[ChunkSize]; BYTE* m_pzChunk; BYTE* m_pdest; Fixed m_uChunk; Fixed m_vChunk; Fixed131 m_iChunk; FixedZ m_zChunk; ////////////////////////////////////////////////////////////////////////////// // // Chunk Pass Helpers // ////////////////////////////////////////////////////////////////////////////// __forceinline int MakeIndex(int index) { return index + ChunkSize; } ////////////////////////////////////////////////////////////////////////////// // // This function works for both CK and not CK since Blend11 with a black // source pixel is the same as color keying. // ////////////////////////////////////////////////////////////////////////////// void CopyTextureZTestZWriteBlend11() { Color565* pcolor565 = (Color565*)m_pdest; Fixed u = m_uChunk; Fixed v = m_vChunk; FixedZ z = m_zChunk; WORD* pz = (WORD*)m_pzChunk; int index = m_count; do { WORD zs = WORD(z.GetInteger(16)); WORD zd = pz[MakeIndex(index)]; if (zs <= zd) { DWORD xt = ((u.GetFixed() >> Fixed::FractionBits()) & m_umask) << 1; DWORD yt = ((v.GetFixed() >> Fixed::FractionBits()) & m_vmask) << (m_ushift + 1); Color565 color565T = *(Color565*)(m_pbTexture + xt + yt); if (color565T != 0) { pz[MakeIndex(index)] = zs; Color565 color565D = pcolor565[MakeIndex(index)]; ColorE colorET = Color565ToColorE(color565T); ColorE colorED = Color565ToColorE(color565D); ColorE colorE = Blend11(colorET, colorED); Color565 color565 = ColorEToColor565(colorE); pcolor565[MakeIndex(index)] = color565; } } z += m_dzdx; u += m_dudx; v += m_dvdx; index ++; } while (index < 0); } ////////////////////////////////////////////////////////////////////////////// // // This function works for both CK and not CK since Blend11 with a black // source pixel is the same as color keying. // ////////////////////////////////////////////////////////////////////////////// void FlatTextureZTestZWriteBlend11() { Color565* pcolor565 = (Color565*)m_pdest; Fixed u = m_uChunk; Fixed v = m_vChunk; FixedZ z = m_zChunk; WORD* pz = (WORD*)m_pzChunk; int index = m_count; do { WORD zs = WORD(z.GetInteger(16)); WORD zd = pz[MakeIndex(index)]; if (zs <= zd) { DWORD xt = ((u.GetFixed() >> Fixed::FractionBits()) & m_umask) << 1; DWORD yt = ((v.GetFixed() >> Fixed::FractionBits()) & m_vmask) << (m_ushift + 1); Color565 color565T = *(Color565*)(m_pbTexture + xt + yt); if (color565T != 0) { pz[MakeIndex(index)] = zs; Color565 color565D = pcolor565[MakeIndex(index)]; ColorE colorET = FlatShade(Color565ToColorE(color565T)); ColorE colorED = Color565ToColorE(color565D); ColorE colorE = Blend11(colorET, colorED); Color565 color565 = ColorEToColor565(colorE); pcolor565[MakeIndex(index)] = color565; } } z += m_dzdx; u += m_dudx; v += m_dvdx; index ++; } while (index < 0); } ////////////////////////////////////////////////////////////////////////////// // // This function works for both CK and not CK since Blend11 with a black // source pixel is the same as color keying. // ////////////////////////////////////////////////////////////////////////////// void FlatBlend1InvA() { Color565* pcolor565 = (Color565*)m_pdest; int index = m_count; do { Color565 color565D = pcolor565[MakeIndex(index)]; ColorE colorD = Color565ToColorE(color565D); ColorE colorE = m_colorE + colorD * m_colorInvA; Color565 color565 = ColorEToColor565(colorE); pcolor565[MakeIndex(index)] = color565; index ++; } while (index < 0); } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void CopyTextureZTestZWriteAndColorKey() { Color565* pcolor565 = (Color565*)m_pdest; Fixed u = m_uChunk; Fixed v = m_vChunk; FixedZ z = m_zChunk; WORD* pz = (WORD*)m_pzChunk; int index = m_count; do { WORD zs = WORD(z.GetInteger(16)); WORD zd = pz[MakeIndex(index)]; if (zs <= zd) { DWORD xt = (u.GetInteger(1) & m_umask); DWORD yt = (v.GetInteger(m_ushift + 1, true) & m_vmask); Color565 color565 = *(Color565*)(m_pbTexture + xt + yt); if (color565 != 0) { pz[MakeIndex(index)] = zs; pcolor565[MakeIndex(index)] = color565; } } z += m_dzdx; u += m_dudx; v += m_dvdx; index ++; } while (index < 0); } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void CopyTextureZWriteAndColorKey() { Color565* pcolor565 = (Color565*)m_pdest; Fixed u = m_uChunk; Fixed v = m_vChunk; FixedZ z = m_zChunk; WORD* pz = (WORD*)m_pzChunk; WORD mask = m_wZBufferMask; int index = m_count; do { WORD zs = WORD(z.GetInteger(16)); WORD zd = pz[MakeIndex(index)]; if (zs <= zd) { DWORD xt = (u.GetInteger(1) & m_umask); DWORD yt = (v.GetInteger(m_ushift + 1, true) & m_vmask); Color565 color565 = *(Color565*)(m_pbTexture + xt + yt); if (color565 != 0) { if ((mask & 1) == 0) { WORD zs = WORD(z.GetInteger(16)); pz[MakeIndex(index)] = zs; pcolor565[MakeIndex(index)] = color565; } } } mask = mask >> 1; z += m_dzdx; u += m_dudx; v += m_dvdx; index ++; } while (index < 0); } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void LoadColor565Texture() { ColorE* pcolorE = m_pcolorEChunk; Fixed u = m_uChunk; Fixed v = m_vChunk; int index = m_count; do { DWORD xt = (u.GetInteger(1) & m_umask); DWORD yt = (v.GetInteger(m_ushift + 1, true) & m_vmask); Color565 color565 = *(Color565*)(m_pbTexture + xt + yt); ColorE colorE = Color565ToColorE(color565); pcolorE[MakeIndex(index)] = colorE; u += m_dudx; v += m_dvdx; index ++; } while (index < 0); } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void Load565Dest() { ColorE* pcolorE = m_pcolorEDest; Color565* pcolor565 = (Color565*)m_pdest; int index = m_count; do { Color565 color565 = pcolor565[MakeIndex(index)]; ColorE colorE = Color565ToColorE(color565); pcolorE[MakeIndex(index)] = colorE; index ++; } while (index < 0); } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void Load555Dest() { ColorE* pcolorE = m_pcolorEDest; Color555* pcolor555 = (Color555*)m_pdest; int index = m_count; do { Color555 color555 = pcolor555[MakeIndex(index)];; ColorE colorE = Color555ToColorE(color555); pcolorE[MakeIndex(index)] = colorE; index ++; } while (index < 0); } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void LoadFlatColor() { ColorE* pcolorE = m_pcolorEChunk; int index = m_count; do { pcolorE[MakeIndex(index)] = m_colorE; index ++; } while (index < 0); } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void CopyTextureZTestZWriteFlat() { Color565* pcolor565 = (Color565*)m_pdest; Fixed u = m_uChunk; Fixed v = m_vChunk; FixedZ z = m_zChunk; WORD* pz = (WORD*)m_pzChunk; int index = m_count; do { WORD zs = WORD(z.GetInteger(16)); WORD zd = pz[MakeIndex(index)]; if (zs <= zd) { DWORD xt = (u.GetInteger(1) & m_umask); DWORD yt = (v.GetInteger(m_ushift + 1, true) & m_vmask); Color565 color565 = *(Color565*)(m_pbTexture + xt + yt); pz[MakeIndex(index)] = zs; pcolor565[MakeIndex(index)] = MakeColor565( GetR(color565) * m_colorR, GetG(color565) * m_colorG, GetB(color565) * m_colorB ); } z += m_dzdx; u += m_dudx; v += m_dvdx; index ++; } while (index < 0); } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void CopyTextureZTestZWriteFlatAndColorKey() { Color565* pcolor565 = (Color565*)m_pdest; Fixed u = m_uChunk; Fixed v = m_vChunk; FixedZ z = m_zChunk; WORD* pz = (WORD*)m_pzChunk; int index = m_count; do { WORD zs = WORD(z.GetInteger(16)); WORD zd = pz[MakeIndex(index)]; if (zs <= zd) { DWORD xt = (u.GetInteger(1) & m_umask); DWORD yt = (v.GetInteger(m_ushift + 1, true) & m_vmask); Color565 color565 = *(Color565*)(m_pbTexture + xt + yt); if (color565 != 0) { pz[MakeIndex(index)] = zs; pcolor565[MakeIndex(index)] = MakeColor565( GetR(color565) * m_colorR, GetG(color565) * m_colorG, GetB(color565) * m_colorB ); } } z += m_dzdx; u += m_dudx; v += m_dvdx; index ++; } while (index < 0); } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// ColorE FlatShade(const ColorE& colorS) { return MakeColorE( GetR(colorS) * m_colorR, GetG(colorS) * m_colorG, GetB(colorS) * m_colorB ); } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void FlatShade() { ColorE* pcolorE = m_pcolorEChunk; WORD mask = m_wZBufferMask; int index = m_count; do { if ((mask & 1) == 0) { pcolorE[MakeIndex(index)] = FlatShade(pcolorE[MakeIndex(index)]); } mask = mask >> 1; index ++; } while (index < 0); } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void CopyTextureZTestZWriteGouraud() { Color565* pcolor565 = (Color565*)m_pdest; Fixed u = m_uChunk; Fixed v = m_vChunk; Fixed131 i = m_iChunk; FixedZ z = m_zChunk; WORD* pz = (WORD*)m_pzChunk; int index = m_count; do { WORD zs = WORD(z.GetInteger(16)); WORD zd = pz[MakeIndex(index)]; if (zs <= zd) { pz[MakeIndex(index)] = zs; DWORD xt = (u.GetInteger(1) & m_umask); DWORD yt = (v.GetInteger(m_ushift + 1, true) & m_vmask); Color565 color565 = *(Color565*)(m_pbTexture + xt + yt); pcolor565[MakeIndex(index)] = color565 * i; } z += m_dzdx; u += m_dudx; v += m_dvdx; i += m_didx; index ++; } while (index < 0); } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void CopyTextureZTestZWriteGouraudAndColorKey() { Color565* pcolor565 = (Color565*)m_pdest; Fixed u = m_uChunk; Fixed v = m_vChunk; Fixed131 i = m_iChunk; FixedZ z = m_zChunk; WORD* pz = (WORD*)m_pzChunk; int index = m_count; do { WORD zs = WORD(z.GetInteger(16)); WORD zd = pz[MakeIndex(index)]; if (zs <= zd) { DWORD xt = (u.GetInteger(1) & m_umask); DWORD yt = (v.GetInteger(m_ushift + 1, true) & m_vmask); Color565 color565 = *(Color565*)(m_pbTexture + xt + yt); if (color565 != 0) { pz[MakeIndex(index)] = zs; pcolor565[MakeIndex(index)] = color565 * i; } } z += m_dzdx; u += m_dudx; v += m_dvdx; i += m_didx; index ++; } while (index < 0); } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void GouraudShade() { ColorE* pcolorE = m_pcolorEChunk; Fixed131 i = m_iChunk; WORD mask = m_wZBufferMask; int index = m_count; do { if ((mask & 1) == 0) { ColorE colorS = pcolorE[MakeIndex(index)]; pcolorE[MakeIndex(index)] = colorS * i; } mask = mask >> 1; i += m_didx; index ++; } while (index < 0); } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void LoadGouraudColor() { ColorE* pcolorE = m_pcolorEChunk; Fixed131 i = m_iChunk; WORD mask = m_wZBufferMask; int index = m_count; do { if ((mask & 1) == 0) { Fixed1616 i1616 = Fixed1616(i.GetFixed(), -i.FractionBits()); pcolorE[MakeIndex(index)] = MakeColorE(i1616, i1616, i1616); } mask = mask >> 1; i += m_didx; index ++; } while (index < 0); } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// ColorE Blend11(const ColorE& c1, const ColorE& c2) { ColorE color = c1 + c2; if ((color & ColorESaturationMask) != 0) { if ((color & ColorERSaturationMask) != 0) { color |= ColorERMask; } if ((color & ColorEGSaturationMask) != 0) { color |= ColorEGMask; } if ((color & ColorEBSaturationMask) != 0) { color |= ColorEBMask; } } return color; } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void Blend11() { ColorE* pcolorE = m_pcolorEChunk; ColorE* pcolorEDest = m_pcolorEDest; WORD mask = m_wZBufferMask; int index = m_count; do { if ((mask & 1) == 0) { ColorE colorS = pcolorE [MakeIndex(index)]; ColorE colorD = pcolorEDest[MakeIndex(index)]; ColorE color = Blend11(colorS, colorD); pcolorE[MakeIndex(index)] = color; } mask = mask >> 1; index ++; } while (index < 0); } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void Blend1InvA() { ColorE* pcolorE = m_pcolorEChunk; ColorE* pcolorEDest = m_pcolorEDest; WORD mask = m_wZBufferMask; int index = m_count; do { if ((mask & 1) == 0) { ColorE colorS = pcolorE [MakeIndex(index)]; ColorE colorD = pcolorEDest[MakeIndex(index)]; pcolorE[MakeIndex(index)] = colorS + colorD * m_colorInvA; } mask = mask >> 1; index ++; } while (index < 0); } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void CopyToColor565Destination() { ColorE* pcolorE = m_pcolorEChunk; Color565* pcolor565 = (Color565*)m_pdest; WORD mask = m_wZBufferMask; int index = m_count; if (mask == 0) { do { pcolor565[MakeIndex(index)] = ColorEToColor565(pcolorE[MakeIndex(index)]); index++; } while (index < 0); } else { do { if ((mask & 1) == 0) { pcolor565[MakeIndex(index)] = ColorEToColor565(pcolorE[MakeIndex(index)]); } mask = mask >> 1; index ++; } while (index < 0); } } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void CopyToColor555Destination() { ColorE* pcolorE = m_pcolorEChunk; Color555* pcolor555 = (Color555*)m_pdest; WORD mask = m_wZBufferMask; int index = m_count; if (mask == 0) { do { pcolor555[MakeIndex(index)] = ColorEToColor555(pcolorE[MakeIndex(index)]); index++; } while (index < 0); } else { do { if ((mask & 1) == 0) { pcolor555[MakeIndex(index)] = ColorEToColor555(pcolorE[MakeIndex(index)]); } mask = mask >> 1; index++; } while (index < 0); } } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void ZTestAndWrite() { FixedZ z = m_zChunk; WORD* pz = (WORD*)m_pzChunk; WORD bit = 1; int index = m_count; do { WORD zs = WORD(z.GetInteger(16)); WORD zd = pz[MakeIndex(index)]; if (zs <= zd) { pz[MakeIndex(index)] = zs; } else { m_wZBufferMask |= bit; } bit = bit << 1; z += m_dzdx; index ++; } while (index < 0); } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void ZTest() { FixedZ z = m_zChunk; WORD* pz = (WORD*)m_pzChunk; WORD bit = 1; int index = m_count; do { WORD zs = WORD(z.GetInteger(16)); WORD zd = pz[MakeIndex(index)]; if (!(zs <= zd)) { m_wZBufferMask |= bit; } bit = bit << 1; z += m_dzdx; index ++; } while (index < 0); } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void ZWrite() { FixedZ z = m_zChunk; WORD* pz = (WORD*)m_pzChunk; WORD mask = m_wZBufferMask; int index = m_count; do { if ((mask & 1) == 0) { WORD zs = WORD(z.GetInteger(16)); pz[MakeIndex(index)] = zs; } mask = mask >> 1; z += m_dzdx; index ++; } while (index < 0); } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void ColorKeyTest() { ColorE* pcolorE = m_pcolorEChunk; WORD bit = 1; int index = m_count; do { ColorE colorE = pcolorE[MakeIndex(index)]; if (colorE == 0) { m_wZBufferMask |= bit; } bit = bit << 1; index ++; } while (index < 0); } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void DoPasses() { for(int pass = 0; pass < m_passCount; pass++) { (this->*(m_ppfnFillChunk[pass]))(); if (m_wZBufferMask == 0xffff) { break; } } } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void FillSubTriangleMultiPassChunk( const int ymin, const int ymax ) { // // fill the triangle // BYTE* pscan = m_pbSurface + ymin * m_pitchSurface; BYTE* pzscan = m_pbZBuffer + ymin * m_pitchSurface; for (int y = ymin; y < ymax; y++) { int count = m_xmax - m_xmin; if (count > 0) { // // Initial values // m_pdest = pscan + m_xmin * 2; m_pzChunk = pzscan + m_xmin * 2; m_uChunk = m_u; m_vChunk = m_v; m_iChunk = m_i; m_zChunk = m_z; // // ChunkSize pixel chunks // m_count = -ChunkSize; while (count >= ChunkSize) { m_wZBufferMask = 0; DoPasses(); m_pdest += 2 * ChunkSize; m_pzChunk += 2 * ChunkSize; m_uChunk += m_dudx * ChunkSize; m_vChunk += m_dvdx * ChunkSize; m_iChunk += m_didx * ChunkSize; m_zChunk += m_dzdx * ChunkSize; count -= ChunkSize; } // // Remaining pixels // if (count > 0) { int delta = ChunkSize - count; m_count = -count; m_pdest -= 2 * delta; m_pzChunk -= 2 * delta; m_wZBufferMask = 0; DoPasses(); } } // // y++ // pscan += m_pitchSurface; pzscan += m_pitchSurface; m_xminFrac += m_dxmindyFrac; if (m_xminFrac >= 0) { m_xminFrac -= 1; m_xmin += m_dxmindyBig; m_u += m_dudyBig; m_v += m_dvdyBig; m_i += m_didyBig; m_z += m_dzdyBig; } else { m_xmin += m_dxmindyLittle; m_u += m_dudyLittle; m_v += m_dvdyLittle; m_i += m_didyLittle; m_z += m_dzdyLittle; } m_xmaxFrac += m_dxmaxdyFrac; if (m_xmaxFrac >= 0) { m_xmaxFrac -= 1; m_xmax += m_dxmaxdyBig; } else { m_xmax += m_dxmaxdyLittle; } } } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void FillSubTriangleMultiPass( const int ymin, const int ymax ) { // // fill the triangle // BYTE* pscan = m_pbSurface + ymin * m_pitchSurface; BYTE* pzscan = m_pbZBuffer + ymin * m_pitchSurface; for (int y = ymin; y < ymax; y++) { int count = m_xmax - m_xmin; if (count > 0) { // // Initial values // m_pdest = pscan + m_xmin * 2; m_pzChunk = pzscan + m_xmin * 2; m_uChunk = m_u; m_vChunk = m_v; m_iChunk = m_i; m_zChunk = m_z; // // Call the scan routine // int delta = ChunkSize - count; m_count = -count; m_pdest -= 2 * delta; m_pzChunk -= 2 * delta; DoPasses(); } // // y++ // pscan += m_pitchSurface; pzscan += m_pitchSurface; m_xminFrac += m_dxmindyFrac; if (m_xminFrac >= 0) { m_xminFrac -= 1; m_xmin += m_dxmindyBig; m_u += m_dudyBig; m_v += m_dvdyBig; m_i += m_didyBig; m_z += m_dzdyBig; } else { m_xmin += m_dxmindyLittle; m_u += m_dudyLittle; m_v += m_dvdyLittle; m_i += m_didyLittle; m_z += m_dzdyLittle; } m_xmaxFrac += m_dxmaxdyFrac; if (m_xmaxFrac >= 0) { m_xmaxFrac -= 1; m_xmax += m_dxmaxdyBig; } else { m_xmax += m_dxmaxdyLittle; } } } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void FillSubTriangleTextureZTestZWriteAndColorKey( const int ymin, const int ymax ) { // // fill the triangle // BYTE* pscan = m_pbSurface + ymin * m_pitchSurface; BYTE* pzscan = m_pbZBuffer + ymin * m_pitchSurface; for (int y = ymin; y < ymax; y++) { int count = m_xmax - m_xmin; if (count > 0) { // // Initial values // Color565* pcolor565 = (Color565*)(pscan + m_xmin * 2); WORD* pz = (WORD*)(pzscan + m_xmin * 2); Fixed u = m_u; Fixed v = m_v; FixedZ z = m_z; // // Call the scan routine // int index = 0; if (m_bColorKeyOn) { do { WORD zs = WORD(z.GetInteger(16)); WORD zd = pz[index]; if (zs <= zd) { DWORD xt = (u.GetInteger(1) & m_umask); DWORD yt = (v.GetInteger(m_ushift + 1, true) & m_vmask); Color565 color565 = *(Color565*)(m_pbTexture + xt + yt); if (color565 != 0) { pz[index] = zs; pcolor565[index] = color565; } } z += m_dzdx; u += m_dudx; v += m_dvdx; index ++; } while (index < count); } else { do { WORD zs = WORD(z.GetInteger(16)); WORD zd = pz[index]; if (zs <= zd) { DWORD xt = (u.GetInteger(1) & m_umask); DWORD yt = (v.GetInteger(m_ushift + 1, true) & m_vmask); Color565 color565 = *(Color565*)(m_pbTexture + xt + yt); pz[index] = zs; pcolor565[index] = color565; } z += m_dzdx; u += m_dudx; v += m_dvdx; index ++; } while (index < count); } } // // y++ // pscan += m_pitchSurface; pzscan += m_pitchSurface; m_xminFrac += m_dxmindyFrac; if (m_xminFrac >= 0) { m_xminFrac -= 1; m_xmin += m_dxmindyBig; m_u += m_dudyBig; m_v += m_dvdyBig; m_z += m_dzdyBig; } else { m_xmin += m_dxmindyLittle; m_u += m_dudyLittle; m_v += m_dvdyLittle; m_z += m_dzdyLittle; } m_xmaxFrac += m_dxmaxdyFrac; if (m_xmaxFrac >= 0) { m_xmaxFrac -= 1; m_xmax += m_dxmaxdyBig; } else { m_xmax += m_dxmaxdyLittle; } } } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void FillSubTriangleNoop( const int ymin, const int ymax ) { } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void UpdateZBuffer() { if (m_psurface->GetSurfaceType().Test(SurfaceTypeZBuffer())) { if (m_pitchZBuffer != m_pitchSurface) { m_pitchZBuffer = m_pitchSurface; if (m_pbZBuffer) { delete m_pbZBuffer; } m_pbZBuffer = new BYTE[ m_pitchSurface * m_sizeSurface.Y() ]; } } else { if (m_pbZBuffer) { delete m_pbZBuffer; } m_pbZBuffer = NULL; } } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void UpdateTextureInfo() { if (m_psurfaceTexture) { m_pbTexture = m_psurfaceTexture->GetWritablePointer(); m_pitchTexture = m_psurfaceTexture->GetPitch(); m_sizeTexture = m_psurfaceTexture->GetSize(); m_uscale = (float)m_sizeTexture.X(); m_vscale = (float)m_sizeTexture.Y(); m_ushift = GetShift(m_sizeTexture.X()); m_vshift = GetShift(m_sizeTexture.Y()); m_umask = MakeMask(m_ushift, 1); m_vmask = MakeMask(m_vshift, m_ushift + 1); m_bColorKey = m_psurfaceTexture->HasColorKey(); } } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void CalcXMin( const VertexScreen* pva, const VertexScreen* pvb, const int ymin ) { // // calculate ydelta // const float qdy = 1 / (pvb->y - pva->y); const float yDelta = (float(ymin) + 0.5f) - pva->y; // // calculate dxmindy // const float dxmindy = (pvb->x - pva->x) * qdy; const float xminIntercept = pva->x + dxmindy * yDelta; m_xmin = MakeInt(xminIntercept); const float xDelta = (float(m_xmin) + 0.5f) - pva->x; if (GreaterEqualZero(dxmindy)) { m_dxmindyLittle = MakeInt(dxmindy - 0.5f); m_dxmindyBig = m_dxmindyLittle + 1; m_dxmindyFrac = dxmindy - float(m_dxmindyLittle); m_xminFrac = xminIntercept - (float(m_xmin) + 0.5f); } else { m_dxmindyLittle = MakeInt(dxmindy + 0.5f); m_dxmindyBig = m_dxmindyLittle - 1; m_dxmindyFrac = float(m_dxmindyLittle) - dxmindy; m_xminFrac = (float(m_xmin) - 0.5f) - xminIntercept; } // // calculate qu, qv, and qw deltas // m_dudyLittle = Fixed(m_uscale * (m_floatdudy + m_floatdudx * m_dxmindyLittle)); m_dvdyLittle = Fixed(m_vscale * (m_floatdvdy + m_floatdvdx * m_dxmindyLittle)); m_didyLittle = FixedD131(m_floatdidy + m_floatdidx * m_dxmindyLittle); m_dzdyLittle = FixedDZ (m_floatdzdy + m_floatdzdx * m_dxmindyLittle); if (m_dxmindyBig >= 0) { m_dudyBig = m_dudyLittle + m_dudx; m_dvdyBig = m_dvdyLittle + m_dvdx; m_didyBig = m_didyLittle + m_didx; m_dzdyBig = m_dzdyLittle + m_dzdx; } else { m_dudyBig = m_dudyLittle - m_dudx; m_dvdyBig = m_dvdyLittle - m_dvdx; m_didyBig = m_didyLittle - m_didx; m_dzdyBig = m_dzdyLittle - m_dzdx; } // // Initial values // m_u = Fixed(m_uscale * (pva->u + m_floatdudy * yDelta + m_floatdudx * xDelta)); m_v = Fixed(m_vscale * (pva->v + m_floatdvdy * yDelta + m_floatdvdx * xDelta)); m_i = Fixed131( (float(pva->color & 0xff) * g_componentFloatToIntScale / 255.0f) + m_floatdidy * yDelta + m_floatdidx * xDelta ); m_z = FixedZ(pva->z + m_floatdzdy * yDelta + m_floatdzdx * xDelta); } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void CalcXMax( const VertexScreen* pva, const VertexScreen* pvb, const int ymax ) { // // calculate ydelta // const float qdy = 1 / (pvb->y - pva->y); const float yDelta = (float(ymax) + 0.5f) - pva->y; // // calculate dxmaxdy // const float dxmaxdy = (pvb->x - pva->x) * qdy; const float xmaxIntercept = pva->x + dxmaxdy * yDelta; m_xmax = MakeInt(xmaxIntercept); if (GreaterEqualZero(dxmaxdy)) { m_dxmaxdyLittle = MakeInt(dxmaxdy - 0.5f); m_dxmaxdyBig = m_dxmaxdyLittle + 1; m_dxmaxdyFrac = dxmaxdy - float(m_dxmaxdyLittle); m_xmaxFrac = xmaxIntercept - (float(m_xmax) + 0.5f); } else { m_dxmaxdyLittle = MakeInt(dxmaxdy + 0.5f); m_dxmaxdyBig = m_dxmaxdyLittle - 1; m_dxmaxdyFrac = float(m_dxmaxdyLittle) - dxmaxdy; m_xmaxFrac = (float(m_xmax) - 0.5f) - xmaxIntercept; } } ////////////////////////////////////////////////////////////////////////////// // // Calculate Interpolants // ////////////////////////////////////////////////////////////////////////////// void CalculateInterpolants( const VertexScreen* pva, const VertexScreen* pvb, const VertexScreen* pvc, float xabn, float yabn, float xacn, float yacn ) { float uab = pvb->u - pva->u; float uac = pvc->u - pva->u; m_floatdudy = uab * xacn - uac * xabn; m_floatdudx = uac * yabn - uab * yacn; m_dudx = Fixed(m_uscale * m_floatdudx); float vab = pvb->v - pva->v; float vac = pvc->v - pva->v; m_floatdvdy = vab * xacn - vac * xabn; m_floatdvdx = vac * yabn - vab * yacn; m_dvdx = Fixed(m_vscale * m_floatdvdx); int ia = int(pva->color & 0xff); int ib = int(pvb->color & 0xff); int ic = int(pvc->color & 0xff); float iab = (float(ib - ia) * g_componentFloatToIntScale / 255.0f); float iac = (float(ic - ia) * g_componentFloatToIntScale / 255.0f); m_floatdidy = iab * xacn - iac * xabn; m_floatdidx = iac * yabn - iab * yacn; m_didx = FixedD131(m_floatdidx); float zab = pvb->z - pva->z; float zac = pvc->z - pva->z; m_floatdzdy = zab * xacn - zac * xabn; m_floatdzdx = zac * yabn - zab * yacn; m_dzdx = FixedDZ(m_floatdzdx); } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void DrawFlatTriangle( const VertexScreen* pva, const VertexScreen* pvb, const VertexScreen* pvc ) { SetColor(pva->color); DrawTriangle(pva, pvb, pvc); } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void DrawTriangle( const VertexScreen* pva, const VertexScreen* pvb, const VertexScreen* pvc ) { // // Get int y coordinates // float ya = pva->y; float yb = pvb->y; float yc = pvc->y; int iya; int iyb; int iyc; MakeIntMacro(ya, iya); MakeIntMacro(yb, iyb); MakeIntMacro(yc, iyc); { // // If the triangle has zero height there is nothing to draw. // int idyab = (iyb - iya); int idyac = (iyc - iya); int idybc = (iyc - iyb); if (idyab == 0 && idyac == 0 && idybc == 0) { return; } } // // Get int x coordinates // { float xa = pva->x; float xb = pvb->x; float xc = pvc->x; int ixa; int ixb; int ixc; MakeIntMacro(xa, ixa); MakeIntMacro(xb, ixb); MakeIntMacro(xc, ixc); int idxab = (ixb - ixa); int idxac = (ixc - ixa); int idxbc = (ixc - ixb); // // If the triangle has zero width there is nothing to draw. // if (idxab == 0 && idxac == 0 && idxbc == 0) { return; } } // // Calculate the triangles area // float xab = pvb->x - pva->x; float yab = pvb->y - pva->y; float xac = pvc->x - pva->x; float yac = pvc->y - pva->y; float area = yab * xac - yac * xab; // // Figure out which vertex is topmost. // const VertexScreen* pvaDraw; const VertexScreen* pvbDraw; const VertexScreen* pvcDraw; if (iya <= iyc && iya <= iyb) { pvaDraw = pva; pvbDraw = pvb; pvcDraw = pvc; } else if (iyc < iya && iyc < iyb) { pvaDraw = pvc; pvbDraw = pva; pvcDraw = pvb; int i = iya; iya = iyc; iyc = iyb; iyb = i; } else { pvaDraw = pvb; pvbDraw = pvc; pvcDraw = pva; int i = iya; iya = iyb; iyb = iyc; iyc = i; } // // If area is negative switch from ccw to cw // if (GreaterZero(area)) { if (m_cullMode == CullModeCCW) { return; } m_pixels += area; } else { if (m_cullMode == CullModeCW) { return; } m_pixels -= area; swap(pvbDraw, pvcDraw); swap(iyb, iyc); } // // Calculate the interpolants // float qarea = 1 / area; float xabn = xab * qarea; float yabn = yab * qarea; float xacn = xac * qarea; float yacn = yac * qarea; CalculateInterpolants(pva, pvb, pvc, xabn, yabn, xacn, yacn); // // Draw the subtriangles // if (iya == iyb) { CalcXMin(pvbDraw, pvcDraw, iyb); CalcXMax(pvaDraw, pvcDraw, iya); (this->*m_pfnFillSubTriangle)(iyb, iyc); } else if (iya == iyc) { CalcXMin(pvaDraw, pvbDraw, iya); CalcXMax(pvcDraw, pvbDraw, iyc); (this->*m_pfnFillSubTriangle)(iya, iyb); } else if (iyb == iyc) { CalcXMin(pvaDraw, pvbDraw, iya); CalcXMax(pvaDraw, pvcDraw, iya); (this->*m_pfnFillSubTriangle)(iya, iyb); } else if (iyb < iyc) { CalcXMin(pvaDraw, pvbDraw, iya); CalcXMax(pvaDraw, pvcDraw, iya); (this->*m_pfnFillSubTriangle)(iya, iyb); CalcXMin(pvbDraw, pvcDraw, iyb); (this->*m_pfnFillSubTriangle)(iyb, iyc); } else { CalcXMin(pvaDraw, pvbDraw, iya); CalcXMax(pvaDraw, pvcDraw, iya); (this->*m_pfnFillSubTriangle)(iya, iyc); CalcXMax(pvcDraw, pvbDraw, iyc); (this->*m_pfnFillSubTriangle)(iyc, iyb); } } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void DrawLine( const VertexScreen* pva, const VertexScreen* pvb ) { ZAssert(pva->color == pvb->color); // // snap to pixel centers // int xstart = FloorInt(pva->x); int ystart = FloorInt(pva->y); int xend = FloorInt(pvb->x); int yend = FloorInt(pvb->y); int xdelta = xend - xstart; int ydelta = yend - ystart; int error; int ddestMajor; int ddestMinor; int derrorMajor; int derrorMinor; int count; if (abs(xdelta) >= abs(ydelta)) { // // Handle zero sized lines // if (xdelta == 0) { return; } // // Mostly horizontal line // count = abs(xdelta); if (ydelta > 0) { ddestMinor = m_pitchSurface; derrorMajor = ydelta; } else { ddestMinor = -int(m_pitchSurface); derrorMajor = -ydelta; } if (xdelta > 0) { ddestMajor = 2; derrorMinor = -xdelta; error = -xdelta / 2; } else { ddestMajor = -2; derrorMinor = xdelta; error = xdelta / 2; } } else { // // Mostly Vertical line. // count = abs(ydelta); if (xdelta > 0) { ddestMinor = 2; derrorMajor = xdelta; } else { ddestMinor = -2; derrorMajor = -xdelta; } if (ydelta > 0) { ddestMajor = m_pitchSurface; derrorMinor = -ydelta; error = -ydelta / 2; } else { ddestMajor = -int(m_pitchSurface); derrorMinor = ydelta; error = ydelta / 2; } } // // Minor steps include major steps // derrorMinor += derrorMajor; ddestMinor += ddestMajor; // // Draw the pixels // if (count > 0) { // // Get a pixel value from a D3DColor // WORD pixel; if (m_b565) { pixel = (WORD)( ((pva->color >> 8) & 0xf800) | ((pva->color >> 5) & 0x07e0) | ((pva->color >> 3) & 0x001f) ); } else { pixel = (WORD)( ((pva->color >> 9) & 0x7c00) | ((pva->color >> 6) & 0x03e0) | ((pva->color >> 3) & 0x001f) ); } // // Pre make the first major step // error += derrorMajor; // // Starting address // BYTE* pdest = m_pbSurface + xstart * 2 + ystart * m_pitchSurface; // // Loop through the pixels // do { *(WORD*)pdest = pixel; if (error > 0) { pdest += ddestMinor; error += derrorMinor; } else { pdest += ddestMajor; error += derrorMajor; } count--; } while (count > 0); } } ////////////////////////////////////////////////////////////////////////////// // // This code is subpixel accurate but sometimes doesn't draw the last pixel when it should // ////////////////////////////////////////////////////////////////////////////// /* void DrawLine( const VertexScreen* pva, const VertexScreen* pvb ) { ZAssert(pva->color == pvb->color); WORD color = WORD(pva->color); float xdelta = pvb->x - pva->x; float ydelta = pvb->y - pva->y; if (abs(xdelta) >= abs(ydelta)) { // // Handle zero sized line. // if (xdelta == 0.0f) { return; } // // Mostly horizontal line // int xstart = FloorInt(pva->x); int xend = FloorInt(pvb->x); int ystart = FloorInt(pva->y); int ddestdx; int ddestdy; if (xend > xstart) { ddestdx = 2; } else { ddestdx = -2; xdelta = -xdelta; } float slope = ydelta / xdelta; float e; if (slope == 0) { e = 0; } else { // // x distance from end point to starting pixel center // float xdeltaCenter = (float(xstart) + 0.5f - pva->x); // // y intercept of pixel x center line // float ycenter = pva->y + slope * xdeltaCenter; // // error // if (slope > 0) { // // error = distance of intercept from pixel max // e = ycenter - (float(ystart) + 1.0f); ddestdy = m_pitchSurface; } else { // // error = distance of intercept from pixel min // e = float(ystart) - ycenter; slope = -slope; ddestdy = -FloorInt(m_pitchSurface); } } // // Draw the pixels // BYTE* pdest = m_pbSurface + xstart * 2 + ystart * m_pitchSurface; int count = abs(xend - xstart); while (count > 0) { *(WORD*)pdest = color; pdest += ddestdx; e += slope; if (e > 0) { pdest += ddestdy; e -= 1; } count--; } } else { // // Mostly Vertical line. // int xstart = FloorInt(pva->x); int ystart = FloorInt(pva->y); int yend = FloorInt(pvb->y); int ddestdx; int ddestdy; if (yend > ystart) { ddestdy = m_pitchSurface; } else { ddestdy = -FloorInt(m_pitchSurface); ydelta = -ydelta; } float slope = xdelta / ydelta; float e; if (slope == 0) { e = 0; } else { // // y distance from end point to starting pixel center // float ydeltaCenter = (float(ystart) + 0.5f - pva->y); // // x intercept of pixel x center line // float xcenter = pva->x + slope * ydeltaCenter; // // error // if (slope > 0) { // // error = distance of intercept from pixel max // e = xcenter - (float(xstart) + 1.0f); ddestdx = 2; } else { // // error = distance of intercept from pixel min // e = float(xstart) - xcenter; slope = -slope; ddestdx = -2; } } // // Draw the pixels // BYTE* pdest = m_pbSurface + xstart * 2 + ystart * m_pitchSurface; int count = abs(yend - ystart); while (count > 0) { *(WORD*)pdest = color; pdest += ddestdy; e += slope; if (e > 0) { pdest += ddestdx; e -= 1; } count--; } } } */ ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void DrawPoint( const VertexScreen* pva ) { } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// bool ShouldZTest() { return (m_pbZBuffer != NULL) && m_bZTest; } bool ShouldZWrite() { return (m_pbZBuffer != NULL) && m_bZWrite; } void UpdatePointers() { if (m_bUpdatePointers) { m_bUpdatePointers = false; // // Primitives // m_pfnDrawTriangle = DrawTriangle; m_pfnDrawLine = DrawLine; m_pfnDrawPoint = DrawPoint; switch (m_shadeMode) { case ShadeModeFlat: m_pfnDrawTriangle = DrawFlatTriangle; break; case ShadeModeNone: case ShadeModeCopy: case ShadeModeGouraud: m_pfnDrawTriangle = DrawTriangle; break; } // // Is ColorKey on? // m_bColorKeyOn = m_bColorKeyEnabled && m_psurfaceTexture != NULL && m_psurfaceTexture->HasColorKey(); if (m_bColorKeyOn) { ZAssert(m_psurfaceTexture->GetColorKey() == Color::Black()); } // // Subtriangles // m_passCount = 0; if (m_shadeMode == ShadeModeNone) { m_pfnFillSubTriangle = FillSubTriangleNoop; return; } else if (m_psurfaceTexture == NULL) { if ( m_blendMode == BlendModeSourceAlpha && m_shadeMode == ShadeModeFlat && !ShouldZTest() && !ShouldZWrite() && m_b565 ) { m_pfnFillSubTriangle = FillSubTriangleMultiPass; m_ppfnFillChunk[m_passCount++] = FlatBlend1InvA; return; } } else if ( (m_pbZBuffer != NULL) && ShouldZTest() && ShouldZWrite() && m_b565 ) { // // Fast paths // m_pfnFillSubTriangle = FillSubTriangleMultiPass; if (m_blendMode == BlendModeSource) { if (m_shadeMode == ShadeModeCopy) { m_pfnFillSubTriangle = FillSubTriangleTextureZTestZWriteAndColorKey; } else { // // Multi pass // switch (m_shadeMode) { case ShadeModeFlat: if (m_bColorKeyOn) { m_ppfnFillChunk[m_passCount++] = CopyTextureZTestZWriteFlatAndColorKey; } else { m_ppfnFillChunk[m_passCount++] = CopyTextureZTestZWriteFlat; } break; case ShadeModeGouraud: if (m_bColorKeyOn) { m_ppfnFillChunk[m_passCount++] = CopyTextureZTestZWriteGouraudAndColorKey; } else { m_ppfnFillChunk[m_passCount++] = CopyTextureZTestZWriteGouraud; } break; default: ZBadCase(); } } return; } else if (m_blendMode == BlendModeAdd) { switch (m_shadeMode) { case ShadeModeCopy: m_ppfnFillChunk[m_passCount++] = CopyTextureZTestZWriteBlend11; return; case ShadeModeFlat: if (m_bColorKeyOn) { m_ppfnFillChunk[m_passCount++] = FlatTextureZTestZWriteBlend11; return; } } } } // // Chunked multi pass // m_pfnFillSubTriangle = FillSubTriangleMultiPassChunk; // // ZTest // if (ShouldZTest()) { m_ppfnFillChunk[m_passCount++] = ZTest; } // // Source color // if (m_psurfaceTexture) { // // Texture // m_ppfnFillChunk[m_passCount++] = LoadColor565Texture; // // Color key // if (m_bColorKeyOn) { m_ppfnFillChunk[m_passCount++] = ColorKeyTest; } // // Shading // switch (m_shadeMode) { case ShadeModeCopy: break; case ShadeModeFlat: m_ppfnFillChunk[m_passCount++] = FlatShade; break; case ShadeModeGouraud: case ShadeModeGlobalColor: m_ppfnFillChunk[m_passCount++] = GouraudShade; break; } } else { // // No texture shading // switch (m_shadeMode) { case ShadeModeGlobalColor: // !!! ZUnimplemented(); // fall through to flat shading case ShadeModeCopy: case ShadeModeFlat: m_ppfnFillChunk[m_passCount++] = LoadFlatColor; break; case ShadeModeGouraud: m_ppfnFillChunk[m_passCount++] = LoadGouraudColor; break; } } // // Alpha Blending // if ( m_blendMode == BlendModeAdd || m_blendMode == BlendModeSourceAlpha ) { if (m_b565) { m_ppfnFillChunk[m_passCount++] = Load565Dest; } else { m_ppfnFillChunk[m_passCount++] = Load555Dest; } if (m_blendMode == BlendModeAdd) { m_ppfnFillChunk[m_passCount++] = Blend11; } else { m_ppfnFillChunk[m_passCount++] = Blend1InvA; } }; // // Pixel store // if (m_b565) { m_ppfnFillChunk[m_passCount++] = CopyToColor565Destination; } else { m_ppfnFillChunk[m_passCount++] = CopyToColor555Destination; } // // ZWrite // if (ShouldZWrite()) { m_ppfnFillChunk[m_passCount++] = ZWrite; } ZAssert(m_passCount <= MaxChunkPasses); } } ////////////////////////////////////////////////////////////////////////////// // // Debug // ////////////////////////////////////////////////////////////////////////////// void CheckVertices(const VertexScreen* pvertex, int vcount) { /* #ifdef _DEBUG { float error = 0.5f; for (int index = 0; index < vcount; index++) { ZAssert(pvertex[index].x >= m_rectClip.XMin() - error); ZAssert(pvertex[index].x <= m_rectClip.XMax() + error); ZAssert(pvertex[index].y >= m_rectClip.YMin() - error); ZAssert(pvertex[index].y <= m_rectClip.YMax() + error); ZAssert(pvertex[index].z >= 0.0f - error); ZAssert(pvertex[index].z <= 1.0f + error); } } #endif */ VertexScreen* pcheck = (VertexScreen*)pvertex; for (int index = 0; index < vcount; index++) { if (pcheck[index].x < m_rectClip.XMin()) { pcheck[index].x = m_rectClip.XMin(); } else if (pcheck[index].x > m_rectClip.XMax()) { pcheck[index].x = m_rectClip.XMax(); } if (pcheck[index].y < m_rectClip.YMin()) { pcheck[index].y = m_rectClip.YMin(); } else if (pcheck[index].y > m_rectClip.YMax()) { pcheck[index].y = m_rectClip.YMax(); } if (pcheck[index].z < 0) { pcheck[index].z = 0; } else if (pcheck[index].z > 1) { pcheck[index].z = 1; } } } void CheckIndices(const WORD* pindex, int icount, int vcount) { #ifdef _DEBUG for (int index = 0; index < icount; index++) { ZAssert(pindex[index] >=0 && pindex[index] < vcount); } #endif } ////////////////////////////////////////////////////////////////////////////// // // Rendering // ////////////////////////////////////////////////////////////////////////////// void DrawTriangles(const VertexScreen* pvertex, int vcount, const WORD* pindex, int icount) { InitializeControlWord(); CheckVertices(pvertex, vcount); CheckIndices(pindex, icount, vcount); UpdatePointers(); for(int index = 0; index < icount; index += 3) { (this->*m_pfnDrawTriangle)( &(pvertex[pindex[index ]]), &(pvertex[pindex[index + 1]]), &(pvertex[pindex[index + 2]]) ); } RestoreControlWord(); } void DrawLines(const VertexScreen* pvertex, int vcount, const WORD* pindex, int icount) { InitializeControlWord(); CheckVertices(pvertex, vcount); CheckIndices(pindex, icount, vcount); UpdatePointers(); for(int index = 0; index < icount; index += 2) { (this->*m_pfnDrawLine)( &(pvertex[pindex[index ]]), &(pvertex[pindex[index + 1]]) ); } } void DrawPoints(const VertexScreen* pvertex, int vcount) { CheckVertices(pvertex, vcount); if (m_b565) { // 565 for (int index = 0; index < vcount; index++) { BYTE* ppixel = m_pbSurface + FloorInt(pvertex[index].x) * 2 + FloorInt(pvertex[index].y) * m_pitchSurface; DWORD color = pvertex[index].color; WORD pixel = (WORD)( ((color >> 8) & 0xf800) | ((color >> 5) & 0x07e0) | ((color >> 3) & 0x001f) ); *(WORD*)(ppixel) = pixel; } } else { // 555 for (int index = 0; index < vcount; index++) { BYTE* ppixel = m_pbSurface + FloorInt(pvertex[index].x) * 2 + FloorInt(pvertex[index].y) * m_pitchSurface; DWORD color = pvertex[index].color; WORD pixel = (WORD)( ((color >> 9) & 0x7c00) | ((color >> 6) & 0x03e0) | ((color >> 3) & 0x001f) ); *(WORD*)(ppixel) = pixel; } } } }; TRef CreateSoftwareRasterizer(PrivateSurface* psurface) { return new SoftwareRasterizer(psurface); }