shader.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889
  1. /*
  2. Minetest
  3. Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. Copyright (C) 2013 Kahrl <kahrl@gmx.net>
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU Lesser General Public License as published by
  7. the Free Software Foundation; either version 2.1 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public License along
  14. with this program; if not, write to the Free Software Foundation, Inc.,
  15. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  16. */
  17. #include <fstream>
  18. #include <iterator>
  19. #include "shader.h"
  20. #include "irrlichttypes_extrabloated.h"
  21. #include "debug.h"
  22. #include "filesys.h"
  23. #include "util/container.h"
  24. #include "util/thread.h"
  25. #include "settings.h"
  26. #include <ICameraSceneNode.h>
  27. #include <IGPUProgrammingServices.h>
  28. #include <IMaterialRenderer.h>
  29. #include <IMaterialRendererServices.h>
  30. #include <IShaderConstantSetCallBack.h>
  31. #include "client/renderingengine.h"
  32. #include "EShaderTypes.h"
  33. #include "log.h"
  34. #include "gamedef.h"
  35. #include "client/tile.h"
  36. /*
  37. A cache from shader name to shader path
  38. */
  39. MutexedMap<std::string, std::string> g_shadername_to_path_cache;
  40. /*
  41. Gets the path to a shader by first checking if the file
  42. name_of_shader/filename
  43. exists in shader_path and if not, using the data path.
  44. If not found, returns "".
  45. Utilizes a thread-safe cache.
  46. */
  47. std::string getShaderPath(const std::string &name_of_shader,
  48. const std::string &filename)
  49. {
  50. std::string combined = name_of_shader + DIR_DELIM + filename;
  51. std::string fullpath;
  52. /*
  53. Check from cache
  54. */
  55. bool incache = g_shadername_to_path_cache.get(combined, &fullpath);
  56. if(incache)
  57. return fullpath;
  58. /*
  59. Check from shader_path
  60. */
  61. std::string shader_path = g_settings->get("shader_path");
  62. if (!shader_path.empty()) {
  63. std::string testpath = shader_path + DIR_DELIM + combined;
  64. if(fs::PathExists(testpath))
  65. fullpath = testpath;
  66. }
  67. /*
  68. Check from default data directory
  69. */
  70. if (fullpath.empty()) {
  71. std::string rel_path = std::string("client") + DIR_DELIM
  72. + "shaders" + DIR_DELIM
  73. + name_of_shader + DIR_DELIM
  74. + filename;
  75. std::string testpath = porting::path_share + DIR_DELIM + rel_path;
  76. if(fs::PathExists(testpath))
  77. fullpath = testpath;
  78. }
  79. // Add to cache (also an empty result is cached)
  80. g_shadername_to_path_cache.set(combined, fullpath);
  81. // Finally return it
  82. return fullpath;
  83. }
  84. /*
  85. SourceShaderCache: A cache used for storing source shaders.
  86. */
  87. class SourceShaderCache
  88. {
  89. public:
  90. void insert(const std::string &name_of_shader, const std::string &filename,
  91. const std::string &program, bool prefer_local)
  92. {
  93. std::string combined = name_of_shader + DIR_DELIM + filename;
  94. // Try to use local shader instead if asked to
  95. if(prefer_local){
  96. std::string path = getShaderPath(name_of_shader, filename);
  97. if(!path.empty()){
  98. std::string p = readFile(path);
  99. if (!p.empty()) {
  100. m_programs[combined] = p;
  101. return;
  102. }
  103. }
  104. }
  105. m_programs[combined] = program;
  106. }
  107. std::string get(const std::string &name_of_shader,
  108. const std::string &filename)
  109. {
  110. std::string combined = name_of_shader + DIR_DELIM + filename;
  111. StringMap::iterator n = m_programs.find(combined);
  112. if (n != m_programs.end())
  113. return n->second;
  114. return "";
  115. }
  116. // Primarily fetches from cache, secondarily tries to read from filesystem
  117. std::string getOrLoad(const std::string &name_of_shader,
  118. const std::string &filename)
  119. {
  120. std::string combined = name_of_shader + DIR_DELIM + filename;
  121. StringMap::iterator n = m_programs.find(combined);
  122. if (n != m_programs.end())
  123. return n->second;
  124. std::string path = getShaderPath(name_of_shader, filename);
  125. if (path.empty()) {
  126. infostream << "SourceShaderCache::getOrLoad(): No path found for \""
  127. << combined << "\"" << std::endl;
  128. return "";
  129. }
  130. infostream << "SourceShaderCache::getOrLoad(): Loading path \""
  131. << path << "\"" << std::endl;
  132. std::string p = readFile(path);
  133. if (!p.empty()) {
  134. m_programs[combined] = p;
  135. return p;
  136. }
  137. return "";
  138. }
  139. private:
  140. StringMap m_programs;
  141. std::string readFile(const std::string &path)
  142. {
  143. std::ifstream is(path.c_str(), std::ios::binary);
  144. if(!is.is_open())
  145. return "";
  146. std::ostringstream tmp_os;
  147. tmp_os << is.rdbuf();
  148. return tmp_os.str();
  149. }
  150. };
  151. /*
  152. ShaderCallback: Sets constants that can be used in shaders
  153. */
  154. class ShaderCallback : public video::IShaderConstantSetCallBack
  155. {
  156. std::vector<IShaderConstantSetter*> m_setters;
  157. public:
  158. ShaderCallback(const std::vector<IShaderConstantSetterFactory *> &factories)
  159. {
  160. for (IShaderConstantSetterFactory *factory : factories)
  161. m_setters.push_back(factory->create());
  162. }
  163. ~ShaderCallback()
  164. {
  165. for (IShaderConstantSetter *setter : m_setters)
  166. delete setter;
  167. }
  168. virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData) override
  169. {
  170. video::IVideoDriver *driver = services->getVideoDriver();
  171. sanity_check(driver != NULL);
  172. bool is_highlevel = userData;
  173. for (IShaderConstantSetter *setter : m_setters)
  174. setter->onSetConstants(services, is_highlevel);
  175. }
  176. virtual void OnSetMaterial(const video::SMaterial& material) override
  177. {
  178. for (IShaderConstantSetter *setter : m_setters)
  179. setter->onSetMaterial(material);
  180. }
  181. };
  182. /*
  183. MainShaderConstantSetter: Set basic constants required for almost everything
  184. */
  185. class MainShaderConstantSetter : public IShaderConstantSetter
  186. {
  187. CachedVertexShaderSetting<float, 16> m_world_view_proj;
  188. CachedVertexShaderSetting<float, 16> m_world;
  189. public:
  190. MainShaderConstantSetter() :
  191. m_world_view_proj("mWorldViewProj"),
  192. m_world("mWorld")
  193. {}
  194. ~MainShaderConstantSetter() = default;
  195. virtual void onSetConstants(video::IMaterialRendererServices *services,
  196. bool is_highlevel)
  197. {
  198. video::IVideoDriver *driver = services->getVideoDriver();
  199. sanity_check(driver);
  200. // Set clip matrix
  201. core::matrix4 worldViewProj;
  202. worldViewProj = driver->getTransform(video::ETS_PROJECTION);
  203. worldViewProj *= driver->getTransform(video::ETS_VIEW);
  204. worldViewProj *= driver->getTransform(video::ETS_WORLD);
  205. if (is_highlevel)
  206. m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
  207. else
  208. services->setVertexShaderConstant(worldViewProj.pointer(), 0, 4);
  209. // Set world matrix
  210. core::matrix4 world = driver->getTransform(video::ETS_WORLD);
  211. if (is_highlevel)
  212. m_world.set(*reinterpret_cast<float(*)[16]>(world.pointer()), services);
  213. else
  214. services->setVertexShaderConstant(world.pointer(), 4, 4);
  215. }
  216. };
  217. class MainShaderConstantSetterFactory : public IShaderConstantSetterFactory
  218. {
  219. public:
  220. virtual IShaderConstantSetter* create()
  221. { return new MainShaderConstantSetter(); }
  222. };
  223. /*
  224. ShaderSource
  225. */
  226. class ShaderSource : public IWritableShaderSource
  227. {
  228. public:
  229. ShaderSource();
  230. ~ShaderSource();
  231. /*
  232. - If shader material specified by name is found from cache,
  233. return the cached id.
  234. - Otherwise generate the shader material, add to cache and return id.
  235. The id 0 points to a null shader. Its material is EMT_SOLID.
  236. */
  237. u32 getShaderIdDirect(const std::string &name,
  238. const u8 material_type, const u8 drawtype);
  239. /*
  240. If shader specified by the name pointed by the id doesn't
  241. exist, create it, then return id.
  242. Can be called from any thread. If called from some other thread
  243. and not found in cache, the call is queued to the main thread
  244. for processing.
  245. */
  246. u32 getShader(const std::string &name,
  247. const u8 material_type, const u8 drawtype);
  248. ShaderInfo getShaderInfo(u32 id);
  249. // Processes queued shader requests from other threads.
  250. // Shall be called from the main thread.
  251. void processQueue();
  252. // Insert a shader program into the cache without touching the
  253. // filesystem. Shall be called from the main thread.
  254. void insertSourceShader(const std::string &name_of_shader,
  255. const std::string &filename, const std::string &program);
  256. // Rebuild shaders from the current set of source shaders
  257. // Shall be called from the main thread.
  258. void rebuildShaders();
  259. void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter)
  260. {
  261. m_setter_factories.push_back(setter);
  262. }
  263. private:
  264. // The id of the thread that is allowed to use irrlicht directly
  265. std::thread::id m_main_thread;
  266. // Cache of source shaders
  267. // This should be only accessed from the main thread
  268. SourceShaderCache m_sourcecache;
  269. // A shader id is index in this array.
  270. // The first position contains a dummy shader.
  271. std::vector<ShaderInfo> m_shaderinfo_cache;
  272. // The former container is behind this mutex
  273. std::mutex m_shaderinfo_cache_mutex;
  274. // Queued shader fetches (to be processed by the main thread)
  275. RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
  276. // Global constant setter factories
  277. std::vector<IShaderConstantSetterFactory *> m_setter_factories;
  278. // Shader callbacks
  279. std::vector<ShaderCallback *> m_callbacks;
  280. };
  281. IWritableShaderSource *createShaderSource()
  282. {
  283. return new ShaderSource();
  284. }
  285. /*
  286. Generate shader given the shader name.
  287. */
  288. ShaderInfo generate_shader(const std::string &name,
  289. u8 material_type, u8 drawtype, std::vector<ShaderCallback *> &callbacks,
  290. const std::vector<IShaderConstantSetterFactory *> &setter_factories,
  291. SourceShaderCache *sourcecache);
  292. /*
  293. Load shader programs
  294. */
  295. void load_shaders(const std::string &name, SourceShaderCache *sourcecache,
  296. video::E_DRIVER_TYPE drivertype, bool enable_shaders,
  297. std::string &vertex_program, std::string &pixel_program,
  298. std::string &geometry_program, bool &is_highlevel);
  299. ShaderSource::ShaderSource()
  300. {
  301. m_main_thread = std::this_thread::get_id();
  302. // Add a dummy ShaderInfo as the first index, named ""
  303. m_shaderinfo_cache.emplace_back();
  304. // Add main global constant setter
  305. addShaderConstantSetterFactory(new MainShaderConstantSetterFactory());
  306. }
  307. ShaderSource::~ShaderSource()
  308. {
  309. for (ShaderCallback *callback : m_callbacks) {
  310. delete callback;
  311. }
  312. for (IShaderConstantSetterFactory *setter_factorie : m_setter_factories) {
  313. delete setter_factorie;
  314. }
  315. }
  316. u32 ShaderSource::getShader(const std::string &name,
  317. const u8 material_type, const u8 drawtype)
  318. {
  319. /*
  320. Get shader
  321. */
  322. if (std::this_thread::get_id() == m_main_thread) {
  323. return getShaderIdDirect(name, material_type, drawtype);
  324. }
  325. /*errorstream<<"getShader(): Queued: name=\""<<name<<"\""<<std::endl;*/
  326. // We're gonna ask the result to be put into here
  327. static ResultQueue<std::string, u32, u8, u8> result_queue;
  328. // Throw a request in
  329. m_get_shader_queue.add(name, 0, 0, &result_queue);
  330. /* infostream<<"Waiting for shader from main thread, name=\""
  331. <<name<<"\""<<std::endl;*/
  332. while(true) {
  333. GetResult<std::string, u32, u8, u8>
  334. result = result_queue.pop_frontNoEx();
  335. if (result.key == name) {
  336. return result.item;
  337. }
  338. errorstream << "Got shader with invalid name: " << result.key << std::endl;
  339. }
  340. infostream << "getShader(): Failed" << std::endl;
  341. return 0;
  342. }
  343. /*
  344. This method generates all the shaders
  345. */
  346. u32 ShaderSource::getShaderIdDirect(const std::string &name,
  347. const u8 material_type, const u8 drawtype)
  348. {
  349. //infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;
  350. // Empty name means shader 0
  351. if (name.empty()) {
  352. infostream<<"getShaderIdDirect(): name is empty"<<std::endl;
  353. return 0;
  354. }
  355. // Check if already have such instance
  356. for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
  357. ShaderInfo *info = &m_shaderinfo_cache[i];
  358. if(info->name == name && info->material_type == material_type &&
  359. info->drawtype == drawtype)
  360. return i;
  361. }
  362. /*
  363. Calling only allowed from main thread
  364. */
  365. if (std::this_thread::get_id() != m_main_thread) {
  366. errorstream<<"ShaderSource::getShaderIdDirect() "
  367. "called not from main thread"<<std::endl;
  368. return 0;
  369. }
  370. ShaderInfo info = generate_shader(name, material_type, drawtype,
  371. m_callbacks, m_setter_factories, &m_sourcecache);
  372. /*
  373. Add shader to caches (add dummy shaders too)
  374. */
  375. MutexAutoLock lock(m_shaderinfo_cache_mutex);
  376. u32 id = m_shaderinfo_cache.size();
  377. m_shaderinfo_cache.push_back(info);
  378. infostream<<"getShaderIdDirect(): "
  379. <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;
  380. return id;
  381. }
  382. ShaderInfo ShaderSource::getShaderInfo(u32 id)
  383. {
  384. MutexAutoLock lock(m_shaderinfo_cache_mutex);
  385. if(id >= m_shaderinfo_cache.size())
  386. return ShaderInfo();
  387. return m_shaderinfo_cache[id];
  388. }
  389. void ShaderSource::processQueue()
  390. {
  391. }
  392. void ShaderSource::insertSourceShader(const std::string &name_of_shader,
  393. const std::string &filename, const std::string &program)
  394. {
  395. /*infostream<<"ShaderSource::insertSourceShader(): "
  396. "name_of_shader=\""<<name_of_shader<<"\", "
  397. "filename=\""<<filename<<"\""<<std::endl;*/
  398. sanity_check(std::this_thread::get_id() == m_main_thread);
  399. m_sourcecache.insert(name_of_shader, filename, program, true);
  400. }
  401. void ShaderSource::rebuildShaders()
  402. {
  403. MutexAutoLock lock(m_shaderinfo_cache_mutex);
  404. /*// Oh well... just clear everything, they'll load sometime.
  405. m_shaderinfo_cache.clear();
  406. m_name_to_id.clear();*/
  407. /*
  408. FIXME: Old shader materials can't be deleted in Irrlicht,
  409. or can they?
  410. (This would be nice to do in the destructor too)
  411. */
  412. // Recreate shaders
  413. for (ShaderInfo &i : m_shaderinfo_cache) {
  414. ShaderInfo *info = &i;
  415. if (!info->name.empty()) {
  416. *info = generate_shader(info->name, info->material_type,
  417. info->drawtype, m_callbacks,
  418. m_setter_factories, &m_sourcecache);
  419. }
  420. }
  421. }
  422. ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtype,
  423. std::vector<ShaderCallback *> &callbacks,
  424. const std::vector<IShaderConstantSetterFactory *> &setter_factories,
  425. SourceShaderCache *sourcecache)
  426. {
  427. ShaderInfo shaderinfo;
  428. shaderinfo.name = name;
  429. shaderinfo.material_type = material_type;
  430. shaderinfo.drawtype = drawtype;
  431. shaderinfo.material = video::EMT_SOLID;
  432. switch (material_type) {
  433. case TILE_MATERIAL_OPAQUE:
  434. case TILE_MATERIAL_LIQUID_OPAQUE:
  435. case TILE_MATERIAL_WAVING_LIQUID_OPAQUE:
  436. shaderinfo.base_material = video::EMT_SOLID;
  437. break;
  438. case TILE_MATERIAL_ALPHA:
  439. case TILE_MATERIAL_PLAIN_ALPHA:
  440. case TILE_MATERIAL_LIQUID_TRANSPARENT:
  441. case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
  442. shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
  443. break;
  444. case TILE_MATERIAL_BASIC:
  445. case TILE_MATERIAL_PLAIN:
  446. case TILE_MATERIAL_WAVING_LEAVES:
  447. case TILE_MATERIAL_WAVING_PLANTS:
  448. case TILE_MATERIAL_WAVING_LIQUID_BASIC:
  449. shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
  450. break;
  451. }
  452. bool enable_shaders = g_settings->getBool("enable_shaders");
  453. if (!enable_shaders)
  454. return shaderinfo;
  455. video::IVideoDriver *driver = RenderingEngine::get_video_driver();
  456. video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
  457. if(!gpu){
  458. errorstream<<"generate_shader(): "
  459. "failed to generate \""<<name<<"\", "
  460. "GPU programming not supported."
  461. <<std::endl;
  462. return shaderinfo;
  463. }
  464. // Choose shader language depending on driver type and settings
  465. // Then load shaders
  466. std::string vertex_program;
  467. std::string pixel_program;
  468. std::string geometry_program;
  469. bool is_highlevel;
  470. load_shaders(name, sourcecache, driver->getDriverType(),
  471. enable_shaders, vertex_program, pixel_program,
  472. geometry_program, is_highlevel);
  473. // Check hardware/driver support
  474. if (!vertex_program.empty() &&
  475. !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
  476. !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)){
  477. infostream<<"generate_shader(): vertex shaders disabled "
  478. "because of missing driver/hardware support."
  479. <<std::endl;
  480. vertex_program = "";
  481. }
  482. if (!pixel_program.empty() &&
  483. !driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
  484. !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)){
  485. infostream<<"generate_shader(): pixel shaders disabled "
  486. "because of missing driver/hardware support."
  487. <<std::endl;
  488. pixel_program = "";
  489. }
  490. if (!geometry_program.empty() &&
  491. !driver->queryFeature(video::EVDF_GEOMETRY_SHADER)){
  492. infostream<<"generate_shader(): geometry shaders disabled "
  493. "because of missing driver/hardware support."
  494. <<std::endl;
  495. geometry_program = "";
  496. }
  497. // If no shaders are used, don't make a separate material type
  498. if (vertex_program.empty() && pixel_program.empty() && geometry_program.empty())
  499. return shaderinfo;
  500. // Create shaders header
  501. std::string shaders_header = "#version 120\n";
  502. static const char* drawTypes[] = {
  503. "NDT_NORMAL",
  504. "NDT_AIRLIKE",
  505. "NDT_LIQUID",
  506. "NDT_FLOWINGLIQUID",
  507. "NDT_GLASSLIKE",
  508. "NDT_ALLFACES",
  509. "NDT_ALLFACES_OPTIONAL",
  510. "NDT_TORCHLIKE",
  511. "NDT_SIGNLIKE",
  512. "NDT_PLANTLIKE",
  513. "NDT_FENCELIKE",
  514. "NDT_RAILLIKE",
  515. "NDT_NODEBOX",
  516. "NDT_GLASSLIKE_FRAMED",
  517. "NDT_FIRELIKE",
  518. "NDT_GLASSLIKE_FRAMED_OPTIONAL",
  519. "NDT_PLANTLIKE_ROOTED",
  520. };
  521. for (int i = 0; i < 14; i++){
  522. shaders_header += "#define ";
  523. shaders_header += drawTypes[i];
  524. shaders_header += " ";
  525. shaders_header += itos(i);
  526. shaders_header += "\n";
  527. }
  528. static const char* materialTypes[] = {
  529. "TILE_MATERIAL_BASIC",
  530. "TILE_MATERIAL_ALPHA",
  531. "TILE_MATERIAL_LIQUID_TRANSPARENT",
  532. "TILE_MATERIAL_LIQUID_OPAQUE",
  533. "TILE_MATERIAL_WAVING_LEAVES",
  534. "TILE_MATERIAL_WAVING_PLANTS",
  535. "TILE_MATERIAL_OPAQUE",
  536. "TILE_MATERIAL_WAVING_LIQUID_BASIC",
  537. "TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT",
  538. "TILE_MATERIAL_WAVING_LIQUID_OPAQUE",
  539. "TILE_MATERIAL_PLAIN",
  540. "TILE_MATERIAL_PLAIN_ALPHA",
  541. };
  542. for (int i = 0; i < 12; i++){
  543. shaders_header += "#define ";
  544. shaders_header += materialTypes[i];
  545. shaders_header += " ";
  546. shaders_header += itos(i);
  547. shaders_header += "\n";
  548. }
  549. shaders_header += "#define MATERIAL_TYPE ";
  550. shaders_header += itos(material_type);
  551. shaders_header += "\n";
  552. shaders_header += "#define DRAW_TYPE ";
  553. shaders_header += itos(drawtype);
  554. shaders_header += "\n";
  555. if (g_settings->getBool("generate_normalmaps")) {
  556. shaders_header += "#define GENERATE_NORMALMAPS 1\n";
  557. } else {
  558. shaders_header += "#define GENERATE_NORMALMAPS 0\n";
  559. }
  560. shaders_header += "#define NORMALMAPS_STRENGTH ";
  561. shaders_header += ftos(g_settings->getFloat("normalmaps_strength"));
  562. shaders_header += "\n";
  563. float sample_step;
  564. int smooth = (int)g_settings->getFloat("normalmaps_smooth");
  565. switch (smooth){
  566. case 0:
  567. sample_step = 0.0078125; // 1.0 / 128.0
  568. break;
  569. case 1:
  570. sample_step = 0.00390625; // 1.0 / 256.0
  571. break;
  572. case 2:
  573. sample_step = 0.001953125; // 1.0 / 512.0
  574. break;
  575. default:
  576. sample_step = 0.0078125;
  577. break;
  578. }
  579. shaders_header += "#define SAMPLE_STEP ";
  580. shaders_header += ftos(sample_step);
  581. shaders_header += "\n";
  582. if (g_settings->getBool("enable_bumpmapping"))
  583. shaders_header += "#define ENABLE_BUMPMAPPING\n";
  584. if (g_settings->getBool("enable_parallax_occlusion")){
  585. int mode = g_settings->getFloat("parallax_occlusion_mode");
  586. float scale = g_settings->getFloat("parallax_occlusion_scale");
  587. float bias = g_settings->getFloat("parallax_occlusion_bias");
  588. int iterations = g_settings->getFloat("parallax_occlusion_iterations");
  589. shaders_header += "#define ENABLE_PARALLAX_OCCLUSION\n";
  590. shaders_header += "#define PARALLAX_OCCLUSION_MODE ";
  591. shaders_header += itos(mode);
  592. shaders_header += "\n";
  593. shaders_header += "#define PARALLAX_OCCLUSION_SCALE ";
  594. shaders_header += ftos(scale);
  595. shaders_header += "\n";
  596. shaders_header += "#define PARALLAX_OCCLUSION_BIAS ";
  597. shaders_header += ftos(bias);
  598. shaders_header += "\n";
  599. shaders_header += "#define PARALLAX_OCCLUSION_ITERATIONS ";
  600. shaders_header += itos(iterations);
  601. shaders_header += "\n";
  602. }
  603. shaders_header += "#define USE_NORMALMAPS ";
  604. if (g_settings->getBool("enable_bumpmapping") || g_settings->getBool("enable_parallax_occlusion"))
  605. shaders_header += "1\n";
  606. else
  607. shaders_header += "0\n";
  608. if (g_settings->getBool("enable_waving_water")){
  609. shaders_header += "#define ENABLE_WAVING_WATER 1\n";
  610. shaders_header += "#define WATER_WAVE_HEIGHT ";
  611. shaders_header += ftos(g_settings->getFloat("water_wave_height"));
  612. shaders_header += "\n";
  613. shaders_header += "#define WATER_WAVE_LENGTH ";
  614. shaders_header += ftos(g_settings->getFloat("water_wave_length"));
  615. shaders_header += "\n";
  616. shaders_header += "#define WATER_WAVE_SPEED ";
  617. shaders_header += ftos(g_settings->getFloat("water_wave_speed"));
  618. shaders_header += "\n";
  619. } else{
  620. shaders_header += "#define ENABLE_WAVING_WATER 0\n";
  621. }
  622. shaders_header += "#define ENABLE_WAVING_LEAVES ";
  623. if (g_settings->getBool("enable_waving_leaves"))
  624. shaders_header += "1\n";
  625. else
  626. shaders_header += "0\n";
  627. shaders_header += "#define ENABLE_WAVING_PLANTS ";
  628. if (g_settings->getBool("enable_waving_plants"))
  629. shaders_header += "1\n";
  630. else
  631. shaders_header += "0\n";
  632. if (g_settings->getBool("tone_mapping"))
  633. shaders_header += "#define ENABLE_TONE_MAPPING\n";
  634. shaders_header += "#define FOG_START ";
  635. shaders_header += ftos(rangelim(g_settings->getFloat("fog_start"), 0.0f, 0.99f));
  636. shaders_header += "\n";
  637. // Call addHighLevelShaderMaterial() or addShaderMaterial()
  638. const c8* vertex_program_ptr = 0;
  639. const c8* pixel_program_ptr = 0;
  640. const c8* geometry_program_ptr = 0;
  641. if (!vertex_program.empty()) {
  642. vertex_program = shaders_header + vertex_program;
  643. vertex_program_ptr = vertex_program.c_str();
  644. }
  645. if (!pixel_program.empty()) {
  646. pixel_program = shaders_header + pixel_program;
  647. pixel_program_ptr = pixel_program.c_str();
  648. }
  649. if (!geometry_program.empty()) {
  650. geometry_program = shaders_header + geometry_program;
  651. geometry_program_ptr = geometry_program.c_str();
  652. }
  653. ShaderCallback *cb = new ShaderCallback(setter_factories);
  654. s32 shadermat = -1;
  655. if(is_highlevel){
  656. infostream<<"Compiling high level shaders for "<<name<<std::endl;
  657. shadermat = gpu->addHighLevelShaderMaterial(
  658. vertex_program_ptr, // Vertex shader program
  659. "vertexMain", // Vertex shader entry point
  660. video::EVST_VS_1_1, // Vertex shader version
  661. pixel_program_ptr, // Pixel shader program
  662. "pixelMain", // Pixel shader entry point
  663. video::EPST_PS_1_2, // Pixel shader version
  664. geometry_program_ptr, // Geometry shader program
  665. "geometryMain", // Geometry shader entry point
  666. video::EGST_GS_4_0, // Geometry shader version
  667. scene::EPT_TRIANGLES, // Geometry shader input
  668. scene::EPT_TRIANGLE_STRIP, // Geometry shader output
  669. 0, // Support maximum number of vertices
  670. cb, // Set-constant callback
  671. shaderinfo.base_material, // Base material
  672. 1 // Userdata passed to callback
  673. );
  674. if(shadermat == -1){
  675. errorstream<<"generate_shader(): "
  676. "failed to generate \""<<name<<"\", "
  677. "addHighLevelShaderMaterial failed."
  678. <<std::endl;
  679. dumpShaderProgram(warningstream, "Vertex", vertex_program);
  680. dumpShaderProgram(warningstream, "Pixel", pixel_program);
  681. dumpShaderProgram(warningstream, "Geometry", geometry_program);
  682. delete cb;
  683. return shaderinfo;
  684. }
  685. }
  686. else{
  687. infostream<<"Compiling assembly shaders for "<<name<<std::endl;
  688. shadermat = gpu->addShaderMaterial(
  689. vertex_program_ptr, // Vertex shader program
  690. pixel_program_ptr, // Pixel shader program
  691. cb, // Set-constant callback
  692. shaderinfo.base_material, // Base material
  693. 0 // Userdata passed to callback
  694. );
  695. if(shadermat == -1){
  696. errorstream<<"generate_shader(): "
  697. "failed to generate \""<<name<<"\", "
  698. "addShaderMaterial failed."
  699. <<std::endl;
  700. dumpShaderProgram(warningstream, "Vertex", vertex_program);
  701. dumpShaderProgram(warningstream,"Pixel", pixel_program);
  702. delete cb;
  703. return shaderinfo;
  704. }
  705. }
  706. callbacks.push_back(cb);
  707. // HACK, TODO: investigate this better
  708. // Grab the material renderer once more so minetest doesn't crash on exit
  709. driver->getMaterialRenderer(shadermat)->grab();
  710. // Apply the newly created material type
  711. shaderinfo.material = (video::E_MATERIAL_TYPE) shadermat;
  712. return shaderinfo;
  713. }
  714. void load_shaders(const std::string &name, SourceShaderCache *sourcecache,
  715. video::E_DRIVER_TYPE drivertype, bool enable_shaders,
  716. std::string &vertex_program, std::string &pixel_program,
  717. std::string &geometry_program, bool &is_highlevel)
  718. {
  719. vertex_program = "";
  720. pixel_program = "";
  721. geometry_program = "";
  722. is_highlevel = false;
  723. if(enable_shaders){
  724. // Look for high level shaders
  725. if(drivertype == video::EDT_DIRECT3D9){
  726. // Direct3D 9: HLSL
  727. // (All shaders in one file)
  728. vertex_program = sourcecache->getOrLoad(name, "d3d9.hlsl");
  729. pixel_program = vertex_program;
  730. geometry_program = vertex_program;
  731. }
  732. else if(drivertype == video::EDT_OPENGL){
  733. // OpenGL: GLSL
  734. vertex_program = sourcecache->getOrLoad(name, "opengl_vertex.glsl");
  735. pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.glsl");
  736. geometry_program = sourcecache->getOrLoad(name, "opengl_geometry.glsl");
  737. }
  738. if (!vertex_program.empty() || !pixel_program.empty() || !geometry_program.empty()){
  739. is_highlevel = true;
  740. return;
  741. }
  742. }
  743. }
  744. void dumpShaderProgram(std::ostream &output_stream,
  745. const std::string &program_type, const std::string &program)
  746. {
  747. output_stream << program_type << " shader program:" << std::endl <<
  748. "----------------------------------" << std::endl;
  749. size_t pos = 0;
  750. size_t prev = 0;
  751. s16 line = 1;
  752. while ((pos = program.find('\n', prev)) != std::string::npos) {
  753. output_stream << line++ << ": "<< program.substr(prev, pos - prev) <<
  754. std::endl;
  755. prev = pos + 1;
  756. }
  757. output_stream << line << ": " << program.substr(prev) << std::endl <<
  758. "End of " << program_type << " shader program." << std::endl <<
  759. " " << std::endl;
  760. }