💿🐜 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.

732 lines
25 KiB

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