💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

711 lines
24 KiB

  1. /*
  2. * Copyright (C) 2021 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "render/passes/material-pass.hpp"
  20. #include "config.hpp"
  21. #include "resources/resource-manager.hpp"
  22. #include "gl/rasterizer.hpp"
  23. #include "gl/framebuffer.hpp"
  24. #include "gl/shader-program.hpp"
  25. #include "gl/shader-input.hpp"
  26. #include "gl/vertex-buffer.hpp"
  27. #include "gl/vertex-array.hpp"
  28. #include "gl/vertex-attribute.hpp"
  29. #include "gl/drawing-mode.hpp"
  30. #include "gl/texture-2d.hpp"
  31. #include "gl/texture-wrapping.hpp"
  32. #include "gl/texture-filter.hpp"
  33. #include "render/vertex-attribute.hpp"
  34. #include "render/material-flags.hpp"
  35. #include "render/model.hpp"
  36. #include "render/context.hpp"
  37. #include "scene/camera.hpp"
  38. #include "scene/collection.hpp"
  39. #include "scene/ambient-light.hpp"
  40. #include "scene/directional-light.hpp"
  41. #include "scene/point-light.hpp"
  42. #include "scene/spot-light.hpp"
  43. #include "config.hpp"
  44. #include <cmath>
  45. #include <glad/glad.h>
  46. #include "render/passes/shadow-map-pass.hpp"
  47. namespace render {
  48. static bool operation_compare(const render::operation& a, const render::operation& b);
  49. material_pass::material_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffer, resource_manager* resource_manager):
  50. pass(rasterizer, framebuffer),
  51. fallback_material(nullptr),
  52. mouse_position({0.0f, 0.0f}),
  53. shadow_map_pass(nullptr),
  54. shadow_map(nullptr)
  55. {
  56. max_ambient_light_count = MATERIAL_PASS_MAX_AMBIENT_LIGHT_COUNT;
  57. max_point_light_count = MATERIAL_PASS_MAX_POINT_LIGHT_COUNT;
  58. max_directional_light_count = MATERIAL_PASS_MAX_DIRECTIONAL_LIGHT_COUNT;
  59. max_spot_light_count = MATERIAL_PASS_MAX_SPOTLIGHT_COUNT;
  60. ambient_light_colors = new float3[max_ambient_light_count];
  61. point_light_colors = new float3[max_point_light_count];
  62. point_light_positions = new float3[max_point_light_count];
  63. point_light_attenuations = new float3[max_point_light_count];
  64. directional_light_colors = new float3[max_directional_light_count];
  65. directional_light_directions = new float3[max_directional_light_count];
  66. directional_light_textures = new const gl::texture_2d*[max_directional_light_count];
  67. directional_light_texture_matrices = new float4x4[max_directional_light_count];
  68. directional_light_texture_opacities = new float[max_directional_light_count];
  69. spot_light_colors = new float3[max_spot_light_count];
  70. spot_light_positions = new float3[max_spot_light_count];
  71. spot_light_directions = new float3[max_spot_light_count];
  72. spot_light_attenuations = new float3[max_spot_light_count];
  73. spot_light_cutoffs = new float2[max_spot_light_count];
  74. }
  75. material_pass::~material_pass()
  76. {
  77. delete[] ambient_light_colors;
  78. delete[] point_light_colors;
  79. delete[] point_light_positions;
  80. delete[] point_light_attenuations;
  81. delete[] directional_light_colors;
  82. delete[] directional_light_directions;
  83. delete[] directional_light_textures;
  84. delete[] directional_light_texture_matrices;
  85. delete[] directional_light_texture_opacities;
  86. delete[] spot_light_colors;
  87. delete[] spot_light_positions;
  88. delete[] spot_light_directions;
  89. delete[] spot_light_attenuations;
  90. delete[] spot_light_cutoffs;
  91. }
  92. void material_pass::render(const render::context& ctx, render::queue& queue) const
  93. {
  94. rasterizer->use_framebuffer(*framebuffer);
  95. glDisable(GL_BLEND);
  96. glEnable(GL_DEPTH_TEST);
  97. glDepthMask(GL_TRUE);
  98. glDepthFunc(GL_GREATER);
  99. glEnable(GL_CULL_FACE);
  100. glCullFace(GL_BACK);
  101. glDisable(GL_STENCIL_TEST);
  102. glStencilMask(0x00);
  103. // For half-z buffer
  104. glDepthRange(-1.0f, 1.0f);
  105. auto viewport = framebuffer->get_dimensions();
  106. rasterizer->set_viewport(0, 0, std::get<0>(viewport), std::get<1>(viewport));
  107. float2 resolution = {static_cast<float>(std::get<0>(viewport)), static_cast<float>(std::get<1>(viewport))};
  108. const float3& camera_position = ctx.camera_transform.translation;
  109. float4x4 view = ctx.camera->get_view_tween().interpolate(ctx.alpha);
  110. float4x4 projection = ctx.camera->get_projection_tween().interpolate(ctx.alpha);
  111. float4x4 view_projection = projection * view;
  112. float4x4 model_view_projection;
  113. float4x4 model;
  114. float4x4 model_view;
  115. float3x3 normal_model;
  116. float3x3 normal_model_view;
  117. float2 clip_depth;
  118. clip_depth[0] = ctx.camera->get_clip_near_tween().interpolate(ctx.alpha);
  119. clip_depth[1] = ctx.camera->get_clip_far_tween().interpolate(ctx.alpha);
  120. float log_depth_coef = 2.0f / std::log2(clip_depth[1] + 1.0f);
  121. int active_material_flags = 0;
  122. const gl::shader_program* active_shader_program = nullptr;
  123. const render::material* active_material = nullptr;
  124. const parameter_set* parameters = nullptr;
  125. // Reset light counts
  126. ambient_light_count = 0;
  127. point_light_count = 0;
  128. directional_light_count = 0;
  129. spot_light_count = 0;
  130. // Collect lights
  131. const std::list<scene::object_base*>* lights = ctx.collection->get_objects(scene::light::object_type_id);
  132. for (const scene::object_base* object: *lights)
  133. {
  134. // Skip inactive lights
  135. if (!object->is_active())
  136. continue;
  137. const scene::light* light = static_cast<const scene::light*>(object);
  138. switch (light->get_light_type())
  139. {
  140. // Add ambient light
  141. case scene::light_type::ambient:
  142. {
  143. if (ambient_light_count < max_ambient_light_count)
  144. {
  145. // Pre-expose light
  146. ambient_light_colors[ambient_light_count] = light->get_scaled_color_tween().interpolate(ctx.alpha) * ctx.exposure;
  147. ++ambient_light_count;
  148. }
  149. break;
  150. }
  151. // Add point light
  152. case scene::light_type::point:
  153. {
  154. if (point_light_count < max_point_light_count)
  155. {
  156. // Pre-expose light
  157. point_light_colors[point_light_count] = light->get_scaled_color_tween().interpolate(ctx.alpha) * ctx.exposure;
  158. float3 position = light->get_transform_tween().interpolate(ctx.alpha).translation;
  159. point_light_positions[point_light_count] = position;
  160. point_light_attenuations[point_light_count] = static_cast<const scene::point_light*>(light)->get_attenuation_tween().interpolate(ctx.alpha);
  161. ++point_light_count;
  162. }
  163. break;
  164. }
  165. // Add directional light
  166. case scene::light_type::directional:
  167. {
  168. if (directional_light_count < max_directional_light_count)
  169. {
  170. const scene::directional_light* directional_light = static_cast<const scene::directional_light*>(light);
  171. // Pre-expose light
  172. directional_light_colors[directional_light_count] = light->get_scaled_color_tween().interpolate(ctx.alpha) * ctx.exposure;
  173. float3 direction = static_cast<const scene::directional_light*>(light)->get_direction_tween().interpolate(ctx.alpha);
  174. directional_light_directions[directional_light_count] = direction;
  175. if (directional_light->get_light_texture())
  176. {
  177. directional_light_textures[directional_light_count] = directional_light->get_light_texture();
  178. directional_light_texture_opacities[directional_light_count] = directional_light->get_light_texture_opacity_tween().interpolate(ctx.alpha);
  179. math::transform<float> light_transform = light->get_transform_tween().interpolate(ctx.alpha);
  180. float3 forward = light_transform.rotation * config::global_forward;
  181. float3 up = light_transform.rotation * config::global_up;
  182. float4x4 light_view = math::look_at(light_transform.translation, light_transform.translation + forward, up);
  183. float2 scale = directional_light->get_light_texture_scale_tween().interpolate(ctx.alpha);
  184. float4x4 light_projection = math::ortho(-scale.x, scale.x, -scale.y, scale.y, -1.0f, 1.0f);
  185. directional_light_texture_matrices[directional_light_count] = light_projection * light_view;
  186. }
  187. else
  188. {
  189. directional_light_textures[directional_light_count] = nullptr;
  190. directional_light_texture_opacities[directional_light_count] = 0.0f;
  191. }
  192. ++directional_light_count;
  193. }
  194. break;
  195. }
  196. // Add spot_light
  197. case scene::light_type::spot:
  198. {
  199. if (spot_light_count < max_spot_light_count)
  200. {
  201. const scene::spot_light* spot_light = static_cast<const scene::spot_light*>(light);
  202. // Pre-expose light
  203. spot_light_colors[spot_light_count] = light->get_scaled_color_tween().interpolate(ctx.alpha) * ctx.exposure;
  204. float3 position = light->get_transform_tween().interpolate(ctx.alpha).translation;
  205. spot_light_positions[spot_light_count] = position;
  206. float3 direction = spot_light->get_direction_tween().interpolate(ctx.alpha);
  207. spot_light_directions[spot_light_count] = direction;
  208. spot_light_attenuations[spot_light_count] = spot_light->get_attenuation_tween().interpolate(ctx.alpha);
  209. spot_light_cutoffs[spot_light_count] = spot_light->get_cosine_cutoff_tween().interpolate(ctx.alpha);
  210. ++spot_light_count;
  211. }
  212. break;
  213. }
  214. default:
  215. break;
  216. }
  217. }
  218. float4x4 shadow_matrices_directional[4];
  219. float4 shadow_splits_directional;
  220. if (shadow_map_pass)
  221. {
  222. for (int i = 0; i < 4; ++i)
  223. shadow_matrices_directional[i] = shadow_map_pass->get_shadow_matrices()[i];
  224. // Calculate shadow map split distances
  225. for (int i = 0; i < 4; ++i)
  226. shadow_splits_directional[i] = shadow_map_pass->get_split_distances()[i + 1];
  227. }
  228. // Sort render queue
  229. queue.sort(operation_compare);
  230. for (const render::operation& operation: queue)
  231. {
  232. // Get operation material
  233. const render::material* material = operation.material;
  234. if (!material)
  235. {
  236. if (fallback_material)
  237. {
  238. // No material specified, use fallback material
  239. material = fallback_material;
  240. }
  241. else
  242. {
  243. // No material specified and no fallback material, skip operation
  244. continue;
  245. }
  246. }
  247. // Switch materials if necessary
  248. if (active_material != material)
  249. {
  250. active_material = material;
  251. // Change rasterizer state according to material flags
  252. std::uint32_t material_flags = active_material->get_flags();
  253. if (active_material_flags != material_flags)
  254. {
  255. if ((material_flags & MATERIAL_FLAG_TRANSLUCENT) != (active_material_flags & MATERIAL_FLAG_TRANSLUCENT))
  256. {
  257. if (material_flags & MATERIAL_FLAG_TRANSLUCENT)
  258. {
  259. glEnable(GL_BLEND);
  260. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  261. }
  262. else
  263. {
  264. glDisable(GL_BLEND);
  265. }
  266. }
  267. if ((material_flags & MATERIAL_FLAG_BACK_FACES) != (active_material_flags & MATERIAL_FLAG_BACK_FACES))
  268. {
  269. if (material_flags & MATERIAL_FLAG_BACK_FACES)
  270. {
  271. glEnable(GL_CULL_FACE);
  272. glCullFace(GL_FRONT);
  273. }
  274. else
  275. {
  276. glEnable(GL_CULL_FACE);
  277. glCullFace(GL_BACK);
  278. }
  279. }
  280. else if ((material_flags & MATERIAL_FLAG_FRONT_AND_BACK_FACES) != (active_material_flags & MATERIAL_FLAG_FRONT_AND_BACK_FACES))
  281. {
  282. if (material_flags & MATERIAL_FLAG_FRONT_AND_BACK_FACES)
  283. {
  284. glDisable(GL_CULL_FACE);
  285. }
  286. else
  287. {
  288. glEnable(GL_CULL_FACE);
  289. glCullFace(GL_BACK);
  290. }
  291. }
  292. if ((material_flags & MATERIAL_FLAG_X_RAY) != (active_material_flags & MATERIAL_FLAG_X_RAY))
  293. {
  294. if (material_flags & MATERIAL_FLAG_X_RAY)
  295. {
  296. glDisable(GL_DEPTH_TEST);
  297. }
  298. else
  299. {
  300. glEnable(GL_DEPTH_TEST);
  301. }
  302. }
  303. if ((material_flags & MATERIAL_FLAG_DECAL_SURFACE) != (active_material_flags & MATERIAL_FLAG_DECAL_SURFACE))
  304. {
  305. if (material_flags & MATERIAL_FLAG_DECAL_SURFACE)
  306. {
  307. glEnable(GL_STENCIL_TEST);
  308. glStencilFunc(GL_ALWAYS, 1, ~0);
  309. glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
  310. glStencilMask(~0);
  311. }
  312. else
  313. {
  314. glDisable(GL_STENCIL_TEST);
  315. glStencilMask(0);
  316. }
  317. }
  318. if ((material_flags & MATERIAL_FLAG_DECAL) != (active_material_flags & MATERIAL_FLAG_DECAL))
  319. {
  320. if (material_flags & MATERIAL_FLAG_DECAL)
  321. {
  322. glEnable(GL_DEPTH_TEST);
  323. glDepthFunc(GL_GEQUAL);
  324. glDepthMask(GL_FALSE);
  325. glEnable(GL_STENCIL_TEST);
  326. glStencilFunc(GL_EQUAL, 1, ~0);
  327. //glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
  328. //glStencilMask(~0);
  329. glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  330. glStencilMask(0);
  331. }
  332. else
  333. {
  334. glEnable(GL_DEPTH_TEST);
  335. glDepthFunc(GL_GREATER);
  336. glDepthMask(GL_TRUE);
  337. glDisable(GL_STENCIL_TEST);
  338. glStencilMask(0);
  339. }
  340. }
  341. /*
  342. if ((material_flags & MATERIAL_FLAG_OUTLINE) != (active_material_flags & MATERIAL_FLAG_OUTLINE))
  343. {
  344. if (material_flags & MATERIAL_FLAG_OUTLINE)
  345. {
  346. glEnable(GL_STENCIL_TEST);
  347. glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
  348. glStencilFunc(GL_ALWAYS, 2, 0xFF);
  349. glStencilMask(0xFF);
  350. }
  351. else
  352. {
  353. glDisable(GL_STENCIL_TEST);
  354. glStencilMask(0x00);
  355. }
  356. }
  357. */
  358. active_material_flags = material_flags;
  359. }
  360. // Switch shaders if necessary
  361. const gl::shader_program* shader_program = active_material->get_shader_program();
  362. if (active_shader_program != shader_program)
  363. {
  364. active_shader_program = shader_program;
  365. if (!active_shader_program)
  366. {
  367. continue;
  368. }
  369. // Change shader program
  370. rasterizer->use_program(*active_shader_program);
  371. // Get set of known shader input parameters
  372. if (auto it = parameter_sets.find(active_shader_program); it != parameter_sets.end())
  373. {
  374. parameters = it->second;
  375. }
  376. else
  377. {
  378. parameters = load_parameter_set(active_shader_program);
  379. }
  380. // Upload context-dependent shader parameters
  381. if (parameters->time)
  382. parameters->time->upload(ctx.t);
  383. if (parameters->mouse)
  384. parameters->mouse->upload(mouse_position);
  385. if (parameters->resolution)
  386. parameters->resolution->upload(resolution);
  387. if (parameters->camera_position)
  388. parameters->camera_position->upload(camera_position);
  389. if (parameters->camera_exposure)
  390. parameters->camera_exposure->upload(ctx.exposure);
  391. if (parameters->view)
  392. parameters->view->upload(view);
  393. if (parameters->view_projection)
  394. parameters->view_projection->upload(view_projection);
  395. if (parameters->ambient_light_count)
  396. parameters->ambient_light_count->upload(ambient_light_count);
  397. if (parameters->ambient_light_colors)
  398. parameters->ambient_light_colors->upload(0, ambient_light_colors, ambient_light_count);
  399. if (parameters->point_light_count)
  400. parameters->point_light_count->upload(point_light_count);
  401. if (parameters->point_light_colors)
  402. parameters->point_light_colors->upload(0, point_light_colors, point_light_count);
  403. if (parameters->point_light_positions)
  404. parameters->point_light_positions->upload(0, point_light_positions, point_light_count);
  405. if (parameters->point_light_attenuations)
  406. parameters->point_light_attenuations->upload(0, point_light_attenuations, point_light_count);
  407. if (parameters->directional_light_count)
  408. parameters->directional_light_count->upload(directional_light_count);
  409. if (parameters->directional_light_colors)
  410. parameters->directional_light_colors->upload(0, directional_light_colors, directional_light_count);
  411. if (parameters->directional_light_directions)
  412. parameters->directional_light_directions->upload(0, directional_light_directions, directional_light_count);
  413. if (parameters->directional_light_textures)
  414. parameters->directional_light_textures->upload(0, directional_light_textures, directional_light_count);
  415. if (parameters->directional_light_texture_matrices)
  416. parameters->directional_light_texture_matrices->upload(0, directional_light_texture_matrices, directional_light_count);
  417. if (parameters->directional_light_texture_opacities)
  418. parameters->directional_light_texture_opacities->upload(0, directional_light_texture_opacities, directional_light_count);
  419. if (parameters->spot_light_count)
  420. parameters->spot_light_count->upload(spot_light_count);
  421. if (parameters->spot_light_colors)
  422. parameters->spot_light_colors->upload(0, spot_light_colors, spot_light_count);
  423. if (parameters->spot_light_positions)
  424. parameters->spot_light_positions->upload(0, spot_light_positions, spot_light_count);
  425. if (parameters->spot_light_directions)
  426. parameters->spot_light_directions->upload(0, spot_light_directions, spot_light_count);
  427. if (parameters->spot_light_attenuations)
  428. parameters->spot_light_attenuations->upload(0, spot_light_attenuations, spot_light_count);
  429. if (parameters->spot_light_cutoffs)
  430. parameters->spot_light_cutoffs->upload(0, spot_light_cutoffs, spot_light_count);
  431. if (parameters->shadow_map_directional && shadow_map)
  432. parameters->shadow_map_directional->upload(shadow_map);
  433. if (parameters->shadow_matrices_directional)
  434. parameters->shadow_matrices_directional->upload(0, shadow_matrices_directional, 4);
  435. if (parameters->shadow_splits_directional)
  436. parameters->shadow_splits_directional->upload(shadow_splits_directional);
  437. }
  438. // Upload material properties to shader
  439. active_material->upload(ctx.alpha);
  440. }
  441. // Calculate operation-dependent parameters
  442. model = operation.transform;
  443. model_view_projection = view_projection * model;
  444. model_view = view * model;
  445. normal_model = math::transpose(math::inverse(math::resize<3, 3>(model)));
  446. normal_model_view = math::transpose(math::inverse(math::resize<3, 3>(model_view)));
  447. // Skinning palette
  448. if (operation.bone_count && parameters->skinning_palette)
  449. {
  450. parameters->skinning_palette->upload(0, operation.skinning_palette, operation.bone_count);
  451. }
  452. // Upload operation-dependent parameters
  453. if (parameters->model)
  454. parameters->model->upload(model);
  455. if (parameters->model_view)
  456. parameters->model_view->upload(model_view);
  457. if (parameters->model_view_projection)
  458. parameters->model_view_projection->upload(model_view_projection);
  459. if (parameters->normal_model)
  460. parameters->normal_model->upload(normal_model);
  461. if (parameters->normal_model_view)
  462. parameters->normal_model_view->upload(normal_model_view);
  463. if (parameters->clip_depth)
  464. parameters->clip_depth->upload(clip_depth);
  465. if (parameters->log_depth_coef)
  466. parameters->log_depth_coef->upload(log_depth_coef);
  467. // Draw geometry
  468. if (operation.instance_count)
  469. rasterizer->draw_arrays_instanced(*operation.vertex_array, operation.drawing_mode, operation.start_index, operation.index_count, operation.instance_count);
  470. else
  471. rasterizer->draw_arrays(*operation.vertex_array, operation.drawing_mode, operation.start_index, operation.index_count);
  472. }
  473. }
  474. void material_pass::set_fallback_material(const material* fallback)
  475. {
  476. this->fallback_material = fallback;
  477. }
  478. const material_pass::parameter_set* material_pass::load_parameter_set(const gl::shader_program* program) const
  479. {
  480. // Allocate a new parameter set
  481. parameter_set* parameters = new parameter_set();
  482. // Connect inputs
  483. parameters->time = program->get_input("time");
  484. parameters->mouse = program->get_input("mouse");
  485. parameters->resolution = program->get_input("resolution");
  486. parameters->camera_position = program->get_input("camera.position");
  487. parameters->camera_exposure = program->get_input("camera.exposure");
  488. parameters->model = program->get_input("model");
  489. parameters->view = program->get_input("view");
  490. parameters->projection = program->get_input("projection");
  491. parameters->model_view = program->get_input("model_view");
  492. parameters->view_projection = program->get_input("view_projection");
  493. parameters->model_view_projection = program->get_input("model_view_projection");
  494. parameters->normal_model = program->get_input("normal_model");
  495. parameters->normal_model_view = program->get_input("normal_model_view");
  496. parameters->clip_depth = program->get_input("clip_depth");
  497. parameters->log_depth_coef = program->get_input("log_depth_coef");
  498. parameters->ambient_light_count = program->get_input("ambient_light_count");
  499. parameters->ambient_light_colors = program->get_input("ambient_light_colors");
  500. parameters->point_light_count = program->get_input("point_light_count");
  501. parameters->point_light_colors = program->get_input("point_light_colors");
  502. parameters->point_light_positions = program->get_input("point_light_positions");
  503. parameters->point_light_attenuations = program->get_input("point_light_attenuations");
  504. parameters->directional_light_count = program->get_input("directional_light_count");
  505. parameters->directional_light_colors = program->get_input("directional_light_colors");
  506. parameters->directional_light_directions = program->get_input("directional_light_directions");
  507. parameters->directional_light_textures = program->get_input("directional_light_textures");
  508. parameters->directional_light_texture_matrices = program->get_input("directional_light_texture_matrices");
  509. parameters->directional_light_texture_opacities = program->get_input("directional_light_texture_opacities");
  510. parameters->spot_light_count = program->get_input("spot_light_count");
  511. parameters->spot_light_colors = program->get_input("spot_light_colors");
  512. parameters->spot_light_positions = program->get_input("spot_light_positions");
  513. parameters->spot_light_directions = program->get_input("spot_light_directions");
  514. parameters->spot_light_attenuations = program->get_input("spot_light_attenuations");
  515. parameters->spot_light_cutoffs = program->get_input("spot_light_cutoffs");
  516. parameters->shadow_map_directional = program->get_input("shadow_map_directional");
  517. parameters->shadow_splits_directional = program->get_input("shadow_splits_directional");
  518. parameters->shadow_matrices_directional = program->get_input("shadow_matrices_directional");
  519. parameters->skinning_palette = program->get_input("skinning_palette");
  520. // Add parameter set to map of parameter sets
  521. parameter_sets[program] = parameters;
  522. return parameters;
  523. }
  524. void material_pass::handle_event(const mouse_moved_event& event)
  525. {
  526. mouse_position = {static_cast<float>(event.x), static_cast<float>(event.y)};
  527. }
  528. bool operation_compare(const render::operation& a, const render::operation& b)
  529. {
  530. if (!a.material)
  531. return false;
  532. else if (!b.material)
  533. return true;
  534. bool xray_a = a.material->get_flags() & MATERIAL_FLAG_X_RAY;
  535. bool xray_b = b.material->get_flags() & MATERIAL_FLAG_X_RAY;
  536. if (xray_a)
  537. {
  538. if (xray_b)
  539. {
  540. // A and B are both xray, render back to front
  541. return (a.depth >= b.depth);
  542. }
  543. else
  544. {
  545. // A is xray, B is not. Render B first
  546. return false;
  547. }
  548. }
  549. else
  550. {
  551. if (xray_b)
  552. {
  553. // A is opaque, B is xray. Render A first
  554. return true;
  555. }
  556. else
  557. {
  558. // Determine transparency
  559. bool transparent_a = a.material->get_flags() & MATERIAL_FLAG_TRANSLUCENT;
  560. bool transparent_b = b.material->get_flags() & MATERIAL_FLAG_TRANSLUCENT;
  561. if (transparent_a)
  562. {
  563. if (transparent_b)
  564. {
  565. // Determine decal status
  566. bool decal_a = a.material->get_flags() & MATERIAL_FLAG_DECAL;
  567. bool decal_b = b.material->get_flags() & MATERIAL_FLAG_DECAL;
  568. if (decal_a)
  569. {
  570. if (decal_b)
  571. {
  572. // A and B are both transparent decals, render back to front
  573. return (a.depth >= b.depth);
  574. }
  575. else
  576. {
  577. // A is a transparent decal, B is transparent but not a decal, render A first
  578. return true;
  579. }
  580. }
  581. else
  582. {
  583. if (decal_b)
  584. {
  585. // A is transparent but not a decal, B is a transparent decal, render B first
  586. return false;
  587. }
  588. else
  589. {
  590. // A and B are both transparent, but not decals, render back to front
  591. return (a.depth <= b.depth);
  592. }
  593. }
  594. }
  595. else
  596. {
  597. // A is transparent, B is opaque. Render B first
  598. return false;
  599. }
  600. }
  601. else
  602. {
  603. if (transparent_b)
  604. {
  605. // A is opaque, B is transparent. Render A first
  606. return true;
  607. }
  608. else
  609. {
  610. // A and B are both opaque
  611. if (a.material->get_shader_program() == b.material->get_shader_program())
  612. {
  613. // A and B have the same shader
  614. if (a.vertex_array == b.vertex_array)
  615. {
  616. // A and B have the same VAO, render front to back
  617. return (a.depth < b.depth);
  618. }
  619. else
  620. {
  621. // Sort by VAO
  622. return (a.vertex_array < b.vertex_array);
  623. }
  624. }
  625. else
  626. {
  627. // A and B are both opaque and have different shaders, sort by shader
  628. return (a.material->get_shader_program() < b.material->get_shader_program());
  629. }
  630. }
  631. }
  632. }
  633. }
  634. }
  635. } // namespace render