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

686 lines
23 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 "renderer/passes/material-pass.hpp"
  20. #include "configuration.hpp"
  21. #include "resources/resource-manager.hpp"
  22. #include "gl/rasterizer.hpp"
  23. #include "gl/framebuffer.hpp"
  24. #include "gl/shader.hpp"
  25. #include "gl/shader-type.hpp"
  26. #include "gl/shader-program.hpp"
  27. #include "gl/shader-input.hpp"
  28. #include "gl/vertex-buffer.hpp"
  29. #include "gl/vertex-array.hpp"
  30. #include "gl/vertex-attribute-type.hpp"
  31. #include "gl/drawing-mode.hpp"
  32. #include "gl/texture-2d.hpp"
  33. #include "gl/texture-wrapping.hpp"
  34. #include "gl/texture-filter.hpp"
  35. #include "renderer/vertex-attributes.hpp"
  36. #include "renderer/material-flags.hpp"
  37. #include "renderer/model.hpp"
  38. #include "renderer/render-context.hpp"
  39. #include "scene/camera.hpp"
  40. #include "scene/collection.hpp"
  41. #include "scene/ambient-light.hpp"
  42. #include "scene/directional-light.hpp"
  43. #include "scene/point-light.hpp"
  44. #include "scene/spotlight.hpp"
  45. #include "configuration.hpp"
  46. #include "math/math.hpp"
  47. #include <cmath>
  48. #include <glad/glad.h>
  49. #include "shadow-map-pass.hpp"
  50. static bool operation_compare(const render_operation& a, const render_operation& b);
  51. material_pass::material_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffer, resource_manager* resource_manager):
  52. render_pass(rasterizer, framebuffer),
  53. fallback_material(nullptr),
  54. time_tween(nullptr),
  55. mouse_position({0.0f, 0.0f}),
  56. focal_point_tween(nullptr),
  57. shadow_map_pass(nullptr),
  58. shadow_map(nullptr),
  59. shadow_strength(1.0f)
  60. {
  61. soft_shadows_texture = resource_manager->load<gl::texture_2d>("forest-gobo.tex");
  62. max_ambient_light_count = MATERIAL_PASS_MAX_AMBIENT_LIGHT_COUNT;
  63. max_point_light_count = MATERIAL_PASS_MAX_POINT_LIGHT_COUNT;
  64. max_directional_light_count = MATERIAL_PASS_MAX_DIRECTIONAL_LIGHT_COUNT;
  65. max_spotlight_count = MATERIAL_PASS_MAX_SPOTLIGHT_COUNT;
  66. ambient_light_colors = new float3[max_ambient_light_count];
  67. point_light_colors = new float3[max_point_light_count];
  68. point_light_positions = new float3[max_point_light_count];
  69. point_light_attenuations = new float3[max_point_light_count];
  70. directional_light_colors = new float3[max_directional_light_count];
  71. directional_light_directions = new float3[max_directional_light_count];
  72. spotlight_colors = new float3[max_spotlight_count];
  73. spotlight_positions = new float3[max_spotlight_count];
  74. spotlight_directions = new float3[max_spotlight_count];
  75. spotlight_attenuations = new float3[max_spotlight_count];
  76. spotlight_cutoffs = new float2[max_spotlight_count];
  77. }
  78. material_pass::~material_pass()
  79. {
  80. delete[] ambient_light_colors;
  81. delete[] point_light_colors;
  82. delete[] point_light_positions;
  83. delete[] point_light_attenuations;
  84. delete[] directional_light_colors;
  85. delete[] directional_light_directions;
  86. delete[] spotlight_colors;
  87. delete[] spotlight_positions;
  88. delete[] spotlight_directions;
  89. delete[] spotlight_attenuations;
  90. delete[] spotlight_cutoffs;
  91. }
  92. void material_pass::render(render_context* context) 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. float time = (time_tween) ? time_tween->interpolate(context->alpha) : 0.0f;
  109. float3 focal_point = (focal_point_tween) ? focal_point_tween->interpolate(context->alpha) : float3{0, 0, 0};
  110. float4x4 view = context->camera->get_view_tween().interpolate(context->alpha);
  111. float4x4 projection = context->camera->get_projection_tween().interpolate(context->alpha);
  112. float4x4 view_projection = projection * view;
  113. float4x4 model_view_projection;
  114. float4x4 model;
  115. float4x4 model_view;
  116. float3x3 normal_model_view;
  117. float2 clip_depth;
  118. clip_depth[0] = context->camera->get_clip_near_tween().interpolate(context->alpha);
  119. clip_depth[1] = context->camera->get_clip_far_tween().interpolate(context->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 ::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. spotlight_count = 0;
  130. // Collect lights
  131. const std::list<scene::object_base*>* lights = context->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. ambient_light_colors[ambient_light_count] = light->get_scaled_color_tween().interpolate(context->alpha);
  146. ++ambient_light_count;
  147. }
  148. break;
  149. }
  150. // Add point light
  151. case scene::light_type::point:
  152. {
  153. if (point_light_count < max_point_light_count)
  154. {
  155. point_light_colors[point_light_count] = light->get_scaled_color_tween().interpolate(context->alpha);
  156. // Transform position into view-space
  157. float3 position = light->get_transform_tween().interpolate(context->alpha).translation;
  158. float3 view_space_position = math::resize<3>(view * float4{position.x, position.y, position.z, 1.0f});
  159. point_light_positions[point_light_count] = view_space_position;
  160. point_light_attenuations[point_light_count] = static_cast<const scene::point_light*>(light)->get_attenuation_tween().interpolate(context->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. directional_light_colors[directional_light_count] = light->get_scaled_color_tween().interpolate(context->alpha);
  171. // Transform direction into view-space
  172. float3 direction = static_cast<const scene::directional_light*>(light)->get_direction_tween().interpolate(context->alpha);
  173. float3 view_space_direction = math::normalize(math::resize<3>(view * math::resize<4>(-direction)));
  174. directional_light_directions[directional_light_count] = view_space_direction;
  175. ++directional_light_count;
  176. }
  177. break;
  178. }
  179. // Add spotlight
  180. case scene::light_type::spot:
  181. {
  182. if (spotlight_count < max_spotlight_count)
  183. {
  184. spotlight_colors[spotlight_count] = light->get_scaled_color_tween().interpolate(context->alpha);
  185. // Transform position into view-space
  186. float3 position = light->get_transform_tween().interpolate(context->alpha).translation;
  187. float3 view_space_position = math::resize<3>(view * float4{position.x, position.y, position.z, 1.0f});
  188. spotlight_positions[spotlight_count] = view_space_position;
  189. const scene::spotlight* spotlight = static_cast<const scene::spotlight*>(light);
  190. // Transform direction into view-space
  191. float3 direction = spotlight->get_direction_tween().interpolate(context->alpha);
  192. float3 view_space_direction = math::normalize(math::resize<3>(view * float4{-direction.x, -direction.y, -direction.z, 0.0f}));
  193. spotlight_directions[spotlight_count] = view_space_direction;
  194. spotlight_attenuations[spotlight_count] = spotlight->get_attenuation_tween().interpolate(context->alpha);
  195. spotlight_cutoffs[spotlight_count] = spotlight->get_cosine_cutoff_tween().interpolate(context->alpha);
  196. ++spotlight_count;
  197. }
  198. break;
  199. }
  200. default:
  201. break;
  202. }
  203. }
  204. float4x4 shadow_map_matrices[4];
  205. float4 shadow_map_split_distances;
  206. if (shadow_map_pass)
  207. {
  208. for (int i = 0; i < 4; ++i)
  209. shadow_map_matrices[i] = shadow_map_pass->get_shadow_matrices()[i];
  210. // Calculate shadow map split distances
  211. for (int i = 0; i < 4; ++i)
  212. shadow_map_split_distances[i] = shadow_map_pass->get_split_distances()[i + 1];
  213. }
  214. // Sort render operations
  215. context->operations.sort(operation_compare);
  216. for (const render_operation& operation: context->operations)
  217. {
  218. // Get operation material
  219. const ::material* material = operation.material;
  220. if (!material)
  221. {
  222. if (fallback_material)
  223. {
  224. // No material specified, use fallback material
  225. material = fallback_material;
  226. }
  227. else
  228. {
  229. // No material specified and no fallback material, skip operation
  230. continue;
  231. }
  232. }
  233. // Switch materials if necessary
  234. if (active_material != material)
  235. {
  236. active_material = material;
  237. // Change rasterizer state according to material flags
  238. std::uint32_t material_flags = active_material->get_flags();
  239. if (active_material_flags != material_flags)
  240. {
  241. if ((material_flags & MATERIAL_FLAG_TRANSLUCENT) != (active_material_flags & MATERIAL_FLAG_TRANSLUCENT))
  242. {
  243. if (material_flags & MATERIAL_FLAG_TRANSLUCENT)
  244. {
  245. glEnable(GL_BLEND);
  246. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  247. }
  248. else
  249. {
  250. glDisable(GL_BLEND);
  251. }
  252. }
  253. if ((material_flags & MATERIAL_FLAG_BACK_FACES) != (active_material_flags & MATERIAL_FLAG_BACK_FACES))
  254. {
  255. if (material_flags & MATERIAL_FLAG_BACK_FACES)
  256. {
  257. glEnable(GL_CULL_FACE);
  258. glCullFace(GL_FRONT);
  259. }
  260. else
  261. {
  262. glEnable(GL_CULL_FACE);
  263. glCullFace(GL_BACK);
  264. }
  265. }
  266. else if ((material_flags & MATERIAL_FLAG_FRONT_AND_BACK_FACES) != (active_material_flags & MATERIAL_FLAG_FRONT_AND_BACK_FACES))
  267. {
  268. if (material_flags & MATERIAL_FLAG_FRONT_AND_BACK_FACES)
  269. {
  270. glDisable(GL_CULL_FACE);
  271. }
  272. else
  273. {
  274. glEnable(GL_CULL_FACE);
  275. glCullFace(GL_BACK);
  276. }
  277. }
  278. if ((material_flags & MATERIAL_FLAG_X_RAY) != (active_material_flags & MATERIAL_FLAG_X_RAY))
  279. {
  280. if (material_flags & MATERIAL_FLAG_X_RAY)
  281. {
  282. glDisable(GL_DEPTH_TEST);
  283. }
  284. else
  285. {
  286. glEnable(GL_DEPTH_TEST);
  287. }
  288. }
  289. if ((material_flags & MATERIAL_FLAG_DECAL_SURFACE) != (active_material_flags & MATERIAL_FLAG_DECAL_SURFACE))
  290. {
  291. if (material_flags & MATERIAL_FLAG_DECAL_SURFACE)
  292. {
  293. glEnable(GL_STENCIL_TEST);
  294. glStencilFunc(GL_ALWAYS, 1, ~0);
  295. glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
  296. glStencilMask(~0);
  297. }
  298. else
  299. {
  300. glDisable(GL_STENCIL_TEST);
  301. glStencilMask(0);
  302. }
  303. }
  304. if ((material_flags & MATERIAL_FLAG_DECAL) != (active_material_flags & MATERIAL_FLAG_DECAL))
  305. {
  306. if (material_flags & MATERIAL_FLAG_DECAL)
  307. {
  308. glEnable(GL_DEPTH_TEST);
  309. glDepthFunc(GL_GEQUAL);
  310. glDepthMask(GL_FALSE);
  311. glEnable(GL_STENCIL_TEST);
  312. glStencilFunc(GL_EQUAL, 1, ~0);
  313. //glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
  314. //glStencilMask(~0);
  315. glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  316. glStencilMask(0);
  317. }
  318. else
  319. {
  320. glEnable(GL_DEPTH_TEST);
  321. glDepthFunc(GL_GREATER);
  322. glDepthMask(GL_TRUE);
  323. glDisable(GL_STENCIL_TEST);
  324. glStencilMask(0);
  325. }
  326. }
  327. /*
  328. if ((material_flags & MATERIAL_FLAG_OUTLINE) != (active_material_flags & MATERIAL_FLAG_OUTLINE))
  329. {
  330. if (material_flags & MATERIAL_FLAG_OUTLINE)
  331. {
  332. glEnable(GL_STENCIL_TEST);
  333. glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
  334. glStencilFunc(GL_ALWAYS, 2, 0xFF);
  335. glStencilMask(0xFF);
  336. }
  337. else
  338. {
  339. glDisable(GL_STENCIL_TEST);
  340. glStencilMask(0x00);
  341. }
  342. }
  343. */
  344. active_material_flags = material_flags;
  345. }
  346. // Switch shaders if necessary
  347. const gl::shader_program* shader_program = active_material->get_shader_program();
  348. if (active_shader_program != shader_program)
  349. {
  350. active_shader_program = shader_program;
  351. if (!active_shader_program)
  352. {
  353. continue;
  354. }
  355. // Change shader program
  356. rasterizer->use_program(*active_shader_program);
  357. // Get set of known shader input parameters
  358. if (auto it = parameter_sets.find(active_shader_program); it != parameter_sets.end())
  359. {
  360. parameters = it->second;
  361. }
  362. else
  363. {
  364. parameters = load_parameter_set(active_shader_program);
  365. }
  366. // Upload context-dependent shader parameters
  367. if (parameters->time)
  368. parameters->time->upload(time);
  369. if (parameters->mouse)
  370. parameters->mouse->upload(mouse_position);
  371. if (parameters->resolution)
  372. parameters->resolution->upload(resolution);
  373. if (parameters->view)
  374. parameters->view->upload(view);
  375. if (parameters->view_projection)
  376. parameters->view_projection->upload(view_projection);
  377. if (parameters->ambient_light_count)
  378. parameters->ambient_light_count->upload(ambient_light_count);
  379. if (parameters->ambient_light_colors)
  380. parameters->ambient_light_colors->upload(0, ambient_light_colors, ambient_light_count);
  381. if (parameters->point_light_count)
  382. parameters->point_light_count->upload(point_light_count);
  383. if (parameters->point_light_colors)
  384. parameters->point_light_colors->upload(0, point_light_colors, point_light_count);
  385. if (parameters->point_light_positions)
  386. parameters->point_light_positions->upload(0, point_light_positions, point_light_count);
  387. if (parameters->point_light_attenuations)
  388. parameters->point_light_attenuations->upload(0, point_light_attenuations, point_light_count);
  389. if (parameters->directional_light_count)
  390. parameters->directional_light_count->upload(directional_light_count);
  391. if (parameters->directional_light_colors)
  392. parameters->directional_light_colors->upload(0, directional_light_colors, directional_light_count);
  393. if (parameters->directional_light_directions)
  394. parameters->directional_light_directions->upload(0, directional_light_directions, directional_light_count);
  395. if (parameters->spotlight_count)
  396. parameters->spotlight_count->upload(spotlight_count);
  397. if (parameters->spotlight_colors)
  398. parameters->spotlight_colors->upload(0, spotlight_colors, spotlight_count);
  399. if (parameters->spotlight_positions)
  400. parameters->spotlight_positions->upload(0, spotlight_positions, spotlight_count);
  401. if (parameters->spotlight_directions)
  402. parameters->spotlight_directions->upload(0, spotlight_directions, spotlight_count);
  403. if (parameters->spotlight_attenuations)
  404. parameters->spotlight_attenuations->upload(0, spotlight_attenuations, spotlight_count);
  405. if (parameters->spotlight_cutoffs)
  406. parameters->spotlight_cutoffs->upload(0, spotlight_cutoffs, spotlight_count);
  407. if (parameters->soft_shadows)
  408. parameters->soft_shadows->upload(soft_shadows_texture);
  409. if (parameters->focal_point)
  410. parameters->focal_point->upload(focal_point);
  411. if (parameters->shadow_map_matrices)
  412. parameters->shadow_map_matrices->upload(0, shadow_map_matrices, 4);
  413. if (parameters->shadow_map_split_distances)
  414. parameters->shadow_map_split_distances->upload(shadow_map_split_distances);
  415. if (parameters->shadow_map && shadow_map)
  416. parameters->shadow_map->upload(shadow_map);
  417. if (parameters->shadow_strength)
  418. parameters->shadow_strength->upload(shadow_strength);
  419. }
  420. // Upload material properties to shader
  421. active_material->upload(context->alpha);
  422. }
  423. // Calculate operation-dependent parameters
  424. model = operation.transform;
  425. model_view_projection = view_projection * model;
  426. model_view = view * model;
  427. normal_model_view = math::transpose(math::inverse(math::resize<3, 3>(model_view)));
  428. // Upload operation-dependent parameters
  429. if (parameters->model)
  430. parameters->model->upload(model);
  431. if (parameters->model_view)
  432. parameters->model_view->upload(model_view);
  433. if (parameters->model_view_projection)
  434. parameters->model_view_projection->upload(model_view_projection);
  435. if (parameters->normal_model_view)
  436. parameters->normal_model_view->upload(normal_model_view);
  437. if (parameters->clip_depth)
  438. parameters->clip_depth->upload(clip_depth);
  439. if (parameters->log_depth_coef)
  440. parameters->log_depth_coef->upload(log_depth_coef);
  441. // Draw geometry
  442. if (operation.instance_count)
  443. rasterizer->draw_arrays_instanced(*operation.vertex_array, operation.drawing_mode, operation.start_index, operation.index_count, operation.instance_count);
  444. else
  445. rasterizer->draw_arrays(*operation.vertex_array, operation.drawing_mode, operation.start_index, operation.index_count);
  446. }
  447. }
  448. void material_pass::set_fallback_material(const material* fallback)
  449. {
  450. this->fallback_material = fallback;
  451. }
  452. void material_pass::set_time_tween(const tween<double>* time)
  453. {
  454. this->time_tween = time;
  455. }
  456. void material_pass::set_shadow_strength(float strength)
  457. {
  458. this->shadow_strength = strength;
  459. }
  460. void material_pass::set_focal_point_tween(const tween<float3>* focal_point)
  461. {
  462. this->focal_point_tween = focal_point;
  463. }
  464. const material_pass::parameter_set* material_pass::load_parameter_set(const gl::shader_program* program) const
  465. {
  466. // Allocate a new parameter set
  467. parameter_set* parameters = new parameter_set();
  468. // Connect inputs
  469. parameters->time = program->get_input("time");
  470. parameters->mouse = program->get_input("mouse");
  471. parameters->resolution = program->get_input("resolution");
  472. parameters->model = program->get_input("model");
  473. parameters->view = program->get_input("view");
  474. parameters->projection = program->get_input("projection");
  475. parameters->model_view = program->get_input("model_view");
  476. parameters->view_projection = program->get_input("view_projection");
  477. parameters->model_view_projection = program->get_input("model_view_projection");
  478. parameters->normal_model_view = program->get_input("normal_model_view");
  479. parameters->clip_depth = program->get_input("clip_depth");
  480. parameters->log_depth_coef = program->get_input("log_depth_coef");
  481. parameters->ambient_light_count = program->get_input("ambient_light_count");
  482. parameters->ambient_light_colors = program->get_input("ambient_light_colors");
  483. parameters->point_light_count = program->get_input("point_light_count");
  484. parameters->point_light_colors = program->get_input("point_light_colors");
  485. parameters->point_light_positions = program->get_input("point_light_positions");
  486. parameters->point_light_attenuations = program->get_input("point_light_attenuations");
  487. parameters->directional_light_count = program->get_input("directional_light_count");
  488. parameters->directional_light_colors = program->get_input("directional_light_colors");
  489. parameters->directional_light_directions = program->get_input("directional_light_directions");
  490. parameters->spotlight_count = program->get_input("spotlight_count");
  491. parameters->spotlight_colors = program->get_input("spotlight_colors");
  492. parameters->spotlight_positions = program->get_input("spotlight_positions");
  493. parameters->spotlight_directions = program->get_input("spotlight_directions");
  494. parameters->spotlight_attenuations = program->get_input("spotlight_attenuations");
  495. parameters->spotlight_cutoffs = program->get_input("spotlight_cutoffs");
  496. parameters->soft_shadows = program->get_input("soft_shadows");
  497. parameters->focal_point = program->get_input("focal_point");
  498. parameters->shadow_map_matrices = program->get_input("shadow_map_matrices");
  499. parameters->shadow_map_split_distances = program->get_input("shadow_map_split_distances");
  500. parameters->shadow_map = program->get_input("shadow_map");
  501. parameters->shadow_strength = program->get_input("shadow_strength");
  502. // Add parameter set to map of parameter sets
  503. parameter_sets[program] = parameters;
  504. return parameters;
  505. }
  506. void material_pass::handle_event(const mouse_moved_event& event)
  507. {
  508. mouse_position = {static_cast<float>(event.x), static_cast<float>(event.y)};
  509. }
  510. bool operation_compare(const render_operation& a, const render_operation& b)
  511. {
  512. if (!a.material)
  513. return false;
  514. else if (!b.material)
  515. return true;
  516. bool xray_a = a.material->get_flags() & MATERIAL_FLAG_X_RAY;
  517. bool xray_b = b.material->get_flags() & MATERIAL_FLAG_X_RAY;
  518. if (xray_a)
  519. {
  520. if (xray_b)
  521. {
  522. // A and B are both xray, render back to front
  523. return (a.depth >= b.depth);
  524. }
  525. else
  526. {
  527. // A is xray, B is not. Render B first
  528. return false;
  529. }
  530. }
  531. else
  532. {
  533. if (xray_b)
  534. {
  535. // A is opaque, B is xray. Render A first
  536. return true;
  537. }
  538. else
  539. {
  540. // Determine transparency
  541. bool transparent_a = a.material->get_flags() & MATERIAL_FLAG_TRANSLUCENT;
  542. bool transparent_b = b.material->get_flags() & MATERIAL_FLAG_TRANSLUCENT;
  543. if (transparent_a)
  544. {
  545. if (transparent_b)
  546. {
  547. // Determine decal status
  548. bool decal_a = a.material->get_flags() & MATERIAL_FLAG_DECAL;
  549. bool decal_b = b.material->get_flags() & MATERIAL_FLAG_DECAL;
  550. if (decal_a)
  551. {
  552. if (decal_b)
  553. {
  554. // A and B are both transparent decals, render back to front
  555. return (a.depth >= b.depth);
  556. }
  557. else
  558. {
  559. // A is a transparent decal, B is transparent but not a decal, render A first
  560. return true;
  561. }
  562. }
  563. else
  564. {
  565. if (decal_b)
  566. {
  567. // A is transparent but not a decal, B is a transparent decal, render B first
  568. return false;
  569. }
  570. else
  571. {
  572. // A and B are both transparent, but not decals, render back to front
  573. return (a.depth >= b.depth);
  574. }
  575. }
  576. }
  577. else
  578. {
  579. // A is transparent, B is opaque. Render B first
  580. return false;
  581. }
  582. }
  583. else
  584. {
  585. if (transparent_b)
  586. {
  587. // A is opaque, B is transparent. Render A first
  588. return true;
  589. }
  590. else
  591. {
  592. // A and B are both opaque
  593. if (a.material->get_shader_program() == b.material->get_shader_program())
  594. {
  595. // A and B have the same shader
  596. if (a.vertex_array == b.vertex_array)
  597. {
  598. // A and B have the same VAO, render front to back
  599. return (a.depth < b.depth);
  600. }
  601. else
  602. {
  603. // Sort by VAO
  604. return (a.vertex_array < b.vertex_array);
  605. }
  606. }
  607. else
  608. {
  609. // A and B are both opaque and have different shaders, sort by shader
  610. return (a.material->get_shader_program() < b.material->get_shader_program());
  611. }
  612. }
  613. }
  614. }
  615. }
  616. }