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

262 lines
6.7 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.hpp"
  20. #include "entity/components/transform.hpp"
  21. #include "renderer/renderer.hpp"
  22. #include "scene/point-light.hpp"
  23. #include "scene/directional-light.hpp"
  24. #include "scene/ambient-light.hpp"
  25. #include "scene/spot-light.hpp"
  26. #include <iostream>
  27. namespace entity {
  28. namespace system {
  29. render::render(entity::registry& registry):
  30. updatable(registry),
  31. renderer(nullptr)
  32. {
  33. registry.on_construct<component::model>().connect<&render::on_model_construct>(this);
  34. registry.on_replace<component::model>().connect<&render::on_model_replace>(this);
  35. registry.on_destroy<component::model>().connect<&render::on_model_destroy>(this);
  36. registry.on_construct<component::light>().connect<&render::on_light_construct>(this);
  37. registry.on_replace<component::light>().connect<&render::on_light_replace>(this);
  38. registry.on_destroy<component::light>().connect<&render::on_light_destroy>(this);
  39. }
  40. void render::update(double t, double dt)
  41. {
  42. // Update model instance transforms
  43. registry.view<component::transform, component::model>().each
  44. (
  45. [this](entity::id entity_id, auto& transform, auto& model)
  46. {
  47. scene::model_instance* instance = model_instances[entity_id];
  48. instance->set_transform(transform.world);
  49. if (transform.warp)
  50. {
  51. instance->get_transform_tween().update();
  52. instance->update_tweens();
  53. transform.warp = false;
  54. }
  55. }
  56. );
  57. // Update light transforms
  58. registry.view<component::transform, component::light>().each
  59. (
  60. [this](entity::id entity_id, auto& transform, auto& light)
  61. {
  62. scene::light* light_object = lights[entity_id];
  63. light_object->set_transform(transform.world);
  64. if (transform.warp)
  65. {
  66. light_object->get_transform_tween().update();
  67. light_object->update_tweens();
  68. transform.warp = false;
  69. }
  70. }
  71. );
  72. }
  73. void render::draw(double alpha)
  74. {
  75. if (renderer)
  76. {
  77. for (const scene::collection* collection: layers)
  78. {
  79. renderer->render(alpha, *collection);
  80. }
  81. }
  82. }
  83. void render::add_layer(scene::collection* layer)
  84. {
  85. layers.push_back(layer);
  86. }
  87. void render::remove_layers()
  88. {
  89. layers.clear();
  90. }
  91. void render::set_renderer(::renderer* renderer)
  92. {
  93. this->renderer = renderer;
  94. }
  95. scene::model_instance* render::get_model_instance(entity::id entity_id)
  96. {
  97. if (auto it = model_instances.find(entity_id); it != model_instances.end())
  98. return it->second;
  99. return nullptr;
  100. }
  101. scene::light* render::get_light(entity::id entity_id)
  102. {
  103. if (auto it = lights.find(entity_id); it != lights.end())
  104. return it->second;
  105. return nullptr;
  106. }
  107. void render::update_model_and_materials(entity::id entity_id, component::model& model)
  108. {
  109. if (auto model_it = model_instances.find(entity_id); model_it != model_instances.end())
  110. {
  111. model_it->second->set_model(model.render_model);
  112. model_it->second->set_instanced((model.instance_count > 0), model.instance_count);
  113. for (auto material_it = model.materials.begin(); material_it != model.materials.end(); ++material_it)
  114. {
  115. model_it->second->set_material(material_it->first, material_it->second);
  116. }
  117. // Add model instance to its specified layers
  118. for (std::size_t i = 0; i < std::min<std::size_t>(layers.size(), (sizeof(model.layers) << 3)); ++i)
  119. {
  120. layers[i]->remove_object(model_it->second);
  121. if ((model.layers >> i) & 1)
  122. {
  123. layers[i]->add_object(model_it->second);
  124. }
  125. }
  126. }
  127. }
  128. void render::update_light(entity::id entity_id, entity::component::light& component)
  129. {
  130. if (auto light_it = lights.find(entity_id); light_it != lights.end())
  131. {
  132. scene::light* light = light_it->second;
  133. light->set_color(component.color);
  134. light->set_intensity(component.intensity);
  135. switch (light->get_light_type())
  136. {
  137. case scene::light_type::point:
  138. {
  139. scene::point_light* point = static_cast<scene::point_light*>(light);
  140. point->set_attenuation(component.attenuation);
  141. break;
  142. }
  143. case scene::light_type::spot:
  144. {
  145. scene::spot_light* spot = static_cast<scene::spot_light*>(light);
  146. spot->set_attenuation(component.attenuation);
  147. spot->set_cutoff(component.cutoff);
  148. break;
  149. }
  150. default:
  151. break;
  152. }
  153. }
  154. }
  155. void render::on_model_construct(entity::registry& registry, entity::id entity_id, component::model& model)
  156. {
  157. scene::model_instance* model_instance = new scene::model_instance();
  158. model_instances[entity_id] = model_instance;
  159. update_model_and_materials(entity_id, model);
  160. }
  161. void render::on_model_replace(entity::registry& registry, entity::id entity_id, component::model& model)
  162. {
  163. update_model_and_materials(entity_id, model);
  164. }
  165. void render::on_model_destroy(entity::registry& registry, entity::id entity_id)
  166. {
  167. if (auto it = model_instances.find(entity_id); it != model_instances.end())
  168. {
  169. scene::model_instance* model_instance = it->second;
  170. // Remove model instance from all layers
  171. for (scene::collection* layer: layers)
  172. layer->remove_object(model_instance);
  173. model_instances.erase(it);
  174. delete model_instance;
  175. }
  176. }
  177. void render::on_light_construct(entity::registry& registry, entity::id entity_id, component::light& component)
  178. {
  179. scene::light* light = nullptr;
  180. switch (component.type)
  181. {
  182. case scene::light_type::ambient:
  183. light = new scene::ambient_light();
  184. break;
  185. case scene::light_type::directional:
  186. light = new scene::directional_light();
  187. break;
  188. case scene::light_type::point:
  189. light = new scene::point_light();
  190. break;
  191. case scene::light_type::spot:
  192. light = new scene::spot_light();
  193. break;
  194. default:
  195. break;
  196. }
  197. if (light)
  198. {
  199. lights[entity_id] = light;
  200. for (scene::collection* layer: layers)
  201. layer->add_object(light);
  202. update_light(entity_id, component);
  203. }
  204. }
  205. void render::on_light_replace(entity::registry& registry, entity::id entity_id, component::light& light)
  206. {
  207. update_light(entity_id, light);
  208. }
  209. void render::on_light_destroy(entity::registry& registry, entity::id entity_id)
  210. {
  211. if (auto it = lights.find(entity_id); it != lights.end())
  212. {
  213. scene::light* light = it->second;
  214. for (scene::collection* layer: layers)
  215. layer->remove_object(light);
  216. lights.erase(it);
  217. delete light;
  218. }
  219. }
  220. } // namespace system
  221. } // namespace entity