An unofficial collection of APIs used in FreeJam games and mods
Você não pode selecionar mais de 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.

123 linhas
5.0KB

  1. use genmesh::{generators::Cube, Quad, MapToVertices, Vertices, Vertex};
  2. use obj;
  3. use cgmath::{Quaternion, Euler, Deg, Vector3};
  4. use crate::robocraft;
  5. const SCALE: f32 = 0.5;
  6. const ROTATIONS: [Euler<Deg<f32>>; 24] = [
  7. Euler{x: Deg(0.0), y: Deg(0.0), z: Deg(0.0)}, // 0
  8. Euler{x: Deg(0.0), y: Deg(0.0), z: Deg(90.0)},
  9. Euler{x: Deg(0.0), y: Deg(0.0), z: Deg(180.0)}, // 2
  10. Euler{x: Deg(0.0), y: Deg(0.0), z: Deg(-90.0)},
  11. Euler{x: Deg(0.0), y: Deg(90.0), z: Deg(0.0)}, // 4
  12. Euler{x: Deg(0.0), y: Deg(90.0), z: Deg(90.0)},
  13. Euler{x: Deg(-90.0), y: Deg(-90.0), z: Deg(0.0)}, // 6
  14. Euler{x: Deg(0.0), y: Deg(90.0), z: Deg(-90.0)},
  15. Euler{x: Deg(0.0), y: Deg(-90.0), z: Deg(90.0)}, // 8
  16. Euler{x: Deg(0.0), y: Deg(-90.0), z: Deg(-90.0)},
  17. Euler{x: Deg(90.0), y: Deg(-90.0), z: Deg(0.0)}, // 10
  18. Euler{x: Deg(90.0), y: Deg(90.0), z: Deg(0.0)},
  19. Euler{x: Deg(-90.0), y: Deg(90.0), z: Deg(0.0)}, // 12
  20. Euler{x: Deg(0.0), y: Deg(90.0), z: Deg(180.0)},
  21. Euler{x: Deg(0.0), y: Deg(180.0), z: Deg(0.0)}, // 14
  22. Euler{x: Deg(0.0), y: Deg(180.0), z: Deg(90.0)},
  23. Euler{x: Deg(0.0), y: Deg(180.0), z: Deg(0.0)}, // 16
  24. Euler{x: Deg(0.0), y: Deg(180.0), z: Deg(180.0)},
  25. Euler{x: Deg(0.0), y: Deg(-90.0), z: Deg(-90.0)}, // 18
  26. Euler{x: Deg(0.0), y: Deg(-90.0), z: Deg(0.0)},
  27. Euler{x: Deg(90.0), y: Deg(0.0), z: Deg(180.0)}, // 20
  28. Euler{x: Deg(90.0), y: Deg(180.0), z: Deg(0.0)},
  29. Euler{x: Deg(-90.0), y: Deg(0.0), z: Deg(0.0)}, // 22
  30. Euler{x: Deg(-90.0), y: Deg(180.0), z: Deg(0.0)}, // 23
  31. ];
  32. /// Convert a Robocraft robot's orientation enum into a physical rotation
  33. pub fn cube_rotation_to_quat(orientation: u8) -> Quaternion<f32> {
  34. ROTATIONS[orientation as usize].into()
  35. }
  36. /// Convert a Robocraft robot to a 3D model in Wavefront OBJ format.
  37. pub fn cubes_to_model(robot: robocraft::Cubes) -> obj::Obj {
  38. cubes_to_model_with_lut(robot, default_model_lut)
  39. }
  40. /// Convert a Robocraft robot to a 3D model in Wavefront OBJ format using the provided lookup table function.
  41. pub fn cubes_to_model_with_lut<F: FnMut(u32) -> Vec<Quad<Vertex>>>(robot: robocraft::Cubes, mut lut: F) -> obj::Obj {
  42. let mut positions = Vec::<[f32; 3]>::new(); // vertex positions
  43. let mut normals = Vec::<[f32; 3]>::new(); // vertex normals
  44. let mut objects = Vec::<obj::Object>::new(); // blocks
  45. let mut last = 0;
  46. for cube in robot.into_iter() {
  47. // generate simple cube for every block
  48. // TODO rotate blocks
  49. let vertices = lut(cube.id); // Use lookup table to find correct id <-> block translation
  50. let rotation: Quaternion<_> = cube_rotation_to_quat(cube.orientation);
  51. positions.extend::<Vec::<[f32; 3]>>(
  52. vertices.clone().into_iter().vertex(|v|
  53. {
  54. let rotated = rotation * Vector3{x: v.pos.x * SCALE, y: v.pos.y * SCALE, z: v.pos.z * SCALE};
  55. [rotated.x + (cube.x as f32), rotated.y + (cube.y as f32), rotated.z + (cube.z as f32)]
  56. })
  57. .vertices()
  58. .collect()
  59. );
  60. normals.extend::<Vec::<[f32; 3]>>(
  61. vertices.clone().into_iter().vertex(|v|
  62. {
  63. let rotated = rotation * Vector3{x: v.normal.x * SCALE, y: v.normal.y * SCALE, z: v.normal.z * SCALE};
  64. [rotated.x + (cube.x as f32), rotated.y + (cube.y as f32), rotated.z + (cube.z as f32)]
  65. })
  66. .vertices()
  67. .collect()
  68. );
  69. let polys = vertices.clone().into_iter().vertex(|_| {last+=1; return last-1;})
  70. .map(|Quad{x: v0, y: v1, z: v2, w: v3}|
  71. obj::SimplePolygon(vec![
  72. obj::IndexTuple(v0, Some(0), Some(v0)),
  73. obj::IndexTuple(v1, Some(0), Some(v1)),
  74. obj::IndexTuple(v2, Some(0), Some(v2)),
  75. obj::IndexTuple(v3, Some(0), Some(v3))
  76. ])
  77. /*obj::SimplePolygon(vec![
  78. obj::IndexTuple(v0, None, None),
  79. obj::IndexTuple(v1, None, None),
  80. obj::IndexTuple(v2, None, None),
  81. obj::IndexTuple(v3, None, None)
  82. ])*/
  83. ).collect();
  84. objects.push(
  85. obj::Object{
  86. name: format!("Cube-ID{}-NUM{}", cube.id, objects.len()),
  87. groups: vec![
  88. obj::Group {
  89. name: format!("Cube-ID{}-NUM{}-0", cube.id, objects.len()),
  90. index: 0,
  91. material: None,
  92. polys: polys
  93. },
  94. ]
  95. }
  96. );
  97. }
  98. println!("Last (index): {}, Vertices (len): {}", last, positions.len());
  99. obj::Obj{
  100. data: obj::ObjData {
  101. position: positions,
  102. texture: vec![[0.0, 0.0]],
  103. normal: normals,
  104. objects: objects,
  105. material_libs: Vec::new(),
  106. },
  107. path: std::path::PathBuf::new(),
  108. }
  109. }
  110. pub fn default_model_lut(id: u32) -> Vec<Quad<Vertex>> {
  111. // TODO generate non-cube blocks properly
  112. match id {
  113. _ => Cube::new().collect(),
  114. }
  115. }