mirror of
https://github.com/Theaninova/mhlib.git
synced 2026-02-16 22:12:37 +00:00
pr3d
This commit is contained in:
@@ -16,7 +16,7 @@ Support of games primarily depends on who developed them - Games with structural
|
|||||||
* `.wtn` "Witan Entertainment Engine"
|
* `.wtn` "Witan Entertainment Engine"
|
||||||
* [ ] Moorhuhn
|
* [ ] Moorhuhn
|
||||||
* [ ] Moorhuhn 2
|
* [ ] Moorhuhn 2
|
||||||
* `.dat` Torque3D Engine
|
* `.dat` Power Render 3D Engine
|
||||||
* [ ] Moorhuhn Kart
|
* [ ] Moorhuhn Kart
|
||||||
* [ ] Moorhuhn Kart Extra
|
* [ ] Moorhuhn Kart Extra
|
||||||
* `data/datafile.dat` "Sproing Interactive Engine"
|
* `data/datafile.dat` "Sproing Interactive Engine"
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
@tool
|
|
||||||
extends Node3D
|
|
||||||
|
|
||||||
@export var click = false:
|
|
||||||
get:
|
|
||||||
return false
|
|
||||||
set(value):
|
|
||||||
var lwo = Lwo.new()
|
|
||||||
var mesh = lwo.get_mesh("E:\\Games\\Moorhuhn Kart 3\\extract\\D\\Moorhuhnkart\\3dobjects_cars\\affe.lwo")
|
|
||||||
var instance = MeshInstance3D.new()
|
|
||||||
instance.mesh = mesh
|
|
||||||
add_child(instance)
|
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
[gd_scene load_steps=2 format=3 uid="uid://kyw4wuusc33g"]
|
[gd_scene load_steps=2 format=3 uid="uid://kyw4wuusc33g"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://starforce/test.gd" id="1_uc463"]
|
[ext_resource type="ArrayMesh" path="sar://D:/Moorhuhnkart/3dobjects_cars/affe.lwo" id="2_ab234"]
|
||||||
|
|
||||||
[node name="test" type="Node3D"]
|
[node name="test" type="Node3D"]
|
||||||
script = ExtResource("1_uc463")
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
||||||
|
mesh = ExtResource("2_ab234")
|
||||||
|
|||||||
1
rust/Cargo.lock
generated
1
rust/Cargo.lock
generated
@@ -650,6 +650,7 @@ name = "powerrender-3d"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"binrw",
|
"binrw",
|
||||||
|
"half",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -7,3 +7,4 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
binrw = "0.11.1"
|
binrw = "0.11.1"
|
||||||
|
half = "2.2.1"
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
use crate::pro::read_power_render_object;
|
use crate::pro::PowerRenderObject;
|
||||||
use binrw::{BinRead, BinResult};
|
use binrw::BinRead;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
|
||||||
pub mod pro;
|
pub mod pro;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut file = File::open(r#"E:\Games\Moorhuhn Kart\data\alk.pro"#).unwrap();
|
let mut file = File::open(r#"E:\Games\Moorhuhn Kart\data\alk.pro"#).unwrap();
|
||||||
let result = read_power_render_object(&mut file).unwrap();
|
let result = PowerRenderObject::read(&mut file).unwrap();
|
||||||
println!("{:#?}", result);
|
println!("{:#?}", result);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use binrw::io::{TakeSeek, TakeSeekExt};
|
use binrw::io::TakeSeekExt;
|
||||||
use binrw::meta::{EndianKind, ReadEndian};
|
use binrw::meta::{EndianKind, ReadEndian};
|
||||||
use binrw::{until_eof, BinRead, BinReaderExt, BinResult, Endian};
|
use binrw::{until_eof, BinRead, BinReaderExt, BinResult, Endian};
|
||||||
use std::io::{Read, Seek, SeekFrom};
|
use std::io::{Read, Seek, SeekFrom};
|
||||||
|
|||||||
49
rust/powerrender-3d/src/pro/internal/materials.rs
Normal file
49
rust/powerrender-3d/src/pro/internal/materials.rs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
use crate::pro::Chunk;
|
||||||
|
use binrw::{binread, until_eof, NullString};
|
||||||
|
|
||||||
|
#[binread]
|
||||||
|
pub struct PrMaterialList {
|
||||||
|
#[br(parse_with = until_eof)]
|
||||||
|
pub chunks: Vec<PrMaterialChunks>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[binread]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum PrMaterialChunks {
|
||||||
|
#[br(magic = 0x2101u16)]
|
||||||
|
MaterialName(#[br(map = Chunk::inner)] NullString),
|
||||||
|
#[br(magic = 0x2102u16)]
|
||||||
|
MaterialMethod(#[br(map = Chunk::inner)] u32),
|
||||||
|
#[br(magic = 0x2103u16)]
|
||||||
|
MaterialTexNum(#[br(map = Chunk::inner)] u32),
|
||||||
|
#[br(magic = 0x2104u16)]
|
||||||
|
MaterialBaseColor(#[br(map = Chunk::inner)] u8),
|
||||||
|
#[br(magic = 0x2105u16)]
|
||||||
|
MaterialShades(#[br(map = Chunk::inner)] u32),
|
||||||
|
#[br(magic = 0x2106u16)]
|
||||||
|
MaterialTable(#[br(map = Chunk::inner)] u8),
|
||||||
|
#[br(magic = 0x2107u16)]
|
||||||
|
MaterialEnvMap(#[br(map = Chunk::inner)] (u8, u8)),
|
||||||
|
#[br(magic = 0x2108u16)]
|
||||||
|
MaterialMipMap(#[br(map = Chunk::inner)] ()), // TODO
|
||||||
|
#[br(magic = 0x2109u16)]
|
||||||
|
MaterialColor(#[br(map = Chunk::inner)] [f32; 4]),
|
||||||
|
#[br(magic = 0x2110u16)]
|
||||||
|
MaterialNumStages(#[br(map = Chunk::inner)] u32),
|
||||||
|
#[br(magic = 0x2111u16)]
|
||||||
|
MaterialTexNum2(#[br(map = Chunk::inner)] ()), // TODO
|
||||||
|
#[br(magic = 0x2112u16)]
|
||||||
|
MaterialEnvMap2(#[br(map = Chunk::inner)] ()), // TODO
|
||||||
|
#[br(magic = 0x2113u16)]
|
||||||
|
MaterialBump(#[br(map = Chunk::inner)] (f32, [f32; 4])),
|
||||||
|
#[br(magic = 0x2114u16)]
|
||||||
|
MaterialSpecular(#[br(map = Chunk::inner)] ([f32; 4], f32)),
|
||||||
|
#[br(magic = 0x2115u16)]
|
||||||
|
MaterialTwoSided(#[br(map = Chunk::inner)] u8),
|
||||||
|
#[br(magic = 0x2116u16)]
|
||||||
|
MaterialVertexShaderName(#[br(map = Chunk::inner)] NullString),
|
||||||
|
#[br(magic = 0x2117u16)]
|
||||||
|
MaterialPixelShaderName(#[br(map = Chunk::inner)] NullString),
|
||||||
|
#[br(magic = 0x2199u16)]
|
||||||
|
MaterialEnd(#[br(map = Chunk::inner)] ()),
|
||||||
|
}
|
||||||
86
rust/powerrender-3d/src/pro/internal/mod.rs
Normal file
86
rust/powerrender-3d/src/pro/internal/mod.rs
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
use crate::pro::chunk::Chunk;
|
||||||
|
use crate::pro::internal::materials::{PrMaterialChunks, PrMaterialList};
|
||||||
|
use crate::pro::internal::segment::{PrSegmentChunks, PrSegmentList};
|
||||||
|
use binrw::{binread, until_eof, BinRead, NullString};
|
||||||
|
|
||||||
|
pub mod materials;
|
||||||
|
pub mod segment;
|
||||||
|
pub mod surface;
|
||||||
|
|
||||||
|
#[binread]
|
||||||
|
pub struct PrObject {
|
||||||
|
#[br(parse_with = until_eof)]
|
||||||
|
pub chunks: Vec<PrChunks>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[binread]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum PrChunks {
|
||||||
|
#[br(magic = 0x0000u16)]
|
||||||
|
Version(#[br(map = Chunk::inner)] f32),
|
||||||
|
#[br(magic = 0x0100u16)]
|
||||||
|
ObjectName(#[br(map = Chunk::inner)] NullString),
|
||||||
|
#[br(magic = 0x0101u16)]
|
||||||
|
ObjectFlags(#[br(map = Chunk::inner)] u32),
|
||||||
|
#[br(magic = 0x1000u16)]
|
||||||
|
Segments(#[br(map = |it: Chunk::<PrSegmentList>| it.0.chunks)] Vec<PrSegmentChunks>),
|
||||||
|
#[br(magic = 0x2010u16)]
|
||||||
|
TextureList(#[br(map = |it: Chunk::<VecWithCount<(), NullString>>| it.0.data)] Vec<NullString>),
|
||||||
|
#[br(magic = 0x2011u16)]
|
||||||
|
TextureAlpha(#[br(map = |it: Chunk::<VecWithCount<(), u8>>| it.0.data)] Vec<u8>),
|
||||||
|
#[br(magic = 0x2012u16)]
|
||||||
|
TextureStage(#[br(map = |it: Chunk::<VecWithCount<(), u8>>| it.0.data)] Vec<u8>),
|
||||||
|
#[br(magic = 0x2013u16)]
|
||||||
|
TextureFormat(#[br(map = |it: Chunk::<VecWithCount<(), u8>>| it.0.data)] Vec<u8>),
|
||||||
|
#[br(magic = 0x2014u16)]
|
||||||
|
TextureMulti(#[br(map = |it: Chunk::<VecWithCount<(), u8>>| it.0.data)] Vec<u8>),
|
||||||
|
#[br(magic = 0x2100u16)]
|
||||||
|
MaterialList(#[br(map = |it: Chunk::<PrMaterialList>| it.0.chunks)] Vec<PrMaterialChunks>),
|
||||||
|
#[br(magic = 0x3000u16)]
|
||||||
|
Camera(#[br(map = Chunk::inner)] ()), // TODO
|
||||||
|
#[br(magic = 0x3010u16)]
|
||||||
|
ObjectBbox(#[br(map = Chunk::inner)] Box<PrBoundingInfo>),
|
||||||
|
#[br(magic = 0x3100u16)]
|
||||||
|
VertexShaderList(#[br(map = Chunk::inner)] ()), // TODO
|
||||||
|
#[br(magic = 0x3101u16)]
|
||||||
|
VertexShaderList2(#[br(map = Chunk::inner)] ()), // TODO
|
||||||
|
#[br(magic = 0x3102u16)]
|
||||||
|
VertexShaderList3(#[br(map = Chunk::inner)] ()), // TODO
|
||||||
|
#[br(magic = 0x3200u16)]
|
||||||
|
PixelShaderList(#[br(map = Chunk::inner)] ()), // TODO
|
||||||
|
#[br(magic = 0x3202u16)]
|
||||||
|
PixelShaderList3(#[br(map = Chunk::inner)] ()), // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
#[binread]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PrBoundingInfo {
|
||||||
|
pub min_x: f32,
|
||||||
|
pub max_x: f32,
|
||||||
|
pub min_y: f32,
|
||||||
|
pub max_y: f32,
|
||||||
|
pub min_z: f32,
|
||||||
|
pub max_z: f32,
|
||||||
|
/// Four corners + center vertex
|
||||||
|
pub box_center: [[f32; 3]; 9],
|
||||||
|
/// Same, but transformed
|
||||||
|
pub t_box_center: [[f32; 3]; 9],
|
||||||
|
pub radius: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[binread]
|
||||||
|
pub struct VertexShaderList {
|
||||||
|
pub name: NullString,
|
||||||
|
pub flags: u32,
|
||||||
|
pub size: u32,
|
||||||
|
pub num_constants: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[binread]
|
||||||
|
pub(crate) struct VecWithCount<Args: Clone + Default, T: for<'a> BinRead<Args<'a> = Args> + 'static>
|
||||||
|
{
|
||||||
|
#[br(temp)]
|
||||||
|
count: u16,
|
||||||
|
#[br(count = count)]
|
||||||
|
pub data: Vec<T>,
|
||||||
|
}
|
||||||
92
rust/powerrender-3d/src/pro/internal/segment.rs
Normal file
92
rust/powerrender-3d/src/pro/internal/segment.rs
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
use crate::pro::internal::PrBoundingInfo;
|
||||||
|
use crate::pro::Chunk;
|
||||||
|
use binrw::{binread, until_eof, NullString};
|
||||||
|
|
||||||
|
#[binread]
|
||||||
|
pub struct PrSegmentList {
|
||||||
|
pub segments: u32,
|
||||||
|
#[br(parse_with = until_eof)]
|
||||||
|
pub chunks: Vec<PrSegmentChunks>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[binread]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum PrSegmentChunks {
|
||||||
|
#[br(magic = 0x1010u16)]
|
||||||
|
SegmentName(#[br(map = Chunk::inner)] NullString),
|
||||||
|
#[br(magic = 0x1020u16)]
|
||||||
|
SegmentFlags(#[br(map = Chunk::inner)] u32),
|
||||||
|
#[br(magic = 0x1022u16)]
|
||||||
|
SegmentBbox(#[br(map = Chunk::inner)] Box<PrBoundingInfo>),
|
||||||
|
#[br(magic = 0x1030u16)]
|
||||||
|
Vertices(#[br(map = Chunk::inner)] PrVertices),
|
||||||
|
#[br(magic = 0x1040u16)]
|
||||||
|
Faces(#[br(map = |it: Chunk<PrFaces>| it.inner().faces)] Vec<PrFace>),
|
||||||
|
#[br(magic = 0x1050u16)]
|
||||||
|
SegBuf(#[br(map = Chunk::inner)] ()), // TODO
|
||||||
|
#[br(magic = 0x1051u16)]
|
||||||
|
SegBuf2(#[br(map = Chunk::inner)] ()), // TODO
|
||||||
|
#[br(magic = 0x1052u16)]
|
||||||
|
SegBuf3(#[br(map = Chunk::inner)] ()), // TODO
|
||||||
|
#[br(magic = 0x1060u16)]
|
||||||
|
LodInfo(#[br(map = Chunk::inner)] ()), // TODO
|
||||||
|
#[br(magic = 0x1F00u16)]
|
||||||
|
KeyframePivot(#[br(map = Chunk::inner)] [f32; 3]),
|
||||||
|
#[br(magic = 0x1F10u16)]
|
||||||
|
KeyframeMatrix(#[br(map = Chunk::inner)] [f32; 16]),
|
||||||
|
#[br(magic = 0x1F20u16)]
|
||||||
|
KeyframeRotKeys(#[br(map = Chunk::inner)] ()), // TODO
|
||||||
|
#[br(magic = 0x1F30u16)]
|
||||||
|
KeyframePosKeys(#[br(map = Chunk::inner)] ()), // TODO
|
||||||
|
#[br(magic = 0x1F40u16)]
|
||||||
|
KeyframeScaleKeys(#[br(map = Chunk::inner)] ()), // TODO
|
||||||
|
#[br(magic = 0x1F50u16)]
|
||||||
|
KeyframeLinks(#[br(map = Chunk::inner)] [i32; 3]),
|
||||||
|
#[br(magic = 0x4000u16)]
|
||||||
|
TexCoords(#[br(map = Chunk::inner)] ()), // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
#[binread]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PrVertices {
|
||||||
|
#[br(temp)]
|
||||||
|
count: i32,
|
||||||
|
#[br(count = count)]
|
||||||
|
pub vertices: Vec<PrVertex>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[binread]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PrVertex {
|
||||||
|
pub position: [i32; 3],
|
||||||
|
pub normal: [i16; 3],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[binread]
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct PrFaces {
|
||||||
|
#[br(temp)]
|
||||||
|
pub num_faces: i32,
|
||||||
|
#[br(count = num_faces)]
|
||||||
|
pub faces: Vec<PrFace>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[binread]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PrFace {
|
||||||
|
pub material: u16,
|
||||||
|
pub back_material: u16,
|
||||||
|
pub i0: i32,
|
||||||
|
pub i1: i32,
|
||||||
|
pub i2: i32,
|
||||||
|
pub u0: i32,
|
||||||
|
pub u1: i32,
|
||||||
|
pub u2: i32,
|
||||||
|
pub v0: i32,
|
||||||
|
pub v1: i32,
|
||||||
|
pub v2: i32,
|
||||||
|
pub color: [i32; 3],
|
||||||
|
pub normal: [u16; 3],
|
||||||
|
pub flags: u8,
|
||||||
|
pub dot_prod: u16,
|
||||||
|
}
|
||||||
83
rust/powerrender-3d/src/pro/internal/surface.rs
Normal file
83
rust/powerrender-3d/src/pro/internal/surface.rs
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
use crate::pro::internal::segment::{PrFace, PrVertices};
|
||||||
|
use crate::pro::PowerRenderSurface;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Hash, PartialEq, Eq, Copy, Clone)]
|
||||||
|
struct UniqueVertex {
|
||||||
|
pub pos: [i32; 3],
|
||||||
|
pub normal: [i16; 3],
|
||||||
|
pub color: [i32; 3],
|
||||||
|
pub uv: [i32; 2],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PrVertices {
|
||||||
|
/// converts the relatively uncommonly used format into one that can be used more easily
|
||||||
|
/// by putting it into an array of surfaces that are separated by material
|
||||||
|
pub fn into_surfaces(self, faces: Vec<PrFace>) -> Vec<PowerRenderSurface> {
|
||||||
|
let mut surfaces = HashMap::new();
|
||||||
|
|
||||||
|
for face in faces.into_iter() {
|
||||||
|
let surface_id = ((face.material as u32) << 16) | (face.back_material as u32);
|
||||||
|
let (index_map, surface) = if let Some(surface) = surfaces.get_mut(&surface_id) {
|
||||||
|
surface
|
||||||
|
} else {
|
||||||
|
let surface = PowerRenderSurface {
|
||||||
|
material_index: face.material as usize,
|
||||||
|
back_material_index: face.back_material as usize,
|
||||||
|
uvs: vec![],
|
||||||
|
indices: vec![],
|
||||||
|
colors: vec![],
|
||||||
|
normals: vec![],
|
||||||
|
vertices: vec![],
|
||||||
|
};
|
||||||
|
surfaces.insert(surface_id, (HashMap::<UniqueVertex, i32>::new(), surface));
|
||||||
|
surfaces.get_mut(&surface_id).unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
let triangle = [
|
||||||
|
(face.i0, face.u0, face.v0),
|
||||||
|
(face.i1, face.u1, face.v1),
|
||||||
|
(face.i2, face.u2, face.v2),
|
||||||
|
];
|
||||||
|
for (index, u, v) in triangle {
|
||||||
|
let vertex = &self.vertices[index as usize];
|
||||||
|
let point = UniqueVertex {
|
||||||
|
pos: vertex.position,
|
||||||
|
normal: vertex.normal,
|
||||||
|
color: face.color,
|
||||||
|
uv: [u, v],
|
||||||
|
};
|
||||||
|
let index = if let Some(index) = index_map.get(&point) {
|
||||||
|
*index
|
||||||
|
} else {
|
||||||
|
surface.vertices.push([
|
||||||
|
f32::from_ne_bytes(point.pos[0].to_ne_bytes()),
|
||||||
|
f32::from_ne_bytes(point.pos[1].to_ne_bytes()),
|
||||||
|
f32::from_ne_bytes(point.pos[2].to_ne_bytes()),
|
||||||
|
]);
|
||||||
|
surface.normals.push([
|
||||||
|
point.normal[0] as f32 / 1024.0,
|
||||||
|
point.normal[1] as f32 / 1024.0,
|
||||||
|
point.normal[2] as f32 / 1024.0,
|
||||||
|
]);
|
||||||
|
surface.uvs.push([
|
||||||
|
f32::from_ne_bytes(point.uv[0].to_ne_bytes()),
|
||||||
|
f32::from_ne_bytes(point.uv[1].to_ne_bytes()),
|
||||||
|
]);
|
||||||
|
surface.colors.push([
|
||||||
|
point.color[0] as f32 / 255.0,
|
||||||
|
point.color[1] as f32 / 255.0,
|
||||||
|
point.color[2] as f32 / 255.0,
|
||||||
|
]);
|
||||||
|
|
||||||
|
let index = surface.vertices.len() as i32 - 1;
|
||||||
|
index_map.insert(point, index);
|
||||||
|
index
|
||||||
|
};
|
||||||
|
surface.indices.push(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
surfaces.into_values().map(|(_, surface)| surface).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,163 +1,67 @@
|
|||||||
use crate::pro::chunk::Chunk;
|
use crate::pro::chunk::Chunk;
|
||||||
|
use crate::pro::internal::materials::PrMaterialChunks;
|
||||||
|
use crate::pro::internal::segment::PrSegmentChunks;
|
||||||
|
use crate::pro::internal::{PrChunks, PrObject};
|
||||||
use binrw::__private::magic;
|
use binrw::__private::magic;
|
||||||
use binrw::{binread, until_eof, BinRead, BinReaderExt, BinResult, Endian, NullString};
|
use binrw::meta::{EndianKind, ReadEndian};
|
||||||
|
use binrw::BinRead;
|
||||||
|
use binrw::BinResult;
|
||||||
|
use binrw::Endian;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::io::{Read, Seek};
|
use std::io::{Read, Seek};
|
||||||
|
|
||||||
pub mod chunk;
|
pub(crate) mod chunk;
|
||||||
|
pub(crate) mod internal;
|
||||||
|
|
||||||
pub fn read_power_render_object<R>(reader: &mut R) -> BinResult<Vec<PrChunks>>
|
#[derive(Default, Debug)]
|
||||||
where
|
pub struct PowerRenderObject {
|
||||||
R: Read + Seek,
|
pub version: f32,
|
||||||
{
|
pub name: String,
|
||||||
magic(reader, 0x0303u16, Endian::Little)?;
|
pub segments: Vec<PowerRenderSegment>,
|
||||||
let data: Chunk<PrObject> = Chunk::<PrObject>::read(reader)?;
|
pub materials: Vec<PowerRenderMaterial>,
|
||||||
Ok(data.0.chunks)
|
pub textures: Vec<PowerRenderTexture>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[binread]
|
#[derive(Default, Debug)]
|
||||||
struct PrObject {
|
pub struct PowerRenderSegment {
|
||||||
#[br(parse_with = until_eof)]
|
pub name: String,
|
||||||
pub chunks: Vec<PrChunks>,
|
pub surfaces: Vec<PowerRenderSurface>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[binread]
|
#[derive(Default, Debug)]
|
||||||
#[derive(Debug)]
|
pub struct PowerRenderTexture {
|
||||||
pub enum PrChunks {
|
pub name: String,
|
||||||
#[br(magic = 0x0000u16)]
|
pub has_alpha: bool,
|
||||||
Version(#[br(map = Chunk::inner)] f32),
|
pub is_stage: bool,
|
||||||
#[br(magic = 0x0100u16)]
|
pub is_multi: bool,
|
||||||
ObjectName(#[br(map = Chunk::inner)] NullString),
|
pub format: u8,
|
||||||
#[br(magic = 0x0101u16)]
|
|
||||||
ObjectFlags(#[br(map = Chunk::inner)] u32),
|
|
||||||
#[br(magic = 0x1000u16)]
|
|
||||||
Segments(#[br(map = |it: Chunk::<PrSegmentList>| it.0.chunks)] Vec<PrSegmentChunks>),
|
|
||||||
#[br(magic = 0x2010u16)]
|
|
||||||
TextureList(#[br(map = |it: Chunk::<VecWithCount<(), NullString>>| it.0.data)] Vec<NullString>),
|
|
||||||
#[br(magic = 0x2011u16)]
|
|
||||||
TextureAlpha(#[br(map = |it: Chunk::<VecWithCount<(), u8>>| it.0.data)] Vec<u8>),
|
|
||||||
#[br(magic = 0x2012u16)]
|
|
||||||
TextureStage(#[br(map = |it: Chunk::<VecWithCount<(), u8>>| it.0.data)] Vec<u8>),
|
|
||||||
#[br(magic = 0x2013u16)]
|
|
||||||
TextureFormat(#[br(map = |it: Chunk::<VecWithCount<(), u8>>| it.0.data)] Vec<u8>),
|
|
||||||
#[br(magic = 0x2014u16)]
|
|
||||||
TextureMulti(#[br(map = |it: Chunk::<VecWithCount<(), u8>>| it.0.data)] Vec<u8>),
|
|
||||||
#[br(magic = 0x2100u16)]
|
|
||||||
MaterialList(#[br(map = |it: Chunk::<PrMaterialList>| it.0.chunks)] Vec<PrMaterialChunks>),
|
|
||||||
#[br(magic = 0x3000u16)]
|
|
||||||
Camera(#[br(map = Chunk::inner)] ()), // TODO
|
|
||||||
#[br(magic = 0x3010u16)]
|
|
||||||
ObjectBbox(#[br(map = Chunk::inner)] Box<PrBoundingInfo>),
|
|
||||||
#[br(magic = 0x3100u16)]
|
|
||||||
VertexShaderList(#[br(map = Chunk::inner)] ()), // TODO
|
|
||||||
#[br(magic = 0x3101u16)]
|
|
||||||
VertexShaderList2(#[br(map = Chunk::inner)] ()), // TODO
|
|
||||||
#[br(magic = 0x3102u16)]
|
|
||||||
VertexShaderList3(#[br(map = Chunk::inner)] ()), // TODO
|
|
||||||
#[br(magic = 0x3200u16)]
|
|
||||||
PixelShaderList(#[br(map = Chunk::inner)] ()), // TODO
|
|
||||||
#[br(magic = 0x3202u16)]
|
|
||||||
PixelShaderList3(#[br(map = Chunk::inner)] ()), // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
#[binread]
|
|
||||||
struct PrMaterialList {
|
|
||||||
#[br(parse_with = until_eof)]
|
|
||||||
pub chunks: Vec<PrMaterialChunks>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[binread]
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum PrMaterialChunks {
|
|
||||||
#[br(magic = 0x2101u16)]
|
|
||||||
MaterialName(#[br(map = Chunk::inner)] NullString),
|
|
||||||
#[br(magic = 0x2102u16)]
|
|
||||||
MaterialMethod(#[br(map = Chunk::inner)] u32),
|
|
||||||
#[br(magic = 0x2103u16)]
|
|
||||||
MaterialTexNum(#[br(map = Chunk::inner)] u32),
|
|
||||||
#[br(magic = 0x2104u16)]
|
|
||||||
MaterialBaseColor(#[br(map = Chunk::inner)] u8),
|
|
||||||
#[br(magic = 0x2105u16)]
|
|
||||||
MaterialShades(#[br(map = Chunk::inner)] u32),
|
|
||||||
#[br(magic = 0x2106u16)]
|
|
||||||
MaterialTable(#[br(map = Chunk::inner)] u8),
|
|
||||||
#[br(magic = 0x2107u16)]
|
|
||||||
MaterialEnvMap(#[br(map = Chunk::inner)] (u8, u8)),
|
|
||||||
#[br(magic = 0x2108u16)]
|
|
||||||
MaterialMipMap(#[br(map = Chunk::inner)] ()), // TODO
|
|
||||||
#[br(magic = 0x2109u16)]
|
|
||||||
MaterialColor(#[br(map = Chunk::inner)] [f32; 4]),
|
|
||||||
#[br(magic = 0x2110u16)]
|
|
||||||
MaterialNumStages(#[br(map = Chunk::inner)] u32),
|
|
||||||
#[br(magic = 0x2111u16)]
|
|
||||||
MaterialTexNum2(#[br(map = Chunk::inner)] ()), // TODO
|
|
||||||
#[br(magic = 0x2112u16)]
|
|
||||||
MaterialEnvMap2(#[br(map = Chunk::inner)] ()), // TODO
|
|
||||||
#[br(magic = 0x2113u16)]
|
|
||||||
MaterialBump(#[br(map = Chunk::inner)] (f32, [f32; 4])),
|
|
||||||
#[br(magic = 0x2114u16)]
|
|
||||||
MaterialSpecular(#[br(map = Chunk::inner)] ([f32; 4], f32)),
|
|
||||||
#[br(magic = 0x2115u16)]
|
|
||||||
MaterialTwoSided(#[br(map = Chunk::inner)] u8),
|
|
||||||
#[br(magic = 0x2116u16)]
|
|
||||||
MaterialVertexShaderName(#[br(map = Chunk::inner)] NullString),
|
|
||||||
#[br(magic = 0x2117u16)]
|
|
||||||
MaterialPixelShaderName(#[br(map = Chunk::inner)] NullString),
|
|
||||||
#[br(magic = 0x2199u16)]
|
|
||||||
MaterialEnd(#[br(map = Chunk::inner)] ()),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[binread]
|
|
||||||
pub struct PrSegmentList {
|
|
||||||
pub segments: u32,
|
|
||||||
#[br(parse_with = until_eof)]
|
|
||||||
pub chunks: Vec<PrSegmentChunks>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[binread]
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum PrSegmentChunks {
|
|
||||||
#[br(magic = 0x1010u16)]
|
|
||||||
SegmentName(#[br(map = Chunk::inner)] NullString),
|
|
||||||
#[br(magic = 0x1020u16)]
|
|
||||||
SegmentFlags(#[br(map = Chunk::inner)] u32),
|
|
||||||
#[br(magic = 0x1022u16)]
|
|
||||||
SegmentBbox(#[br(map = Chunk::inner)] Box<PrBoundingInfo>),
|
|
||||||
#[br(magic = 0x1030u16)]
|
|
||||||
Vertices(#[br(map = Chunk::inner)] PrVertices),
|
|
||||||
#[br(magic = 0x1040u16)]
|
|
||||||
Faces(#[br(map = Chunk::inner)] ()), // TODO
|
|
||||||
#[br(magic = 0x1050u16)]
|
|
||||||
SegBuf(#[br(map = Chunk::inner)] ()), // TODO
|
|
||||||
#[br(magic = 0x1051u16)]
|
|
||||||
SegBuf2(#[br(map = Chunk::inner)] ()), // TODO
|
|
||||||
#[br(magic = 0x1052u16)]
|
|
||||||
SegBuf3(#[br(map = Chunk::inner)] ()), // TODO
|
|
||||||
#[br(magic = 0x1060u16)]
|
|
||||||
LodInfo(#[br(map = Chunk::inner)] ()), // TODO
|
|
||||||
#[br(magic = 0x1F00u16)]
|
|
||||||
KeyframePivot(#[br(map = Chunk::inner)] [f32; 3]),
|
|
||||||
#[br(magic = 0x1F10u16)]
|
|
||||||
KeyframeMatrix(#[br(map = Chunk::inner)] [f32; 16]),
|
|
||||||
#[br(magic = 0x1F20u16)]
|
|
||||||
KeyframeRotKeys(#[br(map = Chunk::inner)] ()), // TODO
|
|
||||||
#[br(magic = 0x1F30u16)]
|
|
||||||
KeyframePosKeys(#[br(map = Chunk::inner)] ()), // TODO
|
|
||||||
#[br(magic = 0x1F40u16)]
|
|
||||||
KeyframeScaleKeys(#[br(map = Chunk::inner)] ()), // TODO
|
|
||||||
#[br(magic = 0x1F50u16)]
|
|
||||||
KeyframeLinks(#[br(map = Chunk::inner)] [i32; 3]),
|
|
||||||
#[br(magic = 0x4000u16)]
|
|
||||||
TexCoords(#[br(map = Chunk::inner)] ()), // TODO
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PrVertices {
|
pub struct PowerRenderSurface {
|
||||||
|
pub material_index: usize,
|
||||||
|
pub back_material_index: usize,
|
||||||
pub vertices: Vec<[f32; 3]>,
|
pub vertices: Vec<[f32; 3]>,
|
||||||
pub normals: Vec<[f32; 3]>,
|
pub normals: Vec<[f32; 3]>,
|
||||||
|
pub colors: Vec<[f32; 3]>,
|
||||||
|
pub uvs: Vec<[f32; 2]>,
|
||||||
|
pub indices: Vec<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BinRead for PrVertices {
|
#[derive(Default, Debug)]
|
||||||
|
pub struct PowerRenderMaterial {
|
||||||
|
pub name: String,
|
||||||
|
pub texture_index: usize,
|
||||||
|
pub two_sided: bool,
|
||||||
|
pub frag_shader: Option<String>,
|
||||||
|
pub vert_shader: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReadEndian for PowerRenderObject {
|
||||||
|
const ENDIAN: EndianKind = EndianKind::Endian(Endian::Little);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BinRead for PowerRenderObject {
|
||||||
type Args<'a> = ();
|
type Args<'a> = ();
|
||||||
|
|
||||||
fn read_options<R: Read + Seek>(
|
fn read_options<R: Read + Seek>(
|
||||||
@@ -165,75 +69,98 @@ impl BinRead for PrVertices {
|
|||||||
endian: Endian,
|
endian: Endian,
|
||||||
_: Self::Args<'_>,
|
_: Self::Args<'_>,
|
||||||
) -> BinResult<Self> {
|
) -> BinResult<Self> {
|
||||||
let count = reader.read_type::<u32>(endian)? as usize;
|
magic(reader, 0x0303u16, endian)?;
|
||||||
let mut result = PrVertices {
|
let chunks = Chunk::<PrObject>::read(reader)?;
|
||||||
vertices: Vec::with_capacity(count),
|
|
||||||
normals: Vec::with_capacity(count),
|
let mut obj = PowerRenderObject::default();
|
||||||
};
|
let mut texture_alpha = vec![];
|
||||||
for _ in 0..count {
|
let mut texture_format = vec![];
|
||||||
result.vertices.push(reader.read_type(endian)?);
|
let mut texture_stage = vec![];
|
||||||
let normal: [i16; 3] = reader.read_type(endian)?;
|
let mut texture_multi = vec![];
|
||||||
result.normals.push([
|
|
||||||
normal[0] as f32 / 1024.0,
|
for chunk in chunks.0.chunks {
|
||||||
normal[1] as f32 / 1024.0,
|
match chunk {
|
||||||
normal[2] as f32 / 1024.0,
|
PrChunks::Version(version) => obj.version = version,
|
||||||
]);
|
PrChunks::ObjectName(name) => obj.name = name.to_string(),
|
||||||
|
PrChunks::TextureAlpha(alpha) => texture_alpha = alpha,
|
||||||
|
PrChunks::TextureFormat(format) => texture_format = format,
|
||||||
|
PrChunks::TextureMulti(multi) => texture_multi = multi,
|
||||||
|
PrChunks::TextureStage(stage) => texture_stage = stage,
|
||||||
|
PrChunks::TextureList(texture_list) => {
|
||||||
|
let mut alpha = texture_alpha.iter();
|
||||||
|
let mut formats = texture_format.iter();
|
||||||
|
let mut stages = texture_stage.iter();
|
||||||
|
let mut multi = texture_multi.iter();
|
||||||
|
|
||||||
|
obj.textures = texture_list
|
||||||
|
.into_iter()
|
||||||
|
.map(|name| PowerRenderTexture {
|
||||||
|
name: name.to_string(),
|
||||||
|
has_alpha: *alpha.next().unwrap() != 0,
|
||||||
|
is_stage: *stages.next().unwrap() != 0,
|
||||||
|
is_multi: *multi.next().unwrap() != 0,
|
||||||
|
format: *formats.next().unwrap(),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
}
|
}
|
||||||
Ok(result)
|
PrChunks::MaterialList(chunks) => {
|
||||||
|
for chunk in chunks {
|
||||||
|
match chunk {
|
||||||
|
PrMaterialChunks::MaterialEnd(_) => (),
|
||||||
|
PrMaterialChunks::MaterialName(name) => {
|
||||||
|
obj.materials.push(PowerRenderMaterial {
|
||||||
|
name: name.to_string(),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
PrMaterialChunks::MaterialTexNum(id) => {
|
||||||
|
obj.materials.last_mut().unwrap().texture_index = id as usize;
|
||||||
|
}
|
||||||
|
PrMaterialChunks::MaterialTwoSided(val) => {
|
||||||
|
obj.materials.last_mut().unwrap().two_sided = val != 0
|
||||||
|
}
|
||||||
|
PrMaterialChunks::MaterialPixelShaderName(name) => {
|
||||||
|
if !name.is_empty() {
|
||||||
|
obj.materials.last_mut().unwrap().frag_shader =
|
||||||
|
Some(name.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PrMaterialChunks::MaterialVertexShaderName(name) => {
|
||||||
|
if !name.is_empty() {
|
||||||
|
obj.materials.last_mut().unwrap().vert_shader =
|
||||||
|
Some(name.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x => eprintln!("TODO (Materials): {:?}", x),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PrChunks::Segments(segments) => {
|
||||||
|
let mut vertices = None;
|
||||||
|
for chunk in segments {
|
||||||
|
match chunk {
|
||||||
|
PrSegmentChunks::SegmentName(name) => {
|
||||||
|
obj.segments.push(PowerRenderSegment {
|
||||||
|
name: name.to_string(),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
PrSegmentChunks::Vertices(v) => {
|
||||||
|
vertices = Some(v);
|
||||||
|
}
|
||||||
|
PrSegmentChunks::Faces(faces) => {
|
||||||
|
let surfaces = vertices.unwrap().into_surfaces(faces);
|
||||||
|
vertices = None;
|
||||||
|
obj.segments.last_mut().unwrap().surfaces = surfaces;
|
||||||
|
}
|
||||||
|
x => eprintln!("TODO: {:?}", x),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x => eprintln!("TODO: {:?}", x),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[binread]
|
Ok(obj)
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct PrFace {
|
|
||||||
pub material: u16,
|
|
||||||
pub back_material: u16,
|
|
||||||
pub i0: i32,
|
|
||||||
pub i1: i32,
|
|
||||||
pub i2: i32,
|
|
||||||
pub u0: i32,
|
|
||||||
pub u1: i32,
|
|
||||||
pub u2: i32,
|
|
||||||
pub v0: i32,
|
|
||||||
pub v1: i32,
|
|
||||||
pub v2: i32,
|
|
||||||
pub c0: i32,
|
|
||||||
pub c1: i32,
|
|
||||||
pub c2: i32,
|
|
||||||
pub normal: [u16; 3],
|
|
||||||
pub flags: u8,
|
|
||||||
pub dot_prod: u16,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[binread]
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct PrBoundingInfo {
|
|
||||||
pub min_x: f32,
|
|
||||||
pub max_x: f32,
|
|
||||||
pub min_y: f32,
|
|
||||||
pub max_y: f32,
|
|
||||||
pub min_z: f32,
|
|
||||||
pub max_z: f32,
|
|
||||||
/// Four corners + center vertex
|
|
||||||
pub box_center: [[f32; 3]; 9],
|
|
||||||
/// Same, but transformed
|
|
||||||
pub t_box_center: [[f32; 3]; 9],
|
|
||||||
pub radius: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[binread]
|
|
||||||
pub struct VertexShaderList {
|
|
||||||
pub name: NullString,
|
|
||||||
pub flags: u32,
|
|
||||||
pub size: u32,
|
|
||||||
pub num_constants: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[binread]
|
|
||||||
pub(crate) struct VecWithCount<Args: Clone + Default, T: for<'a> BinRead<Args<'a> = Args> + 'static>
|
|
||||||
{
|
|
||||||
#[br(temp)]
|
|
||||||
count: u16,
|
|
||||||
#[br(count = count)]
|
|
||||||
pub data: Vec<T>,
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user