MuckyFoot-UrbanChaos/fallen/DDEngine/Headers/polypage.h
2017-05-20 11:14:17 +10:00

314 lines
9.3 KiB
C++

// polypage.h
//
// PolyPage class - main low-level rendering
#ifndef TARGET_DC
// PC
// this makes absolutely fuck-all difference to speed (tested)
//#define TEX_EMBED // must be set the same in D3DTexture.h
// Do need to sort, and so need polybuffers
#define WE_NEED_POLYBUFFERS_PLEASE_BOB 1
#else
// DREAMCAST
// But it makes the VQ much more efficient, so do it!
#define TEX_EMBED // must be set the same in D3DTexture.h
// Don't need to sort, and so don't need polybuffers
#define WE_NEED_POLYBUFFERS_PLEASE_BOB 0
#endif
#ifndef _POLYPAGE_
#define _POLYPAGE_
#include "renderstate.h"
#include "vertexbuffer.h"
#include "polypoint.h"
class PolyPage;
// PolyPoly
//
// a polygon in a PolyPage
#if WE_NEED_POLYBUFFERS_PLEASE_BOB
struct PolyPoly
{
float sort_z; // z-value to sort on
UWORD first_vertex; // first vertex #
UWORD num_vertices; // number of vertices; if top bit set, draw as wireframe
PolyPage* page; // page for polygon (only when in a bucket)
PolyPoly* next; // next polygon (only when in a bucket)
};
inline bool operator<(const PolyPoly& arg1, const PolyPoly& arg2) { return arg1.sort_z < arg2.sort_z; }
inline bool operator<=(const PolyPoly& arg1, const PolyPoly& arg2) { return arg1.sort_z <= arg2.sort_z; }
inline bool operator>(const PolyPoly& arg1, const PolyPoly& arg2) { return !(arg1 <= arg2); }
inline bool operator>=(const PolyPoly& arg1, const PolyPoly& arg2) { return !(arg1 < arg2); }
#endif //#if WE_NEED_POLYBUFFERS_PLEASE_BOB
// PolyPage
//
// a polygon page
#pragma pack( push, 4 )
class PolyPage
{
public:
PolyPage(ULONG logsize = 6);
~PolyPage();
#ifdef TEX_EMBED
// texture embedding
PolyPage *pTheRealPolyPage; // The poly page you actually need to add tris to.
// This is never NULL, but may point back to this one.
#if USE_FANCY_TEXTURE_PAGES_PLEASE_BOB
void SetTexOffset ( D3DTexture *src );
#else
void SetTexEmbed(float u_scale, float u_offset, float v_scale, float v_offset);
#endif
void SetTexOffset(UBYTE offset); // 0 for (0,0)-(1,1) else 128 + (0-15) for the subtexture
#endif
#if WE_NEED_POLYBUFFERS_PLEASE_BOB
// fan submission
void AddFan(POLY_Point** pts, ULONG num_vertices);
void AddWirePoly(POLY_Point** pts, ULONG num_vertices);
#endif
// set greenscreen
static void SetGreenScreen(bool enabled = true);
// set scaling for different screen sizes
static void SetScaling(float xmul, float ymul);
#ifdef TARGET_DC
// DC does all our sorting for us.
static void EnableAlphaSort() {}
static void DisableAlphaSort() {}
static bool AlphaSortEnabled() { return FALSE; }
#else
// sort polygons in approx. Z order
void SortBackFirst();
// sort enabling
static void EnableAlphaSort() { s_AlphaSort = true; }
static void DisableAlphaSort() { s_AlphaSort = false; }
static bool AlphaSortEnabled() { return s_AlphaSort; }
#endif
// render polygons to card
#if WE_NEED_POLYBUFFERS_PLEASE_BOB
bool NeedsRendering() { return m_PolyBufUsed > 0; }
#else
bool NeedsRendering() { return m_VBUsed > 0; }
#endif
void Render(IDirect3DDevice3* dev);
#if WE_NEED_POLYBUFFERS_PLEASE_BOB
// render polygons using bucket sort
void AddToBuckets(PolyPoly* buckets[], int count);
void DrawSinglePoly(PolyPoly* poly, IDirect3DDevice3* dev);
#endif
// clear without rendering
void Clear();
// render state for the page
RenderState RS;
// static members
#ifndef TARGET_DC
static bool s_AlphaSort; // alpha sort enabled flag
#endif
static ULONG s_ColourMask; // colour mask for green-screen monitor FX
static float s_XScale; // X scale for screen vertices
static float s_YScale; // Y scale for screen vertices
PolyPoint2D* PointAlloc(ULONG num_points); // allocate some points - DONT USE.
PolyPoint2D* FanAlloc(ULONG num_points); // Allocate a fan polygon.
// You just fill in the data, the indices are handled magically.
#ifdef TEX_EMBED
float m_UScale;
float m_UOffset;
float m_VScale;
float m_VOffset;
#endif
//private:
// member variables
VertexBuffer* m_VertexBuffer; // vertex buffer
PolyPoint2D* m_VertexPtr; // pointer to vertices in buffer
ULONG m_VBLogSize; // log2 of buffer size
ULONG m_VBUsed; // number of vertices used
ULONG GetVBSize() { return 1 << m_VBLogSize; }
#if WE_NEED_POLYBUFFERS_PLEASE_BOB
PolyPoly* m_PolyBuffer; // polygon buffer
ULONG m_PolyBufSize; // size of polygon buffer
ULONG m_PolyBufUsed; // number of polygons used
PolyPoly* m_PolySortBuffer; // polygon sort buffer
ULONG m_PolySortBufSize; // size of polygon sort buffer
#else
// Index buffer.
WORD *m_pwIndexBuffer; // The list of indices.
ULONG m_iNumIndicesAlloc; // How many indices are allocated.
ULONG m_iNumIndicesUsed; // How many indices are used.
#endif
#if USE_D3D_VBUF
IDirect3DVertexBuffer* m_VB; // vertex buffer pointer, only used in bucket sort
#endif
#if WE_NEED_POLYBUFFERS_PLEASE_BOB
// SortBackFirst iteration
void MergeSortIteration(ULONG sort_len);
#endif
// submission helpers
// PolyPoint2D* PointAlloc(ULONG num_points); // allocate some points
#if WE_NEED_POLYBUFFERS_PLEASE_BOB
PolyPoly* PolyBufAlloc(); // allocate a polygon
#endif
// massage vertices according to RS.GetEffect()
void MassageVertices();
};
#pragma pack( pop )
extern PolyPage POLY_Page[POLY_NUM_PAGES];
#endif
// A routine to emulate the DC's DrawPrimtiveMM call on the PC, so
// that people can use it when developing on the PC.
// An actual function.
// Notes:
//
// No front-plane clipping is performed - do it yourself, or use the old AddTri routs.
// Side-band clipping is done by the hardware.
// Only D3D_VERTEX and D3D_LVERTEX types supported.
// No alpha-blended/alpha-tested polys allowed - solid only.
// Lighting is complex - yell at TomF if you want to do lighting. I'm not going to address it in this header file.
// The 12th byte of the vertex data holds the index
// of the matrix it uses for transformation. This byte is the least-significant
// part of the mantissa for N.X - it makes no difference to the lighting at all.
// You can set it easily using this macro:
//#define SET_MM_INDEX(v,i) (((unsigned char*) &v)[12] = (unsigned char)i)
// Remember to do this AFTER copying in all the standard data :-)
// The indices are not actually in list order - they are in strip order, but
// an index of -1 (0xFFFF) starts a new strip. So the order
// The number of indices supplied MUST include the final FFFF. Also, when
// allocating the indices, make sure you allocate one more. Doesn't matter what's in it,
// but it must be valid memory. A small bug in the MS driver means this word is read,
// then discarded, and it doesn't cause a problem except when the index falls off the
// end of an allocated page and causes a page fault. Took me ages to find that bug.
// I will be checking that it is 0x1234 for debugging purposes, unless you give
// me a good reason not to (e.g. you're storing index lists right next to each other).
//
// On this strips-with-termination thing, the index list 0,1,2,3,4,-1,5,6,7,-1,2,4,8,-1 gives you:
//
// 1---3 5---6
// |\ |\ | /
// | \ | \ | /
// | \| \ |/
// 0---2---4 7
// | /
// | /
// |/
// 8
//
// If you want to generate optimal strips from random indexed list data, I have
// some utility routs that will do it for you. Yell - TomF.
// The matrices are generated in a slightly odd way. The easiest way to do this
// is to call this function to generate them:
// If mWorldMatrix == NULL, then the rout will get it from the standard camera setup.
extern void GenerateMMMatrixFromStandardD3DOnes ( D3DMATRIX *mOutput,
const D3DMATRIX *mProjectionMatrix,
const D3DMATRIX *mWorldMatrix,
const D3DVIEWPORT2 *d3dvpt );
// You can usually get the standard data from these globals - I keep them
// all current, and update g_matWorld when you call POLY_set_local_rotation
// and similar calls. You can use a different matrix of course and not call
// POLY_set_local_rotation, which is probably slightly faster.
extern D3DMATRIX g_matProjection;
// Actually, don't use g_matWorld, just pass in NULL.
extern D3DMATRIX g_matWorld;
extern D3DVIEWPORT2 g_viewData;
#ifdef TARGET_DC
// Just a straight alias.
#define DrawIndPrimMM(dev,type,d3dmm,numvert,pwind,numind) dev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,type,(void*)d3dmm,numvert,pwind,numind,D3DDP_MULTIMATRIX)
#else
// This is already defined by DX in a DC build.
struct D3DMULTIMATRIX
{
LPVOID lpvVertices; // Pointer to the vertex data. MUST be 32-byte aligned.
LPD3DMATRIX lpd3dMatrices; // Pointer to the array of matrices. MUST be 32-byte aligned.
LPVOID lpvLightDirs; // Pointer to the array of light vectors (NULL if not lighting). MUST be 8-byte aligned.
LPD3DCOLOR lpLightTable; // Pointer to the fade table (NULL if not lighting). MUST be 4-byte aligned.
};
// Also in the DC/DX headers,
#define SET_MM_INDEX(v,i) (((unsigned char*) &v)[12] = (unsigned char)i)
// dwFVFType must be D3DFVF_VERTEX or D3DFVF_LVERTEX.
// d3dmm is the multimatrix info block:
extern HRESULT DrawIndPrimMM ( LPDIRECT3DDEVICE3 lpDevice,
DWORD dwFVFType,
D3DMULTIMATRIX *d3dmm,
WORD wNumVertices,
WORD *pwIndices,
DWORD dwNumIndices );
#endif
// Useful.
#define GET_MM_INDEX(v) (((unsigned char*)&v)[12])