Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / 3d / meshvp_per_pixel_light.cpp
blob193a77e995dfc21baa6775c93a0fbfa9757c76c2
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 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 "std3d.h"
22 #include "nel/3d/meshvp_per_pixel_light.h"
23 #include "nel/3d/mesh_base_instance.h"
24 #include "nel/3d/driver.h"
25 #include "nel/3d/scene.h"
26 #include "nel/3d/render_trav.h"
27 #include "nel/3d/render_trav.h"
28 #include "nel/3d/vertex_program_parse.h"
32 #include <string>
35 #ifdef DEBUG_NEW
36 #define new DEBUG_NEW
37 #endif
39 namespace NL3D
42 NLMISC::CSmartPtr<CVertexProgramPerPixelLight> CMeshVPPerPixelLight::_VertexProgram[NumVp];
44 // ***************************************************************************
45 // Light VP fragment constants start at 24
46 static const uint VPLightConstantStart = 24;
48 // ***************************************************************************
49 // ***************************************************************************
51 /////////////////
52 // omni lights //
53 /////////////////
55 /** We store the first tangent vector of the tangent space in v[8].
56 * The third vector can be computed using a cross product.
57 * We assume that normal and tangent are normalized.
58 * The position of light must be expressed in object space, and is stored in c[4]
60 // omni light + specular, no normalization
61 static const char* PPLightingVPCodeBegin =
62 "!!VP1.0 \n\
63 #compute B = N ^ T \n\
64 MOV R6, v[2]; \n\
65 MUL R1, R6.yzxw, v[9].zxyw; \n\
66 MAD R1, v[9].yzxw, -R6.zxyw, R1; \n\
67 #vector in tangent space = [ T B N ] * L \n\
68 ADD R2, c[4], -v[0]; # compute L \n\
69 DP3 R3, R2, R2; # get L normalized \n\
70 RSQ R3, R3.x; \n\
71 MUL R2, R3, R2; \n\
72 DP3 o[TEX0].x, v[9], R2; # get x of light vector in tangent space \n\
73 DP3 o[TEX0].y, R1, R2; # get y \n\
74 DP3 o[TEX0].z, R6, R2; # get z \n\
75 #specular part \n\
76 ADD R3, c[5], - v[0]; # compute V (return to eye) \n\
77 #compute inverse norm of V \n\
78 DP3 R4, R3, R3; \n\
79 RSQ R4, R4.x; \n\
80 #we normalize V and add it to L \n\
81 MAD R2, R4, R3, R2; #H in R1 \n\
82 \n\
83 #normalize H \n\
84 DP3 R3, R2, R2; \n\
85 RSQ R3, R3.x; \n\
86 MUL R2, R3, R2; \n\
87 #compute H in tangent space \n\
88 DP3 o[TEX2].x, v[9], R2; \n\
89 DP3 o[TEX2].y, R1, R2; \n\
90 DP3 o[TEX2].z, R6, R2; \n\
91 # Position in R5 for additionnal lighting \n\
92 MOV R5, v[0]; \n\
93 # Normal is in R6 for additionnal lighting \n\
96 /// The same as above, but for skin / MRM : This normalize the tangent basis.
97 static const char* PPLightingVPNormalizeCodeBegin =
98 "!!VP1.0 \n\
99 #normalize the normal \n\
100 DP3 R1, v[2], v[2]; \n\
101 RSQ R1, R1.x; \n\
102 MUL R6, v[2], R1; \n\
104 #normalize the second vector \n\
105 DP3 R1, R6, v[9]; \n\
106 MAD R1, R6, -R1, v[9]; #subtract the normal component \n\
107 DP3 R2, R1, R1; \n\
108 RSQ R2, R2.x; \n\
109 MUL R5, R1, R2; #second basis vector in R5 \n\
110 #compute B = N ^ T \n\
111 MUL R1, R6.yzxw, R5.zxyw; \n\
112 MAD R1, R5.yzxw, -R6.zxyw, R1; #third basis vector in R1 \n\
114 #vector in tangent space = [ T B N ] * L \n\
115 ADD R2, c[4], -v[0]; # compute L \n\
116 DP3 R3, R2, R2; # get L normalized \n\
117 RSQ R3, R3.x; \n\
118 MUL R2, R3, R2; \n\
119 DP3 o[TEX0].x, R5, R2; # get x of light vector in tangent space \n\
120 DP3 o[TEX0].y, R1, R2; # get y \n\
121 DP3 o[TEX0].z, R6, R2; # get z \n\
123 #specular part \n\
124 ADD R3, c[5], - v[0]; # compute V (return to eye) \n\
125 #compute inverse norm of V \n\
126 DP3 R4, R3, R3; \n\
127 RSQ R4, R4.x; \n\
128 #we normalize V and add it to L \n\
129 MAD R2, R4, R3, R2; #H in R1 \n\
131 #normalize H \n\
132 DP3 R3, R2, R2; \n\
133 RSQ R3, R3.x; \n\
134 MUL R2, R3, R2; \n\
135 #compute H in tangent space \n\
136 DP3 o[TEX2].x, R5, R2; \n\
137 DP3 o[TEX2].y, R1, R2; \n\
138 DP3 o[TEX2].z, R6, R2; \n\
139 # Position in R5 for additionnal lighting \n\
140 MOV R5, v[0]; \n\
141 # Normal is in R6 for additionnal lighting \n\
145 // Omni light, no specular
146 static const char* PPLightingNoSpecVPCodeBegin =
147 "!!VP1.0 \n\
148 #compute B = N ^ T \n\
149 MOV R6, v[2]; \n\
150 MUL R1, R6.yzxw, v[9].zxyw; \n\
151 MAD R1, v[9].yzxw, -R6.zxyw, R1; \n\
153 #vector in tangent space = [ T B N ] * L \n\
154 ADD R2, c[4], -v[0]; # compute L \n\
155 DP3 R3, R2, R2; # get L normalized \n\
156 RSQ R3, R3.x; \n\
157 MUL R2, R3, R2; \n\
158 DP3 o[TEX0].x, v[9], R2; # get x of light vector in tangent space \n\
159 DP3 o[TEX0].y, R1, R2; # get y \n\
160 DP3 o[TEX0].z, R6, R2; # get z \n\
163 # Normal is in R6 for additionnal lighting \n\
164 # Position in R5 for additionnal lighting \n\
165 MOV R5, v[0]; \n\
168 /// Omni light with normalization and no specular
169 static const char* PPLightingVPNormalizeNoSpecCodeBegin =
170 "!!VP1.0 \n\
171 #normalize the normal \n\
172 DP3 R1, v[2], v[2]; \n\
173 RSQ R1, R1.x; \n\
174 MUL R6, v[2], R1; \n\
176 #normalize the second vector \n\
177 DP3 R1, R6, v[9]; \n\
178 MAD R1, R6, -R1, v[9]; #subtract the normal component \n\
179 DP3 R2, R1, R1; \n\
180 RSQ R2, R2.x; \n\
181 MUL R5, R1, R2; #second basis vector in R5 \n\
182 #compute B = N ^ T \n\
183 MUL R1, R6.yzxw, R5.zxyw; \n\
184 MAD R1, R5.yzxw, -R6.zxyw, R1; #third basis vector in R1 \n\
186 #vector in tangent space = [ T B N ] * L \n\
187 ADD R2, c[4], -v[0]; # compute L \n\
188 DP3 R3, R2, R2; # get L normalized \n\
189 RSQ R3, R3.x; \n\
190 MUL R2, R3, R2; \n\
191 DP3 o[TEX0].x, R5, R2; # get x of light vector in tangent space \n\
192 DP3 o[TEX0].y, R1, R2; # get y \n\
193 DP3 o[TEX0].z, R6, R2; # get z \n\
195 # Normal is in R6 for additionnal lighting \n\
196 # Position in R5 for additionnal lighting \n\
197 MOV R5, v[0]; \n\
201 /////////////////////////
202 // directionnal lights //
203 /////////////////////////
205 /// We store the direction of the light rather than its position
206 /// The direction must be normalized and expressed in model space.
208 // directionnal, no normalization
209 static const char* PPLightingDirectionnalVPCodeBegin =
210 "!!VP1.0 \n\
211 #compute B = N ^ T \n\
212 MOV R6, v[2]; \n\
213 MUL R1, R6.yzxw, v[9].zxyw; \n\
214 MAD R1, v[9].yzxw, -R6.zxyw, R1; \n\
216 #vector in tangent space = [ T B N ] * L \n\
217 DP3 o[TEX0].x, v[9], -c[4]; # get x of light vector in tangent space \n\
218 DP3 o[TEX0].y, R1, -c[4]; # get y \n\
219 DP3 o[TEX0].z, R6, -c[4]; # get z \n\
221 #specular part \n\
222 ADD R3, c[5], - v[0]; # compute V (return to eye) \n\
223 #compute inverse norm of V \n\
224 DP3 R4, R3, R3; \n\
225 RSQ R4, R4.x; \n\
226 #we normalize V and add it to L. It gives H unnormalized \n\
227 MAD R2, R4, R3, -c[4]; #H in R1 \n\
229 #normalize H \n\
230 DP3 R3, R2, R2; \n\
231 RSQ R3, R3.x; \n\
232 MUL R2, R3, R2; \n\
233 #compute H in tangent space \n\
234 DP3 o[TEX2].x, v[9], R2; \n\
235 DP3 o[TEX2].y, R1, R2; \n\
236 DP3 o[TEX2].z, R6, R2; \n\
238 # Normal is in R6 for additionnal lighting \n\
239 # Position in R5 for additionnal lighting \n\
240 MOV R5, v[0]; \n\
243 // directionnal + normalization
244 static const char* PPLightingDirectionnalVPNormalizeCodeBegin =
245 "!!VP1.0 \n\
246 #normalize the normal \n\
247 DP3 R1, v[2], v[2]; \n\
248 RSQ R1, R1.x; \n\
249 MUL R6, v[2], R1; \n\
251 #normalize the second vector \n\
252 DP3 R1, R6, v[9]; \n\
253 MAD R1, R6, -R1, v[9]; #subtract the normal component \n\
254 DP3 R2, R1, R1; \n\
255 RSQ R2, R2.x; \n\
256 MUL R5, R1, R2; #second basis vector in R5 \n\
257 #compute B = N ^ T \n\
258 MUL R1, R6.yzxw, R5.zxyw; \n\
259 MAD R1, R5.yzxw, -R6.zxyw, R1; #third basis vector in R1 \n\
261 #vector in tangent space = [ T B N ] * L \n\
262 DP3 o[TEX0].x, R5, -c[4]; # get x of light vector in tangent space \n\
263 DP3 o[TEX0].y, R1, -c[4]; # get y \n\
264 DP3 o[TEX0].z, R6, -c[4]; # get z \n\
266 #specular part \n\
267 ADD R3, c[5], - v[0]; # compute V (return to eye) \n\
268 #compute inverse norm of V \n\
269 DP3 R4, R3, R3; \n\
270 RSQ R4, R4.x; \n\
271 #we normalize V and add it to L \n\
272 MAD R2, R4, R3, -c[4]; #H in R1 \n\
274 #normalize H \n\
275 DP3 R3, R2, R2; \n\
276 RSQ R3, R3.x; \n\
277 MUL R2, R3, R2; \n\
278 #compute H in tangent space \n\
279 DP3 o[TEX2].x, R5, R2; \n\
280 DP3 o[TEX2].y, R1, R2; \n\
281 DP3 o[TEX2].z, R6, R2; \n\
282 # Normal is in R6 for additionnal lighting \n\
283 # Position in R5 for additionnal lighting \n\
284 MOV R5, v[0]; \n\
288 // directionnal, no normalization, no specular
289 static const char* PPLightingDirectionnalNoSpecVPCodeBegin =
290 "!!VP1.0 \n\
291 #compute B = N ^ T \n\
292 MOV R6, v[2]; \n\
293 MUL R1, R6.yzxw, v[9].zxyw; \n\
294 MAD R1, v[9].yzxw, -R6.zxyw, R1; \n\
296 #vector in tangent space = [ T B N ] * L \n\
297 DP3 o[TEX0].x, v[9], -c[4]; # get x of light vector in tangent space \n\
298 DP3 o[TEX0].y, R1, -c[4]; # get y \n\
299 DP3 o[TEX0].z, R6, -c[4]; # get z \n\
300 # Normal is in R6 for additionnal lighting \n\
301 # Position in R5 for additionnal lighting \n\
302 MOV R5, v[0]; \n\
305 // directionnal + normalization, no specular
306 static const char* PPLightingDirectionnalNoSpecVPNormalizeCodeBegin =
307 "!!VP1.0 \n\
308 #normalize the normal \n\
309 DP3 R1, v[2], v[2]; \n\
310 RSQ R1, R1.x; \n\
311 MUL R6, v[2], R1; \n\
313 #normalize the second vector \n\
314 DP3 R1, R6, v[9]; \n\
315 MAD R1, R6, -R1, v[9]; #subtract the normal component \n\
316 DP3 R2, R1, R1; \n\
317 RSQ R2, R2.x; \n\
318 MUL R5, R1, R2; #second basis vector in R5 \n\
319 #compute B = N ^ T \n\
320 MUL R1, R6.yzxw, R5.zxyw; \n\
321 MAD R1, R5.yzxw, -R6.zxyw, R1; #third basis vector in R1 \n\
323 #vector in tangent space = [ T B N ] * L \n\
324 DP3 o[TEX0].x, R5, -c[4]; # get x of light vector in tangent space \n\
325 DP3 o[TEX0].y, R1, -c[4]; # get y \n\
326 DP3 o[TEX0].z, R6, -c[4]; # get z \n\
328 # Normal is in R6 for additionnal lighting \n\
329 # Position in R5 for additionnal lighting \n\
330 MOV R5, v[0]; \n\
335 // End of per pixel lighting code : compute pos and setup texture
336 static const char* PPLightingVPCodeEnd=
337 " # compute in Projection space \n\
338 DP4 o[HPOS].x, c[0], v[0]; \n\
339 DP4 o[HPOS].y, c[1], v[0]; \n\
340 DP4 o[HPOS].z, c[2], v[0]; \n\
341 DP4 o[HPOS].w, c[3], v[0]; \n\
342 MOV o[TEX1], v[8]; \n\
343 END \n\
346 /***************************************************************/
347 /******************* THE FOLLOWING CODE IS COMMENTED OUT *******/
348 /***************************************************************
350 // Test code : map the tangent space vector as the diffuse color
351 static const char* PPLightingVPCodeTest =
352 "!!VP1.0 \n\
353 # compute in Projection space \n\
354 DP4 o[HPOS].x, c[0], v[0]; \n\
355 DP4 o[HPOS].y, c[1], v[0]; \n\
356 DP4 o[HPOS].z, c[2], v[0]; \n\
357 DP4 o[HPOS].w, c[3], v[0]; \n\
358 MOV o[COL0], v[9]; \n\
359 END \n\
361 ***************************************************************/
363 class CVertexProgramPerPixelLight : public CVertexProgramLighted
365 public:
366 struct CIdx
368 /// Position or direction of strongest light
369 uint StrongestLight;
370 /// Viewer position
371 uint ViewerPos;
373 CVertexProgramPerPixelLight(uint vp);
374 virtual ~CVertexProgramPerPixelLight() { };
375 virtual void buildInfo();
376 const CIdx &idx() const { return m_Idx; }
378 private:
379 CIdx m_Idx;
383 CVertexProgramPerPixelLight::CVertexProgramPerPixelLight(uint vp)
385 // lighted settings
386 m_FeaturesLighted.SupportSpecular = (vp & 2) != 0;
387 m_FeaturesLighted.NumActivePointLights = MaxLight - 1;
388 m_FeaturesLighted.Normalize = false;
389 m_FeaturesLighted.CtStartNeLVP = VPLightConstantStart;
391 // nelvp
393 // Gives each vp name
394 // Bit 0 : 1 when it is a directionnal light
395 // Bit 1 : 1 when specular is needed
396 // Bit 2 : 1 when normalization of the tangent space is needed
397 static const char *vpName[] =
399 // no spec
400 PPLightingDirectionnalNoSpecVPCodeBegin,
401 PPLightingNoSpecVPCodeBegin,
402 // specular
403 PPLightingDirectionnalVPCodeBegin,
404 PPLightingVPCodeBegin,
405 /////////////// normalized versions
406 // no spec
407 PPLightingDirectionnalNoSpecVPNormalizeCodeBegin,
408 PPLightingVPNormalizeNoSpecCodeBegin,
409 // spec
410 PPLightingDirectionnalVPNormalizeCodeBegin,
411 PPLightingVPNormalizeCodeBegin,
414 uint numvp = sizeof(vpName) / sizeof(const char *);
415 nlassert(CMeshVPPerPixelLight::NumVp == numvp); // make sure that it is in sync with header..todo : compile time assert :)
417 // \todo yoyo TODO_OPTIM Manage different number of pointLights
418 // NB: never call getLightVPFragmentNeLVP() with normalize, because already done by PerPixel fragment before.
419 std::string vpCode = std::string(vpName[vp])
420 + std::string("# ***************") // temp for debug
421 + CRenderTrav::getLightVPFragmentNeLVP(
422 m_FeaturesLighted.NumActivePointLights,
423 m_FeaturesLighted.CtStartNeLVP,
424 m_FeaturesLighted.SupportSpecular,
425 m_FeaturesLighted.Normalize)
426 + std::string("# ***************") // temp for debug
427 + std::string(PPLightingVPCodeEnd);
428 #ifdef NL_DEBUG
429 /** For test : parse those programs before they are used.
430 * As a matter of fact some program will works with the NV_VERTEX_PROGRAM extension,
431 * but won't with EXT_vertex_shader, because there are some limitations (can't read a temp
432 * register that hasn't been written before..)
434 CVPParser vpParser;
435 CVPParser::TProgram result;
436 std::string parseOutput;
437 if (!vpParser.parse(vpCode.c_str(), result, parseOutput))
439 nlwarning(parseOutput.c_str());
440 nlassert(0);
442 #endif
444 CSource *source = new CSource();
445 source->DisplayName = NLMISC::toString("nelvp/MeshVPPerPixel/%i", vp);
446 source->Profile = CVertexProgram::nelvp;
447 source->setSource(vpCode);
448 source->ParamIndices["modelViewProjection"] = 0;
449 addSource(source);
452 // glsl
454 // TODO_VP_GLSL
458 void CVertexProgramPerPixelLight::buildInfo()
460 CVertexProgramLighted::buildInfo();
461 if (profile() == nelvp)
463 m_Idx.StrongestLight = 4;
464 if (m_FeaturesLighted.SupportSpecular)
466 m_Idx.ViewerPos = 5;
468 else
470 m_Idx.ViewerPos = std::numeric_limits<uint>::max();
473 else
475 // TODO_VP_GLSL
477 nlassert(m_Idx.StrongestLight != std::numeric_limits<uint>::max());
478 if (m_FeaturesLighted.SupportSpecular)
480 nlassert(m_Idx.ViewerPos !=std::numeric_limits<uint>::max());
485 //=================================================================================
486 void CMeshVPPerPixelLight::initInstance(CMeshBaseInstance *mbi)
488 // init the vertexProgram code.
489 static bool vpCreated= false;
490 if (!vpCreated)
492 vpCreated = true;
494 for (uint vp = 0; vp < NumVp; ++vp)
496 _VertexProgram[vp] = new CVertexProgramPerPixelLight(vp);
501 //=================================================================================
502 bool CMeshVPPerPixelLight::begin(IDriver *drv,
503 CScene *scene, CMeshBaseInstance *mbi,
504 const NLMISC::CMatrix &invertedModelMat,
505 const NLMISC::CVector &viewerPos)
507 // test if supported by driver
508 if (drv->isVertexProgramEmulated()
509 || !drv->supportPerPixelLighting(SpecularLighting))
511 return false;
514 enable(true, drv); // must enable the vertex program before the vb is activated
515 CVertexProgramPerPixelLight *program = _ActiveVertexProgram;
516 if (!program)
518 // failed to compile vertex program
519 return false;
522 CRenderTrav *renderTrav= &scene->getRenderTrav();
523 /// Setup for gouraud lighting
524 renderTrav->prepareVPLightSetup();
525 renderTrav->beginVPLightSetup(program, invertedModelMat);
527 sint strongestLightIndex = renderTrav->getStrongestLightIndex();
528 if (strongestLightIndex == -1) return false; // if no strongest light, disable this vertex program
529 // setup the strongest light
530 ///\todo disabling of specular lighting with this shader
531 const CLight &strongestLight = renderTrav->getDriverLight(strongestLightIndex);
533 switch (strongestLight.getMode())
535 case CLight::DirectionalLight:
537 // put light direction in object space
538 NLMISC::CVector lPos = invertedModelMat.mulVector(strongestLight.getDirection());
539 drv->setUniform3f(IDriver::VertexProgram, program->idx().StrongestLight, lPos);
540 _IsPointLight = false;
542 break;
543 case CLight::PointLight:
545 // put light in object space
546 NLMISC::CVector lPos = invertedModelMat * strongestLight.getPosition();
547 drv->setUniform3f(IDriver::VertexProgram, program->idx().StrongestLight, lPos);
548 _IsPointLight = true;
550 break;
551 default:
552 return false;
553 break;
557 if (SpecularLighting)
559 // viewer pos in object space
560 NLMISC::CVector vPos = invertedModelMat * viewerPos;
561 drv->setUniform3f(IDriver::VertexProgram, program->idx().ViewerPos, vPos);
564 // c[0..3] take the ModelViewProjection Matrix. After setupModelMatrix();
565 drv->setUniformMatrix(IDriver::VertexProgram, program->getUniformIndex(CProgramIndex::ModelViewProjection), IDriver::ModelViewProjection, IDriver::Identity);
567 return true;
571 //=================================================================================
572 void CMeshVPPerPixelLight::end(IDriver *drv)
574 enable(false, drv);
578 //=================================================================================
579 void CMeshVPPerPixelLight::serial(NLMISC::IStream &f)
581 (void)f.serialVersion(0);
582 f.serial(SpecularLighting);
586 //=================================================================================
587 void CMeshVPPerPixelLight::enable(bool enabled, IDriver *drv)
589 if (enabled != _Enabled)
591 nlassert(drv);
592 if (enabled)
594 /* for (uint k = 0; k < NumVp; ++k)
596 nlinfo("test vp %d", k);
597 drv->activeVertexProgram(_VertexProgram[k].get());
598 } */
599 uint idVP = (drv->isForceNormalize() ? 4 : 0)
600 | (SpecularLighting ? 2 : 0)
601 | (_IsPointLight ? 1 : 0);
603 if (drv->activeVertexProgram((CVertexProgramPerPixelLight *)_VertexProgram[idVP]))
605 _ActiveVertexProgram = _VertexProgram[idVP];
607 else
609 _ActiveVertexProgram = NULL;
612 else
614 drv->activeVertexProgram(NULL);
615 _ActiveVertexProgram = NULL;
617 _Enabled = enabled;
621 //=================================================================================
622 bool CMeshVPPerPixelLight::setupForMaterial(const CMaterial &mat,
623 IDriver *drv,
624 CScene *scene
627 bool enabled = (mat.getShader() == CMaterial::PerPixelLighting || mat.getShader() == CMaterial::PerPixelLightingNoSpec);
628 bool change = (enabled != _Enabled);
629 enable(enabled, drv); // enable disable the vertex program (for material that don't have the right shader)
630 if (enabled)
632 CRenderTrav *renderTrav= &scene->getRenderTrav();
633 renderTrav->changeVPLightSetupMaterial(mat, true /* exclude strongest*/);
635 NLMISC::CRGBA pplDiffuse, pplSpecular;
636 renderTrav->getStrongestLightColors(pplDiffuse, pplSpecular);
637 drv->setPerPixelLightingLight(pplDiffuse, pplSpecular, mat.getShininess());
639 return change;
641 //=================================================================================
642 void CMeshVPPerPixelLight::setupForMaterial(const CMaterial &mat,
643 IDriver *drv,
644 CScene *scene,
645 CVertexBuffer *vb)
648 if (setupForMaterial(mat, drv, scene)) // a switch from v.p enabled / disabled force to reactivate the vertex buffer.
650 drv->activeVertexBuffer(*vb);
655 } // NL3D