Commit 81504d6a authored by Stefan Dösinger's avatar Stefan Dösinger Committed by Alexandre Julliard

wined3d: Support bump environment mapping using GL_NV_texture_shader.

parent 4a8b55d4
......@@ -367,6 +367,21 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar
glEnable(GL_WEIGHT_SUM_UNITY_ARB);
checkGLcall("glEnable(GL_WEIGHT_SUM_UNITY_ARB)");
}
if(GL_SUPPORT(NV_TEXTURE_SHADER2)) {
int s;
glEnable(GL_TEXTURE_SHADER_NV);
checkGLcall("glEnable(GL_TEXTURE_SHADER_NV)");
/* Set up the previous texture input for all shader units. This applies to bump mapping, and in d3d
* the previous texture where to source the offset from is always unit - 1.
*/
for(s = 1; s < GL_LIMITS(textures); s++) {
GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + s));
glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0_ARB + s - 1);
checkGLcall("glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, ...\n");
}
}
if(oldDrawable && oldCtx) {
glXMakeCurrent(display, oldDrawable, oldCtx);
......@@ -599,6 +614,11 @@ static inline void SetupForBlit(IWineD3DDeviceImpl *This, WineD3DContext *contex
glViewport(0, 0, width, height);
checkGLcall("glViewport");
Context_MarkStateDirty(context, STATE_VIEWPORT);
if(GL_SUPPORT(NV_TEXTURE_SHADER2)) {
glDisable(GL_TEXTURE_SHADER_NV);
checkGLcall("glDisable(GL_TEXTURE_SHADER_NV)");
}
}
/*****************************************************************************
......@@ -777,6 +797,10 @@ void ActivateContext(IWineD3DDeviceImpl *This, IWineD3DSurface *target, ContextU
case CTXUSAGE_DRAWPRIM:
/* This needs all dirty states applied */
if(context->last_was_blit && GL_SUPPORT(NV_TEXTURE_SHADER2)) {
glEnable(GL_TEXTURE_SHADER_NV);
checkGLcall("glEnable(GL_TEXTURE_SHADER_NV)");
}
for(i=0; i < context->numDirtyEntries; i++) {
dirtyState = context->dirtyArray[i];
idx = dirtyState >> 5;
......
......@@ -762,6 +762,8 @@ BOOL IWineD3DImpl_FillGLCaps(IWineD3D *iface, Display* display) {
} else if (strcmp(ThisExtn, "GL_NV_texture_shader2") == 0) {
TRACE_(d3d_caps)(" FOUND: NVIDIA (NV) Texture Shader (2) support\n");
gl_info->supported[NV_TEXTURE_SHADER2] = TRUE;
/* Prevent both extensions to be used at the same time. I don't expect them to play nice together */
gl_info->supported[ATI_ENVMAP_BUMPMAP] = FALSE;
} else if (strcmp(ThisExtn, "GL_NV_texture_shader3") == 0) {
TRACE_(d3d_caps)(" FOUND: NVIDIA (NV) Texture Shader (3) support\n");
gl_info->supported[NV_TEXTURE_SHADER3] = TRUE;
......@@ -803,7 +805,12 @@ BOOL IWineD3DImpl_FillGLCaps(IWineD3D *iface, Display* display) {
gl_info->supported[EXT_VERTEX_SHADER] = TRUE;
} else if (strcmp(ThisExtn, "GL_ATI_envmap_bumpmap") == 0) {
TRACE_(d3d_caps)(" FOUND: ATI Environment Bump Mapping support\n");
/* GL_ATI_envmap_bumpmap won't play nice with texture shaders, so disable it
* Won't occur in any real world situation though
*/
if(!gl_info->supported[NV_TEXTURE_SHADER2]) {
gl_info->supported[ATI_ENVMAP_BUMPMAP] = TRUE;
}
/**
* Apple
*/
......@@ -1680,6 +1687,17 @@ static HRESULT WINAPI IWineD3DImpl_CheckDeviceFormat(IWineD3D *iface, UINT Adapt
return WINED3DERR_NOTAVAILABLE;
}
} else if(Usage & WINED3DUSAGE_QUERY_LEGACYBUMPMAP) {
if(GL_SUPPORT(NV_REGISTER_COMBINERS) && GL_SUPPORT(NV_TEXTURE_SHADER2)) {
switch (CheckFormat) {
case WINED3DFMT_V8U8:
TRACE_(d3d_caps)("[OK]\n");
return WINED3D_OK;
/* TODO: Other bump map formats */
default:
TRACE_(d3d_caps)("[FAILED]\n");
return WINED3DERR_NOTAVAILABLE;
}
}
if(GL_SUPPORT(ATI_ENVMAP_BUMPMAP)) {
switch (CheckFormat) {
case WINED3DFMT_V8U8:
......@@ -1689,7 +1707,6 @@ static HRESULT WINAPI IWineD3DImpl_CheckDeviceFormat(IWineD3D *iface, UINT Adapt
TRACE_(d3d_caps)("[FAILED]\n");
return WINED3DERR_NOTAVAILABLE;
}
/* TODO: GL_NV_TEXTURE_SHADER */
}
TRACE_(d3d_caps)("[FAILED]\n");
return WINED3DERR_NOTAVAILABLE;
......@@ -2225,8 +2242,14 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter,
if(GL_SUPPORT(ATI_ENVMAP_BUMPMAP)) {
*pCaps->TextureOpCaps |= WINED3DTEXOPCAPS_BUMPENVMAP;
} else if(GL_SUPPORT(NV_TEXTURE_SHADER)) {
/* TODO: environment bump mapping support with GL_NV_texture_shader */
} else if(GL_SUPPORT(NV_TEXTURE_SHADER2)) {
/* Bump mapping is supported already in NV_TEXTURE_SHADER, but that extension does
* not support 3D textures. This asks for trouble if an app uses both bump mapping
* and 3D textures. It also allows us to keep the code simpler by having texture
* shaders constantly enabled.
*/
*pCaps->TextureOpCaps |= WINED3DTEXOPCAPS_BUMPENVMAP;
/* TODO: Luminance bump map? */
}
#if 0
/* FIXME: Add
......
......@@ -1552,10 +1552,23 @@ static void state_ckeyblend(DWORD state, IWineD3DStateBlockImpl *stateblock, Win
* Does not care for the colorop or correct gl texture unit(when using nvrc)
* Requires the caller to activate the correct unit before
*/
static void activate_dimensions(DWORD stage, IWineD3DStateBlockImpl *stateblock) {
static void activate_dimensions(DWORD stage, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) {
BOOL bumpmap = FALSE;
if(stage > 0 && (stateblock->textureState[stage - 1][WINED3DTSS_COLOROP] == WINED3DTOP_BUMPENVMAPLUMINANCE ||
stateblock->textureState[stage - 1][WINED3DTSS_COLOROP] == WINED3DTOP_BUMPENVMAP)) {
bumpmap = TRUE;
context->texShaderBumpMap |= (1 << stage);
} else {
context->texShaderBumpMap &= ~(1 << stage);
}
if(stateblock->textures[stage]) {
switch(stateblock->textureDimensions[stage]) {
case GL_TEXTURE_2D:
if(GL_SUPPORT(NV_TEXTURE_SHADER2)) {
glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, bumpmap ? GL_OFFSET_TEXTURE_2D_NV : GL_TEXTURE_2D);
} else {
glDisable(GL_TEXTURE_3D);
checkGLcall("glDisable(GL_TEXTURE_3D)");
if(GL_SUPPORT(ARB_TEXTURE_CUBE_MAP)) {
......@@ -1564,8 +1577,12 @@ static void activate_dimensions(DWORD stage, IWineD3DStateBlockImpl *stateblock)
}
glEnable(GL_TEXTURE_2D);
checkGLcall("glEnable(GL_TEXTURE_2D)");
}
break;
case GL_TEXTURE_3D:
if(GL_SUPPORT(NV_TEXTURE_SHADER2)) {
glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_3D);
} else {
if(GL_SUPPORT(ARB_TEXTURE_CUBE_MAP)) {
glDisable(GL_TEXTURE_CUBE_MAP_ARB);
checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
......@@ -1574,17 +1591,27 @@ static void activate_dimensions(DWORD stage, IWineD3DStateBlockImpl *stateblock)
checkGLcall("glDisable(GL_TEXTURE_2D)");
glEnable(GL_TEXTURE_3D);
checkGLcall("glEnable(GL_TEXTURE_3D)");
glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_3D);
}
break;
case GL_TEXTURE_CUBE_MAP_ARB:
if(GL_SUPPORT(NV_TEXTURE_SHADER2)) {
glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_CUBE_MAP_ARB);
} else {
glDisable(GL_TEXTURE_2D);
checkGLcall("glDisable(GL_TEXTURE_2D)");
glDisable(GL_TEXTURE_3D);
checkGLcall("glDisable(GL_TEXTURE_3D)");
glEnable(GL_TEXTURE_CUBE_MAP_ARB);
checkGLcall("glEnable(GL_TEXTURE_CUBE_MAP_ARB)");
glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_CUBE_MAP_ARB);
}
break;
}
} else {
if(GL_SUPPORT(NV_TEXTURE_SHADER2)) {
glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_NONE);
} else {
glDisable(GL_TEXTURE_2D);
checkGLcall("glDisable(GL_TEXTURE_2D)");
glDisable(GL_TEXTURE_3D);
......@@ -1595,6 +1622,7 @@ static void activate_dimensions(DWORD stage, IWineD3DStateBlockImpl *stateblock)
}
/* Binding textures is done by samplers. A dummy texture will be bound */
}
}
}
static void tex_colorop(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) {
......@@ -1649,6 +1677,9 @@ static void tex_colorop(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3D
checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
}
}
if(GL_SUPPORT(NV_TEXTURE_SHADER2)) {
glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_NONE);
}
/* All done */
return;
}
......@@ -1657,7 +1688,7 @@ static void tex_colorop(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3D
* if the sampler for this stage is dirty
*/
if(!isStateDirty(context, STATE_SAMPLER(stage))) {
if (mapped_stage != -1) activate_dimensions(stage, stateblock);
if (mapped_stage != -1) activate_dimensions(stage, stateblock, context);
}
/* Set the texture combiners */
......@@ -1668,6 +1699,22 @@ static void tex_colorop(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3D
stateblock->textureState[stage][WINED3DTSS_COLORARG2],
stateblock->textureState[stage][WINED3DTSS_COLORARG0],
mapped_stage);
/* In register combiners bump mapping is done in the stage AFTER the one that has the bump map operation set,
* thus the texture shader may have to be updated
*/
if(GL_SUPPORT(NV_TEXTURE_SHADER2)) {
BOOL usesBump = (stateblock->textureState[stage][WINED3DTSS_COLOROP] == WINED3DTOP_BUMPENVMAPLUMINANCE ||
stateblock->textureState[stage][WINED3DTSS_COLOROP] == WINED3DTOP_BUMPENVMAP) ? TRUE : FALSE;
BOOL usedBump = (context->texShaderBumpMap & 1 << (stage + 1)) ? TRUE : FALSE;
if(usesBump != usedBump) {
GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + mapped_stage + 1));
checkGLcall("glActiveTextureARB");
activate_dimensions(stage + 1, stateblock, context);
GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + mapped_stage));
checkGLcall("glActiveTextureARB");
}
}
} else {
set_tex_op((IWineD3DDevice *)stateblock->wineD3DDevice, FALSE, stage,
stateblock->textureState[stage][WINED3DTSS_COLOROP],
......@@ -2061,7 +2108,7 @@ static void sampler(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DCont
checkGLcall("glEnable(stateblock->textureDimensions[sampler])");
} else if(sampler < stateblock->lowest_disabled_stage) {
if(!isStateDirty(context, STATE_TEXTURESTAGE(sampler, WINED3DTSS_COLOROP))) {
activate_dimensions(sampler, stateblock);
activate_dimensions(sampler, stateblock, context);
}
if(stateblock->renderState[WINED3DRS_COLORKEYENABLE] && sampler == 0) {
......@@ -2075,7 +2122,7 @@ static void sampler(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DCont
if(sampler < stateblock->lowest_disabled_stage) {
/* TODO: What should I do with pixel shaders here ??? */
if(!isStateDirty(context, STATE_TEXTURESTAGE(sampler, WINED3DTSS_COLOROP))) {
activate_dimensions(sampler, stateblock);
activate_dimensions(sampler, stateblock, context);
}
} /* Otherwise tex_colorop disables the stage */
glBindTexture(GL_TEXTURE_2D, stateblock->wineD3DDevice->dummyTextureName[sampler]);
......@@ -2176,7 +2223,24 @@ static void tex_bumpenvmat(DWORD state, IWineD3DStateBlockImpl *stateblock, Wine
(float *) &(stateblock->textureState[stage][WINED3DTSS_BUMPENVMAT00])));
checkGLcall("glTexBumpParameterfvATI");
}
/* TODO: GL_NV_texture_shader */
if(GL_SUPPORT(NV_TEXTURE_SHADER2)) {
/* Direct3D sets the matrix in the stage reading the perturbation map. The result is used to
* offset the destination stage(always stage + 1 in d3d). In GL_NV_texture_shader, the bump
* map offseting is done in the stage reading the bump mapped texture, and the perturbation
* map is read from a specified source stage(always stage - 1 for d3d). Thus set the matrix
* for stage + 1. Keep the nvrc tex unit mapping in mind too
*/
DWORD mapped_stage = stateblock->wineD3DDevice->texUnitMap[stage + 1];
if(mapped_stage < GL_LIMITS(textures)) {
GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + mapped_stage));
checkGLcall("GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + mapped_stage))");
glTexEnvfv(GL_TEXTURE_SHADER_NV, GL_OFFSET_TEXTURE_MATRIX_NV,
(float *) &(stateblock->textureState[stage][WINED3DTSS_BUMPENVMAT00]));
checkGLcall("glTexEnvfv(GL_TEXTURE_SHADER_NV, GL_OFFSET_TEXTURE_MATRIX_NV, mat)\n");
}
}
}
static void transform_world(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) {
......
......@@ -866,7 +866,6 @@ void set_tex_op_nvrc(IWineD3DDevice *iface, BOOL is_alpha, int stage, WINED3DTEX
/* This is called by a state handler which has the gl lock held and a context for the thread */
switch(op)
{
case WINED3DTOP_DISABLE:
......@@ -1130,6 +1129,23 @@ void set_tex_op_nvrc(IWineD3DDevice *iface, BOOL is_alpha, int stage, WINED3DTEX
GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE));
break;
case WINED3DTOP_BUMPENVMAPLUMINANCE:
case WINED3DTOP_BUMPENVMAP:
if(GL_SUPPORT(NV_TEXTURE_SHADER)) {
/* The bump map stage itself isn't exciting, just read the texture. But tell the next stage to
* perform bump mapping and source from the current stage. Pretty much a SELECTARG2.
* ARG2 is passed through unmodified(apps will most likely use D3DTA_CURRENT for arg2, arg1
* (which will most likely be D3DTA_TEXTURE) is available as a texture shader input for the next stage
*/
GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV,
tex_op_args.input[1], tex_op_args.mapping[1], tex_op_args.component_usage[1]));
GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV,
GL_ZERO, GL_UNSIGNED_INVERT_NV, portion));
GL_EXTCALL(glCombinerOutputNV(target, portion, GL_SPARE0_NV, GL_DISCARD_NV,
GL_DISCARD_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE));
break;
}
default:
FIXME("Unhandled WINED3DTOP: stage %d, is_alpha %d, op %s (%#x), arg1 %#x, arg2 %#x, arg3 %#x, texture_idx %d\n",
stage, is_alpha, debug_d3dtop(op), op, arg1, arg2, arg3, texture_idx);
......@@ -1727,6 +1743,7 @@ void set_tex_op(IWineD3DDevice *iface, BOOL isAlpha, int Stage, WINED3DTEXTUREOP
}
case WINED3DTOP_BUMPENVMAPLUMINANCE:
FIXME("Implement bump environment mapping in GL_NV_texture_env_combine4 path\n");
default:
Handled = FALSE;
......@@ -2201,12 +2218,13 @@ void set_tex_op(IWineD3DDevice *iface, BOOL isAlpha, int Stage, WINED3DTEXTUREOP
checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2");
Handled = TRUE;
} else {
/* If GL_NV_TEXTURE_SHADER is supported insted the GL_NV_register_combiner path
* will be taken instead
} else if(GL_SUPPORT(NV_TEXTURE_SHADER2)) {
/* Technically texture shader support without register combiners is possible, but not expected to occur
* on real world cards, so for now a fixme should be enough
*/
Handled = FALSE;
FIXME("Implement bump mapping with GL_NV_texture_shader in non register combiner path\n");
}
Handled = FALSE;
break;
default:
Handled = FALSE;
......
......@@ -516,6 +516,7 @@ struct WineD3DContext {
BOOL lastWasPow2Texture[MAX_TEXTURES];
GLenum tracking_parm; /* Which source is tracking current colour */
BOOL last_was_blit, last_was_ckey;
char texShaderBumpMap;
/* The actual opengl context */
GLXContext glCtx;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment