clouds.cpp 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. /*
  2. Minetest
  3. Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include "clouds.h"
  17. #include "noise.h"
  18. #include "constants.h"
  19. #include "debug.h"
  20. #include "profiler.h"
  21. #include "settings.h"
  22. // Menu clouds are created later
  23. class Clouds;
  24. Clouds *g_menuclouds = NULL;
  25. irr::scene::ISceneManager *g_menucloudsmgr = NULL;
  26. static void cloud_3d_setting_changed(const std::string &settingname, void *data)
  27. {
  28. ((Clouds *)data)->readSettings();
  29. }
  30. Clouds::Clouds(
  31. scene::ISceneNode* parent,
  32. scene::ISceneManager* mgr,
  33. s32 id,
  34. u32 seed,
  35. s16 cloudheight
  36. ):
  37. scene::ISceneNode(parent, mgr, id),
  38. m_seed(seed),
  39. m_camera_pos(0,0),
  40. m_time(0),
  41. m_camera_offset(0,0,0)
  42. {
  43. m_material.setFlag(video::EMF_LIGHTING, false);
  44. //m_material.setFlag(video::EMF_BACK_FACE_CULLING, false);
  45. m_material.setFlag(video::EMF_BACK_FACE_CULLING, true);
  46. m_material.setFlag(video::EMF_BILINEAR_FILTER, false);
  47. m_material.setFlag(video::EMF_FOG_ENABLE, true);
  48. m_material.setFlag(video::EMF_ANTI_ALIASING, true);
  49. //m_material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
  50. m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
  51. m_passed_cloud_y = cloudheight;
  52. readSettings();
  53. g_settings->registerChangedCallback("enable_3d_clouds",
  54. &cloud_3d_setting_changed, this);
  55. m_box = core::aabbox3d<f32>(-BS*1000000,m_cloud_y-BS,-BS*1000000,
  56. BS*1000000,m_cloud_y+BS,BS*1000000);
  57. }
  58. Clouds::~Clouds()
  59. {
  60. g_settings->deregisterChangedCallback("enable_3d_clouds",
  61. &cloud_3d_setting_changed, this);
  62. }
  63. void Clouds::OnRegisterSceneNode()
  64. {
  65. if(IsVisible)
  66. {
  67. SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
  68. //SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
  69. }
  70. ISceneNode::OnRegisterSceneNode();
  71. }
  72. #define MYROUND(x) (x > 0.0 ? (int)x : (int)x - 1)
  73. void Clouds::render()
  74. {
  75. video::IVideoDriver* driver = SceneManager->getVideoDriver();
  76. if(SceneManager->getSceneNodeRenderPass() != scene::ESNRP_TRANSPARENT)
  77. //if(SceneManager->getSceneNodeRenderPass() != scene::ESNRP_SOLID)
  78. return;
  79. ScopeProfiler sp(g_profiler, "Rendering of clouds, avg", SPT_AVG);
  80. int num_faces_to_draw = m_enable_3d ? 6 : 1;
  81. m_material.setFlag(video::EMF_BACK_FACE_CULLING, m_enable_3d);
  82. driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
  83. driver->setMaterial(m_material);
  84. /*
  85. Clouds move from Z+ towards Z-
  86. */
  87. const float cloud_size = BS * 64;
  88. const v2f cloud_speed(0, -BS * 2);
  89. const float cloud_full_radius = cloud_size * m_cloud_radius_i;
  90. // Position of cloud noise origin in world coordinates
  91. v2f world_cloud_origin_pos_f = m_time * cloud_speed;
  92. // Position of cloud noise origin from the camera
  93. v2f cloud_origin_from_camera_f = world_cloud_origin_pos_f - m_camera_pos;
  94. // The center point of drawing in the noise
  95. v2f center_of_drawing_in_noise_f = -cloud_origin_from_camera_f;
  96. // The integer center point of drawing in the noise
  97. v2s16 center_of_drawing_in_noise_i(
  98. MYROUND(center_of_drawing_in_noise_f.X / cloud_size),
  99. MYROUND(center_of_drawing_in_noise_f.Y / cloud_size)
  100. );
  101. // The world position of the integer center point of drawing in the noise
  102. v2f world_center_of_drawing_in_noise_f = v2f(
  103. center_of_drawing_in_noise_i.X * cloud_size,
  104. center_of_drawing_in_noise_i.Y * cloud_size
  105. ) + world_cloud_origin_pos_f;
  106. /*video::SColor c_top(128,b*240,b*240,b*255);
  107. video::SColor c_side_1(128,b*230,b*230,b*255);
  108. video::SColor c_side_2(128,b*220,b*220,b*245);
  109. video::SColor c_bottom(128,b*205,b*205,b*230);*/
  110. video::SColorf c_top_f(m_color);
  111. video::SColorf c_side_1_f(m_color);
  112. video::SColorf c_side_2_f(m_color);
  113. video::SColorf c_bottom_f(m_color);
  114. c_side_1_f.r *= 0.95;
  115. c_side_1_f.g *= 0.95;
  116. c_side_1_f.b *= 0.95;
  117. c_side_2_f.r *= 0.90;
  118. c_side_2_f.g *= 0.90;
  119. c_side_2_f.b *= 0.90;
  120. c_bottom_f.r *= 0.80;
  121. c_bottom_f.g *= 0.80;
  122. c_bottom_f.b *= 0.80;
  123. c_top_f.a = 0.9;
  124. c_side_1_f.a = 0.9;
  125. c_side_2_f.a = 0.9;
  126. c_bottom_f.a = 0.9;
  127. video::SColor c_top = c_top_f.toSColor();
  128. video::SColor c_side_1 = c_side_1_f.toSColor();
  129. video::SColor c_side_2 = c_side_2_f.toSColor();
  130. video::SColor c_bottom = c_bottom_f.toSColor();
  131. // Get fog parameters for setting them back later
  132. video::SColor fog_color(0,0,0,0);
  133. video::E_FOG_TYPE fog_type = video::EFT_FOG_LINEAR;
  134. f32 fog_start = 0;
  135. f32 fog_end = 0;
  136. f32 fog_density = 0;
  137. bool fog_pixelfog = false;
  138. bool fog_rangefog = false;
  139. driver->getFog(fog_color, fog_type, fog_start, fog_end, fog_density,
  140. fog_pixelfog, fog_rangefog);
  141. // Set our own fog
  142. driver->setFog(fog_color, fog_type, cloud_full_radius * 0.5,
  143. cloud_full_radius*1.2, fog_density, fog_pixelfog, fog_rangefog);
  144. // Read noise
  145. bool *grid = new bool[m_cloud_radius_i * 2 * m_cloud_radius_i * 2];
  146. float cloud_size_noise = cloud_size / BS / 200;
  147. for(s16 zi = -m_cloud_radius_i; zi < m_cloud_radius_i; zi++) {
  148. u32 si = (zi + m_cloud_radius_i) * m_cloud_radius_i * 2 + m_cloud_radius_i;
  149. for (s16 xi = -m_cloud_radius_i; xi < m_cloud_radius_i; xi++) {
  150. u32 i = si + xi;
  151. v2s16 p_in_noise_i(
  152. xi + center_of_drawing_in_noise_i.X,
  153. zi + center_of_drawing_in_noise_i.Y
  154. );
  155. double noise = noise2d_perlin(
  156. (float)p_in_noise_i.X * cloud_size_noise,
  157. (float)p_in_noise_i.Y * cloud_size_noise,
  158. m_seed, 3, 0.5);
  159. grid[i] = (noise >= 0.4);
  160. }
  161. }
  162. #define GETINDEX(x, z, radius) (((z)+(radius))*(radius)*2 + (x)+(radius))
  163. #define INAREA(x, z, radius) \
  164. ((x) >= -(radius) && (x) < (radius) && (z) >= -(radius) && (z) < (radius))
  165. for (s16 zi0= -m_cloud_radius_i; zi0 < m_cloud_radius_i; zi0++)
  166. for (s16 xi0= -m_cloud_radius_i; xi0 < m_cloud_radius_i; xi0++)
  167. {
  168. s16 zi = zi0;
  169. s16 xi = xi0;
  170. // Draw from front to back (needed for transparency)
  171. /*if(zi <= 0)
  172. zi = -m_cloud_radius_i - zi;
  173. if(xi <= 0)
  174. xi = -m_cloud_radius_i - xi;*/
  175. // Draw from back to front
  176. if(zi >= 0)
  177. zi = m_cloud_radius_i - zi - 1;
  178. if(xi >= 0)
  179. xi = m_cloud_radius_i - xi - 1;
  180. u32 i = GETINDEX(xi, zi, m_cloud_radius_i);
  181. if(grid[i] == false)
  182. continue;
  183. v2f p0 = v2f(xi,zi)*cloud_size + world_center_of_drawing_in_noise_f;
  184. video::S3DVertex v[4] = {
  185. video::S3DVertex(0,0,0, 0,0,0, c_top, 0, 1),
  186. video::S3DVertex(0,0,0, 0,0,0, c_top, 1, 1),
  187. video::S3DVertex(0,0,0, 0,0,0, c_top, 1, 0),
  188. video::S3DVertex(0,0,0, 0,0,0, c_top, 0, 0)
  189. };
  190. /*if(zi <= 0 && xi <= 0){
  191. v[0].Color.setBlue(255);
  192. v[1].Color.setBlue(255);
  193. v[2].Color.setBlue(255);
  194. v[3].Color.setBlue(255);
  195. }*/
  196. f32 rx = cloud_size/2;
  197. f32 ry = 8 * BS;
  198. f32 rz = cloud_size / 2;
  199. for(int i=0; i<num_faces_to_draw; i++)
  200. {
  201. switch(i)
  202. {
  203. case 0: // top
  204. for(int j=0;j<4;j++){
  205. v[j].Normal.set(0,1,0);
  206. }
  207. v[0].Pos.set(-rx, ry,-rz);
  208. v[1].Pos.set(-rx, ry, rz);
  209. v[2].Pos.set( rx, ry, rz);
  210. v[3].Pos.set( rx, ry,-rz);
  211. break;
  212. case 1: // back
  213. if (INAREA(xi, zi - 1, m_cloud_radius_i)) {
  214. u32 j = GETINDEX(xi, zi - 1, m_cloud_radius_i);
  215. if(grid[j])
  216. continue;
  217. }
  218. for(int j=0;j<4;j++){
  219. v[j].Color = c_side_1;
  220. v[j].Normal.set(0,0,-1);
  221. }
  222. v[0].Pos.set(-rx, ry,-rz);
  223. v[1].Pos.set( rx, ry,-rz);
  224. v[2].Pos.set( rx,-ry,-rz);
  225. v[3].Pos.set(-rx,-ry,-rz);
  226. break;
  227. case 2: //right
  228. if (INAREA(xi + 1, zi, m_cloud_radius_i)) {
  229. u32 j = GETINDEX(xi+1, zi, m_cloud_radius_i);
  230. if(grid[j])
  231. continue;
  232. }
  233. for(int j=0;j<4;j++){
  234. v[j].Color = c_side_2;
  235. v[j].Normal.set(1,0,0);
  236. }
  237. v[0].Pos.set( rx, ry,-rz);
  238. v[1].Pos.set( rx, ry, rz);
  239. v[2].Pos.set( rx,-ry, rz);
  240. v[3].Pos.set( rx,-ry,-rz);
  241. break;
  242. case 3: // front
  243. if (INAREA(xi, zi + 1, m_cloud_radius_i)) {
  244. u32 j = GETINDEX(xi, zi + 1, m_cloud_radius_i);
  245. if(grid[j])
  246. continue;
  247. }
  248. for(int j=0;j<4;j++){
  249. v[j].Color = c_side_1;
  250. v[j].Normal.set(0,0,-1);
  251. }
  252. v[0].Pos.set( rx, ry, rz);
  253. v[1].Pos.set(-rx, ry, rz);
  254. v[2].Pos.set(-rx,-ry, rz);
  255. v[3].Pos.set( rx,-ry, rz);
  256. break;
  257. case 4: // left
  258. if (INAREA(xi-1, zi, m_cloud_radius_i)) {
  259. u32 j = GETINDEX(xi-1, zi, m_cloud_radius_i);
  260. if(grid[j])
  261. continue;
  262. }
  263. for(int j=0;j<4;j++){
  264. v[j].Color = c_side_2;
  265. v[j].Normal.set(-1,0,0);
  266. }
  267. v[0].Pos.set(-rx, ry, rz);
  268. v[1].Pos.set(-rx, ry,-rz);
  269. v[2].Pos.set(-rx,-ry,-rz);
  270. v[3].Pos.set(-rx,-ry, rz);
  271. break;
  272. case 5: // bottom
  273. for(int j=0;j<4;j++){
  274. v[j].Color = c_bottom;
  275. v[j].Normal.set(0,-1,0);
  276. }
  277. v[0].Pos.set( rx,-ry, rz);
  278. v[1].Pos.set(-rx,-ry, rz);
  279. v[2].Pos.set(-rx,-ry,-rz);
  280. v[3].Pos.set( rx,-ry,-rz);
  281. break;
  282. }
  283. v3f pos(p0.X, m_cloud_y, p0.Y);
  284. pos -= intToFloat(m_camera_offset, BS);
  285. for(u16 i=0; i<4; i++)
  286. v[i].Pos += pos;
  287. u16 indices[] = {0,1,2,2,3,0};
  288. driver->drawVertexPrimitiveList(v, 4, indices, 2,
  289. video::EVT_STANDARD, scene::EPT_TRIANGLES, video::EIT_16BIT);
  290. }
  291. }
  292. delete[] grid;
  293. // Restore fog settings
  294. driver->setFog(fog_color, fog_type, fog_start, fog_end, fog_density,
  295. fog_pixelfog, fog_rangefog);
  296. }
  297. void Clouds::step(float dtime)
  298. {
  299. m_time += dtime;
  300. }
  301. void Clouds::update(v2f camera_p, video::SColorf color)
  302. {
  303. m_camera_pos = camera_p;
  304. m_color = color;
  305. //m_brightness = brightness;
  306. //dstream<<"m_brightness="<<m_brightness<<std::endl;
  307. }
  308. void Clouds::readSettings()
  309. {
  310. m_cloud_y = BS * (m_passed_cloud_y ? m_passed_cloud_y :
  311. g_settings->getS16("cloud_height"));
  312. m_cloud_radius_i = g_settings->getU16("cloud_radius");
  313. m_enable_3d = g_settings->getBool("enable_3d_clouds");
  314. }