diff --git a/godot/kart/entry.tscn b/godot/kart/entry.tscn new file mode 100644 index 0000000..2bbe62f --- /dev/null +++ b/godot/kart/entry.tscn @@ -0,0 +1,91 @@ +[gd_scene load_steps=5 format=3 uid="uid://4n26dt3e4pv3"] + +[ext_resource type="Shader" path="res://kart/flag.gdshader" id="1_lbvg8"] +[ext_resource type="FontFile" uid="uid://b50bdb32aerbb" path="res://remakes/font/LondrinaSolid-Regular.otf" id="2_fj37l"] + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_y6o8u"] +shader = ExtResource("1_lbvg8") +shader_parameter/rotation = 2.2 +shader_parameter/size = 160.0 +shader_parameter/time_scale = 0.125 +shader_parameter/wave_amount = 0.6 +shader_parameter/wave_scale = 0.2 +shader_parameter/color1 = Color(0.12549, 0.12549, 0.12549, 1) +shader_parameter/color2 = Color(1, 1, 1, 1) + +[sub_resource type="Theme" id="Theme_ugqrn"] + +[node name="Control" type="PanelContainer"] +material = SubResource("ShaderMaterial_y6o8u") +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme = SubResource("Theme_ugqrn") + +[node name="Logo" type="Control" parent="."] +custom_minimum_size = Vector2(300, 200) +layout_mode = 2 + +[node name="Label" type="Label" parent="Logo"] +layout_mode = 1 +anchors_preset = 5 +anchor_left = 0.5 +anchor_right = 0.5 +offset_left = -151.0 +offset_right = 151.0 +offset_bottom = 73.0 +grow_horizontal = 2 +theme_override_colors/font_color = Color(0.996078, 0.92549, 0.14902, 1) +theme_override_colors/font_outline_color = Color(0.776471, 0.215686, 0.14902, 1) +theme_override_constants/outline_size = 23 +theme_override_fonts/font = ExtResource("2_fj37l") +theme_override_font_sizes/font_size = 60 +text = "Moorhuhn" +horizontal_alignment = 1 +uppercase = true + +[node name="Label2" type="Label" parent="Logo/Label"] +layout_mode = 0 +offset_top = 50.0 +offset_right = 302.0 +offset_bottom = 162.0 +theme_override_colors/font_color = Color(0.894118, 0.133333, 0.0705882, 1) +theme_override_colors/font_outline_color = Color(1, 1, 1, 1) +theme_override_constants/outline_size = 15 +theme_override_constants/line_spacing = -140 +theme_override_fonts/font = ExtResource("2_fj37l") +theme_override_font_sizes/font_size = 97 +text = "»KART«" +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="Label3" type="Label" parent="Logo/Label"] +layout_mode = 2 +offset_left = 174.0 +offset_top = 156.0 +offset_right = 337.0 +offset_bottom = 214.0 +rotation = -0.338594 +theme_override_colors/font_color = Color(0.913725, 0.945098, 0.952941, 1) +theme_override_colors/font_outline_color = Color(0, 0, 0, 1) +theme_override_constants/outline_size = 14 +theme_override_fonts/font = ExtResource("2_fj37l") +theme_override_font_sizes/font_size = 48 +text = "ULTIMATE" +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="MarginContainer" type="MarginContainer" parent="."] +layout_mode = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"] +layout_mode = 2 +size_flags_horizontal = 4 +size_flags_vertical = 4 +alignment = 1 + +[node name="Button" type="Button" parent="MarginContainer/VBoxContainer"] +layout_mode = 2 +text = "Start" diff --git a/godot/kart/flag.gdshader b/godot/kart/flag.gdshader new file mode 100644 index 0000000..43ef2aa --- /dev/null +++ b/godot/kart/flag.gdshader @@ -0,0 +1,29 @@ +shader_type canvas_item; + +uniform float rotation: hint_range(0.0, 3.14156, 0.01) = 1.4; +uniform float size: hint_range(0.0, 1000.0, 1.0) = 40.0; +uniform float time_scale = 50.0; +uniform float wave_amount = 0.5; +uniform float wave_scale = 0.25; + +uniform vec4 color1: source_color = vec4(0, 0, 0, 1); +uniform vec4 color2: source_color = vec4(1); + +float aaStep(float compValue, float gradient){ + float halfChange = fwidth(gradient) / 2.0; + //base the range of the inverse lerp on the change over one pixel + float lowerEdge = compValue - halfChange; + float upperEdge = compValue + halfChange; + //do the inverse interpolation + float stepped = (gradient - lowerEdge) / (upperEdge - lowerEdge); + stepped = clamp(stepped, 0.0, 1.0); + return stepped; +} + +void fragment() { + vec2 pos = FRAGCOORD.xy; + pos.y += sin(pos.x / (size * wave_amount) + TIME * time_scale) * (wave_scale * size); + pos *= mat2(vec2(sin(rotation), -cos(rotation)), vec2(cos(rotation), sin(rotation))); + pos = abs(fract(pos / size) - 0.5); + COLOR = mix(color1, color2, aaStep(0.5, pos.x + pos.y)); +} diff --git a/godot/project.godot b/godot/project.godot index 6493d57..e3d6e87 100644 --- a/godot/project.godot +++ b/godot/project.godot @@ -19,12 +19,6 @@ boot_splash/fullsize=false boot_splash/use_filter=false config/icon="res://icon.png" -[display] - -window/size/viewport_width=512 -window/size/viewport_height=256 -window/size/borderless=true - [input] "Move Up"={ diff --git a/godot/textures/body_albedo.png b/godot/textures/body_albedo.png new file mode 100644 index 0000000..11872d4 Binary files /dev/null and b/godot/textures/body_albedo.png differ diff --git a/godot/textures/body_albedo.png.import b/godot/textures/body_albedo.png.import new file mode 100644 index 0000000..cb6eb96 --- /dev/null +++ b/godot/textures/body_albedo.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bralq5uqyflys" +path="res://.godot/imported/body_albedo.png-580b6ee686dffd181a2d7b7b9fe62e81.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://textures/body_albedo.png" +dest_files=["res://.godot/imported/body_albedo.png-580b6ee686dffd181a2d7b7b9fe62e81.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 7a1b6ab..5d8690f 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -85,6 +85,12 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + [[package]] name = "cfg-if" version = "1.0.0" @@ -423,6 +429,15 @@ version = "0.2.144" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +[[package]] +name = "libpr4-sys" +version = "0.1.0" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "lightwave-3d" version = "1.0.0" @@ -611,6 +626,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + [[package]] name = "png" version = "0.17.8" @@ -624,6 +645,13 @@ dependencies = [ "miniz_oxide 0.7.1", ] +[[package]] +name = "powerrender-3d" +version = "0.1.0" +dependencies = [ + "binrw", +] + [[package]] name = "proc-macro2" version = "1.0.56" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index dc762a7..3d22520 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,3 +1,3 @@ [workspace] -members = ["renderwarelib", "springylib", "starforcelib", "mhex", "mhgd"] +members = ["renderwarelib", "springylib", "starforcelib", "mhex", "mhgd", "powerrender-3d", "libpr4-sys"] diff --git a/rust/libpr4-sys/Cargo.toml b/rust/libpr4-sys/Cargo.toml new file mode 100644 index 0000000..a3411d5 --- /dev/null +++ b/rust/libpr4-sys/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "libpr4-sys" +version = "0.1.0" +build = "build.rs" +links = "https://archive.org/details/tucows_223698_Power_Render_3D_Engine" +edition = "2021" + +[dependencies] +libc = "0.2.144" + +[build-dependencies] +cc = "1.0.79" +pkg-config = "0.3.27" diff --git a/rust/libpr4-sys/build.rs b/rust/libpr4-sys/build.rs new file mode 100644 index 0000000..f328e4d --- /dev/null +++ b/rust/libpr4-sys/build.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/rust/libpr4-sys/src/lib.rs b/rust/libpr4-sys/src/lib.rs new file mode 100644 index 0000000..7d12d9a --- /dev/null +++ b/rust/libpr4-sys/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/rust/powerrender-3d/Cargo.toml b/rust/powerrender-3d/Cargo.toml new file mode 100644 index 0000000..d233aef --- /dev/null +++ b/rust/powerrender-3d/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "powerrender-3d" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +binrw = "0.11.1" diff --git a/rust/powerrender-3d/src/main.rs b/rust/powerrender-3d/src/main.rs new file mode 100644 index 0000000..95c4167 --- /dev/null +++ b/rust/powerrender-3d/src/main.rs @@ -0,0 +1,11 @@ +use crate::pro::read_power_render_object; +use binrw::{BinRead, BinResult}; +use std::fs::File; + +pub mod pro; + +fn main() { + let mut file = File::open(r#"E:\Games\Moorhuhn Kart\data\alk.pro"#).unwrap(); + let result = read_power_render_object(&mut file).unwrap(); + println!("{:#?}", result); +} diff --git a/rust/powerrender-3d/src/pro/chunk.rs b/rust/powerrender-3d/src/pro/chunk.rs new file mode 100644 index 0000000..2fb9eab --- /dev/null +++ b/rust/powerrender-3d/src/pro/chunk.rs @@ -0,0 +1,65 @@ +use binrw::io::{TakeSeek, TakeSeekExt}; +use binrw::meta::{EndianKind, ReadEndian}; +use binrw::{until_eof, BinRead, BinReaderExt, BinResult, Endian}; +use std::io::{Read, Seek, SeekFrom}; + +pub struct Chunk(pub T) +where + for<'a> T: BinRead = Args>; + +impl Chunk +where + for<'a> T: BinRead = Args>, +{ + pub fn inner(self) -> T { + self.0 + } +} + +pub fn chunk_until_eof( + reader: &mut Reader, + endian: Endian, + args: Arg, +) -> BinResult +where + T: for<'a> BinRead = Arg>, + Reader: Read + Seek, + Arg: Clone, + Ret: FromIterator, +{ + let len = reader.read_type::(endian)? as u64 - 6; + let pos = reader.stream_position()?; + let end = pos + len; + let mut sub_stream = reader.take_seek(len); + let result = until_eof(&mut sub_stream, endian, args)?; + reader.seek(SeekFrom::Start(end))?; + Ok(result) +} + +impl ReadEndian for Chunk +where + for<'a> T: BinRead = Args>, +{ + const ENDIAN: EndianKind = EndianKind::Endian(Endian::Little); +} + +impl BinRead for Chunk +where + for<'a> T: BinRead = Args>, +{ + type Args<'a> = Args; + + fn read_options( + reader: &mut R, + endian: Endian, + args: Self::Args<'_>, + ) -> BinResult { + let len = reader.read_type::(endian)? as u64 - 6; + let pos = reader.stream_position()?; + let end = pos + len; + let mut sub_stream = reader.take_seek(len); + let result = T::read_options(&mut sub_stream, endian, args)?; + reader.seek(SeekFrom::Start(end))?; + Ok(Chunk(result)) + } +} diff --git a/rust/powerrender-3d/src/pro/mod.rs b/rust/powerrender-3d/src/pro/mod.rs new file mode 100644 index 0000000..23ea421 --- /dev/null +++ b/rust/powerrender-3d/src/pro/mod.rs @@ -0,0 +1,239 @@ +use crate::pro::chunk::Chunk; +use binrw::__private::magic; +use binrw::{binread, until_eof, BinRead, BinReaderExt, BinResult, Endian, NullString}; +use std::fmt::Debug; +use std::io::{Read, Seek}; + +pub mod chunk; + +pub fn read_power_render_object(reader: &mut R) -> BinResult> +where + R: Read + Seek, +{ + magic(reader, 0x0303u16, Endian::Little)?; + let data: Chunk = Chunk::::read(reader)?; + Ok(data.0.chunks) +} + +#[binread] +struct PrObject { + #[br(parse_with = until_eof)] + pub chunks: Vec, +} + +#[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::| it.0.chunks)] Vec), + #[br(magic = 0x2010u16)] + TextureList(#[br(map = |it: Chunk::>| it.0.data)] Vec), + #[br(magic = 0x2011u16)] + TextureAlpha(#[br(map = |it: Chunk::>| it.0.data)] Vec), + #[br(magic = 0x2012u16)] + TextureStage(#[br(map = |it: Chunk::>| it.0.data)] Vec), + #[br(magic = 0x2013u16)] + TextureFormat(#[br(map = |it: Chunk::>| it.0.data)] Vec), + #[br(magic = 0x2014u16)] + TextureMulti(#[br(map = |it: Chunk::>| it.0.data)] Vec), + #[br(magic = 0x2100u16)] + MaterialList(#[br(map = |it: Chunk::| it.0.chunks)] Vec), + #[br(magic = 0x3000u16)] + Camera(#[br(map = Chunk::inner)] ()), // TODO + #[br(magic = 0x3010u16)] + ObjectBbox(#[br(map = Chunk::inner)] Box), + #[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, +} + +#[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, +} + +#[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), + #[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)] +pub struct PrVertices { + pub vertices: Vec<[f32; 3]>, + pub normals: Vec<[f32; 3]>, +} + +impl BinRead for PrVertices { + type Args<'a> = (); + + fn read_options( + reader: &mut R, + endian: Endian, + _: Self::Args<'_>, + ) -> BinResult { + let count = reader.read_type::(endian)? as usize; + let mut result = PrVertices { + vertices: Vec::with_capacity(count), + normals: Vec::with_capacity(count), + }; + for _ in 0..count { + result.vertices.push(reader.read_type(endian)?); + let normal: [i16; 3] = reader.read_type(endian)?; + result.normals.push([ + normal[0] as f32 / 1024.0, + normal[1] as f32 / 1024.0, + normal[2] as f32 / 1024.0, + ]); + } + Ok(result) + } +} + +#[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 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 BinRead = Args> + 'static> +{ + #[br(temp)] + count: u16, + #[br(count = count)] + pub data: Vec, +}