Files
fs2open.github.com/code/graphics/grd3dcalls.cpp
T

479 lines
15 KiB
C++

/*
* Copyright (C) Volition, Inc. 1999. All rights reserved.
*
* All source code herein is the property of Volition, Inc. You may not sell
* or otherwise commercially exploit the source or things you created based on the
* source.
*
*/
/*
** $Logfile: /Freespace2/code/Graphics/GrD3DCalls.cpp $
*/
#include <d3d8.h>
#include "graphics/grd3d.h"
#include "graphics/grd3dinternal.h"
#include "cmdline/cmdline.h"
// Uncomment this to disable checking if states are already set, slower but useful for searching for bugs
#define D3D_CALLS_CHECK 1
// Heres the internal vertex information that DX need to know to render them
VertexTypeInfo vertex_types[D3DVT_MAX] =
{
(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1), sizeof(D3DVERTEX2D),
(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2), sizeof(D3DTLVERTEX),
(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1), sizeof(D3DLVERTEX),
(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX2), sizeof(D3DVERTEX),
(D3DFVF_XYZ /*| D3DFVF_PSIZE*/), sizeof(D3DPOINTVERTEX),
};
// This is all stuff needed for set render state calls
const float fone = 1.0f;
const float fzero = 0.0f;
const float fsixtyfour = 64.0f;
DWORD *pfone = (DWORD *) &fone;
DWORD *pfzero = (DWORD *) &fzero;
DWORD *pfsixtyfour = (DWORD *) &fsixtyfour;
const int NUM_STATES = 174;
unsigned long current_render_states[NUM_STATES];
// These are the default states that D3D8 starts with an returns to on a reset
const unsigned long default_render_states[NUM_STATES] =
{
0,0,0,0,0,0,0, // not used
D3DZB_TRUE, // D3DRS_ZENABLE = 7,
D3DFILL_SOLID, // D3DRS_FILLMODE = 8,
D3DSHADE_GOURAUD, // D3DRS_SHADEMODE = 9,
0, // D3DRS_LINEPATTERN = 10,
0,0,0,
TRUE, // D3DRS_ZWRITEENABLE = 14,
FALSE, // D3DRS_ALPHATESTENABLE = 15,
TRUE, // D3DRS_LASTPIXEL = 16,
0,0,
D3DBLEND_ONE, // D3DRS_SRCBLEND = 19,
D3DBLEND_ZERO, // D3DRS_DESTBLEND = 20,
0,
D3DCULL_CCW, // D3DRS_CULLMODE = 22,
D3DCMP_LESSEQUAL, // D3DRS_ZFUNC = 23,
0x00000000, // D3DRS_ALPHAREF = 24, ?????????????????????
D3DCMP_ALWAYS, // D3DRS_ALPHAFUNC = 25,
FALSE, // D3DRS_DITHERENABLE = 26,
FALSE, // D3DRS_ALPHABLENDENABLE = 27,
FALSE, // D3DRS_FOGENABLE = 28,
FALSE, // D3DRS_SPECULARENABLE = 29,
0, // D3DRS_ZVISIBLE (not supported) = 30,
0,0,0,
0, // D3DRS_FOGCOLOR = 34,
D3DFOG_NONE, // D3DRS_FOGTABLEMODE = 35,
*pfzero, // D3DRS_FOGSTART = 36,
*pfone, // D3DRS_FOGEND = 37,
*pfone, // D3DRS_FOGDENSITY = 38,
0,
FALSE, // D3DRS_EDGEANTIALIAS = 40,
0,0,0,0,0,0,
0, // D3DRS_ZBIAS = 47,
FALSE, // D3DRS_RANGEFOGENABLE = 48,
0,0,0,
FALSE, // D3DRS_STENCILENABLE = 52,
D3DSTENCILOP_KEEP, // D3DRS_STENCILFAIL = 53,
D3DSTENCILOP_KEEP, // D3DRS_STENCILZFAIL = 54,
D3DSTENCILOP_KEEP, // D3DRS_STENCILPASS = 55,
D3DCMP_ALWAYS, // D3DRS_STENCILFUNC = 56,
0, // D3DRS_STENCILREF = 57,
0xFFFFFFFF, // D3DRS_STENCILMASK = 58,
0xFFFFFFFF, // D3DRS_STENCILWRITEMASK = 59,
0xFFFFFFFF, // D3DRS_TEXTUREFACTOR = 60,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,
0, // D3DRS_WRAP0 = 128,
0, // D3DRS_WRAP1 = 129,
0, // D3DRS_WRAP2 = 130,
0, // D3DRS_WRAP3 = 131,
0, // D3DRS_WRAP4 = 132,
0, // D3DRS_WRAP5 = 133,
0, // D3DRS_WRAP6 = 134,
0, // D3DRS_WRAP7 = 135,
TRUE, // D3DRS_CLIPPING = 136,
TRUE, // D3DRS_LIGHTING = 137,
0,
0, // D3DRS_AMBIENT = 139,
0,
D3DFOG_NONE, // D3DRS_FOGVERTEXMODE = 140,
TRUE, // D3DRS_COLORVERTEX = 141,
TRUE, // D3DRS_LOCALVIEWER = 142,
FALSE, // D3DRS_NORMALIZENORMALS = 143,
0,
D3DMCS_COLOR1, // D3DRS_DIFFUSEMATERIALSOURCE = 145,
D3DMCS_COLOR2, // D3DRS_SPECULARMATERIALSOURCE = 146,
D3DMCS_COLOR2, // D3DRS_AMBIENTMATERIALSOURCE = 147,
D3DMCS_MATERIAL, // D3DRS_EMISSIVEMATERIALSOURCE = 148,
0,0,
D3DVBF_DISABLE, // D3DRS_VERTEXBLEND = 151,
0, // D3DRS_CLIPPLANEENABLE = 152,
TRUE, // D3DRS_SOFTWAREVERTEXPROCESSING = 153, RT, never us this!
*pfone, // D3DRS_POINTSIZE = 154,
*pfzero, // D3DRS_POINTSIZE_MIN = 155,
FALSE, // D3DRS_POINTSPRITEENABLE = 156,
FALSE, // D3DRS_POINTSCALEENABLE = 157,
*pfone, // D3DRS_POINTSCALE_A = 158,
*pfzero, // D3DRS_POINTSCALE_B = 159,
*pfzero, // D3DRS_POINTSCALE_C = 160,
TRUE, // D3DRS_MULTISAMPLEANTIALIAS = 161,
0xFFFFFFFF, // D3DRS_MULTISAMPLEMASK = 162,
D3DPATCHEDGE_DISCRETE, // D3DRS_PATCHEDGESTYLE = 163,
*pfone, // D3DRS_PATCHSEGMENTS = 164,
D3DDMT_ENABLE, // D3DRS_DEBUGMONITORTOKEN = 165,
*pfsixtyfour, // D3DRS_POINTSIZE_MAX = 166,
FALSE, // D3DRS_INDEXEDVERTEXBLENDENABLE = 167,
0x0000000F, // D3DRS_COLORWRITEENABLE = 168,
*pfzero, // D3DRS_TWEENFACTOR = 170,
D3DBLENDOP_ADD, // D3DRS_BLENDOP = 171,
D3DORDER_CUBIC, // D3DRS_POSITIONORDER = 172,
D3DORDER_LINEAR // D3DRS_NORMALORDER = 173,
};
/**
* Resets all render states to defaults,
*
* @return void
*/
void d3d_reset_render_states()
{
memcpy(current_render_states, default_render_states, sizeof(unsigned long) * NUM_STATES);
}
/**
* This is a wrapper function for the D3D8.1 call SetRenderState,
*
* @param D3DRENDERSTATETYPE render_state_type - Check DX docs
* @param DWORD render_state - Check DX docs
*
* @return HRESULT - directx error code
*/
HRESULT d3d_SetRenderState( D3DRENDERSTATETYPE render_state_type, DWORD render_state, bool set, bool initaliseing )
{
Assert(render_state_type < NUM_STATES);
#ifdef D3D_CALLS_CHECK
// If the state is already set to that parameter
if(!initaliseing && current_render_states[render_state_type] == render_state) {
// Leave without setting
return S_OK;
}
#endif
HRESULT hr = D3D_OK;
if(set)
hr = GlobalD3DVars::lpD3DDevice->SetRenderState(render_state_type, render_state );
// A set render state should never fail because we should always know the caps.
if(FAILED(hr)) {
mprintf(("Failed set render state %d!", render_state_type));
} else {
current_render_states[render_state_type] = render_state;
}
return hr;
}
// This is all stuff needed for draw primitive call
uint D3D_vertex_type = 0;
HRESULT d3d_CreateVertexBuffer(int vertex_type, int size, DWORD usage, void **buffer)
{
return GlobalD3DVars::lpD3DDevice->CreateVertexBuffer(
vertex_types[D3DVT_VERTEX].size * size,
usage,
vertex_types[D3DVT_VERTEX].fvf,
D3DPOOL_MANAGED,
(IDirect3DVertexBuffer8**) buffer);
}
int d3d_get_num_prims(int vertex_count, D3DPRIMITIVETYPE prim_type)
{
int prim_count;
switch( prim_type)
{
case D3DPT_POINTLIST:
prim_count = vertex_count;
break;
case D3DPT_LINELIST:
prim_count = vertex_count / 2;
break;
case D3DPT_LINESTRIP:
prim_count = vertex_count - 1;
break;
case D3DPT_TRIANGLELIST:
prim_count = vertex_count / 3;
break;
case D3DPT_TRIANGLESTRIP:
case D3DPT_TRIANGLEFAN:
prim_count = vertex_count - 2;
break;
default:
return -1;
}
return prim_count;
}
int d3d_get_num_vertex(int prim_count, D3DPRIMITIVETYPE prim_type)
{
int vertex_count;
switch( prim_type)
{
case D3DPT_POINTLIST:
vertex_count = prim_count;
break;
case D3DPT_LINELIST:
vertex_count = prim_count * 2;
break;
case D3DPT_LINESTRIP:
vertex_count = prim_count + 1;
break;
case D3DPT_TRIANGLELIST:
vertex_count = prim_count * 3;
break;
case D3DPT_TRIANGLESTRIP:
case D3DPT_TRIANGLEFAN:
vertex_count = prim_count + 2;
break;
default:
return -1;
}
return vertex_count;
}
/**
* This is a wrapper function for the D3D8.1 call DrawPrimitveUP, it also handles the vertex shader
*
* @param int vertex_type - This should be one of D3DVT_TLVERTEX, D3DVT_LVERTEX or D3DVT_VERTEX,
* @param D3DPRIMITIVETYPE prim_type - Look at DX docs
* @param LPVOID pvertices - Pointer to the vertex data, must match the vertex_type chosen
* @param DWORD vertex_count - Number of vertices in the array to render
*
* @return HRESULT - directx error code
*/
HRESULT d3d_DrawPrimitive(int vertex_type, D3DPRIMITIVETYPE prim_type, LPVOID pvertices, DWORD vertex_count)
{
HRESULT hr;
Assert( vertex_type < D3DVT_MAX);
int prim_count = d3d_get_num_prims(vertex_count, prim_type);
if(prim_count == -1) {
return !S_OK;
}
hr = d3d_SetVertexShader(vertex_types[vertex_type].fvf );
if(FAILED(hr))
{
return hr;
}
hr = GlobalD3DVars::lpD3DDevice->DrawPrimitiveUP(prim_type, prim_count, pvertices, vertex_types[vertex_type].size);
if(FAILED(hr)) {
mprintf(("Failed to draw primitive %d\n",prim_count));
}
return hr;
}
HRESULT d3d_SetVertexShader(uint fvf)
{
#ifdef D3D_CALLS_CHECK
if(D3D_vertex_type != fvf)
#endif
{
HRESULT hr = GlobalD3DVars::lpD3DDevice->SetVertexShader(fvf);
if(FAILED(hr)) {
mprintf(("Failed to set vertex shader"));
Error( LOCATION, "Failed to set vertex shader: %d\n", fvf );
return hr;
}
D3D_vertex_type = fvf;
}
return S_OK;
}
// This is all stuff needed for set texture stage state
const int NUM_STAGE_TYPES = 29;
unsigned long current_stages_zero[NUM_STAGE_TYPES];
const unsigned long default_stages_zero[NUM_STAGE_TYPES] =
{
0,
D3DTOP_MODULATE, // D3DTSS_COLOROP = 1,
D3DTA_TEXTURE, // D3DTSS_COLORARG1 = 2,
D3DTA_CURRENT, // D3DTSS_COLORARG2 = 3,
D3DTOP_SELECTARG1, // D3DTSS_ALPHAOP = 4,
D3DTA_DIFFUSE, // D3DTSS_ALPHAARG1 = 5,
D3DTA_CURRENT, // D3DTSS_ALPHAARG2 = 6,
*pfzero, // D3DTSS_BUMPENVMAT00 = 7,
*pfzero, // D3DTSS_BUMPENVMAT01 = 8,
*pfzero, // D3DTSS_BUMPENVMAT10 = 9,
*pfzero, // D3DTSS_BUMPENVMAT11 = 10,
0, // D3DTSS_TEXCOORDINDEX = 11,
0,
D3DTADDRESS_WRAP, // D3DTSS_ADDRESSU = 13,
D3DTADDRESS_WRAP, // D3DTSS_ADDRESSV = 14,
0x00000000, // D3DTSS_BORDERCOLOR = 15,
D3DTEXF_POINT, // D3DTSS_MAGFILTER = 16,
D3DTEXF_POINT, // D3DTSS_MINFILTER = 17,
D3DTEXF_NONE, // D3DTSS_MIPFILTER = 18,
*pfzero, // D3DTSS_MIPMAPLODBIAS = 19,
0, // D3DTSS_MAXMIPLEVEL = 20,
1, // D3DTSS_MAXANISOTROPY = 21,
*pfzero, // D3DTSS_BUMPENVLSCALE = 22,
*pfzero, // D3DTSS_BUMPENVLOFFSET = 23,
D3DTTFF_DISABLE, // D3DTSS_TEXTURETRANSFORMFLAGS = 24,
D3DTADDRESS_WRAP, // D3DTSS_ADDRESSW = 25,
D3DTA_CURRENT, // D3DTSS_COLORARG0 = 26,
D3DTA_CURRENT, // D3DTSS_ALPHAARG0 = 27,
D3DTA_CURRENT // D3DTSS_RESULTARG = 28,
};
/**
* Set current texture states to default, stage 0 only
* @return void
*/
void d3d_reset_texture_stage_states()
{
memcpy( current_stages_zero, default_stages_zero, sizeof(unsigned long) * NUM_STAGE_TYPES);
}
/**
* This is a wrapper function for the D3D8.1 call SetTextureStageState, consult DX documentation
* for parameter options
*
* @param DWORD stage - Texture state, currently only 0 is supported
* @param D3DTEXTURESTAGESTATETYPE type - Type to attemp to change
* @param DWORD value - New value to attempt to set
*
* @return HRESULT - DirectX error code
*/
HRESULT d3d_SetTextureStageState(DWORD stage, D3DTEXTURESTAGESTATETYPE type, DWORD value, bool set, bool initaliseing)
{
// Only for first stage because it has different default properties to the others but
// since they are not even in use, who cares!
#ifdef D3D_CALLS_CHECK
if(!initaliseing && stage == 0 && current_stages_zero[type] == value) {
return S_OK;
}
#endif
HRESULT hr = D3D_OK;
if(set)
hr = GlobalD3DVars::lpD3DDevice->SetTextureStageState(stage, type, value);
if(FAILED(hr)) {
mprintf(("Failed to set TextureStageState %d for stage %d", type, stage));
} else if (stage == 0) {
current_stages_zero[type] = value;
}
return hr;
}
// Texture set call
const int MAX_TSTAGES = 8;
IDirect3DBaseTexture8 *tinterfaces[MAX_TSTAGES] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
/**
* This should be called if the device is lost, this will ensure all state default are properly reset
*
* @param int stage - Can only be in range 0 - 7, only 0 is currently supported by vertex coords
* @param IDirect3DBaseTexture8* texture_ptr - Pointer to texture to be used
* @return HRESULT
*
*/
HRESULT d3d_SetTexture(int stage, IDirect3DBaseTexture8* texture_ptr)
{
#ifdef D3D_CALLS_CHECK
if( texture_ptr == tinterfaces[stage]) {
return S_OK;
}
#endif
HRESULT hr = GlobalD3DVars::lpD3DDevice->SetTexture(stage, texture_ptr);
if(FAILED(hr)) {
mprintf(("Failed to set texture"));
} else {
tinterfaces[stage] = texture_ptr;
}
return hr;
}
/**
* This should be called if the device is lost, this will ensure all state default are properly reset
*
* @return void
*
*/
extern IDirect3DIndexBuffer8 *global_index_buffer;
// Returns:
// TRUE = the device is lost and cannot be recovered yet
// FALSE = the device is fine or has been successfully reset
BOOL d3d_lost_device()
{
// if we can't reset the device yet then back out but only after Sleep()ing a little
if ( GlobalD3DVars::lpD3DDevice->TestCooperativeLevel() == D3DERR_DEVICELOST ) {
Sleep(5);
return TRUE;
}
// Calling Reset causes all texture memory surfaces to be lost, managed textures to be flushed
// from video memory, and all state information to be lost. Before calling the Reset method for a
// device, an application should release any explicit render targets, depth stencil surfaces,
// additional swap chains and D3DPOOL_DEFAULT resources associated with the device.
if ( GlobalD3DVars::lpD3DDevice->TestCooperativeLevel() == D3DERR_DEVICENOTRESET ) {
// Set states to what they will be after reset
gr_d3d_set_state(TEXTURE_SOURCE_NONE, ALPHA_BLEND_NONE, ZBUFFER_TYPE_DEFAULT);
if (global_index_buffer != NULL) {
int m = 1;
while ( m > 0 ) {
m = global_index_buffer->Release();
}
global_index_buffer = NULL;
}
GlobalD3DVars::lpD3DDevice->Reset(&GlobalD3DVars::d3dpp);
d3d_reset_render_states();
d3d_reset_texture_stage_states();
memset(tinterfaces, 0, sizeof(IDirect3DBaseTexture8 *) * MAX_TSTAGES);
d3d_set_initial_render_state();
D3D_vertex_type = 0;
}
return FALSE;
}