shader.cpp 26 KB

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