Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

166 linhas
5.1 KiB

  1. use std::mem::size_of;
  2. use glc::{
  3. buffer::{Buffer, Usage},
  4. misc::{BindGuard, Bindable},
  5. shader::{Program, Type, Uniform},
  6. texture::Texture,
  7. vector::{Vector2f, Vector3f},
  8. vertex_array::{DataType, VertexArray},
  9. };
  10. use space_crush_common::{
  11. components::{Planet, Player, PlayerOwned, Position},
  12. misc::{ComponentEvent, LogResult, StorageHelper, StorageHelperMut},
  13. };
  14. use specs::{prelude::*, ReadStorage, System, World};
  15. use crate::{
  16. constants::{
  17. PLANET_SIZE, PLAYER_COLOR_DEFAULT, UNIFORM_BUFFER_INDEX_CAMERA,
  18. UNIFORM_BUFFER_INDEX_UNIFORM,
  19. },
  20. misc::WorldHelper,
  21. Error,
  22. };
  23. pub struct Planets {
  24. program: Program,
  25. texture: Texture,
  26. vertex_array: VertexArray,
  27. reader_id: ReaderId<ComponentEvent<Planet>>,
  28. planet_count: usize,
  29. }
  30. #[repr(C, packed)]
  31. struct VertexData {
  32. pos: Vector2f,
  33. size: gl::GLfloat,
  34. color: Vector3f,
  35. }
  36. impl Planets {
  37. pub fn new(world: &mut World) -> Result<Self, Error> {
  38. WriteStorage::<Planet>::setup(world);
  39. let program = world.load_program(vec![
  40. (Type::Vertex, "resources/shader/planet/vert.glsl"),
  41. (Type::Geometry, "resources/shader/planet/geom.glsl"),
  42. (Type::Fragment, "resources/shader/planet/frag.glsl"),
  43. ])?;
  44. program.uniform_block_binding("Camera", UNIFORM_BUFFER_INDEX_CAMERA)?;
  45. program.uniform_block_binding("Global", UNIFORM_BUFFER_INDEX_UNIFORM)?;
  46. program.bind();
  47. program.uniform("uTexture", Uniform::Texture(0))?;
  48. program.unbind();
  49. let texture = world.load_texture("resources/textures/planet01.png")?;
  50. const STRIDE: gl::GLsizei = size_of::<VertexData>() as gl::GLsizei;
  51. const OFFSET_POS: gl::GLsizei = 0;
  52. const OFFSET_SIZ: gl::GLsizei = OFFSET_POS + size_of::<Vector2f>() as gl::GLsizei;
  53. const OFFSET_CLR: gl::GLsizei = OFFSET_SIZ + size_of::<gl::GLfloat>() as gl::GLsizei;
  54. let vertex_array = VertexArray::builder()
  55. .bind_buffer(Buffer::new()?)
  56. .vertex_attrib_pointer(0, 2, DataType::Float, false, STRIDE, OFFSET_POS)?
  57. .vertex_attrib_pointer(1, 1, DataType::Float, false, STRIDE, OFFSET_SIZ)?
  58. .vertex_attrib_pointer(2, 3, DataType::Float, false, STRIDE, OFFSET_CLR)?
  59. .build()?;
  60. let reader_id = world
  61. .system_data::<WriteStorage<Planet>>()
  62. .register_event_reader();
  63. let planet_count = 0;
  64. Ok(Self {
  65. program,
  66. texture,
  67. vertex_array,
  68. reader_id,
  69. planet_count,
  70. })
  71. }
  72. }
  73. #[derive(SystemData)]
  74. pub struct PlanetsData<'a> {
  75. positions: ReadStorage<'a, Position>,
  76. planets: ReadStorage<'a, Planet>,
  77. players: ReadStorage<'a, Player>,
  78. owned: ReadStorage<'a, PlayerOwned>,
  79. }
  80. impl<'a> System<'a> for Planets {
  81. type SystemData = PlanetsData<'a>;
  82. fn run(&mut self, data: Self::SystemData) {
  83. let PlanetsData {
  84. positions,
  85. planets,
  86. players,
  87. owned,
  88. } = data;
  89. /* handle events */
  90. let mut need_update = false;
  91. let events = planets.channel().read(&mut self.reader_id);
  92. for event in events {
  93. match event {
  94. ComponentEvent::Inserted(_, _) => {
  95. need_update = true;
  96. self.planet_count += 1;
  97. }
  98. ComponentEvent::Removed(_, _) => {
  99. need_update = true;
  100. self.planet_count -= 1;
  101. }
  102. ComponentEvent::Modified(_, _) => {
  103. unreachable!("Updates of the planet component should not be tracked!")
  104. }
  105. }
  106. }
  107. /* update vertex array */
  108. let buffer = &mut self.vertex_array.buffers_mut()[0];
  109. if need_update {
  110. buffer
  111. .buffer_size(
  112. Usage::StaticDraw,
  113. self.planet_count * size_of::<VertexData>(),
  114. )
  115. .panic("Unable to change buffer size for planet data");
  116. let data = (&positions, &planets, owned.maybe());
  117. let mut buffer = buffer
  118. .map_mut::<VertexData>(true)
  119. .panic("Unable to map buffer for planet data");
  120. for (i, (position, _, owned)) in data.join().enumerate() {
  121. let mut d = &mut buffer[i];
  122. d.pos = *position.pos();
  123. d.size = position.shape().circle().unwrap_or(PLANET_SIZE);
  124. d.color = match owned.and_then(|owned| players.get(owned.owner())) {
  125. Some(pv) => *pv.color(),
  126. None => PLAYER_COLOR_DEFAULT,
  127. };
  128. }
  129. }
  130. /* render planets */
  131. let _guard = BindGuard::new(&self.program);
  132. let _guard = BindGuard::new(&self.vertex_array);
  133. let _guard = BindGuard::new(&self.texture);
  134. gl::enable(gl::BLEND);
  135. gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
  136. gl::draw_arrays(gl::POINTS, 0, self.planet_count as _);
  137. gl::disable(gl::BLEND);
  138. }
  139. }