#include "quakedef.h" #ifdef D3DQUAKE #include "shader.h" #include extern LPDIRECT3DDEVICE9 pD3DDev9; typedef struct { shader_t *curshader; texnums_t *curtexnums; texid_t curlightmap; texid_t curdeluxmap; } d3dbackend_t; static d3dbackend_t d3dbackend; extern int be_maxpasses; void BE_Init(void) { be_maxpasses = 1; } static void D3DBE_ApplyShaderBits(unsigned int bits) { if (bits & SBITS_BLEND_BITS) { int src; int dst; switch(bits & SBITS_SRCBLEND_BITS) { case SBITS_SRCBLEND_ZERO: src = D3DBLEND_ZERO; break; case SBITS_SRCBLEND_ONE: src = D3DBLEND_ONE; break; case SBITS_SRCBLEND_DST_COLOR: src = D3DBLEND_DESTCOLOR; break; case SBITS_SRCBLEND_ONE_MINUS_DST_COLOR: src = D3DBLEND_INVDESTCOLOR; break; case SBITS_SRCBLEND_SRC_ALPHA: src = D3DBLEND_SRCALPHA; break; case SBITS_SRCBLEND_ONE_MINUS_SRC_ALPHA: src = D3DBLEND_INVSRCALPHA; break; case SBITS_SRCBLEND_DST_ALPHA: src = D3DBLEND_DESTALPHA; break; case SBITS_SRCBLEND_ONE_MINUS_DST_ALPHA: src = D3DBLEND_INVDESTALPHA; break; case SBITS_SRCBLEND_ALPHA_SATURATE: src = D3DBLEND_SRCALPHASAT; break; default: Sys_Error("Bad shader blend src\n"); return; } switch(bits & SBITS_DSTBLEND_BITS) { case SBITS_DSTBLEND_ZERO: dst = D3DBLEND_ZERO; break; case SBITS_DSTBLEND_ONE: dst = D3DBLEND_ONE; break; case SBITS_DSTBLEND_SRC_ALPHA: dst = D3DBLEND_SRCALPHA; break; case SBITS_DSTBLEND_ONE_MINUS_SRC_ALPHA: dst = D3DBLEND_INVSRCALPHA; break; case SBITS_DSTBLEND_DST_ALPHA: dst = D3DBLEND_DESTALPHA; break; case SBITS_DSTBLEND_ONE_MINUS_DST_ALPHA: dst = D3DBLEND_INVDESTALPHA; break; case SBITS_DSTBLEND_SRC_COLOR: dst = D3DBLEND_SRCCOLOR; break; case SBITS_DSTBLEND_ONE_MINUS_SRC_COLOR: dst = D3DBLEND_INVSRCCOLOR; break; default: Sys_Error("Bad shader blend dst\n"); return; } IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHABLENDENABLE, TRUE); IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_SRCBLEND, src); IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_DESTBLEND, dst); } else IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHABLENDENABLE, FALSE); switch(bits & SBITS_ATEST_BITS) { case SBITS_ATEST_NONE: IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHATESTENABLE, FALSE); // IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHAREF, 0); // IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHAFUNC, 0); break; case SBITS_ATEST_GT0: IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHATESTENABLE, TRUE); IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHAREF, 0); IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHAFUNC, D3DCMP_GREATER); break; case SBITS_ATEST_LT128: IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHATESTENABLE, TRUE); IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHAREF, 128); IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHAFUNC, D3DCMP_LESS); break; case SBITS_ATEST_GE128: IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHATESTENABLE, TRUE); IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHAREF, 128); IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); break; } if(bits & SBITS_MISC_DEPTHWRITE) IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ZWRITEENABLE, TRUE); else IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ZWRITEENABLE, FALSE); if(bits & SBITS_MISC_NODEPTHTEST) IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ZENABLE, FALSE); else IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ZENABLE, TRUE); switch(bits & (SBITS_MISC_DEPTHEQUALONLY|SBITS_MISC_DEPTHCLOSERONLY)) { default: case 0: IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ZFUNC, D3DCMP_LESSEQUAL); break; case SBITS_MISC_DEPTHEQUALONLY: IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ZFUNC, D3DCMP_EQUAL); break; case SBITS_MISC_DEPTHCLOSERONLY: IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ZFUNC, D3DCMP_LESS); break; } } unsigned int workingbuffer[65536]; static void BE_DrawMeshChain_Internal(mesh_t *meshchain) { float *xyz; unsigned int *colour; float *st[1]; unsigned int fmt = 0; unsigned int stride; int i; if (!d3dbackend.curshader) return; if (!d3dbackend.curtexnums) return; stride = 0; memset(workingbuffer, 0, sizeof(workingbuffer)); xyz = (float*)(workingbuffer+stride); stride += 3; fmt |= D3DFVF_XYZ; colour = (unsigned int*)(workingbuffer+stride); stride += 1; fmt |= D3DFVF_DIFFUSE; st[0] = (float*)(workingbuffer+stride); stride += 2; fmt |= D3DFVF_TEX1; D3DBE_ApplyShaderBits(d3dbackend.curshader->passes[0].shaderbits); IDirect3DDevice9_SetFVF(pD3DDev9, fmt); switch(d3dbackend.curshader->passes[0].texgen) { default: case T_GEN_DIFFUSE: IDirect3DDevice9_SetTexture (pD3DDev9, 0, d3dbackend.curtexnums->base.ptr); break; case T_GEN_SINGLEMAP: IDirect3DDevice9_SetTexture (pD3DDev9, 0, d3dbackend.curshader->passes[0].anim_frames[0].ptr); break; } switch(d3dbackend.curshader->passes[1].texgen) { case T_GEN_LIGHTMAP: IDirect3DDevice9_SetTexture (pD3DDev9, 1, d3dbackend.curlightmap.ptr); IDirect3DDevice9_SetTextureStageState(pD3DDev9, 1, D3DTSS_COLORARG1, D3DTA_TEXTURE); IDirect3DDevice9_SetTextureStageState(pD3DDev9, 1, D3DTSS_COLORARG2, D3DTA_CURRENT); IDirect3DDevice9_SetTextureStageState(pD3DDev9, 1, D3DTSS_COLOROP, D3DTOP_MODULATE2X); break; default: IDirect3DDevice9_SetTexture (pD3DDev9, 1, NULL); IDirect3DDevice9_SetTextureStageState(pD3DDev9, 1, D3DTSS_COLOROP, D3DTOP_DISABLE); break; } if (meshchain->colors4b_array) { /*I'm guessing I ought to create a temp vertex buffer for this*/ for (; meshchain; meshchain = meshchain->next) { for (i = 0; i < meshchain->numvertexes; i++) { VectorCopy(meshchain->xyz_array[i], (xyz+stride*i)); *(colour+stride*i) = ((unsigned int)meshchain->colors4b_array[i][3]<<24) | ((unsigned int)meshchain->colors4b_array[i][0]<<16) | ((unsigned int)meshchain->colors4b_array[i][1]<<8) | ((unsigned int)meshchain->colors4b_array[i][2]); Vector2Copy(meshchain->st_array[i], (st[0]+stride*i)); } IDirect3DDevice9_DrawIndexedPrimitiveUP(pD3DDev9, D3DPT_TRIANGLELIST, 0, meshchain->numvertexes, meshchain->numindexes/3, meshchain->indexes, D3DFMT_QINDEX, workingbuffer, stride*4); } } else { /*I'm guessing I ought to create a temp vertex buffer for this*/ for (; meshchain; meshchain = meshchain->next) { for (i = 0; i < meshchain->numvertexes; i++) { VectorCopy(meshchain->xyz_array[i], (xyz+stride*i)); *(colour+stride*i) = 0xffffffff;//*(unsigned int*)meshchain->colors4b_array[i]; Vector2Copy(meshchain->st_array[i], (st[0]+stride*i)); } IDirect3DDevice9_DrawIndexedPrimitiveUP(pD3DDev9, D3DPT_TRIANGLELIST, 0, meshchain->numvertexes, meshchain->numindexes/3, meshchain->indexes, D3DFMT_QINDEX, workingbuffer, stride*4); } } } void BE_DrawMeshChain(shader_t *shader, mesh_t *meshchain, vbo_t *vbo, texnums_t *texnums) { d3dbackend.curshader = shader; d3dbackend.curtexnums = texnums; BE_DrawMeshChain_Internal(meshchain); } void BE_SelectMode(backendmode_t mode, unsigned int flags) { } /*Generates an optimised vbo for each of the given model's textures*/ void BE_GenBrushModelVBO(model_t *mod) { } /*Wipes a vbo*/ void BE_ClearVBO(vbo_t *vbo) { } /*upload all lightmaps at the start to reduce lags*/ void BE_UploadAllLightmaps(void) { } static void DrawSurfaceChain(msurface_t *s, shader_t *shader, vbo_t *vbo) { //doesn't merge surfaces, but tells gl to do each vertex arrayed surface individually, which means no vertex copying. int i; mesh_t *ml, *m; if (!vbo) return; d3dbackend.curshader = shader; d3dbackend.curtexnums = &shader->defaulttextures; ml = NULL; for (; s ; s=s->texturechain) { m = s->mesh; if (!m) //urm. continue; if (m->numvertexes <= 1) continue; if (s->lightmaptexturenum < 0) { //pull out the surfaces with no lightmap info m->next = ml; ml = m; } else { //surfaces that do have a lightmap m->next = lightmap[s->lightmaptexturenum]->meshchain; lightmap[s->lightmaptexturenum]->meshchain = m; } } if (ml) { //draw the lightmapless surfaces BE_DrawMeshChain_Internal(ml); } //and then draw the lit chains for (i = 0; i < numlightmaps; i++) { if (!lightmap[i] || !lightmap[i]->meshchain) continue; /* if (lightmap[i]->modified) { glRect_t *theRect; lightmap[i]->modified = false; theRect = &lightmap[i]->rectchange; GL_Bind(lightmap_textures[i]); qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE, lightmap[i]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes); theRect->l = LMBLOCK_WIDTH; theRect->t = LMBLOCK_HEIGHT; theRect->h = 0; theRect->w = 0; checkerror(); if (lightmap[i]->deluxmodified) { lightmap[i]->deluxmodified = false; theRect = &lightmap[i]->deluxrectchange; GL_Bind(deluxmap_textures[i]); qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, LMBLOCK_WIDTH, theRect->h, GL_RGB, GL_UNSIGNED_BYTE, lightmap[i]->deluxmaps+(theRect->t) *LMBLOCK_WIDTH*3); theRect->l = LMBLOCK_WIDTH; theRect->t = LMBLOCK_HEIGHT; theRect->h = 0; theRect->w = 0; checkerror(); } } */ d3dbackend.curlightmap = lightmap_textures[i]; d3dbackend.curdeluxmap = deluxmap_textures[i]; BE_DrawMeshChain_Internal(lightmap[i]->meshchain); lightmap[i]->meshchain = NULL; } } static void BE_BaseTextureChain(msurface_t *first) { texture_t *t, *tex; shader_t *shader; t = first->texinfo->texture; tex = R_TextureAnimation (t); //TEMP: use shader as an input parameter, not tex. shader = tex->shader; if (!shader) { shader = R_RegisterShader_Lightmap(tex->name); tex->shader = shader; } DrawSurfaceChain(first, shader, &t->vbo); } void BE_BaseEntTextures(void) { extern model_t *currentmodel; int i; entity_t *ent; if (!r_drawentities.ival) return; // draw sprites seperately, because of alpha blending for (i=0 ; imodel) continue; if (ent->model->needload) continue; // if (!PPL_ShouldDraw()) // continue; switch(ent->model->type) { case mod_brush: // BaseBrushTextures(ent); break; case mod_alias: R_DrawGAliasModel (ent, BEM_STANDARD); break; } } } void BE_SubmitMeshes (void) { texture_t *t; msurface_t *s; int i; model_t *model = cl.worldmodel; unsigned int fl; for (i=0 ; inumtextures ; i++) { t = model->textures[i]; if (!t) continue; s = t->texturechain; if (!s) continue; fl = s->texinfo->texture->shader->flags; BE_BaseTextureChain(s); } BE_BaseEntTextures(); } void BE_DrawWorld (qbyte *vis) { RSpeedLocals(); //make sure the world draws correctly r_worldentity.shaderRGBAf[0] = 1; r_worldentity.shaderRGBAf[1] = 1; r_worldentity.shaderRGBAf[2] = 1; r_worldentity.shaderRGBAf[3] = 1; r_worldentity.axis[0][0] = 1; r_worldentity.axis[1][1] = 1; r_worldentity.axis[2][2] = 1; BE_SelectMode(BEM_STANDARD, 0); RSpeedRemark(); BE_SubmitMeshes(); RSpeedEnd(RSPEED_WORLD); } #endif