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

689 lines
23 KiB

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