No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

414 líneas
14 KiB

  1. use std::cell::RefCell;
  2. use std::mem::{size_of, swap};
  3. use std::rc::Rc;
  4. use glc::{
  5. buffer::{Buffer, Usage},
  6. misc::{BindGuard, Bindable},
  7. shader::{Program, TransformFeedbackVaryingsMode, Type, Uniform},
  8. texture::Texture,
  9. transform_feedback::TransformFeedback,
  10. vector::{Vector2f, Vector3f},
  11. vertex_array::{DataType, VertexArray},
  12. };
  13. use space_crush_common::{
  14. components::{Player, PlayerOwned, Position, Ship, ShipType, Velocity},
  15. misc::{ComponentEvent, LogResult, StorageHelper, StorageHelperMut},
  16. };
  17. use specs::{
  18. hibitset::{BitSet, BitSetAll, BitSetLike},
  19. prelude::*,
  20. world::Index as Id,
  21. ReadStorage, System, World,
  22. };
  23. use crate::{
  24. constants::{PLAYER_COLOR_DEFAULT, UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM},
  25. misc::WorldHelper,
  26. Error,
  27. };
  28. pub struct Ships {
  29. program_ship: Program,
  30. program_tail_update: Program,
  31. program_tail_render: Program,
  32. ship_data: BufferRef,
  33. ship_render: VertexArray<BufferRef>,
  34. input: TailObjects,
  35. output: TailObjects,
  36. texture_bomber: Texture,
  37. texture_fighter: Texture,
  38. texture_transporter: Texture,
  39. reader_id: ReaderId<ComponentEvent<Ship>>,
  40. need_init: BitSet,
  41. id_to_index: Vec<u32>,
  42. index_to_id: Vec<Id>,
  43. }
  44. #[derive(SystemData)]
  45. pub struct ShipsData<'a> {
  46. positions: ReadStorage<'a, Position>,
  47. velocities: ReadStorage<'a, Velocity>,
  48. players: ReadStorage<'a, Player>,
  49. owned: ReadStorage<'a, PlayerOwned>,
  50. ships: ReadStorage<'a, Ship>,
  51. }
  52. struct TailObjects {
  53. tail_data: BufferRef,
  54. tail_update: VertexArray<BufferRef>,
  55. tail_render: VertexArray<BufferRef>,
  56. transform_feedback: TransformFeedback<BufferRef>,
  57. }
  58. type BufferRef = Rc<RefCell<Buffer>>;
  59. #[repr(C, packed)]
  60. struct ShipData {
  61. pos: Vector2f,
  62. dir: Vector2f,
  63. color: Vector3f,
  64. texture: gl::GLint,
  65. }
  66. #[repr(C, packed)]
  67. #[derive(Debug)]
  68. struct TailData {
  69. pos: [Vector2f; 5],
  70. }
  71. impl Ships {
  72. pub fn new(world: &World) -> Result<Self, Error> {
  73. /* program ship */
  74. let program_ship = world.load_program(vec![
  75. (Type::Vertex, SHDR_SHIP_VERT),
  76. (Type::Geometry, SHDR_SHIP_GEOM),
  77. (Type::Fragment, SHDR_SHIP_FRAG),
  78. ])?;
  79. program_ship.uniform_block_binding("Camera", UNIFORM_BUFFER_INDEX_CAMERA)?;
  80. program_ship.uniform_block_binding("Global", UNIFORM_BUFFER_INDEX_UNIFORM)?;
  81. program_ship.bind();
  82. program_ship.uniform("uTexture", Uniform::TextureVec(&[0, 1, 2]))?;
  83. program_ship.unbind();
  84. /* program tail update */
  85. let program_tail_update = Program::builder()
  86. .add_shader(world.load_shader(Type::Vertex, SHDR_TAIL_UPDATE_VERT)?)
  87. .add_shader(world.load_shader(Type::Geometry, SHDR_TAIL_UPDATE_GEOM)?)
  88. .set_transform_feedback_varyings(
  89. TransformFeedbackVaryingsMode::Interleaved,
  90. SHDR_TAIL_VARYINGS,
  91. )
  92. .build()?;
  93. program_tail_update.uniform_block_binding("Global", UNIFORM_BUFFER_INDEX_UNIFORM)?;
  94. /* program tail render */
  95. let program_tail_render = world.load_program(vec![
  96. (Type::Vertex, SHDR_TAIL_RENDER_VERT),
  97. (Type::Geometry, SHDR_TAIL_RENDER_GEOM),
  98. (Type::Fragment, SHDR_TAIL_RENDER_FRAG),
  99. ])?;
  100. program_tail_render.uniform_block_binding("Camera", UNIFORM_BUFFER_INDEX_CAMERA)?;
  101. /* ship data */
  102. let ship_data = Rc::new(RefCell::new(Buffer::new()?));
  103. /* vertex array ship */
  104. let ship_render = VertexArray::builder()
  105. .bind_buffer(ship_data.clone())
  106. .vertex_attrib_pointer(0, 2, DataType::Float, false, SHIP_STRIDE, SHIP_OFFSET_POS)?
  107. .vertex_attrib_pointer(1, 2, DataType::Float, false, SHIP_STRIDE, SHIP_OFFSET_DIR)?
  108. .vertex_attrib_pointer(2, 3, DataType::Float, false, SHIP_STRIDE, SHIP_OFFSET_CLR)?
  109. .vertex_attrib_pointer(3, 1, DataType::Int, false, SHIP_STRIDE, SHIP_OFFSET_TEX)?
  110. .build()?;
  111. /* tail objects */
  112. let input = TailObjects::new(&ship_data)?;
  113. let output = TailObjects::new(&ship_data)?;
  114. /* textures */
  115. let texture_bomber = world.load_texture("resources/textures/ship_bomber.png")?;
  116. let texture_fighter = world.load_texture("resources/textures/ship_fighter.png")?;
  117. let texture_transporter = world.load_texture("resources/textures/ship_transporter.png")?;
  118. /* event readers */
  119. let reader_id = world
  120. .system_data::<WriteStorage<Ship>>()
  121. .register_event_reader();
  122. /* rest */
  123. let need_init = BitSet::new();
  124. let id_to_index = Vec::new();
  125. let index_to_id = Vec::new();
  126. Ok(Self {
  127. program_ship,
  128. program_tail_update,
  129. program_tail_render,
  130. ship_data,
  131. ship_render,
  132. input,
  133. output,
  134. texture_bomber,
  135. texture_fighter,
  136. texture_transporter,
  137. reader_id,
  138. need_init,
  139. id_to_index,
  140. index_to_id,
  141. })
  142. }
  143. fn handle_events(&mut self, d: &ShipsData<'_>) {
  144. self.need_init.clear();
  145. let events = d.ships.channel().read(&mut self.reader_id);
  146. for event in events {
  147. match event {
  148. ComponentEvent::Inserted(id, _) => self.add_ship(*id),
  149. ComponentEvent::Removed(id, _) => self.remove_ship(*id),
  150. ComponentEvent::Modified(_, _) => {
  151. unreachable!("Updates of the ship component should not be tracked!")
  152. }
  153. }
  154. }
  155. }
  156. fn update_vertices(&self, d: &ShipsData<'_>) {
  157. let mut borrow_ship = self.ship_data.borrow_mut();
  158. let mut buf_ship = borrow_ship
  159. .map_mut::<ShipData>(true)
  160. .panic("Unable to map buffer for ship data");
  161. let ids = BitSetAll;
  162. let data = (
  163. &ids as &dyn BitSetLike,
  164. &d.positions,
  165. &d.velocities,
  166. &d.ships,
  167. d.owned.maybe(),
  168. );
  169. for (id, position, velocity, ship, owned) in data.join() {
  170. let index = self.id_to_index[id as usize];
  171. let mut s = &mut buf_ship[index as usize];
  172. s.pos = *position.pos();
  173. s.dir = *velocity.dir();
  174. if self.need_init.contains(id) {
  175. s.color = match owned.and_then(|owned| d.players.get(owned.owner())) {
  176. Some(pv) => *pv.color(),
  177. None => PLAYER_COLOR_DEFAULT,
  178. };
  179. s.texture = match ship.type_() {
  180. ShipType::Fighter => 0,
  181. ShipType::Bomber => 1,
  182. ShipType::Transporter => 2,
  183. };
  184. let mut pos = *position.pos();
  185. let mut borrow_tail = self.input.tail_data.borrow_mut();
  186. let mut buf_tail = borrow_tail
  187. .map_mut::<TailData>(true)
  188. .panic("Unable to map buffer for tail data");
  189. for p in &mut buf_tail[index as usize].pos {
  190. pos -= Vector2f::new(10.0, 0.0);
  191. *p = pos;
  192. }
  193. }
  194. }
  195. }
  196. fn update_tail(&mut self) {
  197. let guard_prog = BindGuard::new(&self.program_tail_update);
  198. let guard_trfm = BindGuard::new(&self.output.transform_feedback);
  199. let guard_data = BindGuard::new(&self.input.tail_update);
  200. gl::enable(gl::RASTERIZER_DISCARD);
  201. gl::begin_transform_feedback(gl::POINTS);
  202. gl::draw_arrays(gl::POINTS, 0, self.index_to_id.len() as _);
  203. gl::end_transform_feedback();
  204. gl::disable(gl::RASTERIZER_DISCARD);
  205. drop(guard_trfm);
  206. drop(guard_data);
  207. drop(guard_prog);
  208. swap(&mut self.input, &mut self.output);
  209. }
  210. fn render_tails(&self) {
  211. let _guard = BindGuard::new(&self.program_tail_render);
  212. let _guard = BindGuard::new(&self.input.tail_render);
  213. gl::enable(gl::BLEND);
  214. gl::blend_func(gl::SRC_ALPHA, gl::ONE);
  215. gl::draw_arrays(gl::POINTS, 0, self.index_to_id.len() as _);
  216. gl::disable(gl::BLEND);
  217. }
  218. fn render_ships(&self) {
  219. let _guard = BindGuard::new(&self.program_ship);
  220. let _guard = BindGuard::new(&self.ship_render);
  221. gl::active_texture(gl::TEXTURE2);
  222. let _guard = BindGuard::new(&self.texture_transporter);
  223. gl::active_texture(gl::TEXTURE1);
  224. let _guard = BindGuard::new(&self.texture_bomber);
  225. gl::active_texture(gl::TEXTURE0);
  226. let _guard = BindGuard::new(&self.texture_fighter);
  227. gl::enable(gl::BLEND);
  228. gl::blend_func(gl::SRC_ALPHA, gl::ONE);
  229. gl::draw_arrays(gl::POINTS, 0, self.index_to_id.len() as _);
  230. gl::disable(gl::BLEND);
  231. }
  232. fn add_ship(&mut self, id: Id) {
  233. /* store id */
  234. self.need_init.add(id);
  235. let id = id as usize;
  236. if self.id_to_index.len() <= id {
  237. self.id_to_index.resize_with(id + 1, Default::default);
  238. }
  239. let index = self.index_to_id.len();
  240. if self.index_to_id.len() <= index {
  241. self.index_to_id.resize_with(index + 1, Default::default);
  242. }
  243. self.id_to_index[id] = index as u32;
  244. self.index_to_id[index] = id as u32;
  245. /* update ship buffer */
  246. let size = size_of::<TailData>() * self.index_to_id.len();
  247. let mut buffer = self.ship_data.borrow_mut();
  248. if size > buffer.size() {
  249. buffer
  250. .buffer_size(Usage::DynamicDraw, size)
  251. .panic("Unable to change buffer size for ship data");
  252. }
  253. /* update tail buffer */
  254. let size = size_of::<TailData>() * self.index_to_id.len();
  255. let mut buffer = self.input.tail_data.borrow_mut();
  256. if size > buffer.size() {
  257. buffer
  258. .buffer_size(Usage::DynamicDraw, size)
  259. .panic("Unable to change buffer size for input tail data");
  260. }
  261. let mut buffer = self.output.tail_data.borrow_mut();
  262. if size > buffer.size() {
  263. buffer
  264. .buffer_size(Usage::DynamicDraw, size)
  265. .panic("Unable to change buffer size for output tail data");
  266. }
  267. }
  268. fn remove_ship(&mut self, id: Id) {
  269. let _id = id;
  270. // TODO
  271. }
  272. }
  273. impl<'a> System<'a> for Ships {
  274. type SystemData = ShipsData<'a>;
  275. fn run(&mut self, data: Self::SystemData) {
  276. self.handle_events(&data);
  277. self.update_vertices(&data);
  278. self.update_tail();
  279. self.render_tails();
  280. self.render_ships();
  281. }
  282. }
  283. impl TailObjects {
  284. fn new(ship_data: &BufferRef) -> Result<Self, Error> {
  285. /* tail data */
  286. let tail_data = Rc::new(RefCell::new(Buffer::new()?));
  287. tail_data
  288. .borrow_mut()
  289. .buffer_size(Usage::DynamicDraw, size_of::<TailData>() as _)?;
  290. /* vertex array tail update */
  291. let tail_update = VertexArray::builder()
  292. .bind_buffer(ship_data.clone())
  293. .vertex_attrib_pointer(0, 2, DataType::Float, false, SHIP_STRIDE, SHIP_OFFSET_POS)?
  294. .bind_buffer(tail_data.clone())
  295. .vertex_attrib_pointer(1, 2, DataType::Float, false, TAIL_STRIDE, TAIL_OFFSET_TL0)?
  296. .vertex_attrib_pointer(2, 2, DataType::Float, false, TAIL_STRIDE, TAIL_OFFSET_TL1)?
  297. .vertex_attrib_pointer(3, 2, DataType::Float, false, TAIL_STRIDE, TAIL_OFFSET_TL2)?
  298. .vertex_attrib_pointer(4, 2, DataType::Float, false, TAIL_STRIDE, TAIL_OFFSET_TL3)?
  299. .vertex_attrib_pointer(5, 2, DataType::Float, false, TAIL_STRIDE, TAIL_OFFSET_TL4)?
  300. .build()?;
  301. /* vertex array tail render */
  302. let tail_render = VertexArray::builder()
  303. .bind_buffer(ship_data.clone())
  304. .vertex_attrib_pointer(0, 3, DataType::Float, false, SHIP_STRIDE, SHIP_OFFSET_CLR)?
  305. .bind_buffer(tail_data.clone())
  306. .vertex_attrib_pointer(1, 2, DataType::Float, false, TAIL_STRIDE, TAIL_OFFSET_TL0)?
  307. .vertex_attrib_pointer(2, 2, DataType::Float, false, TAIL_STRIDE, TAIL_OFFSET_TL1)?
  308. .vertex_attrib_pointer(3, 2, DataType::Float, false, TAIL_STRIDE, TAIL_OFFSET_TL2)?
  309. .vertex_attrib_pointer(4, 2, DataType::Float, false, TAIL_STRIDE, TAIL_OFFSET_TL3)?
  310. .vertex_attrib_pointer(5, 2, DataType::Float, false, TAIL_STRIDE, TAIL_OFFSET_TL4)?
  311. .build()?;
  312. /* transform feedback buffer */
  313. let transform_feedback = TransformFeedback::builder()
  314. .bind_buffer(0, tail_data.clone())?
  315. .build()?;
  316. Ok(Self {
  317. tail_data,
  318. tail_update,
  319. tail_render,
  320. transform_feedback,
  321. })
  322. }
  323. }
  324. const SHDR_SHIP_VERT: &str = "resources/shader/ship/ship_vert.glsl";
  325. const SHDR_SHIP_GEOM: &str = "resources/shader/ship/ship_geom.glsl";
  326. const SHDR_SHIP_FRAG: &str = "resources/shader/ship/ship_frag.glsl";
  327. const SHDR_TAIL_UPDATE_VERT: &str = "resources/shader/ship/tail_update_vert.glsl";
  328. const SHDR_TAIL_UPDATE_GEOM: &str = "resources/shader/ship/tail_update_geom.glsl";
  329. const SHDR_TAIL_VARYINGS: &[&str] = &["outTail0", "outTail1", "outTail2", "outTail3", "outTail4"];
  330. const SHDR_TAIL_RENDER_VERT: &str = "resources/shader/ship/tail_render_vert.glsl";
  331. const SHDR_TAIL_RENDER_GEOM: &str = "resources/shader/ship/tail_render_geom.glsl";
  332. const SHDR_TAIL_RENDER_FRAG: &str = "resources/shader/ship/tail_render_frag.glsl";
  333. const SHIP_STRIDE: gl::GLsizei = size_of::<ShipData>() as gl::GLsizei;
  334. const SHIP_OFFSET_POS: gl::GLsizei = 0;
  335. const SHIP_OFFSET_DIR: gl::GLsizei = SHIP_OFFSET_POS + size_of::<Vector2f>() as gl::GLsizei;
  336. const SHIP_OFFSET_CLR: gl::GLsizei = SHIP_OFFSET_DIR + size_of::<Vector2f>() as gl::GLsizei;
  337. const SHIP_OFFSET_TEX: gl::GLsizei = SHIP_OFFSET_CLR + size_of::<Vector3f>() as gl::GLsizei;
  338. const TAIL_STRIDE: gl::GLsizei = size_of::<TailData>() as gl::GLsizei;
  339. const TAIL_OFFSET_TL0: gl::GLsizei = 0;
  340. const TAIL_OFFSET_TL1: gl::GLsizei = TAIL_OFFSET_TL0 + size_of::<Vector2f>() as gl::GLsizei;
  341. const TAIL_OFFSET_TL2: gl::GLsizei = TAIL_OFFSET_TL1 + size_of::<Vector2f>() as gl::GLsizei;
  342. const TAIL_OFFSET_TL3: gl::GLsizei = TAIL_OFFSET_TL2 + size_of::<Vector2f>() as gl::GLsizei;
  343. const TAIL_OFFSET_TL4: gl::GLsizei = TAIL_OFFSET_TL3 + size_of::<Vector2f>() as gl::GLsizei;