00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "std3d.h"
00027
00028 #include "3d/material.h"
00029 #include "3d/texture.h"
00030 #include "3d/shader.h"
00031 #include "3d/driver.h"
00032 #include "nel/misc/stream.h"
00033
00034 using namespace std;
00035 using namespace NLMISC;
00036
00037 namespace NL3D
00038 {
00039
00040
00041 CMaterial::CMaterial()
00042 {
00043 _Touched= 0;
00044 _Flags= IDRV_MAT_ZWRITE;
00045
00046 _ShaderType= Normal;
00047 _SrcBlend= srcalpha;
00048 _DstBlend= invsrcalpha;
00049 _ZFunction= lessequal;
00050 _ZBias= 0;
00051 _Color.set(255,255,255,255);
00052 _StainedGlassWindow = false;
00053 _AlphaTestThreshold= 0.5f;
00054 }
00055
00056
00057 void CMaterial::initUnlit()
00058 {
00059 setShader(Normal);
00060 setLighting(false);
00061 setColor(CRGBA(255,255,255,255));
00062 for(uint32 i=0;i<IDRV_MAT_MAXTEXTURES;i++)
00063 setTexture((uint8)i ,NULL);
00064 setZBias(0);
00065 setZFunc(lessequal);
00066 setZWrite(true);
00067 setBlend(false);
00068 setAlphaTestThreshold(0.5f);
00069 }
00070
00071
00072
00073 void CMaterial::initLighted()
00074 {
00075 initUnlit();
00076 setLighting(true);
00077 }
00078
00079
00080
00081 CMaterial &CMaterial::operator=(const CMaterial &mat)
00082 {
00083 _ShaderType= mat._ShaderType;
00084 _Flags= mat._Flags;
00085 _SrcBlend= mat._SrcBlend;
00086 _DstBlend= mat._DstBlend;
00087 _ZFunction= mat._ZFunction;
00088 _ZBias= mat._ZBias;
00089 _Color= mat._Color;
00090 _Emissive= mat._Emissive;
00091 _Ambient= mat._Ambient;
00092 _Diffuse= mat._Diffuse;
00093 _Specular= mat._Specular;
00094 _Shininess= mat._Shininess;
00095 _AlphaTestThreshold= mat._AlphaTestThreshold;
00096
00097 for(uint32 i=0;i<IDRV_MAT_MAXTEXTURES;i++)
00098 {
00099 _Textures[i]= mat._Textures[i];
00100 _TexEnvs[i]= mat._TexEnvs[i];
00101 _TexAddrMode[i] = mat._TexAddrMode[i];
00102 }
00103
00104
00105 _LightMaps= mat._LightMaps;
00106
00107
00108 if (mat._TexUserMat.get())
00109 {
00110 std::auto_ptr<CUserTexMat> texMatClone( new CUserTexMat(*(mat._TexUserMat)));
00111 std::swap(texMatClone, _TexUserMat);
00112 }
00113 else
00114 {
00115 _TexUserMat.reset();
00116 }
00117
00118
00119
00120
00121 _Touched= IDRV_TOUCHED_ALL;
00122
00123 return *this;
00124 }
00125
00126
00127
00128 CMaterial::~CMaterial()
00129 {
00130
00131 pShader.kill();
00132 }
00133
00134
00135
00136 void CMaterial::serial(NLMISC::IStream &f)
00137 {
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155 sint ver= f.serialVersion(6);
00156
00157 nlassert(IDRV_MAT_MAXTEXTURES==4);
00158
00159 f.serialEnum(_ShaderType);
00160 f.serial(_Flags);
00161 f.serialEnum(_SrcBlend);
00162 f.serialEnum(_DstBlend);
00163 f.serialEnum(_ZFunction);
00164 f.serial(_ZBias);
00165 f.serial(_Color);
00166 f.serial(_Emissive, _Ambient, _Diffuse, _Specular);
00167 if(ver>=2)
00168 {
00169 f.serial(_Shininess);
00170 }
00171 if(ver>=5)
00172 {
00173 f.serial(_AlphaTestThreshold);
00174 }
00175
00176
00177 for(uint32 i=0;i<IDRV_MAT_MAXTEXTURES;i++)
00178 {
00179
00180 ITexture* text;
00181 if(f.isReading())
00182 {
00183 f.serialPolyPtr(text);
00184 _Textures[i]= text;
00185 }
00186 else
00187 {
00188 text= _Textures[i];
00189 f.serialPolyPtr(text);
00190 }
00191
00192
00193 if(ver>=1)
00194 {
00195 f.serial(_TexEnvs[i]);
00196 }
00197 else
00198 {
00199
00200 if(f.isReading())
00201 _TexEnvs[i].setDefault();
00202 }
00203 }
00204
00205 if(ver>=3)
00206 {
00207 f.serialCont(_LightMaps);
00208 }
00209
00210 if (ver >= 4)
00211 {
00212 if (_Flags & IDRV_MAT_TEX_ADDR)
00213 {
00214 for(uint32 i=0;i<IDRV_MAT_MAXTEXTURES;i++)
00215 {
00216 f.serial(_TexAddrMode[i]);
00217 }
00218 }
00219 }
00220
00221 if(f.isReading())
00222 {
00223
00224 if(_Flags & IDRV_MAT_DEFMAT)
00225 {
00226 setEmissive(CRGBA::Black);
00227 setAmbient(CRGBA::White);
00228 setDiffuse(CRGBA::White);
00229 setSpecular(CRGBA::Black);
00230 }
00231
00232
00233 _Touched= IDRV_TOUCHED_ALL;
00234
00235 if ((_Flags & IDRV_MAT_USER_TEX_MAT_ALL))
00236 {
00237 std::auto_ptr<CUserTexMat> newPtr(new CUserTexMat);
00238 std::swap(_TexUserMat, newPtr);
00239 }
00240 }
00241
00242 if (ver >= 6)
00243 {
00244 for(uint i=0; i < IDRV_MAT_MAXTEXTURES; ++i)
00245 {
00246 if (isUserTexMatEnabled(i))
00247 {
00248 f.serial(_TexUserMat->TexMat[i]);
00249 }
00250 }
00251 }
00252
00253 }
00254
00255
00256
00257 void CMaterial::setShader(TShader val)
00258 {
00259
00260 uint nTexts= IDRV_MAT_MAXTEXTURES;
00261
00262 if(_ShaderType==LightMap || _ShaderType==UserColor)
00263 nTexts=1;
00264
00265 for(uint i=0;i<nTexts;i++)
00266 setTexture(i ,NULL);
00267
00268
00269 if(val== CMaterial::UserColor)
00270 {
00271
00272 _ShaderType=CMaterial::Normal;
00273
00274
00275 texEnvOpRGB(0, InterpolateTexture);
00276 texEnvArg0RGB(0, Texture, SrcColor);
00277 texEnvArg1RGB(0, Constant, SrcColor);
00278
00279 texEnvOpAlpha(0, Replace);
00280 texEnvArg0Alpha(0, Previous, SrcAlpha);
00281
00282
00283 texEnvOpRGB(1, Modulate);
00284 texEnvArg0RGB(1, Previous, SrcColor);
00285 texEnvArg1RGB(1, Diffuse, SrcColor);
00286
00287 texEnvOpAlpha(1, Replace);
00288 texEnvArg0Alpha(1, Previous, SrcAlpha);
00289 }
00290
00291 _ShaderType= val;
00292 _Touched|=IDRV_TOUCHED_SHADER;
00293 }
00294
00295
00296
00297 void CMaterial::setTexture(uint8 n, ITexture* ptex)
00298 {
00299 nlassert(n<IDRV_MAT_MAXTEXTURES);
00300
00301
00302 if( _ShaderType== CMaterial::UserColor)
00303 {
00304
00305 nlassert( n==0 );
00306
00307
00308 _Textures[0]=ptex;
00309 _Textures[1]=ptex;
00310 _Touched|=IDRV_TOUCHED_TEX[0];
00311 _Touched|=IDRV_TOUCHED_TEX[1];
00312 }
00313 else if( _ShaderType== CMaterial::LightMap)
00314 {
00315
00316 nlassert( n==0 );
00317 _Textures[n]=ptex;
00318 _Touched|=IDRV_TOUCHED_TEX[n];
00319 }
00320
00321 else
00322 {
00323 _Textures[n]=ptex;
00324 _Touched|=IDRV_TOUCHED_TEX[n];
00325 }
00326 }
00327
00328
00329
00330 void CMaterial::flushTextures (IDriver &driver)
00331 {
00332
00333 for (uint tex=0; tex<IDRV_MAT_MAXTEXTURES; tex++)
00334 {
00335
00336 if (_Textures[tex])
00337 {
00338
00339 driver.setupTexture (*_Textures[tex]);
00340 }
00341 }
00342
00343
00344 if(_ShaderType==LightMap)
00345 {
00346
00347 for (uint lmap=0; lmap<_LightMaps.size(); lmap++)
00348 {
00349
00350 if(_LightMaps[lmap].Texture)
00351 {
00352
00353 driver.setupTexture (*_LightMaps[lmap].Texture);
00354 }
00355 }
00356 }
00357
00358 }
00359
00360
00361
00362 void CMaterial::setLightMap(uint lmapId, ITexture *lmap)
00363 {
00364 nlassert(_ShaderType==CMaterial::LightMap);
00365 if(lmapId>=_LightMaps.size())
00366 _LightMaps.resize(lmapId+1);
00367 _LightMaps[lmapId].Texture= lmap;
00368
00369 _Touched|=IDRV_TOUCHED_LIGHTMAP;
00370 }
00371
00372
00373 ITexture *CMaterial::getLightMap(uint lmapId) const
00374 {
00375 nlassert(_ShaderType==CMaterial::LightMap);
00376 if(lmapId<_LightMaps.size())
00377 return _LightMaps[lmapId].Texture;
00378 else
00379 return NULL;
00380 }
00381
00382
00383 void CMaterial::setLightMapFactor(uint lmapId, CRGBA factor)
00384 {
00385 if (_ShaderType==CMaterial::LightMap)
00386 {
00387 if(lmapId>=_LightMaps.size())
00388 _LightMaps.resize(lmapId+1);
00389 _LightMaps[lmapId].Factor= factor;
00390
00391 _Touched|=IDRV_TOUCHED_LIGHTMAP;
00392 }
00393 }
00394
00395
00396
00397 void CMaterial::CLightMap::serial(NLMISC::IStream &f)
00398 {
00399 f.serial(Factor);
00400
00401 ITexture* text= NULL;
00402 if(f.isReading())
00403 {
00404 f.serialPolyPtr(text);
00405 Texture= text;
00406 }
00407 else
00408 {
00409 text= Texture;
00410 f.serialPolyPtr(text);
00411 }
00412 }
00413
00414
00415
00416
00417 void CMaterial::enableTexAddrMode(bool enable )
00418 {
00419 if (enable)
00420 {
00421 if (!(_Flags & IDRV_MAT_TEX_ADDR))
00422 {
00423 _Flags |= IDRV_MAT_TEX_ADDR;
00424 for (uint32 k = 0; k < IDRV_MAT_MAXTEXTURES; ++k)
00425 {
00426 _TexAddrMode[k] = (uint8) FetchTexture;
00427 }
00428 }
00429 }
00430 else
00431 {
00432 _Flags &= ~IDRV_MAT_TEX_ADDR;
00433 }
00434 }
00435
00436
00437 bool CMaterial::texAddrEnabled() const
00438 {
00439 return( _Flags & IDRV_MAT_TEX_ADDR) != 0;
00440 }
00441
00442
00443 void CMaterial::setTexAddressingMode(uint8 stage, TTexAddressingMode mode)
00444 {
00445 nlassert(_Flags & IDRV_MAT_TEX_ADDR);
00446 nlassert(stage < IDRV_MAT_MAXTEXTURES);
00447 nlassert(mode < TexAddrCount);
00448 _TexAddrMode[stage] = (uint8) mode;
00449 }
00450
00451
00452
00453 CMaterial::TTexAddressingMode CMaterial::getTexAddressingMode(uint8 stage)
00454 {
00455 nlassert(_Flags & IDRV_MAT_TEX_ADDR);
00456 nlassert(stage < IDRV_MAT_MAXTEXTURES);
00457 return (TTexAddressingMode) _TexAddrMode[stage];
00458 }
00459
00460
00461 void CMaterial::decompUserTexMat(uint stage, float &uTrans, float &vTrans, float &wRot, float &uScale, float &vScale)
00462 {
00463 nlassert(stage < IDRV_MAT_MAXTEXTURES);
00464 nlassert(isUserTexMatEnabled(stage));
00465 const NLMISC::CMatrix texMat = _TexUserMat->TexMat[stage];
00466 uTrans = texMat.getPos().x;
00467 vTrans = texMat.getPos().y;
00469 NLMISC::CVector i = texMat.getI();
00470 NLMISC::CVector j = texMat.getJ();
00471 float normI = i.norm();
00472 float normJ = i.norm();
00473 i /= normI;
00474 j /= normJ;
00475 float angle = ::acosf(i.x);
00476 if (i.y < 0)
00477 {
00478 angle = 2.f * (float) NLMISC::Pi - angle;
00479 }
00480 wRot = angle;
00481 uScale = normI;
00482 vScale = normJ;
00483 }
00484
00485
00486 void CMaterial::selectTextureSet(uint index)
00487 {
00488 for (uint k = 0; k < IDRV_MAT_MAXTEXTURES; ++k)
00489 {
00490 if (_Textures[k] != NULL) _Textures[k]->selectTexture(index);
00491 }
00492 }
00493
00494 }
00495