Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

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