diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c index 86e8430fd7a..4742447ee98 100644 --- a/dlls/wined3d/arb_program_shader.c +++ b/dlls/wined3d/arb_program_shader.c @@ -119,6 +119,15 @@ void shader_arb_load_constants( GL_LIMITS(pshader_constantsF), stateBlock->pixelShaderConstantF, &stateBlock->set_pconstantsF); + if(((IWineD3DPixelShaderImpl *) pshader)->bumpenvmatconst) { + /* needsbumpmat stores the stage number from where to load the matrix. bumpenvmatconst stores the + * number of the constant to load the matrix into. + * The state manager takes care that this function is always called if the bump env matrix changes + */ + IWineD3DPixelShaderImpl *psi = (IWineD3DPixelShaderImpl *) pshader; + float *data = (float *) &stateBlock->textureState[(int) psi->needsbumpmat][WINED3DTSS_BUMPENVMAT00]; + GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, psi->bumpenvmatconst, data)); + } } } @@ -159,6 +168,19 @@ void shader_generate_arb_declarations( shader_addline(buffer, "MOV T%u, fragment.texcoord[%u];\n", i, i); } + if(reg_maps->bumpmat /* Only a pshader can use texbem */) { + /* If the shader does not use all available constants, use the next free constant to load the bump mapping environment matrix from + * the stateblock into the shader. If no constant is available don't load, texbem will then just sample the texture without applying + * bump mapping. + */ + if(max_constantsF < GL_LIMITS(pshader_constantsF)) { + ((IWineD3DPixelShaderImpl *)This)->bumpenvmatconst = max_constantsF; + shader_addline(buffer, "PARAM bumpenvmat = program.env[%d];\n", ((IWineD3DPixelShaderImpl *)This)->bumpenvmatconst); + } else { + FIXME("No free constant found to load environemnt bump mapping matrix into the shader. texbem instruction will not apply bump mapping\n"); + } + } + /* Need to PARAM the environment parameters (constants) so we can use relative addressing */ shader_addline(buffer, "PARAM C[%d] = { program.env[0..%d] };\n", max_constantsF, max_constantsF - 1); @@ -662,7 +684,7 @@ void pshader_hw_texreg2gb(SHADER_OPCODE_ARG* arg) { } void pshader_hw_texbem(SHADER_OPCODE_ARG* arg) { - +#if 0 SHADER_BUFFER* buffer = arg->buffer; DWORD reg1 = arg->dst & WINED3DSP_REGNUM_MASK; DWORD reg2 = arg->src[0] & WINED3DSP_REGNUM_MASK; @@ -672,6 +694,35 @@ void pshader_hw_texbem(SHADER_OPCODE_ARG* arg) { sprintf(dst_str, "T%u", reg1); shader_addline(buffer, "ADD TMP.rg, fragment.texcoord[%u], T%u;\n", reg1, reg2); shader_hw_sample(arg, reg1, dst_str, "TMP"); +#endif + IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + + DWORD dst = arg->dst; + DWORD src = arg->src[0] & WINED3DSP_REGNUM_MASK; + SHADER_BUFFER* buffer = arg->buffer; + + char reg_coord[40]; + DWORD reg_dest_code; + + /* All versions have a destination register */ + reg_dest_code = dst & WINED3DSP_REGNUM_MASK; + /* Can directly use the name because texbem is only valid for <= 1.3 shaders */ + pshader_get_register_name(dst, reg_coord); + + if(This->bumpenvmatconst) { + /*shader_addline(buffer, "MOV T%u, fragment.texcoord[%u];\n", 1, 1); Not needed - done already */ + shader_addline(buffer, "SWZ TMP2, bumpenvmat, x, z, 0, 0;\n"); + shader_addline(buffer, "DP3 TMP.r, TMP2, T%u;\n", src); + shader_addline(buffer, "SWZ TMP2, bumpenvmat, y, w, 0, 0;\n"); + shader_addline(buffer, "DP3 TMP.g, TMP2, T%u;\n", src); + shader_addline(buffer, "ADD TMP.rg, TMP, %s;\n", reg_coord); + /* Not sure about this, but hl2 needs it. It uses a projected texture with texbem and depends on the 4th coordinate */ + shader_addline(buffer, "MOV TMP.a, %s;\n", reg_coord); + shader_hw_sample(arg, reg_dest_code, reg_coord, "TMP"); + } else { + /* Without a bump matrix loaded, just sample with the unmodified coordinates */ + shader_hw_sample(arg, reg_dest_code, reg_coord, reg_coord); + } } void pshader_hw_texm3x2pad(SHADER_OPCODE_ARG* arg) { diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index 566442bdf0a..f270af7867c 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -1767,15 +1767,50 @@ void pshader_glsl_texm3x3vspec(SHADER_OPCODE_ARG* arg) { /** Process the WINED3DSIO_TEXBEM instruction in GLSL. * Apply a fake bump map transform. - * FIXME: Should apply the BUMPMAPENV matrix. For now, just sample the texture */ + * texbem is pshader <= 1.3 only, this saves a few version checks + */ void pshader_glsl_texbem(SHADER_OPCODE_ARG* arg) { + IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device; + char dst_swizzle[6]; + glsl_sample_function_t sample_function; + DWORD sampler_type; + DWORD sampler_idx; + BOOL projected; + DWORD mask = 0; + DWORD flags; + char coord_mask[6]; - DWORD reg1 = arg->dst & WINED3DSP_REGNUM_MASK; - DWORD reg2 = arg->src[0] & WINED3DSP_REGNUM_MASK; + /* All versions have a destination register */ + shader_glsl_append_dst(arg->buffer, arg); - FIXME("Not applying the BUMPMAPENV matrix for pixel shader instruction texbem.\n"); - shader_addline(arg->buffer, "T%u = texture2D(Psampler%u, gl_TexCoord[%u].xy + T%u.xy);\n", - reg1, reg1, reg1, reg2); + sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK; + flags = deviceImpl->stateBlock->textureState[sampler_idx][WINED3DTSS_TEXTURETRANSFORMFLAGS]; + + /* TODO: Does texbem even support projected textures? half-life 2 uses it */ + if (flags & WINED3DTTFF_PROJECTED) { + projected = TRUE; + switch (flags & ~WINED3DTTFF_PROJECTED) { + case WINED3DTTFF_COUNT1: FIXME("WINED3DTTFF_PROJECTED with WINED3DTTFF_COUNT1?\n"); break; + case WINED3DTTFF_COUNT2: mask = WINED3DSP_WRITEMASK_1; break; + case WINED3DTTFF_COUNT3: mask = WINED3DSP_WRITEMASK_2; break; + case WINED3DTTFF_COUNT4: + case WINED3DTTFF_DISABLE: mask = WINED3DSP_WRITEMASK_3; break; + } + } else { + projected = FALSE; + } + + sampler_type = arg->reg_maps->samplers[sampler_idx] & WINED3DSP_TEXTURETYPE_MASK; + shader_glsl_get_sample_function(sampler_type, projected, &sample_function); + mask |= sample_function.coord_mask; + + shader_glsl_get_write_mask(arg->dst, dst_swizzle); + + shader_glsl_get_write_mask(mask, coord_mask); + FIXME("Bump map transform not handled yet\n"); + shader_addline(arg->buffer, "%s(Psampler%u, T%u%s)%s);\n", + sample_function.name, sampler_idx, sampler_idx, coord_mask, dst_swizzle); } /** Process the WINED3DSIO_TEXREG2AR instruction in GLSL