Skip to content

Commit

Permalink
Merge pull request #301 from hearth-rs/renderer-bindings
Browse files Browse the repository at this point in the history
kindling-host: renderer bindings
  • Loading branch information
marceline-cramer committed Mar 18, 2024
2 parents 69b828d + d400594 commit 7b6b437
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 17 deletions.
11 changes: 9 additions & 2 deletions guest/rust/hearth-guest/src/lib.rs
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
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
@@ -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
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);
}

0 comments on commit 7b6b437

Please sign in to comment.