mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-10 04:31:34 -10:00
479 lines
15 KiB
C++
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;
|
|
}
|