Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kindling-host: renderer bindings #301

Merged
merged 7 commits into from
Mar 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions guest/rust/hearth-guest/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ impl Message {
}

/// A loaded lump.
#[derive(Debug)]
pub struct Lump(u32);

impl Drop for Lump {
Expand All @@ -315,8 +316,8 @@ impl Drop for Lump {
}

impl Lump {
/// Loads a new lump from in-process data.
pub fn load(data: &[u8]) -> Self {
/// Loads a new lump directly from in-process bytes.
pub fn load_raw(data: &[u8]) -> Self {
unsafe {
let ptr = data.as_ptr() as u32;
let len = data.len() as u32;
Expand All @@ -325,6 +326,12 @@ impl Lump {
}
}

/// Loads a JSON-encoded lump from a serializable data type.
pub fn load(data: &impl Serialize) -> Self {
let bytes = serde_json::to_vec(data).unwrap();
Self::load_raw(&bytes)
}

/// Loads a lump from the ID of an already existing lump.
pub fn load_by_id(id: &LumpId) -> Self {
unsafe {
Expand Down
1 change: 1 addition & 0 deletions kindling/host/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub mod canvas;
pub mod debug_draw;
pub mod fs;
pub mod registry;
pub mod renderer;
pub mod terminal;
pub mod time;
pub mod wasm;
Expand Down
166 changes: 166 additions & 0 deletions kindling/host/src/renderer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
// Copyright (c) 2024 the Hearth contributors.
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// This file is part of Hearth.
//
// Hearth is free software: you can redistribute it and/or modify it under the
// terms of the GNU Affero General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// Hearth is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
// details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Hearth. If not, see <https://www.gnu.org/licenses/>.

use super::*;

use glam::{Mat4, Vec3};
use hearth_guest::{renderer::*, Lump};

lazy_static::lazy_static! {
static ref RENDERER: RequestResponse<RendererRequest, RendererResponse> =
RequestResponse::expect_service("hearth.Renderer");
}

/// Set the global ambient lighting levels.
pub fn set_ambient_lighting(color: Vec3) {
let (result, _) = RENDERER.request(
RendererRequest::SetAmbientLighting {
ambient: color.extend(1.0),
},
&[],
);

let _ = result.unwrap();
}

/// Update the skybox with the given lump containing [TextureData].
pub fn set_skybox(texture: &Lump) {
let (result, _) = RENDERER.request(
RendererRequest::SetSkybox {
texture: texture.get_id(),
},
&[],
);

let _ = result.unwrap();
}

/// A directional light.
pub struct DirectionalLight(Capability);

impl Drop for DirectionalLight {
fn drop(&mut self) {
self.0.kill();
}
}

impl DirectionalLight {
/// Create a new directional light.
pub fn new(state: DirectionalLightState) -> Self {
let (result, caps) = RENDERER.request(
RendererRequest::AddDirectionalLight {
initial_state: state,
},
&[],
);

let _ = result.expect("failed to create directional light");

Self(caps.first().unwrap().clone())
}

/// Internal helper function to update this light.
fn update(&self, update: DirectionalLightUpdate) {
self.0.send(&update, &[]);
}

/// Set this directional light's color.
pub fn set_color(&self, color: Vec3) {
self.update(DirectionalLightUpdate::Color(color));
}

/// Set this directional light's intensity.
pub fn set_intensity(&self, intensity: f32) {
self.update(DirectionalLightUpdate::Intensity(intensity));
}

/// Set this directional light's direction.
pub fn set_direction(&self, direction: Vec3) {
self.update(DirectionalLightUpdate::Direction(direction));
}

/// Set this distanceal light's distance.
pub fn set_distance(&self, distance: f32) {
self.update(DirectionalLightUpdate::Distance(distance));
}
}

/// Configuration for the creation of an [Object].
#[derive(Clone, Debug)]
pub struct ObjectConfig<'a> {
/// A reference to the lump containing this object's [MeshData].
pub mesh: &'a Lump,

/// An optional list of skeleton joint matrices for this object.
pub skeleton: Option<Vec<Mat4>>,

/// The lump containing this object's [MaterialData].
pub material: &'a Lump,

/// The initial transform of this object.
pub transform: Mat4,
}

/// An object.
pub struct Object(Capability);

impl Drop for Object {
fn drop(&mut self) {
self.0.kill();
}
}

impl Object {
/// Create a new object in the scene with the given [ObjectConfig].
pub fn new(config: ObjectConfig) -> Self {
let (result, caps) = RENDERER.request(
RendererRequest::AddObject {
mesh: config.mesh.get_id(),
skeleton: config.skeleton,
material: config.material.get_id(),
transform: config.transform,
},
&[],
);

let _ = result.expect("failed to create object");

Self(caps.first().unwrap().clone())
}

/// Updates the transform of this object.
pub fn set_transform(&self, transform: Mat4) {
self.0.send(&ObjectUpdate::Transform(transform), &[]);
}

/// Update the joint matrices of this mesh.
pub fn set_joint_matrices(&self, joints: Vec<Mat4>) {
self.0.send(&ObjectUpdate::JointMatrices(joints), &[]);
}

/// Update the joint transforms of this mesh.
pub fn set_joint_transforms(&self, joint_global: Vec<Mat4>, inverse_bind: Vec<Mat4>) {
self.0.send(
&ObjectUpdate::JointTransforms {
joint_global,
inverse_bind,
},
&[],
);
}
}
22 changes: 7 additions & 15 deletions kindling/services/skybox/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@
// along with Hearth. If not, see <https://www.gnu.org/licenses/>.

use hearth_guest::{renderer::*, Lump};
use kindling_host::prelude::RequestResponse;

type Renderer = RequestResponse<RendererRequest, RendererResponse>;
use kindling_host::renderer::set_skybox;

/// Helper function to append a skybox image to the cube texture data.
fn add_face(data: &mut Vec<u8>, image: &[u8]) {
Expand All @@ -37,17 +35,11 @@ pub extern "C" fn run() {
add_face(&mut data, include_bytes!("elyvisions/sh_rt.png"));
add_face(&mut data, include_bytes!("elyvisions/sh_lf.png"));

let texture = Lump::load(
&serde_json::to_vec(&TextureData {
label: None,
size: (1024, 1024).into(),
data,
})
.unwrap(),
)
.get_id();
let texture = Lump::load(&TextureData {
label: None,
size: (1024, 1024).into(),
data,
});

let renderer = Renderer::expect_service("hearth.Renderer");
let (result, _) = renderer.request(RendererRequest::SetSkybox { texture }, &[]);
result.unwrap();
set_skybox(&texture);
}
Loading