Linux multi-monitor fullscreen support
[ryzomcore.git] / nel / src / 3d / driver / direct3d / driver_direct3d_material.cpp
blob1436e5aa4f2e6b7b7ac570f5bb1da8bcb6dbca50
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "stddirect3d.h"
22 #include "nel/3d/vertex_buffer.h"
23 #include "nel/3d/light.h"
24 #include "nel/3d/index_buffer.h"
25 #include "nel/3d/texture_bump.h"
26 #include "nel/misc/rect.h"
27 #include "nel/3d/viewport.h"
28 #include "nel/3d/scissor.h"
29 #include "nel/3d/u_driver.h"
31 #include "driver_direct3d.h"
33 #ifdef DEBUG_NEW
34 #define new DEBUG_NEW
35 #endif
37 using namespace std;
38 using namespace NLMISC;
43 namespace NL3D
46 // ***************************************************************************
48 const D3DBLEND RemapBlendTypeNeL2D3D[CMaterial::blendCount]=
50 D3DBLEND_ONE, // one
51 D3DBLEND_ZERO, // zero
52 D3DBLEND_SRCALPHA, // srcalpha
53 D3DBLEND_INVSRCALPHA, // invsrcalpha
54 D3DBLEND_SRCCOLOR, // srccolor
55 D3DBLEND_INVSRCCOLOR, // invsrccolor
56 D3DBLEND_ONE, // blendConstantColor
57 D3DBLEND_ONE, // blendConstantInvColor
58 D3DBLEND_ONE, // blendConstantAlpha
59 D3DBLEND_ONE, // blendConstantInvAlpha
62 // ***************************************************************************
64 const D3DCMPFUNC RemapZFuncTypeNeL2D3D[CMaterial::zfuncCount]=
66 D3DCMP_ALWAYS, // always
67 D3DCMP_NEVER, // never
68 D3DCMP_EQUAL, // equal
69 D3DCMP_NOTEQUAL, // notequal
70 D3DCMP_LESS, // less
71 D3DCMP_LESSEQUAL, // lessequal
72 D3DCMP_GREATER, // greater
73 D3DCMP_GREATEREQUAL,// greaterequal
76 // ***************************************************************************
78 // For stage 0 only
79 const D3DTEXTUREOP RemapTexOpType0NeL2D3D[CMaterial::TexOperatorCount]=
81 D3DTOP_SELECTARG1, // Replace
82 D3DTOP_MODULATE, // Modulate
83 D3DTOP_ADD, // Add
84 D3DTOP_ADDSIGNED, // AddSigned
85 D3DTOP_BLENDTEXTUREALPHA, // InterpolateTexture
86 D3DTOP_BLENDDIFFUSEALPHA, // InterpolatePrevious
87 D3DTOP_BLENDDIFFUSEALPHA, // InterpolateDiffuse
88 D3DTOP_LERP, // InterpolateConstant
89 D3DTOP_BUMPENVMAP, // EMBM
90 D3DTOP_MULTIPLYADD // MAD
93 // ***************************************************************************
95 const D3DTEXTUREOP RemapTexOpTypeNeL2D3D[CMaterial::TexOperatorCount]=
97 D3DTOP_SELECTARG1, // Replace
98 D3DTOP_MODULATE, // Modulate
99 D3DTOP_ADD, // Add
100 D3DTOP_ADDSIGNED, // AddSigned
101 D3DTOP_BLENDTEXTUREALPHA, // InterpolateTexture
102 D3DTOP_BLENDCURRENTALPHA, // InterpolatePrevious
103 D3DTOP_BLENDDIFFUSEALPHA, // InterpolateDiffuse
104 D3DTOP_LERP, // InterpolateConstant
105 D3DTOP_BUMPENVMAP, // EMBM
106 D3DTOP_MULTIPLYADD // MAD
109 const uint OpNumArg[CMaterial::TexOperatorCount] =
111 1, // Replace
112 2, // Modulate
113 2, // Add
114 2, // AddSigned
115 2, // InterpolateTexture
116 2, // InterpolatePrevious
117 2, // InterpolateDiffuse
118 3, // InterpolateConstant
119 2, // EMBM
120 3 // MAD
124 // ***************************************************************************
126 // For stage 0 only
127 const DWORD RemapTexArg0NeL2D3D[CMaterial::TexSourceCount]=
129 D3DTA_TEXTURE, // Texture
130 D3DTA_DIFFUSE, // Previous
131 D3DTA_DIFFUSE, // Diffuse
132 D3DTA_TFACTOR, // todo hulud constant color D3DTA_CONSTANT, // Constant
135 // ***************************************************************************
137 const DWORD RemapTexArgNeL2D3D[CMaterial::TexSourceCount]=
139 D3DTA_TEXTURE, // Texture
140 D3DTA_CURRENT, // Previous
141 D3DTA_DIFFUSE, // Diffuse
142 D3DTA_TFACTOR, // todo hulud constant color D3DTA_CONSTANT, // Constant
145 // ***************************************************************************
146 const DWORD RemapTexOpArgTypeNeL2D3D[CMaterial::TexOperandCount]=
148 0, // SrcColor
149 D3DTA_COMPLEMENT, // InvSrcColor
150 D3DTA_ALPHAREPLICATE, // SrcAlpha
151 D3DTA_ALPHAREPLICATE|D3DTA_COMPLEMENT, // InvSrcAlpha
155 // ***************************************************************************
157 const DWORD RemapTexArg0TypeNeL2D3D[CMaterial::TexOperatorCount]=
159 D3DTA_TFACTOR, // todo hulud constant color D3DTA_CONSTANT, // Replace not used
160 D3DTA_TFACTOR, // todo hulud constant color D3DTA_CONSTANT, // Modulate not used
161 D3DTA_TFACTOR, // todo hulud constant color D3DTA_CONSTANT, // Add not used
162 D3DTA_TFACTOR, // todo hulud constant color D3DTA_CONSTANT, // AddSigned not used
163 D3DTA_TFACTOR, // todo hulud constant color D3DTA_CONSTANT, // InterpolateTexture not used
164 D3DTA_TFACTOR, // todo hulud constant color D3DTA_CONSTANT, // InterpolatePrevious not used
165 D3DTA_TFACTOR, // todo hulud constant color D3DTA_CONSTANT, // InterpolateDiffuse not used
166 D3DTA_TFACTOR|D3DTA_ALPHAREPLICATE, // todo hulud constant color D3DTA_CONSTANT|D3DTA_ALPHAREPLICATE, // InterpolateConstant
167 D3DTA_TFACTOR, // todo hulud constant color D3DTA_CONSTANT, // EMBM not used
168 D3DTA_TFACTOR // todo hulud constant color D3DTA_CONSTANT // MAD
171 // ***************************************************************************
173 const DWORD RemapTexGenTypeNeL2D3D[CMaterial::numTexCoordGenMode]=
175 D3DTSS_TCI_SPHEREMAP, // TexCoordGenReflect
176 D3DTSS_TCI_CAMERASPACEPOSITION, // TexCoordGenObjectSpace, not supported
177 D3DTSS_TCI_CAMERASPACEPOSITION, // TexCoordGenEyeSpace
180 // ***************************************************************************
182 const DWORD RemapTexGenCubeTypeNeL2D3D[CMaterial::numTexCoordGenMode]=
184 D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR, // TexCoordGenReflect
185 D3DTSS_TCI_CAMERASPACEPOSITION, // TexCoordGenObjectSpace, not supported
186 D3DTSS_TCI_CAMERASPACEPOSITION, // TexCoordGenEyeSpace
189 // ***************************************************************************
191 void CMaterialDrvInfosD3D::buildTexEnv (uint stage, const CMaterial::CTexEnv &env, bool textured)
193 H_AUTO_D3D(CMaterialDrvInfosD3D_buildTexEnv)
194 if (textured)
196 // The source operator pointer
197 const DWORD *srcOp = (stage==0)?RemapTexArg0NeL2D3D:RemapTexArgNeL2D3D;
199 ColorOp[stage] = ((stage==0)?RemapTexOpType0NeL2D3D:RemapTexOpTypeNeL2D3D)[env.Env.OpRGB];
200 NumColorArg[stage] = OpNumArg[env.Env.OpRGB];
201 if (env.Env.OpRGB == CMaterial::Mad)
203 ColorArg2[stage] = srcOp[env.Env.SrcArg0RGB];
204 ColorArg2[stage] |= RemapTexOpArgTypeNeL2D3D[env.Env.OpArg0RGB];
205 ColorArg1[stage] = srcOp[env.Env.SrcArg1RGB];
206 ColorArg1[stage] |= RemapTexOpArgTypeNeL2D3D[env.Env.OpArg1RGB];
207 ColorArg0[stage] = srcOp[env.Env.SrcArg2RGB];
208 ColorArg0[stage] |= RemapTexOpArgTypeNeL2D3D[env.Env.OpArg2RGB];
210 else
212 // Only used for InterpolateConstant
213 ColorArg0[stage] = RemapTexArg0TypeNeL2D3D[env.Env.OpRGB];
214 ColorArg1[stage] = srcOp[env.Env.SrcArg0RGB];
215 ColorArg1[stage] |= RemapTexOpArgTypeNeL2D3D[env.Env.OpArg0RGB];
216 ColorArg2[stage] = srcOp[env.Env.SrcArg1RGB];
217 ColorArg2[stage] |= RemapTexOpArgTypeNeL2D3D[env.Env.OpArg1RGB];
219 AlphaOp[stage] = ((stage==0)?RemapTexOpType0NeL2D3D:RemapTexOpTypeNeL2D3D)[env.Env.OpAlpha];
220 NumAlphaArg[stage] = OpNumArg[env.Env.OpAlpha];
221 if (env.Env.OpAlpha == CMaterial::Mad)
223 AlphaArg2[stage] = srcOp[env.Env.SrcArg0Alpha];
224 AlphaArg2[stage] |= RemapTexOpArgTypeNeL2D3D[env.Env.OpArg0Alpha];
225 AlphaArg1[stage] = srcOp[env.Env.SrcArg1Alpha];
226 AlphaArg1[stage] |= RemapTexOpArgTypeNeL2D3D[env.Env.OpArg1Alpha];
227 AlphaArg0[stage] = srcOp[env.Env.SrcArg2Alpha];
228 AlphaArg0[stage] |= RemapTexOpArgTypeNeL2D3D[env.Env.OpArg2Alpha];
230 else
232 // Only used for InterpolateConstant
233 AlphaArg0[stage] = RemapTexArg0TypeNeL2D3D[env.Env.OpAlpha];
234 AlphaArg1[stage] = srcOp[env.Env.SrcArg0Alpha];
235 AlphaArg1[stage] |= RemapTexOpArgTypeNeL2D3D[env.Env.OpArg0Alpha];
236 AlphaArg2[stage] = srcOp[env.Env.SrcArg1Alpha];
237 AlphaArg2[stage] |= RemapTexOpArgTypeNeL2D3D[env.Env.OpArg1Alpha];
239 ConstantColor[stage] = NL_D3DCOLOR_RGBA(env.ConstantColor);
241 else
243 // The stage is disabled, active only the lighting
244 ColorOp[stage] = D3DTOP_SELECTARG1;
245 DWORD opSrc = D3DTA_DIFFUSE;
246 ColorArg0[stage] = opSrc;
247 ColorArg1[stage] = opSrc;
248 ColorArg2[stage] = opSrc;
249 AlphaOp[stage] = D3DTOP_SELECTARG1;
250 AlphaArg0[stage] = opSrc;
251 AlphaArg1[stage] = opSrc;
252 AlphaArg2[stage] = opSrc;
253 ConstantColor[stage] = NL_D3DCOLOR_RGBA(CRGBA::White);
254 NumColorArg[stage] = 1;
255 NumAlphaArg[stage] = 1;
260 // ***************************************************************************
261 static inline DWORD replaceDiffuseWithConstant(DWORD value)
263 if ((value & D3DTA_SELECTMASK) == D3DTA_DIFFUSE)
265 return (value & ~D3DTA_SELECTMASK) | D3DTA_TFACTOR;
267 return value;
273 // helpers to set shaders parameters
275 // Set a color in the shader
276 static inline void setShaderParam(CMaterialDrvInfosD3D *pShader, uint index, INT value)
278 nlassert(pShader->FXCache);
279 pShader->FXCache->Params.setColor(index, value);
282 // Set a color
283 static inline void setShaderParam(CMaterialDrvInfosD3D *pShader, uint index, CRGBA color)
285 nlassert(pShader->FXCache);
286 float values[4];
287 NL_FLOATS(values, color);
288 pShader->FXCache->Params.setVector(index, D3DXVECTOR4(values[0], values[1], values[2], values[3]));
292 // Set a float value in the shader
293 static inline void setShaderParam(CMaterialDrvInfosD3D *pShader, uint index, FLOAT value)
295 nlassert(pShader->FXCache);
296 pShader->FXCache->Params.setFloat(index, value);
300 // Set a vector of floats
301 static inline void setShaderParam(CMaterialDrvInfosD3D *pShader, uint index, float vector[4])
303 nlassert(pShader->FXCache); \
304 pShader->FXCache->Params.setVector(index, D3DXVECTOR4(vector[0], vector[1], vector[2], vector[3]));
307 // ***************************************************************************
308 bool CDriverD3D::setupMaterial(CMaterial &mat)
310 H_AUTO_D3D(CDriverD3D_setupMaterial)
311 CMaterialDrvInfosD3D* pShader;
313 // Stats
314 _NbSetupMaterialCall++;
316 // Max texture
317 const uint maxTexture = inlGetNumTextStages();
319 // Update material
320 uint32 touched=mat.getTouched();
322 // No shader ?
323 if (!mat._MatDrvInfo)
325 // Insert into driver list. (so it is deleted when driver is deleted).
326 ItMatDrvInfoPtrList it= _MatDrvInfos.insert(_MatDrvInfos.end(), (NL3D::IMaterialDrvInfos*)NULL);
328 *it = mat._MatDrvInfo = new CMaterialDrvInfosD3D(this, it);
330 // Must create all OpenGL shader states.
331 touched = IDRV_TOUCHED_ALL;
333 pShader = static_cast<CMaterialDrvInfosD3D*>((IMaterialDrvInfos*)(mat._MatDrvInfo));
335 // Now we can get the supported shader from the cache.
336 CMaterial::TShader matShader = _PixelProgramUser ? CMaterial::Program : mat.getShader();
338 if (_CurrentMaterialSupportedShader != CMaterial::Normal)
340 // because of multipass, some shader need to disable fog
341 // restore fog here
342 if(_FogEnabled && _FogColor != _RenderStateCache[D3DRS_FOGCOLOR].Value)
344 // restore fog
345 setRenderState(D3DRS_FOGCOLOR, _FogColor);
349 H_AUTO_D3D(CDriverD3D_setupMaterial_light)
350 // if the shader has changed since last time
351 if(matShader != _CurrentMaterialSupportedShader)
353 // if current shader is normal shader, then must restore uv routing, because it may have been changed by a previous shader (such as lightmap)
354 if (matShader == CMaterial::Normal)
356 for(uint k = 0; k < MaxTexture; ++k)
358 setTextureIndexUV (k, _CurrentUVRouting[k]);
361 // if old was lightmap, restore standard lighting
362 if(_CurrentMaterialSupportedShader==CMaterial::LightMap)
364 _MustRestoreLight = true;
367 // if new is lightmap, setup dynamic lighting
368 if(matShader==CMaterial::LightMap)
370 setupLightMapDynamicLighting(true);
371 _MustRestoreLight = false;
374 if (mat.isLighted() && _MustRestoreLight)
376 setupLightMapDynamicLighting(false);
377 _MustRestoreLight = false;
379 // setup the global
380 _CurrentMaterialSupportedShader= matShader;
385 // count number of tex stages
386 uint numUsedTexStages = 0;
387 for(numUsedTexStages = 0; numUsedTexStages < IDRV_MAT_MAXTEXTURES; ++numUsedTexStages)
389 if (mat.getTexture(uint8(numUsedTexStages)) == NULL) break;
392 H_AUTO_D3D(CDriverD3D_setupMaterial_touchupdate)
393 if (pShader->NumUsedTexStages != numUsedTexStages)
395 touched |= IDRV_TOUCHED_TEXENV;
397 // Something to setup ?
398 if (touched)
400 if (touched & IDRV_TOUCHED_SHADER)
402 delete pShader->FXCache;
403 pShader->FXCache = NULL;
404 // See if material actually needs a fx cache
405 if (mat.getShader() != CMaterial::Specular && mat.getShader() != CMaterial::Normal)
407 pShader->FXCache = new CFXCache;
410 /* Exception: if only Textures are modified in the material, no need to "Bind OpenGL States", or even to test
411 for change, because textures are activated alone, see below.
412 No problem with delete/new problem (see below), because in this case, IDRV_TOUCHED_ALL is set (see above).
414 // If any flag is set (but a flag of texture).
415 if(touched & (~_MaterialAllTextureTouchedFlag))
417 // Convert Material to driver shader.
418 if (touched & IDRV_TOUCHED_BLENDFUNC)
420 pShader->SrcBlend = RemapBlendTypeNeL2D3D[mat.getSrcBlend()];
421 pShader->DstBlend = RemapBlendTypeNeL2D3D[mat.getDstBlend()];
423 if (touched & IDRV_TOUCHED_ZFUNC)
425 pShader->ZComp = RemapZFuncTypeNeL2D3D[mat.getZFunc()];
427 if (touched & IDRV_TOUCHED_LIGHTING)
429 // Lighted material ?
430 if (mat.isLighted())
432 // Setup the color
433 NL_D3DCOLORVALUE_RGBA(pShader->Material.Diffuse, mat.getDiffuse());
434 NL_D3DCOLORVALUE_RGBA(pShader->Material.Ambient, mat.getAmbient());
435 NL_D3DCOLORVALUE_RGBA(pShader->Material.Emissive, mat.getEmissive());
437 // Specular
438 CRGBA spec = mat.getSpecular();
439 if (spec != CRGBA::Black)
441 NL_D3DCOLORVALUE_RGBA(pShader->Material.Specular, spec);
442 pShader->SpecularEnabled = TRUE;
443 pShader->Material.Power = mat.getShininess();
445 else
446 setRenderState (D3DRS_SPECULARENABLE, FALSE);
448 else
450 // No specular
451 pShader->SpecularEnabled = FALSE;
454 if (touched & IDRV_TOUCHED_COLOR)
456 // Setup the color
457 pShader->UnlightedColor = NL_D3DCOLOR_RGBA(mat.getColor());
459 if (touched & IDRV_TOUCHED_ALPHA_TEST_THRE)
461 float alphaRef = (float)floor(mat.getAlphaTestThreshold() * 255.f + 0.5f);
462 clamp (alphaRef, 0.f, 255.f);
463 pShader->AlphaRef = (DWORD)alphaRef;
465 if (touched & IDRV_TOUCHED_SHADER)
467 // todo hulud d3d material shaders
468 // Get shader. Fallback to other shader if not supported.
469 // pShader->SupportedShader= getSupportedShader(mat.getShader());
471 if (touched & IDRV_TOUCHED_TEXENV)
473 // Build the tex env cache.
474 // Do not do it for Lightmap and per pixel lighting , because done in multipass in a very special fashion.
475 // This avoid the useless multiple change of texture states per lightmapped object.
476 // Don't do it also for Specular because the EnvFunction and the TexGen may be special.
477 if(matShader == CMaterial::Normal)
479 uint stage;
480 for(stage=0 ; stage<maxTexture; ++stage)
482 // Build the tex env
483 pShader->buildTexEnv (stage, mat._TexEnvs[stage], mat.getTexture(uint8(stage)) != NULL);
487 if (touched & (IDRV_TOUCHED_TEXGEN|IDRV_TOUCHED_ALLTEX))
489 uint stage;
490 for(stage=0 ; stage<maxTexture; ++stage)
492 pShader->ActivateSpecularWorldTexMT[stage] = false;
493 pShader->ActivateInvViewModelTexMT[stage] = false;
495 // Build the tex env
496 ITexture *text= mat.getTexture(uint8(stage));
497 if (text && text->isTextureCube())
499 if (mat.getTexCoordGen(stage))
501 // Texture cube
502 pShader->TexGen[stage] = RemapTexGenCubeTypeNeL2D3D[mat.getTexCoordGenMode (stage)];
504 // Texture matrix
505 pShader->ActivateSpecularWorldTexMT[stage] = mat.getTexCoordGenMode (stage) == CMaterial::TexCoordGenReflect;
507 else
509 pShader->TexGen[stage] = mat.getTexCoordGen(stage);
512 else
514 if (mat.getTexCoordGen(stage))
516 pShader->TexGen[stage] = RemapTexGenTypeNeL2D3D[mat.getTexCoordGenMode (stage)];
518 // Texture matrix
519 pShader->ActivateInvViewModelTexMT[stage] = mat.getTexCoordGenMode (stage) == CMaterial::TexCoordGenObjectSpace;
521 else
523 pShader->TexGen[stage] = mat.getTexCoordGen(stage);
529 // Does this material needs a pixel shader ?
530 if (touched & (IDRV_TOUCHED_TEXENV|IDRV_TOUCHED_BLEND|IDRV_TOUCHED_ALPHA_TEST))
532 std::fill(pShader->RGBPipe, pShader->RGBPipe + IDRV_MAT_MAXTEXTURES, true);
533 std::fill(pShader->AlphaPipe, pShader->AlphaPipe + IDRV_MAT_MAXTEXTURES, true);
535 pShader->MultipleConstantNoPixelShader = false;
536 pShader->MultiplePerStageConstant = false;
537 pShader->VertexColorLighted = mat.getLightedVertexColor();
538 bool _needPixelShader = false;
539 pShader->ConstantIndex = 0xff;
540 pShader->ConstantIndex2 = 0xff;
541 if (matShader == CMaterial::Normal)
543 // Need of constants ?
544 uint numConstants;
545 uint firstConstant;
546 uint secondConstant;
547 needsConstants (numConstants, firstConstant, secondConstant, mat);
549 pShader->ConstantIndex = uint8(firstConstant);
550 pShader->ConstantIndex2 = uint8(secondConstant);
552 // Need a constant color for the diffuse component ?
553 pShader->NeedsConstantForDiffuse = needsConstantForDiffuse (mat);
555 // Need pixel shader ?
556 #ifndef NL_FORCE_PIXEL_SHADER_USE_FOR_NORMAL_SHADERS
557 _needPixelShader = (numConstants > 1) || ((numConstants==1) && pShader->NeedsConstantForDiffuse);
558 #else // NL_FORCE_PIXEL_SHADER_USE_FOR_NORMAL_SHADERS
559 _needPixelShader = true;
560 #endif // NL_FORCE_PIXEL_SHADER_USE_FOR_NORMAL_SHADERS
561 if (_needPixelShader)
563 // The shader description
564 CNormalShaderDesc normalShaderDesc;
566 // Setup descriptor
567 uint stage;
568 for(stage=0 ; stage<(uint)maxTexture; stage++)
570 // Stage used ?
571 normalShaderDesc.StageUsed[stage] = mat.getTexture (uint8(stage)) != NULL;
572 normalShaderDesc.TexEnvMode[stage] = mat.getTexEnvMode(uint8(stage));
575 if (_PixelProgram)
577 #ifdef NL_DEBUG_D3D
578 // Check, should not occur
579 nlassertex (_PixelShader, ("STOP : no pixel shader available. Can't render this material."));
580 #endif // NL_DEBUG_D3D
582 // Build the pixel shader
583 pShader->PixelShader = buildPixelShader (normalShaderDesc, false);
584 if (!mat.isLighted())
585 pShader->PixelShaderUnlightedNoVertexColor = buildPixelShader (normalShaderDesc, true);
586 else
587 pShader->PixelShaderUnlightedNoVertexColor = NULL;
589 else
591 // Possible configurations are :
592 // unlighted, 1 constant diffuse + 1 per stage constant
593 // unlighted, 2 constants (second constant emulated with material emissive + diffuse), possibly with vertex color (aliased to specular)
595 // If there are no pixel shader then we're likely to have three stage or less
596 pShader->MultipleConstantNoPixelShader = true;
597 pShader->MultiplePerStageConstant = numConstants > 1;
598 #ifdef NL_DEBUG
599 nlassert(numConstants <= 2);
600 #endif
601 if (secondConstant != 0xffffffff)
603 pShader->Constant2 = mat.getTexConstantColor(secondConstant);
605 pShader->PixelShader = NULL;
606 pShader->PixelShaderUnlightedNoVertexColor = NULL;
607 // compute relevant parts of the pipeline
608 computeRelevantTexEnv(mat, pShader->RGBPipe, pShader->AlphaPipe);
611 else
613 // compute relevant parts of the pipeline
614 computeRelevantTexEnv(mat, pShader->RGBPipe, pShader->AlphaPipe);
617 else
619 // Other shaders
620 pShader->MultipleConstantNoPixelShader = false;
621 pShader->NeedsConstantForDiffuse = false;
624 if (!_needPixelShader)
626 // Remove the old one
627 pShader->PixelShader = NULL;
628 pShader->PixelShaderUnlightedNoVertexColor = NULL;
629 pShader->MultipleConstantNoPixelShader = 0;
633 // Since modified, must rebind all D3D states. And do this also for the delete/new problem.
634 /* If an old material is deleted, _CurrentMaterial is invalid. But this is grave only if a new
635 material is created, with the same pointer (bad luck). Since an newly allocated material always
636 pass here before use, we are sure to avoid any problems.
638 _CurrentMaterial= NULL;
641 // Optimize: reset all flags at the end.
642 mat.clearTouched(0xFFFFFFFF);
643 pShader->NumUsedTexStages = numUsedTexStages;
649 H_AUTO_D3D(CDriverD3D_setupMaterial_bindTexture)
650 // 2. Setup / Bind Textures.
651 //==========================
652 // Must setup textures each frame. (need to test if touched).
653 // Must separate texture setup and texture activation in 2 "for"...
654 // because setupTexture() may disable all stage.
656 if (matShader == CMaterial::Normal
657 || ((matShader == CMaterial::Program) && (_PixelProgramUser->features().MaterialFlags & CProgramFeatures::TextureStages))
660 uint stage;
661 for(stage=0 ; stage<maxTexture; ++stage)
663 ITexture *text= mat.getTexture(uint8(stage));
664 if (!text) break;
665 if (text != NULL && !setupTexture(*text))
666 return(false);
672 // Activate the textures.
673 // Do not do it for Lightmap and per pixel lighting , because done in multipass in a very special fashion.
674 // This avoid the useless multiple change of texture states per lightmapped object.
675 // Don't do it also for Specular because the EnvFunction and the TexGen may be special.
677 H_AUTO_D3D(CDriverD3D_setupMaterial_normalShaderActivateTextures)
678 if (matShader == CMaterial::Normal
679 || ((matShader == CMaterial::Program) && (_PixelProgramUser->features().MaterialFlags & CProgramFeatures::TextureStages))
682 uint stage;
683 for(stage=0 ; stage<maxTexture; ++stage)
685 ITexture *text= mat.getTexture(uint8(stage));
686 if (text)
688 // activate the texture, or disable texturing if NULL.
689 setTexture(stage, text);
691 else
693 setTexture (stage, (LPDIRECT3DBASETEXTURE9)NULL);
694 if (stage != 0)
696 setTextureState (stage, D3DTSS_COLOROP, D3DTOP_DISABLE);
697 //setTextureState (stage, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
698 break; // stage after this one are ignored
700 else
702 setTextureState (1, D3DTSS_COLOROP, D3DTOP_DISABLE);
706 // Set the texture states
707 if (text || (stage == 0))
709 if (matShader == CMaterial::Program)
711 // Do nothing for user pixel shader
713 else if (!pShader->PixelShader)
715 // Doesn't use a pixel shader ? Set the textures stages
716 if (pShader->RGBPipe[stage])
718 setTextureState (stage, D3DTSS_COLOROP, pShader->ColorOp[stage]);
719 setTextureState (stage, D3DTSS_COLORARG1, pShader->ColorArg1[stage]);
720 if (pShader->NumColorArg[stage] > 1)
722 setTextureState (stage, D3DTSS_COLORARG2, pShader->ColorArg2[stage]);
723 if (pShader->NumColorArg[stage] > 2)
725 setTextureState (stage, D3DTSS_COLORARG0, pShader->ColorArg0[stage]);
729 if (pShader->AlphaPipe[stage])
731 setTextureState (stage, D3DTSS_ALPHAOP, pShader->AlphaOp[stage]);
732 setTextureState (stage, D3DTSS_ALPHAARG1, pShader->AlphaArg1[stage]);
733 if (pShader->NumAlphaArg[stage] > 1)
735 setTextureState (stage, D3DTSS_ALPHAARG2, pShader->AlphaArg2[stage]);
736 if (pShader->NumAlphaArg[stage] > 2)
738 setTextureState (stage, D3DTSS_ALPHAARG0, pShader->AlphaArg0[stage]);
742 // If there is one constant and the tfactor is not needed for diffuse, use the tfactor as constant
743 if (pShader->ConstantIndex == stage)
744 setRenderState (D3DRS_TEXTUREFACTOR, pShader->ConstantColor[stage]);
746 else
748 float colors[4];
749 D3DCOLOR_FLOATS (colors, pShader->ConstantColor[stage]);
750 setPixelShaderConstant (stage, colors);
754 // Set texture generator state
755 setTextureIndexMode (stage, pShader->TexGen[stage]!=D3DTSS_TCI_PASSTHRU, pShader->TexGen[stage]);
757 // Need user matrix ?
758 bool needUserMtx = mat.isUserTexMatEnabled(stage);
759 D3DXMATRIX userMtx;
760 if (needUserMtx)
762 // If tex gen mode is used, or a cube texture is used, then use the matrix 'as it'.
763 // Must build a 3x3 matrix for 2D texture coordinates in D3D (which is kind of weird ...)
764 if (pShader->TexGen[stage] != D3DTSS_TCI_PASSTHRU || (mat.getTexture(uint8(stage)) && mat.getTexture(uint8(stage))->isTextureCube()))
766 NL_D3D_MATRIX(userMtx, mat.getUserTexMat(stage));
768 else
770 const CMatrix &m = mat.getUserTexMat(stage);
771 NL_D3D_TEX2D_MATRIX(userMtx, m);
775 // Need cubic texture coord generator ?
776 if (pShader->ActivateSpecularWorldTexMT[stage])
778 // Set the driver matrix
779 setTextureState (stage, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT3);
780 if (!needUserMtx)
781 setMatrix ((D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0+stage), _D3DSpecularWorldTex);
782 else
784 D3DXMatrixMultiply (&userMtx, &_D3DSpecularWorldTex, &userMtx);
785 setMatrix ((D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0+stage), userMtx);
788 else if (pShader->ActivateInvViewModelTexMT[stage])
790 // Set the driver matrix
791 setTextureState (stage, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT3);
792 if (!needUserMtx)
793 setMatrix ((D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0+stage), _D3DInvModelView);
794 else
796 D3DXMatrixMultiply (&userMtx, &_D3DInvModelView, &userMtx);
797 setMatrix ((D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0+stage), userMtx);
800 else
802 if (_NbNeLTextureStages == 3)
804 // Fix for Radeon 7xxx
805 // In some situation, texture transform stays enabled after a material change, so enable it all the
806 // time and use identity matrix instead of the D3DTTFF_DISABLE flag
807 setTextureState (stage, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT3);
808 setMatrix ((D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0+stage), needUserMtx ? userMtx : _D3DMatrixIdentity);
810 else
812 // Set the driver matrix
813 if (needUserMtx)
815 setTextureState (stage, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT3);
816 setMatrix ((D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0+stage), userMtx);
818 else
820 setTextureState (stage, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
824 if (!text && stage == 0) break;
829 if (_CurrentMaterial != &mat)
831 // Material has changed ?
832 // Restore fog state to its current value
834 H_AUTO_D3D(CDriverD3D_setupMaterial_updateFog)
835 setRenderState (D3DRS_FOGENABLE, _FogEnabled?TRUE:FALSE);
838 // Flags
839 const uint32 flags = mat.getFlags();
841 // Two sided
842 _DoubleSided = (flags&IDRV_MAT_DOUBLE_SIDED)!=0;
845 H_AUTO_D3D(CDriverD3D_setupMaterial_handleBackSide)
846 // Handle backside
847 if (_CullMode == CCW)
849 setRenderState (D3DRS_CULLMODE, _DoubleSided?D3DCULL_NONE:_InvertCullMode?D3DCULL_CCW:D3DCULL_CW);
851 else
853 setRenderState (D3DRS_CULLMODE, _DoubleSided?D3DCULL_NONE:_InvertCullMode?D3DCULL_CW:D3DCULL_CCW);
858 bool blend = (flags&IDRV_MAT_BLEND) != 0;
860 H_AUTO_D3D(CDriverD3D_setupMaterial_updateBlend)
861 // Active states
862 if (blend)
864 setRenderState (D3DRS_ALPHABLENDENABLE, TRUE);
865 setRenderState (D3DRS_SRCBLEND, pShader->SrcBlend);
866 setRenderState (D3DRS_DESTBLEND, pShader->DstBlend);
868 else
869 setRenderState (D3DRS_ALPHABLENDENABLE, FALSE);
871 // Alpha test
872 if (flags&IDRV_MAT_ALPHA_TEST)
874 setRenderState (D3DRS_ALPHATESTENABLE, TRUE);
875 setRenderState (D3DRS_ALPHAREF, pShader->AlphaRef);
876 setRenderState (D3DRS_ALPHAFUNC, D3DCMP_GREATER);
878 else
879 setRenderState (D3DRS_ALPHATESTENABLE, FALSE);
883 H_AUTO_D3D(CDriverD3D_setupMaterial_updateZBuffer)
884 // Z buffer
885 setRenderState (D3DRS_ZWRITEENABLE, (flags&IDRV_MAT_ZWRITE)?TRUE:FALSE);
886 setRenderState (D3DRS_ZFUNC, pShader->ZComp);
887 float flt = mat.getZBias () * _OODeltaZ;
888 setRenderState (D3DRS_DEPTHBIAS, FTODW(flt));
892 H_AUTO_D3D(CDriverD3D_setupMaterial_updateLighting)
893 // Active lighting
894 if (mat.isLighted())
896 setRenderState (D3DRS_LIGHTING, TRUE);
897 setMaterialState(pShader->Material);
899 else
901 setRenderState (D3DRS_LIGHTING, FALSE);
903 // Set pixel shader unlighted color ?
904 if (pShader->PixelShader)
906 float colors[4];
907 D3DCOLOR_FLOATS(colors,pShader->UnlightedColor);
908 setPixelShaderConstant (5, colors);
911 setRenderState (D3DRS_SPECULARENABLE, pShader->SpecularEnabled);
915 H_AUTO_D3D(CDriverD3D_setupMaterial_updateVertexColorLighted)
916 // Active vertex color if not lighted or vertex color forced
917 if (mat.isLightedVertexColor ())
919 setRenderState (D3DRS_COLORVERTEX, TRUE);
921 setRenderState (D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
923 else
925 setRenderState (D3DRS_COLORVERTEX, FALSE);
926 setRenderState (D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);
931 H_AUTO_D3D(CDriverD3D_setupMaterial_disableFog)
932 // Disable fog if dest blend is ONE
933 if (blend && (pShader->DstBlend == D3DBLEND_ONE))
935 setRenderState (D3DRS_FOGENABLE, FALSE);
939 // Set the good shader
940 switch (matShader)
942 case CMaterial::Normal:
944 H_AUTO_D3D(CDriverD3D_setupMaterial_setupNormalshader)
945 // No shader
946 activeShader (NULL);
948 /* If unlighted trick is needed, set the shader later */
949 if (!pShader->NeedsConstantForDiffuse && _PixelProgram)
950 setPixelShader (pShader->PixelShader);
952 break;
953 case CMaterial::LightMap:
955 H_AUTO_D3D(CDriverD3D_setupMaterial_setupLightmapShader)
956 setPixelShader (NULL);
957 static const uint32 RGBMaskPacked = CRGBA(255,255,255,0).getPacked();
959 if (_NbNeLTextureStages == 3)
961 touchRenderVariable(&_MaterialState);
964 // if the dynamic lightmap light has changed since the last render (should not happen), resetup
965 // normal way is that setupLightMapDynamicLighting() is called at begin of setupMaterial() if shader different from prec
966 if(_LightMapDynamicLightDirty)
967 setupLightMapDynamicLighting(true);
969 // Count the lightmaps
970 uint lightmap;
971 uint lightmapCount = 0;
972 uint lightmapMask = 0;
973 for(lightmap=0 ; lightmap<(sint)mat._LightMaps.size() ; lightmap++)
975 if (mat._LightMaps[lightmap].Factor.getPacked() & RGBMaskPacked)
977 lightmapCount++;
978 lightmapMask |= 1<<lightmap;
983 // activate the appropriate shader
984 if (mat.getBlend())
986 if(mat._LightMapsMulx2)
988 switch (lightmapCount)
990 case 0: activeShader (&_ShaderLightmap0BlendX2); break;
991 case 1: activeShader (&_ShaderLightmap1BlendX2); break;
992 case 2: activeShader (&_ShaderLightmap2BlendX2); break;
993 case 3: activeShader (&_ShaderLightmap3BlendX2); break;
994 default: activeShader (&_ShaderLightmap4BlendX2); break;
997 else
999 switch (lightmapCount)
1001 case 0: activeShader (&_ShaderLightmap0Blend); break;
1002 case 1: activeShader (&_ShaderLightmap1Blend); break;
1003 case 2: activeShader (&_ShaderLightmap2Blend); break;
1004 case 3: activeShader (&_ShaderLightmap3Blend); break;
1005 default: activeShader (&_ShaderLightmap4Blend); break;
1009 else
1011 if(mat._LightMapsMulx2)
1013 switch (lightmapCount)
1015 case 0: activeShader (&_ShaderLightmap0X2); break;
1016 case 1: activeShader (&_ShaderLightmap1X2); break;
1017 case 2: activeShader (&_ShaderLightmap2X2); break;
1018 case 3: activeShader (&_ShaderLightmap3X2); break;
1019 default: activeShader (&_ShaderLightmap4X2); break;
1022 else
1024 switch (lightmapCount)
1026 case 0: activeShader (&_ShaderLightmap0); break;
1027 case 1: activeShader (&_ShaderLightmap1); break;
1028 case 2: activeShader (&_ShaderLightmap2); break;
1029 case 3: activeShader (&_ShaderLightmap3); break;
1030 default: activeShader (&_ShaderLightmap4); break;
1035 // Setup the texture
1036 ITexture *texture = mat.getTexture(0);
1037 if (!setShaderTexture (0, texture, pShader->FXCache))
1038 return false;
1040 // Get the effect
1041 nlassert (_CurrentShader);
1042 CShaderDrvInfosD3D *shaderInfo = static_cast<CShaderDrvInfosD3D*>((IShaderDrvInfos*)_CurrentShader->_DrvInfo);
1043 // ID3DXEffect *effect = shaderInfo->Effect;
1046 // Set the ambiant for 8Bit Light Compression
1048 // Sum ambiant of all active lightmaps.
1049 uint32 r=0;
1050 uint32 g=0;
1051 uint32 b=0;
1052 for(lightmap=0 ; lightmap<(sint)mat._LightMaps.size() ; lightmap++)
1054 if (lightmapMask & (1<<lightmap))
1056 uint wla= lightmap;
1057 // must mul them by their respective mapFactor too
1058 CRGBA ambFactor = mat._LightMaps[wla].Factor;
1059 CRGBA lmcAmb= mat._LightMaps[wla].LMCAmbient;
1060 r+= ((uint32)ambFactor.R * ((uint32)lmcAmb.R+(lmcAmb.R>>7))) >>8;
1061 g+= ((uint32)ambFactor.G * ((uint32)lmcAmb.G+(lmcAmb.G>>7))) >>8;
1062 b+= ((uint32)ambFactor.B * ((uint32)lmcAmb.B+(lmcAmb.B>>7))) >>8;
1065 r= std::min(r, (uint32)255);
1066 g= std::min(g, (uint32)255);
1067 b= std::min(b, (uint32)255);
1068 CRGBA lmcAmbient((uint8)r,(uint8)g,(uint8)b,255);
1070 // Set into FX shader
1071 setShaderParam(pShader, 0, (INT) NL_D3DCOLOR_RGBA(lmcAmbient));
1072 if (shaderInfo->FactorHandle[0])
1074 setShaderParam(pShader, 0, lmcAmbient);
1079 // Set the lightmaps
1080 lightmapCount = 0;
1081 for(lightmap=0 ; lightmap<(sint)mat._LightMaps.size() ; lightmap++)
1083 if (lightmapMask & (1<<lightmap))
1085 // Set the lightmap texture
1086 ITexture *text= mat._LightMaps[lightmap].Texture;
1087 if (text != NULL && !setShaderTexture (lightmapCount+1, text, pShader->FXCache))
1088 return false;
1090 // Get the lightmap color factor, and mul by lmcDiffuse compression
1091 CRGBA lmapFactor = mat._LightMaps[lightmap].Factor;
1092 CRGBA lmcDiff= mat._LightMaps[lightmap].LMCDiffuse;
1093 lmapFactor.R = (uint8)(((uint32)lmapFactor.R * ((uint32)lmcDiff.R+(lmcDiff.R>>7))) >>8);
1094 lmapFactor.G = (uint8)(((uint32)lmapFactor.G * ((uint32)lmcDiff.G+(lmcDiff.G>>7))) >>8);
1095 lmapFactor.B = (uint8)(((uint32)lmapFactor.B * ((uint32)lmcDiff.B+(lmcDiff.B>>7))) >>8);
1096 lmapFactor.A = 255;
1098 // Set the lightmap color factor into shader
1099 setShaderParam(pShader, lightmapCount+1, (INT) NL_D3DCOLOR_RGBA(lmapFactor));
1100 if (shaderInfo->FactorHandle[lightmapCount+1])
1102 setShaderParam(pShader, lightmapCount+1, lmapFactor);
1104 lightmapCount++;
1108 break;
1109 case CMaterial::Specular:
1111 H_AUTO_D3D(CDriverD3D_setupMaterial_setupSpecularShader)
1112 // No shader
1113 activeShader (NULL);
1114 setPixelShader (NULL);
1116 // Setup the texture
1117 ITexture *texture = mat.getTexture(0);
1118 if (!texture || !setupTexture (*texture))
1119 return false;
1120 setTexture (0, texture);
1122 // Setup the texture
1123 texture = mat.getTexture(1);
1124 if (!texture || !setupTexture (*texture))
1125 return false;
1126 setTexture (1, texture);
1128 // Set the driver matrix
1129 if (texture->isTextureCube())
1131 setTextureIndexMode (1, true, D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
1132 setTextureState (1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT3);
1133 setMatrix ((D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0+1), _D3DSpecularWorldTex);
1136 setRenderState (D3DRS_LIGHTING, mat.isLighted()?TRUE:FALSE);
1137 setRenderState (D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);
1138 setTextureState (0, D3DTSS_COLOROP, D3DTOP_MODULATE);
1139 setTextureState (0, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
1140 setTextureState (0, D3DTSS_COLORARG2, D3DTA_TEXTURE);
1141 setTextureState (0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
1142 setTextureState (0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
1143 setTextureState (1, D3DTSS_COLOROP, D3DTOP_MULTIPLYADD);
1144 setTextureState (1, D3DTSS_COLORARG0, D3DTA_CURRENT);
1145 setTextureState (1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
1146 setTextureState (1, D3DTSS_COLORARG2, D3DTA_CURRENT|D3DTA_ALPHAREPLICATE);
1147 setTextureState (1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
1148 setTextureState (1, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
1151 break;
1152 case CMaterial::Cloud:
1154 H_AUTO_D3D(CDriverD3D_setupMaterial_setupCloudShader)
1155 activeShader (&_ShaderCloud);
1157 // Get the shader
1158 nlassert (_CurrentShader);
1159 // CShaderDrvInfosD3D *shaderInfo = static_cast<CShaderDrvInfosD3D*>((IShaderDrvInfos*)_CurrentShader->_DrvInfo);
1161 // Set the constant
1162 // ID3DXEffect *effect = shaderInfo->Effect;
1163 CRGBA color = mat.getColor();
1164 color.R = 255;
1165 color.G = 255;
1166 color.B = 255;
1167 setShaderParam(pShader, 0, color);
1169 // Set the texture
1170 if (!setShaderTexture (0, mat.getTexture(0), pShader->FXCache) || !setShaderTexture (1, mat.getTexture(1), pShader->FXCache))
1171 return false;
1173 break;
1174 case CMaterial::Water:
1176 H_AUTO_D3D(CDriverD3D_setupMaterial_setupWaterShader)
1177 activeShader(mat.getTexture(3) ? &_ShaderWaterDiffuse : &_ShaderWaterNoDiffuse);
1178 // Get the shader
1179 nlassert (_CurrentShader);
1180 // CShaderDrvInfosD3D *shaderInfo = static_cast<CShaderDrvInfosD3D*>((IShaderDrvInfos*)_CurrentShader->_DrvInfo);
1181 // Set the textures
1182 if (_PixelShaderVersion >= D3DPS_VERSION(1, 4))
1184 ITexture *tex = mat.getTexture(0);
1185 if (tex)
1187 tex->setUploadFormat(ITexture::RGBA8888);
1188 // if (tex->isBumpMap())
1189 // {
1190 // CTextureBump *tb = static_cast<CTextureBump *>(tex);
1191 // }
1192 setupTexture(*tex);
1193 setShaderTexture (0, tex, pShader->FXCache);
1196 ITexture *tex = mat.getTexture(1);
1197 if (tex)
1199 if (_PixelShaderVersion < D3DPS_VERSION(1, 4))
1201 tex->setUploadFormat(ITexture::DsDt);
1202 // if (tex->isBumpMap())
1203 // {
1204 // CTextureBump *tb = static_cast<CTextureBump *>(tex);
1205 // }
1207 else
1209 tex->setUploadFormat(ITexture::RGBA8888);
1210 // if (tex->isBumpMap())
1211 // {
1212 // CTextureBump *tb = static_cast<CTextureBump *>(tex);
1213 // }
1215 setupTexture(*tex);
1216 setShaderTexture (1, tex, pShader->FXCache);
1219 tex = mat.getTexture(2);
1220 if (tex)
1222 setupTexture(*tex);
1223 setShaderTexture (2, tex, pShader->FXCache);
1225 tex = mat.getTexture(3);
1226 if (tex)
1228 setupTexture(*tex);
1229 setShaderTexture (3, tex, pShader->FXCache);
1232 // Set the constants
1233 // ID3DXEffect *effect = shaderInfo->Effect;
1234 if (_PixelShaderVersion < D3DPS_VERSION(2, 0))
1236 if (_PixelShaderVersion < D3DPS_VERSION(1, 4))
1238 if (mat.getTexture(1) && mat.getTexture(1)->isBumpMap())
1240 float factor = NLMISC::safe_cast<CTextureBump *>(mat.getTexture(1))->getNormalizationFactor();
1241 setShaderParam(pShader, 0, factor);
1243 else
1245 setShaderParam(pShader, 0, 1.f);
1248 else
1250 if (mat.getTexture(0) && mat.getTexture(0)->isBumpMap())
1252 float factor = NLMISC::safe_cast<CTextureBump *>(mat.getTexture(0))->getNormalizationFactor();
1253 float cst[4] = { factor, factor, factor, 0.f };
1254 setShaderParam(pShader, 0, cst);
1256 else
1258 float cst[4] = { 1.f, 1.f, 1.f, 0.f };
1259 setShaderParam(pShader, 0, cst);
1262 if (mat.getTexture(1) && mat.getTexture(1)->isBumpMap())
1264 float factor = NLMISC::safe_cast<CTextureBump *>(mat.getTexture(1))->getNormalizationFactor();
1265 float cst[4] = { factor, factor, factor, 0.f };
1266 setShaderParam(pShader, 1, cst);
1268 else
1270 float cst[4] = { 1.f, 1.f, 1.f, 0.f };
1271 setShaderParam(pShader, 1, cst);
1275 else
1277 // setup the constant
1278 if (mat.getTexture(0) && mat.getTexture(0)->isBumpMap())
1280 float factor = 0.25f * NLMISC::safe_cast<CTextureBump *>(mat.getTexture(0))->getNormalizationFactor();
1281 float bmScale[4] = { -1.f * factor, -1.f * factor, 2.f * factor, 0.f };
1282 setShaderParam(pShader, 0, bmScale);
1284 else
1286 float bmScale[4] = { -1.f, -1.f, 2.f, 0.f };
1287 setShaderParam(pShader, 0, bmScale);
1289 // setup the constant
1290 if (mat.getTexture(1) && mat.getTexture(1)->isBumpMap())
1292 float factor = NLMISC::safe_cast<CTextureBump *>(mat.getTexture(1))->getNormalizationFactor();
1293 float bmScale[4] = { -1.f * factor, -1.f * factor, 2.f * factor, 0.f };
1294 setShaderParam(pShader, 1, bmScale);
1296 else
1298 float bmScale[4] = { -1.f, -1.f, 2.f, 0.f };
1299 setShaderParam(pShader, 1, bmScale);
1303 break; // CMaterial::Water
1304 case CMaterial::Program:
1306 H_AUTO_D3D(CDriverD3D_setupMaterial_setupProgramshader)
1307 // No material shader
1308 activeShader(NULL);
1310 break;
1313 // New material setuped
1314 _CurrentMaterial = &mat;
1316 // Update variables
1317 _CurrentMaterialInfo = pShader;
1320 return true;
1323 // ***************************************************************************
1324 // Add one set to another
1325 static void add(std::set<uint> &dest, const std::set<uint> &toAdd)
1327 for (std::set<uint>::const_iterator it = toAdd.begin(); it != toAdd.end(); ++it)
1329 dest.insert(*it);
1334 // ***************************************************************************
1335 bool CDriverD3D::needsConstants (uint &numConstant, uint &firstConstant, uint &secondConstant, CMaterial &mat)
1337 H_AUTO_D3D(CDriverD3D_needsConstants)
1338 firstConstant = 0xffffffff;
1339 secondConstant = 0xffffffff;
1340 // Of course std::set could be avoided, but much simpler that way
1341 std::set<uint> rgbPipe[2]; // constant used to compute the rgb component
1342 std::set<uint> alphaPipe[2]; // constant used to compute the alpha component
1343 for (uint i=0; i<IDRV_MAT_MAXTEXTURES; i++)
1345 if (!mat.getTexture(uint8(i))) break;
1346 CMaterial::CTexEnv texEnv;
1347 texEnv.EnvPacked = mat.getTexEnvMode(i);
1348 rgbPipe[1].clear();
1349 alphaPipe[1].clear();
1350 if (texEnv.Env.OpRGB == CMaterial::InterpolateConstant)
1352 rgbPipe[1].insert(i);
1354 if (texEnv.Env.OpRGB == CMaterial::InterpolatePrevious)
1356 rgbPipe[1] = rgbPipe[0];
1358 if (texEnv.Env.OpAlpha == CMaterial::InterpolateConstant)
1360 alphaPipe[1].insert(i);
1362 if (texEnv.Env.OpAlpha == CMaterial::InterpolatePrevious)
1364 alphaPipe[1] = alphaPipe[0];
1366 for(uint l = 0; l < OpNumArg[texEnv.Env.OpRGB]; ++l)
1368 // color pipe
1369 if (texEnv.getColorArg(l) == CMaterial::Constant)
1371 rgbPipe[1].insert(i);
1373 else
1374 if (texEnv.getColorArg(l) == CMaterial::Previous)
1376 if (texEnv.getColorOperand(l) == CMaterial::SrcColor || texEnv.getColorOperand(l) == CMaterial::InvSrcColor)
1378 add(rgbPipe[1], rgbPipe[0]);
1380 if (texEnv.getColorOperand(l) == CMaterial::SrcAlpha || texEnv.getColorOperand(l) == CMaterial::InvSrcColor)
1382 add(rgbPipe[1], alphaPipe[0]);
1386 for(uint l = 0; l < OpNumArg[texEnv.Env.OpAlpha]; ++l)
1388 // alpha pipe
1389 if (texEnv.getAlphaArg(l) == CMaterial::Constant)
1391 alphaPipe[1].insert(i);
1393 if (texEnv.getAlphaArg(l) == CMaterial::Previous)
1395 add(alphaPipe[1], alphaPipe[0]);
1398 alphaPipe[0].swap(alphaPipe[1]);
1399 rgbPipe[0].swap(rgbPipe[1]);
1401 bool alphaRelevant = false;
1402 if (mat.getAlphaTest())
1404 alphaRelevant = true;
1406 else
1407 if (mat.getBlend())
1409 // see if alpha is relevant to blending
1410 if (mat.getSrcBlend() == CMaterial::srcalpha ||
1411 mat.getSrcBlend() == CMaterial::invsrcalpha ||
1412 mat.getDstBlend() == CMaterial::srcalpha ||
1413 mat.getDstBlend() == CMaterial::invsrcalpha
1416 alphaRelevant = true;
1419 if (!alphaRelevant)
1421 alphaPipe[0].clear();
1423 add(rgbPipe[0], alphaPipe[0]);
1424 numConstant = (uint)rgbPipe[0].size();
1425 if (numConstant)
1427 firstConstant = *(rgbPipe[0].begin());
1428 if (numConstant == 2)
1430 secondConstant = *(++rgbPipe[0].begin());
1432 // can emulate up to 2 constants only ...
1434 return false;
1438 // ***************************************************************************
1439 bool CDriverD3D::needsConstantForDiffuse (CMaterial &mat)
1441 H_AUTO_D3D(CDriverD3D_needsConstantForDiffuse)
1442 // If lighted, don't need the tfactor
1443 if (mat.isLighted())
1444 return false;
1445 if (mat.getTexture(0) == NULL) return true; // RGB diffuse is output
1446 // Inspect the RGB & alpha pipe : if a diffuse value manage to propagate to the last stage, and if the pipe is required for
1447 // fragment blending, then diffuse is useful in the shader, and thus must be replaced by constant for unlighted material
1448 bool propRGB = false; // diffuse RGB propagated to current stage
1449 bool propAlpha = false; // diffuse RGB propagated to current stage
1450 for (uint i=0; i<IDRV_MAT_MAXTEXTURES; i++)
1452 if (!mat.getTexture(uint8(i))) break;
1453 CMaterial::CTexEnv texEnv;
1454 texEnv.EnvPacked = mat.getTexEnvMode(i);
1455 bool newPropRGB = false;
1456 bool newPropAlpha = false;
1457 if (texEnv.Env.OpRGB == CMaterial::InterpolateDiffuse || (texEnv.Env.OpRGB == CMaterial::InterpolatePrevious && i == 0))
1459 newPropRGB = true;
1461 if (texEnv.Env.OpRGB == CMaterial::InterpolatePrevious)
1463 if (propAlpha) newPropRGB = true;
1465 if (texEnv.Env.OpAlpha == CMaterial::InterpolateDiffuse || (texEnv.Env.OpAlpha == CMaterial::InterpolatePrevious && i == 0))
1467 newPropAlpha = true;
1469 if (texEnv.Env.OpAlpha == CMaterial::InterpolatePrevious)
1471 if (propAlpha) newPropAlpha = true;
1473 for(uint l = 0; l < OpNumArg[texEnv.Env.OpRGB]; ++l)
1475 // color pipe
1476 if (texEnv.getColorArg(l) == CMaterial::Diffuse || (texEnv.getColorArg(l) == CMaterial::Previous && i == 0))
1478 newPropRGB = true;
1480 else
1481 if (texEnv.getColorArg(l) == CMaterial::Previous)
1483 if (texEnv.getColorOperand(l) == CMaterial::SrcColor || texEnv.getColorOperand(l) == CMaterial::InvSrcColor)
1485 if (propRGB) newPropRGB = true;
1487 if (texEnv.getColorOperand(l) == CMaterial::SrcAlpha || texEnv.getColorOperand(l) == CMaterial::InvSrcColor)
1489 if (propAlpha) newPropAlpha = true;
1493 // alpha pipe
1494 for(uint l = 0; l < OpNumArg[texEnv.Env.OpAlpha]; ++l)
1496 if (texEnv.getAlphaArg(l) == CMaterial::Diffuse || (texEnv.getAlphaArg(l) == CMaterial::Previous && i == 0))
1498 newPropAlpha = true;
1501 if (texEnv.getAlphaArg(l) == CMaterial::Previous)
1503 if (propAlpha) newPropAlpha = true;
1507 propRGB = newPropRGB;
1508 propAlpha = newPropAlpha;
1510 if (propRGB) return true;
1511 if (propAlpha)
1513 if (mat.getAlphaTest()) return true;
1514 if (mat.getBlend())
1516 // see if alpha is relevant to blending
1517 if (mat.getSrcBlend() == CMaterial::srcalpha ||
1518 mat.getSrcBlend() == CMaterial::invsrcalpha ||
1519 mat.getDstBlend() == CMaterial::srcalpha ||
1520 mat.getDstBlend() == CMaterial::invsrcalpha
1523 return true;
1527 return false;
1531 // ***************************************************************************
1532 void CDriverD3D::computeRelevantTexEnv(CMaterial &mat, bool rgbPipe[IDRV_MAT_MAXTEXTURES], bool alphaPipe[IDRV_MAT_MAXTEXTURES])
1534 // TODO : see if worth the trouble (during profile, I see a very small gain : 0.03% less time spent in driver for my test scene)
1535 // TODO : could be more efficient if I could see when alpha is useless...
1536 H_AUTO_D3D(CDriverD3D_computeRelevantTexEnv)
1538 static bool testStuff = false;
1539 if (testStuff)
1541 std::fill(rgbPipe, rgbPipe + IDRV_MAT_MAXTEXTURES, true);
1542 std::fill(alphaPipe, alphaPipe + IDRV_MAT_MAXTEXTURES, true);
1543 return;
1546 uint numStages = 0;
1547 for (uint i=0; i<IDRV_MAT_MAXTEXTURES; i++)
1549 if (mat.getTexture(uint8(i)) == NULL) break;
1550 ++ numStages;
1552 std::fill(rgbPipe, rgbPipe + IDRV_MAT_MAXTEXTURES, false);
1553 std::fill(alphaPipe, alphaPipe + IDRV_MAT_MAXTEXTURES, false);
1554 bool rgbUsed = true;
1555 bool alphaUsed = false;
1558 if (mat.getAlphaTest())
1560 alphaUsed = true;
1562 else
1563 if (mat.getBlend())
1565 // see if alpha is relevant to blending
1566 if (mat.getSrcBlend() == CMaterial::srcalpha ||
1567 mat.getSrcBlend() == CMaterial::invsrcalpha ||
1568 mat.getDstBlend() == CMaterial::srcalpha ||
1569 mat.getDstBlend() == CMaterial::invsrcalpha
1572 alphaUsed = true;
1577 alphaUsed = true;
1579 if (numStages == 0)
1581 // just diffuse material, no textures
1582 rgbPipe[0] = rgbUsed;
1583 alphaPipe[0] = alphaUsed;
1584 return;
1586 sint currStage = numStages - 1;
1587 while (currStage >= 0)
1589 rgbPipe[currStage] = rgbUsed;
1590 alphaPipe[currStage] = alphaUsed;
1591 bool newAlphaUsed = false;
1592 bool newRGBUsed = false;
1593 CMaterial::CTexEnv texEnv;
1594 texEnv.EnvPacked = mat.getTexEnvMode(currStage);
1595 // test for rgb propagate
1596 if (rgbUsed)
1598 if (texEnv.Env.OpRGB == CMaterial::InterpolatePrevious)
1600 newAlphaUsed = true;
1602 for(uint l = 0; l < OpNumArg[texEnv.Env.OpRGB]; ++l)
1604 if (texEnv.getColorArg(l) == CMaterial::Previous ||
1605 (currStage != 0 && texEnv.getColorArg(l) == CMaterial::Texture && mat.getTexEnvOpRGB(currStage - 1) == CMaterial::EMBM)
1608 if (texEnv.getColorOperand(l) == CMaterial::SrcColor || texEnv.getColorOperand(l) == CMaterial::InvSrcColor)
1610 newRGBUsed = true;
1612 if (texEnv.getColorOperand(l) == CMaterial::SrcAlpha || texEnv.getColorOperand(l) == CMaterial::InvSrcAlpha)
1614 newAlphaUsed = true;
1619 // test for alpha propagate
1620 if (alphaUsed)
1622 if (texEnv.Env.OpAlpha == CMaterial::InterpolatePrevious)
1624 newAlphaUsed = true;
1626 for(uint l = 0; l < OpNumArg[texEnv.Env.OpAlpha]; ++l)
1628 if (texEnv.getAlphaArg(l) == CMaterial::Previous ||
1629 (currStage != 0 && texEnv.getAlphaArg(l) == CMaterial::Texture && mat.getTexEnvOpRGB(currStage - 1) == CMaterial::EMBM)
1632 if (texEnv.getAlphaOperand(l) == CMaterial::SrcAlpha || texEnv.getAlphaOperand(l) == CMaterial::InvSrcAlpha)
1634 newAlphaUsed = true;
1639 alphaUsed = newAlphaUsed;
1640 rgbUsed = newRGBUsed;
1642 -- currStage;
1647 // ***************************************************************************
1649 const char *RemapPSInstructions[CMaterial::TexOperatorCount]=
1651 "mov", // Replace
1652 "mul", // Modulate
1653 "add", // Add
1654 "add", // AddSigned
1655 "lrp", // InterpolateTexture
1656 "lrp", // InterpolatePrevious
1657 "lrp", // InterpolateDiffuse
1658 "lrp", // InterpolateConstant
1659 "bem", // EMBM
1660 "mad" // MAD
1663 // ***************************************************************************
1665 const char *RemapPSThirdArguments[CMaterial::TexOperatorCount][2]=
1667 {"", ""}, // Replace
1668 {"", ""}, // Modulate
1669 {"", ""}, // Add
1670 {"", ""}, // AddSigned
1671 {"t", "t"}, // InterpolateTexture
1672 {"r0", "r0"}, // InterpolatePrevious
1673 {"v0", "c5"}, // InterpolateDiffuse
1674 {"c", "c"}, // InterpolateConstant
1675 {"", ""}, // EMBM
1676 {"", ""} // MAD (not used)
1679 // ***************************************************************************
1681 // Only for stage 0
1682 const char *RemapPSThirdArguments0[CMaterial::TexOperatorCount][2]=
1684 {"", ""}, // Replace
1685 {"", ""}, // Modulate
1686 {"", ""}, // Add
1687 {"", ""}, // AddSigned
1688 {"t", "t"}, // InterpolateTexture
1689 {"v0", "c5"}, // InterpolatePrevious
1690 {"v0", "c5"}, // InterpolateDiffuse
1691 {"c", "c"}, // InterpolateConstant
1692 {"", ""}, // EMBM
1693 {"", ""} // MAD (not used)
1696 // ***************************************************************************
1698 const char *RemapPSSecondRegisterModificator[CMaterial::TexOperatorCount]=
1700 "", // Replace
1701 "", // Modulate
1702 "", // Add
1703 "_bias", // AddSigned
1704 "", // InterpolateTexture
1705 "", // InterpolatePrevious
1706 "", // InterpolateDiffuse
1707 "", // InterpolateConstant
1708 "", // EMBM
1709 "" // MAD
1712 // ***************************************************************************
1714 const char *RemapPSArguments[CMaterial::TexOperatorCount][2]=
1716 {"t", "t"}, // Texture
1717 {"r0", "r0"}, // Previous
1718 {"v0", "c5"}, // Diffuse
1719 {"c", "c"}, // Constant
1722 // ***************************************************************************
1724 // Only for stage 0
1725 const char *RemapPSArguments0[CMaterial::TexOperatorCount][2]=
1727 {"t", "t"}, // Texture
1728 {"v0", "c5"}, // Previous
1729 {"v0", "c5"}, // Diffuse
1730 {"c", "c"}, // Constant
1733 // ***************************************************************************
1735 void buildColorOperation (string &dest, const char *prefix, const char *destSizzle, uint stage, CMaterial::TTexOperator &op, CMaterial::TTexSource src0, CMaterial::TTexSource src1, CMaterial::TTexSource src2, CMaterial::TTexOperand &op0, CMaterial::TTexOperand &op1, CMaterial::TTexOperand &op2, bool unlightedNoVertexColor)
1737 H_AUTO_D3D(buildColorOperation)
1738 // Refix
1739 dest += prefix;
1741 // RGB operation
1742 dest += RemapPSInstructions[op];
1744 // Destination argument
1745 dest += " r0";
1746 dest += destSizzle;
1748 // Need a third argument ?
1749 if (op != CMaterial::Mad)
1751 const char *remapPSThirdArguments = ((stage==0)?RemapPSThirdArguments0:RemapPSThirdArguments)[op][(uint)unlightedNoVertexColor];
1752 if (remapPSThirdArguments[0] != 0)
1754 dest += ", ";
1755 dest += remapPSThirdArguments;
1757 // Need stage postfix ?
1758 if ((op == CMaterial::InterpolateTexture) || (op == CMaterial::InterpolateConstant))
1759 dest += toString (stage);
1761 // Add alpha swizzle
1762 dest += ".w";
1766 // First argument
1767 dest += ", ";
1769 // Inverted ?
1770 if ((op0 == CMaterial::InvSrcColor) || (op0 == CMaterial::InvSrcAlpha))
1771 dest += "1-";
1773 // The first operator argument
1774 dest += ((stage==0)?RemapPSArguments0:RemapPSArguments)[src0][(uint)unlightedNoVertexColor];
1776 // Need stage postfix ?
1777 if ((src0 == CMaterial::Texture) || (src0 == CMaterial::Constant))
1778 dest += toString (stage);
1780 // Need alpha ?
1781 if ((op0 == CMaterial::SrcAlpha) || (op0 == CMaterial::InvSrcAlpha))
1782 dest += ".w";
1784 if (op != CMaterial::Replace)
1786 dest += ", ";
1788 // Inverted ?
1789 if ((op1 == CMaterial::InvSrcColor) || (op1 == CMaterial::InvSrcAlpha))
1790 dest += "1-";
1792 dest += ((stage==0)?RemapPSArguments0:RemapPSArguments)[src1][(uint)unlightedNoVertexColor];
1794 // Second register modifier
1795 dest += RemapPSSecondRegisterModificator[op];
1797 // Need stage postfix ?
1798 if ((src1 == CMaterial::Texture) || (src1 == CMaterial::Constant))
1799 dest += toString (stage);
1801 // Need alpha ?
1802 if ((op1 == CMaterial::SrcAlpha) || (op1 == CMaterial::InvSrcAlpha))
1803 dest += ".w";
1806 if (op == CMaterial::Mad)
1808 dest += ", ";
1810 // Inverted ?
1811 if ((op2 == CMaterial::InvSrcColor) || (op2 == CMaterial::InvSrcAlpha))
1812 dest += "1-";
1814 dest += ((stage==0)?RemapPSArguments0:RemapPSArguments)[src2][(uint)unlightedNoVertexColor];
1816 // Second register modifier
1817 dest += RemapPSSecondRegisterModificator[op];
1819 // Need stage postfix ?
1820 if ((src2 == CMaterial::Texture) || (src2 == CMaterial::Constant))
1821 dest += toString (stage);
1823 // Need alpha ?
1824 if ((op2 == CMaterial::SrcAlpha) || (op2 == CMaterial::InvSrcAlpha))
1825 dest += ".w";
1828 // End
1829 dest += ";\n";
1832 // ***************************************************************************
1834 IDirect3DPixelShader9 *CDriverD3D::buildPixelShader (const CNormalShaderDesc &normalShaderDesc, bool unlightedNoVertexColor)
1836 H_AUTO_D3D(CDriverD3D_buildPixelShader)
1837 static string shaderText;
1838 shaderText = "ps_1_1;\n";
1840 // Look for a shader already created
1841 std::list<CNormalShaderDesc> &normalPixelShaders = _NormalPixelShaders[(uint)unlightedNoVertexColor];
1842 std::list<CNormalShaderDesc>::iterator ite = normalPixelShaders.begin();
1843 while (ite != normalPixelShaders.end())
1845 if (normalShaderDesc == *ite)
1847 // Good one
1848 return (*ite).PixelShader;
1850 ite++;
1853 // For each state, texture lookup
1854 uint i;
1855 for (i=0; i<IDRV_MAT_MAXTEXTURES; i++)
1857 // Stage used ?
1858 if (normalShaderDesc.StageUsed[i])
1860 #ifdef NL_DEBUG
1861 CMaterial::CTexEnv texEnv;
1862 texEnv.EnvPacked = normalShaderDesc.TexEnvMode[i];
1863 nlassert(texEnv.Env.OpRGB != CMaterial::EMBM); // Pixel shader equivalent for EMBM not supported
1864 // For now this is not a problem because
1865 // buildPixelShader is used when the shader uses per stage color
1866 // (which is not always supported by the fixed pixel pipe),
1867 // and currently all our shaders with EMBM don't use that feature.
1868 #endif
1869 shaderText += "tex t"+toString (i)+";\n";
1873 // For each state, color operations
1874 for (i=0; i<IDRV_MAT_MAXTEXTURES; i++)
1876 // Stage used ?
1877 if (normalShaderDesc.StageUsed[i])
1879 // Texenv
1880 CMaterial::CTexEnv texEnv;
1881 texEnv.EnvPacked = normalShaderDesc.TexEnvMode[i];
1883 // RGB
1884 CMaterial::TTexOperator texOp = (CMaterial::TTexOperator)texEnv.Env.OpRGB;
1885 CMaterial::TTexSource src0 = (CMaterial::TTexSource)texEnv.Env.SrcArg0RGB;
1886 CMaterial::TTexSource src1 = (CMaterial::TTexSource)texEnv.Env.SrcArg1RGB;
1887 CMaterial::TTexSource src2 = (CMaterial::TTexSource)texEnv.Env.SrcArg2RGB;
1888 CMaterial::TTexOperand op0 = (CMaterial::TTexOperand)texEnv.Env.OpArg0RGB;
1889 CMaterial::TTexOperand op1 = (CMaterial::TTexOperand)texEnv.Env.OpArg1RGB;
1890 CMaterial::TTexOperand op2 = (CMaterial::TTexOperand)texEnv.Env.OpArg2RGB;
1891 buildColorOperation (shaderText, "", ".xyz", i, texOp, src0, src1, src2, op0, op1, op2, unlightedNoVertexColor);
1893 // Alpha
1894 texOp = (CMaterial::TTexOperator)texEnv.Env.OpAlpha;
1895 src0 = (CMaterial::TTexSource)texEnv.Env.SrcArg0Alpha;
1896 src1 = (CMaterial::TTexSource)texEnv.Env.SrcArg1Alpha;
1897 src2 = (CMaterial::TTexSource)texEnv.Env.SrcArg2Alpha;
1898 op0 = (CMaterial::TTexOperand)texEnv.Env.OpArg0Alpha;
1899 op1 = (CMaterial::TTexOperand)texEnv.Env.OpArg1Alpha;
1900 op2 = (CMaterial::TTexOperand)texEnv.Env.OpArg2Alpha;
1901 buildColorOperation (shaderText, "+", ".w", i, texOp, src0, src1, src2, op0, op1, op2, unlightedNoVertexColor);
1903 // No texture shader ?
1904 else if (i == 0)
1906 // RGB
1907 CMaterial::TTexOperator texOp = CMaterial::Replace;
1908 CMaterial::TTexSource src0 = CMaterial::Diffuse;
1909 CMaterial::TTexOperand op0 = CMaterial::SrcColor;
1910 buildColorOperation (shaderText, "", ".xyz", i, texOp, src0, src0, src0, op0, op0, op0, unlightedNoVertexColor);
1912 // Alpha
1913 texOp = CMaterial::Replace;
1914 src0 = CMaterial::Diffuse;
1915 op0 = CMaterial::SrcAlpha;
1916 buildColorOperation (shaderText, "+", ".w", i, texOp, src0, src0, src0, op0, op0, op0, unlightedNoVertexColor);
1920 // Add the specular
1921 shaderText += "add r0.rgb, r0, v1;\n";
1923 // Dump the pixel shader
1924 #ifdef NL_DEBUG_D3D
1925 nlinfo("Assemble Pixel Shader : ");
1926 string::size_type lineBegin = 0;
1927 string::size_type lineEnd;
1928 while ((lineEnd = shaderText.find('\n', lineBegin)) != string::npos)
1930 nlinfo(shaderText.substr (lineBegin, lineEnd-lineBegin).c_str());
1931 lineBegin = lineEnd+1;
1933 nlinfo(shaderText.substr (lineBegin, lineEnd-lineBegin).c_str());
1934 #endif // NL_DEBUG_D3D
1936 // Add the shader
1937 normalPixelShaders.push_back (normalShaderDesc);
1939 // Assemble and create the shader
1940 LPD3DXBUFFER pShader;
1941 LPD3DXBUFFER pErrorMsgs;
1942 if (D3DXAssembleShader (shaderText.c_str(), (UINT)shaderText.size(), NULL, NULL, 0, &pShader, &pErrorMsgs) == D3D_OK)
1944 IDirect3DPixelShader9 *shader;
1945 if (_DeviceInterface->CreatePixelShader((DWORD*)pShader->GetBufferPointer(), &shader) == D3D_OK)
1946 normalPixelShaders.back().PixelShader = shader;
1947 else
1948 normalPixelShaders.back().PixelShader = NULL;
1950 else
1952 nlwarning ("Can't assemble pixel shader:");
1953 nlwarning ((const char*)pErrorMsgs->GetBufferPointer());
1954 normalPixelShaders.back().PixelShader = NULL;
1957 return normalPixelShaders.back().PixelShader;
1960 // ***************************************************************************
1962 void CDriverD3D::startSpecularBatch()
1964 /* Not used in direct3d, use normal caching */
1967 // ***************************************************************************
1969 void CDriverD3D::endSpecularBatch()
1971 /* Not used in direct3d, use normal caching */
1974 // ***************************************************************************
1976 bool CDriverD3D::supportBlendConstantColor() const
1978 /* Not supported in D3D */
1979 return false;
1982 // ***************************************************************************
1984 void CDriverD3D::setBlendConstantColor(NLMISC::CRGBA /* col */)
1986 /* Not supported in D3D */
1989 // ***************************************************************************
1991 NLMISC::CRGBA CDriverD3D::getBlendConstantColor() const
1993 /* Not supported in D3D */
1994 return CRGBA::White;
1997 // ***************************************************************************
1999 void CDriverD3D::enablePolygonSmoothing(bool /* smooth */)
2001 /* Not supported in D3D */
2004 // ***************************************************************************
2006 bool CDriverD3D::isPolygonSmoothingEnabled() const
2008 /* Not supported in D3D */
2009 return false;
2012 // ***************************************************************************
2014 sint CDriverD3D::beginMaterialMultiPass()
2016 H_AUTO_D3D(CDriverD3D_beginMaterialMultiPass)
2017 beginMultiPass ();
2018 return _CurrentShaderPassCount;
2021 // ***************************************************************************
2023 void CDriverD3D::setupMaterialPass(uint pass)
2025 H_AUTO_D3D(CDriver3D_setupMaterialPass);
2026 activePass (pass);
2029 // ***************************************************************************
2031 void CDriverD3D::endMaterialMultiPass()
2033 H_AUTO_D3D(CDriver3D_endMaterialMultiPass);
2034 endMultiPass ();
2037 // ***************************************************************************
2039 bool CDriverD3D::supportCloudRenderSinglePass () const
2041 H_AUTO_D3D(CDriver3D_supportCloudRenderSinglePass);
2042 return _PixelProgram;
2045 // ***************************************************************************
2047 void CDriverD3D::getNumPerStageConstant(uint &lightedMaterial, uint &unlightedMaterial) const
2049 lightedMaterial = _MaxNumPerStageConstantLighted;
2050 unlightedMaterial = _MaxNumPerStageConstantUnlighted;
2055 } // NL3D