Shader Get.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. #include "../Shaders/!Header CPU.h"
  4. namespace EE{
  5. /******************************************************************************
  6. !! Warning: Never return the same shader for Multi-Materials as Single-Materials !!
  7. Because crash/memory corruption may occur, since they need to operate on different containers 'MultiMaterialShaderDraws' and 'ShaderDraws'
  8. /******************************************************************************/
  9. ShaderImage* FindShaderImage(CChar8 *name) {return ShaderImages.find(Str8Temp(name));}
  10. ShaderImage* GetShaderImage(CChar8 *name) {ShaderImage *image=FindShaderImage(name); if(!image)Exit(S+"Shader Image \""+name+"\" not found."); return image;}
  11. ShaderParam* FindShaderParam(CChar8 *name)
  12. {
  13. Str8Temp key(name); // use 'Str8Temp' to prevent memory allocation
  14. if(ShaderParam *sp=ShaderParams.find(key))return sp;
  15. // maybe we're looking for array member
  16. FREPA(key)
  17. {
  18. if(name[i]=='[') // check for existence of '['
  19. {
  20. Char8 parent_name[MAX_LONG_PATH]; if(InRange(i, parent_name))
  21. {
  22. i++; Set(parent_name, name, i); // copy all before '['
  23. if(ShaderParam *parent=ShaderParams.find(Str8Temp(parent_name)))
  24. {
  25. Int index=TextInt(name+i); if(InRange(index, parent->_elements))
  26. {
  27. ShaderParams.lock (); ShaderParam &elm=*ShaderParams(key); if(!elm.is())elm.initAsElement(*parent, index); // init only if not initialized yet, in case it just got initialized on another thread before the lock
  28. ShaderParams.unlock();
  29. return &elm;
  30. }
  31. }
  32. }
  33. break;
  34. }
  35. }
  36. return null;
  37. }
  38. ShaderParam* GetShaderParam(CChar8 *name) {ShaderParam *param=FindShaderParam(name); if(!param)Exit(S+"Shader Param \""+name+"\" not found."); return param;}
  39. /******************************************************************************/
  40. ShaderBuffer* FindShaderBuffer(CChar8 *name) {return ShaderBuffers.find(Str8Temp(name));}
  41. ShaderBuffer* GetShaderBuffer(CChar8 *name) {ShaderBuffer *sb=FindShaderBuffer(name); if(!sb)Exit(S+"Shader Buffer \""+name+"\" not found."); return sb;}
  42. /******************************************************************************/
  43. static Int Textures(C Material &material)
  44. {
  45. if(material.base_0)
  46. {
  47. if(material.base_1)return 2;
  48. return 1;
  49. } return 0;
  50. }
  51. static Int BumpMode(C Material &material, UInt mesh_base_flag)
  52. {
  53. if(mesh_base_flag&VTX_NRM)
  54. {
  55. if((mesh_base_flag&VTX_TEX0) && (mesh_base_flag&VTX_TAN) && D.bumpMode()>=BUMP_NORMAL && material.base_0 && material.base_1)
  56. {
  57. if(D.bumpMode()>BUMP_NORMAL && material.bump>EPS_MATERIAL_BUMP)
  58. {
  59. if(D.bumpMode()==BUMP_RELIEF)return SBUMP_RELIEF;
  60. return Mid(Ceil(material.bump/0.0075f)+SBUMP_PARALLAX0, SBUMP_PARALLAX_MIN, SBUMP_PARALLAX_MAX);
  61. }
  62. if(material.rough>EPS_COL)return SBUMP_NORMAL;
  63. }
  64. return SBUMP_FLAT;
  65. }
  66. return SBUMP_ZERO;
  67. }
  68. static Bool Detail (C Material &material) {return material. detail_map && material.det_power>EPS_COL && material.det_scale;}
  69. static Bool Macro (C Material &material) {return material. macro_map;}
  70. static Bool Reflect(C Material &material) {return material.reflection_map && material.reflect >EPS_COL && !material.hasGrass() && !material.hasLeaf();}
  71. static UInt FlagHeightmap(UInt mesh_base_flag, Bool heightmap)
  72. {
  73. if(heightmap)
  74. {
  75. if(mesh_base_flag&VTX_POS)mesh_base_flag|=VTX_TEX0; // heightmap shaders generate tex from pos
  76. if(mesh_base_flag&VTX_NRM)mesh_base_flag|=VTX_TAN ; // heightmap shaders generate tan from nrm
  77. }
  78. return mesh_base_flag;
  79. }
  80. /******************************************************************************/
  81. DefaultShaders::DefaultShaders(C Material *material, UInt mesh_base_flag, Int lod_index, Bool heightmap)
  82. {
  83. C Material *materials[4]=
  84. {
  85. material,
  86. null ,
  87. null ,
  88. null ,
  89. };
  90. init(materials, mesh_base_flag, lod_index, heightmap);
  91. }
  92. void DefaultShaders::init(C Material *material[4], UInt mesh_base_flag, Int lod_index, Bool heightmap)
  93. {
  94. if(!mesh_base_flag){set_empty: valid=false; return;}
  95. C Material *m=(material ? material[0] : null); if(!m){if(D.drawNullMaterials())m=&MaterialDefault;else goto set_empty;}
  96. valid=true;
  97. mesh_base_flag=FlagHeightmap(mesh_base_flag, heightmap);
  98. // !! Never return the same shader for Multi-Materials as Single-Materials !!
  99. T.heightmap=heightmap;
  100. materials=1;
  101. textures =0;
  102. bump =SBUMP_ZERO;
  103. detail =false;
  104. macro =false;
  105. reflect =false;
  106. Bool tex =((mesh_base_flag&VTX_TEX0 )!=0);
  107. normal =((mesh_base_flag&VTX_NRM )!=0);
  108. color =((mesh_base_flag&VTX_COLOR )!=0);
  109. size =((mesh_base_flag&VTX_SIZE )!=0);
  110. if(material)
  111. {
  112. MAX(textures, Textures(*m)); MAX(bump, BumpMode(*m, mesh_base_flag)); MAX(detail, Detail(*m)); MAX(macro, Macro(*m)); MAX(reflect, Reflect(*m));
  113. if(material[1]) // && (mesh_base_flag&VTX_MATERIAL)) we must always return a different shader even when there's no VTX_MATERIAL component, because we need a different shader for multi-material parts that have umm, as they operate on 'MultiMaterialShaderDraws' and not 'ShaderDraws', otherwise crash or memory corruption may occur, because ShaderBase.shader_index would point to wrong container
  114. {
  115. materials++; MAX(textures, Textures(*material[1])); MAX(bump, BumpMode(*material[1], mesh_base_flag)); MAX(detail, Detail(*material[1])); MAX(macro, Macro(*material[1])); MAX(reflect, Reflect(*material[1]));
  116. if(material[2])
  117. {
  118. materials++; MAX(textures, Textures(*material[2])); MAX(bump, BumpMode(*material[2], mesh_base_flag)); MAX(detail, Detail(*material[2])); MAX(macro, Macro(*material[2])); MAX(reflect, Reflect(*material[2]));
  119. #if MAX_MTRLS>=4
  120. if(material[3])
  121. {
  122. materials++; MAX(textures, Textures(*material[3])); MAX(bump, BumpMode(*material[3], mesh_base_flag)); MAX(detail, Detail(*material[3])); MAX(macro, Macro(*material[3])); MAX(reflect, Reflect(*material[3]));
  123. }
  124. #endif
  125. }
  126. }
  127. switch(D.texDetail())
  128. {
  129. case TEX_USE_DISABLE: detail=false; break;
  130. case TEX_USE_SINGLE : if(materials>1)detail=false; break;
  131. }
  132. switch(D.texReflection())
  133. {
  134. case TEX_USE_DISABLE: reflect=false; break;
  135. case TEX_USE_SINGLE : if(materials>1)reflect=false; break;
  136. }
  137. if(!D.texMacro() || lod_index<=0)macro =false; // disable macro for LOD's=0
  138. if( lod_index> 0)detail=false; // disable detail for LOD's>0
  139. if( lod_index> 0)MIN(bump, SBUMP_NORMAL); // limit to normal mapping for LOD's>0
  140. if(!tex ){detail=macro=false; textures=0;}
  141. if(!normal )reflect=false;
  142. if(materials>1 )MAX(textures, 1); // multi-materials don't support 0 textures
  143. if(materials>1 && (bump>SBUMP_PARALLAX_MAX_MULTI && bump<=SBUMP_PARALLAX_MAX))bump=SBUMP_PARALLAX_MAX_MULTI; // multi-materials have a different limit for parallax steps
  144. }
  145. fur =(normal && tex && materials==1 && !heightmap && m->technique==MTECH_FUR ); // this requires tex coordinates, but not a material texture, we can do fur with just material color and 'FurCol'
  146. blend =( materials==1 && !heightmap && m->technique==MTECH_BLEND); // this shouldn't require a texture, we can do alpha blending with just material color
  147. grass =(normal && materials==1 && textures>=1 && !heightmap && m->hasGrass ());
  148. leaf =(normal && (mesh_base_flag&VTX_HLP) && materials==1 && textures>=1 && !heightmap && m->hasLeaf () && D.bendLeafs());
  149. ambient =( m->ambient.max()>EPS_COL); // this doesn't operate on a texture, 'materials' are checked in 'Ambient' method because this member is used only there
  150. alpha =( materials==1 && textures>=1 && !heightmap && m->hasAlpha ()); // this is about having alpha channel in material textures so we need a texture
  151. alpha_test =( materials==1 && textures>=1 && !heightmap && m->hasAlphaTest ());
  152. alpha_blend =( materials==1 && !heightmap && m->hasAlphaBlend ()); // this shouldn't require a texture, we can do alpha blending with just material color
  153. alpha_blend_light=( materials==1 && !heightmap && m->hasAlphaBlendLight ()); // this shouldn't require a texture, we can do alpha blending with just material color
  154. mtrl_blend =( materials> 1 && D.materialBlend() ); // this is multi-material blending (blending between multiple materials)
  155. skin =((mesh_base_flag&VTX_SKIN)==VTX_SKIN && materials==1 && !heightmap && !grass && !leaf );
  156. fx =(grass ? FX_GRASS : leaf ? (size ? FX_LEAFS : FX_LEAF) : FX_NONE);
  157. light_map =((mesh_base_flag&VTX_TEX1) && materials==1 && textures>=1 && m->light_map && !fx);
  158. tess =((lod_index<=0) && D.shaderModel()>=SM_5 && D.tesselation() && (!heightmap || D.tesselationHeightmap()) && normal && !fx);
  159. if(fx){detail=macro=false; MIN(bump, SBUMP_NORMAL);} // currently shaders with effects don't support detail/macro/fancy bump
  160. }
  161. Shader* DefaultShaders::EarlyZ()C
  162. {
  163. #if SUPPORT_EARLY_Z
  164. if(valid && !alpha_blend && !alpha_test && !fx && !tess)return ShaderFiles("Early Z")->get(TechNameEarlyZ(skin));
  165. #endif
  166. return null;
  167. }
  168. Shader* DefaultShaders::Simple()C
  169. {
  170. if(valid && !alpha_blend)
  171. {
  172. // !! Never return the same shader for Multi-Materials as Single-Materials !!
  173. Str8 name;
  174. if(normal )name=TechNameSimple(skin, materials, (materials>1) ? 1 : textures, SBUMP_FLAT, alpha_test, light_map, reflect, color, mtrl_blend, heightmap, fx, Renderer.simplePrecision(), tess);else // simple supports only 1 texture for multi-materials (there's no alpha testing/blending, and no support for 0 textures)
  175. if(materials==1)name=TechNameSimple(skin, materials, 0, SBUMP_ZERO, false , light_map, reflect, color, mtrl_blend, heightmap, fx, Renderer.simplePrecision(), tess);
  176. return ShaderFiles("Simple")->get(name);
  177. }
  178. return null;
  179. }
  180. Shader* DefaultShaders::Solid(Bool mirror)C
  181. {
  182. if(valid && !alpha_blend && Renderer.anyDeferred())
  183. {
  184. // !! Never return the same shader for Multi-Materials as Single-Materials !!
  185. if(fur)return ShaderFiles("Fur")->get(TechNameFurBase(skin, size, textures!=0));
  186. Bool detail=T.detail, tess=T.tess; Byte bump=T.bump; if(mirror){detail=false; tess=false; MIN(bump, SBUMP_NORMAL);} // disable detail tesselation and fancy bump for mirror
  187. Str8 name;
  188. if(normal )name=TechNameDeferred(skin, materials, textures, bump , alpha_test, light_map, detail, macro, reflect, color, mtrl_blend, heightmap, fx, tess);else
  189. if(materials==1)name=TechNameDeferred(skin, materials, 0, SBUMP_ZERO, false , light_map, false , false, reflect, color, mtrl_blend, heightmap, fx, tess);
  190. return ShaderFiles("Deferred")->get(name);
  191. }
  192. return null;
  193. }
  194. Shader* DefaultShaders::Ambient()C
  195. {
  196. #if SUPPORT_MATERIAL_AMBIENT
  197. if(valid && !alpha_blend && ambient && materials==1 && !heightmap && !fx)return ShaderFiles("Ambient")->get(TechNameAmbient(skin, alpha_test ? textures : 0));
  198. #endif
  199. return null;
  200. }
  201. Shader* DefaultShaders::Outline()C
  202. {
  203. if(valid && !alpha_blend && !fx)return ShaderFiles("Set Color")->get(TechNameSetColor(skin, alpha_test ? textures : 0, tess));
  204. return null;
  205. }
  206. Shader* DefaultShaders::Behind()C
  207. {
  208. if(valid && !fx)return ShaderFiles("Behind")->get(TechNameBehind(skin, alpha_test ? textures : 0));
  209. return null;
  210. }
  211. Shader* DefaultShaders::Fur()C
  212. {
  213. if(valid && fur)return ShaderFiles("Fur")->get(TechNameFurSoft(skin, size, textures!=0));
  214. return null;
  215. }
  216. Shader* DefaultShaders::Shadow()C
  217. {
  218. if(valid && (!alpha_blend || alpha_test))return ShaderFiles("Position")->get(TechNamePosition(skin, alpha_test ? textures : 0, alpha_test && alpha_blend_light, fx, tess));
  219. return null;
  220. }
  221. Shader* DefaultShaders::Blend()C
  222. {
  223. if(valid && blend) // "!blend" here will return null so BLST can be used in 'drawBlend'
  224. return ShaderFiles("Blend")->get(TechNameBlend(skin, color, reflect, textures, light_map));
  225. return null;
  226. }
  227. Shader* DefaultShaders::Overlay()C
  228. {
  229. if(valid)return ShaderFiles("Tattoo")->get(TechNameTattoo(skin, tess));
  230. return null;
  231. }
  232. Shader* DefaultShaders::get(RENDER_MODE mode)C
  233. {
  234. switch(mode)
  235. {
  236. default : return null;
  237. case RM_EARLY_Z: return EarlyZ();
  238. case RM_SIMPLE : return Simple();
  239. case RM_SOLID : return Solid();
  240. case RM_SOLID_M: return Solid(true);
  241. case RM_AMBIENT: return Ambient();
  242. case RM_OUTLINE: return Outline();
  243. case RM_BEHIND : return Behind();
  244. case RM_FUR : return Fur();
  245. case RM_SHADOW : return Shadow();
  246. case RM_BLEND : return Blend();
  247. case RM_OVERLAY: return Overlay();
  248. }
  249. }
  250. FRST* DefaultShaders::Frst()C
  251. {
  252. if(valid && !alpha_blend && Renderer.anyForward())
  253. {
  254. FRSTKey key;
  255. key.skin =skin;
  256. key.materials =materials;
  257. key.textures =textures;
  258. key.bump_mode =Min(bump, SBUMP_NORMAL); // forward supports only normal bump
  259. key.alpha_test=alpha_test;
  260. key.light_map =light_map;
  261. key.detail =(detail && materials==1); // forward doesn't support detail in multi-material
  262. key.rflct =reflect;
  263. key.color =color;
  264. key.mtrl_blend=mtrl_blend;
  265. key.fx =fx;
  266. key.heightmap =heightmap;
  267. key.tess =tess;
  268. return Frsts(key);
  269. }
  270. return null;
  271. }
  272. BLST* DefaultShaders::Blst()C
  273. {
  274. if(valid
  275. //&& alpha_blend_light - always return because 'Mesh.drawBlend' may use it
  276. && normal // lighting requires vertex normals
  277. && materials==1
  278. )
  279. {
  280. BLSTKey key;
  281. key.per_pixel =((Renderer.type()==RT_SIMPLE) ? Renderer.simplePrecision() : true);
  282. key.color =color;
  283. key.textures =textures;
  284. key.bump_mode =Min(bump, (Renderer.type()==RT_SIMPLE) ? SBUMP_FLAT : SBUMP_NORMAL); // blend light supports only flat/normal bump
  285. key.alpha_test=alpha_test;
  286. key.alpha =alpha;
  287. key.light_map =light_map;
  288. key.rflct =reflect;
  289. key.skin =skin;
  290. key.fx =fx;
  291. return Blsts(key);
  292. }
  293. return null;
  294. }
  295. void DefaultShaders::set(Shader *shader[RM_SHADER_NUM], FRST **frst, BLST **blst)
  296. {
  297. if(shader)
  298. {
  299. shader[RM_EARLY_Z]=EarlyZ();
  300. shader[RM_SIMPLE ]=Simple();
  301. shader[RM_SOLID ]=Solid();
  302. shader[RM_SOLID_M]=Solid(true);
  303. shader[RM_AMBIENT]=Ambient();
  304. shader[RM_OUTLINE]=Outline();
  305. shader[RM_BEHIND ]=Behind();
  306. shader[RM_FUR ]=Fur();
  307. shader[RM_SHADOW ]=Shadow();
  308. shader[RM_BLEND ]=Blend();
  309. shader[RM_OVERLAY]=Overlay();
  310. }
  311. if(frst)*frst=Frst();
  312. if(blst)*blst=Blst();
  313. }
  314. /******************************************************************************/
  315. }
  316. /******************************************************************************/