tirbofish/dropbear · commit
cd3689deb60bedaf605e67f43ebcba3571334bbc
feature: input detection works with buttons wip: button **still** doesnt render text. Unverified
@@ -1,3 +1,3 @@ [target.x86_64-unknown-linux-gnu] linker = "clang" -rustflags = ["-C", "link-arg=-fuse-ld=mold"] +rustflags = ["-C", "link-arg=-fuse-ld=mold", "-C", "relocation-model=pic"] @@ -74,7 +74,7 @@ rapier3d = { version = "0.32", features = [ "simd-stable", "serde-serialize" ] } cbindgen = { version = "0.29.2" } postcard = { version = "1.1"} pollster = "0.4" -yakui = { git = "https://github.com/SecondHalfGames/yakui", rev = "af8fc1f" } +yakui = { git = "https://github.com/SecondHalfGames/yakui", rev = "af8fc1f", features = ["default-fonts"] } yakui-wgpu = { git = "https://github.com/SecondHalfGames/yakui", rev = "af8fc1f" } yakui-winit = { git = "https://github.com/SecondHalfGames/yakui", rev = "af8fc1f" } thiserror = "2.0" @@ -3,6 +3,8 @@ <h1 align="center">dropbear</h1> </p> +--- + dropbear is a game engine used to create games, made in Rust and scripted with the Kotlin Language. It's name is a double entendre, with it being the nickname of koalas but also fits in nicely with the theme of rust utilising memory management with "drops". @@ -16,6 +18,7 @@ If you might have not realised, all the crates/projects names are after Australi - [eucalyptus-core](https://github.com/tirbofish/dropbear/tree/main/crates/eucalyptus-core) is the library used by both `redback-runtime` and `eucalyptus-editor` to share configs and metadata between each other. - [redback-runtime](https://github.com/tirbofish/dropbear/tree/main/crates/redback-runtime) is the runtime used to load .eupak files and run the game loaded on them. - [magna-carta](https://github.com/tirbofish/dropbear/tree/main/crates/magna-carta) is a rust library used to generate compile-time Kotlin/Native and Kotlin/JVM metadata for searching. +- [slank](https://github.com/tirbofish/dropbear/tree/main/crates/slank) is a slang compiler that compiles .slang files into shaders during build.rs compilation time. [//]: # (- [eucalyptus-sdk](https://github.com/tirbofish/dropbear/tree/main/eucalyptus-sdk) is used to develop plugins to be used with the `eucalyptus-editor`) @@ -1004,6 +1004,8 @@ impl ApplicationHandler for App { .lock() .handle_input(&state.window, &event); + state.scene_manager.handle_event(&event); + match event { WindowEvent::Resized(size) => { state.resize(size.width, size.height); @@ -12,7 +12,7 @@ pub struct MipMapper { impl MipMapper { pub fn new(device: &wgpu::Device) -> Self { - let blit_shader = device.create_shader_module(slank::compiled::CompiledSlangShader::from_bytes( + let blit_shader = device.create_shader_module(slank::CompiledSlangShader::from_bytes( "mipmap blit_shader", include_slang!("blit_shader") ).create_wgpu_shader()); @@ -27,7 +27,7 @@ pub struct LightCubePipeline { impl DropbearShaderPipeline for LightCubePipeline { fn new(graphics: Arc<SharedGraphicsContext>) -> Self { - let shader = Shader::from_slang(graphics.clone(), &slank::compiled::CompiledSlangShader::from_bytes("light cube", include_slang!("light_cube"))); + let shader = Shader::from_slang(graphics.clone(), &slank::CompiledSlangShader::from_bytes("light cube", include_slang!("light_cube"))); let pipeline_layout = graphics.device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("light cube pipeline layout"), @@ -4,6 +4,7 @@ use winit::event_loop::ActiveEventLoop; use winit::window::WindowId; +use winit::event::WindowEvent; use crate::{WindowData, graphics::{SharedGraphicsContext}, input}; use parking_lot::RwLock; @@ -15,6 +16,7 @@ pub trait Scene { fn update(&mut self, dt: f32, graphics: Arc<SharedGraphicsContext>); fn render<'a>(&mut self, graphics: Arc<SharedGraphicsContext>); fn exit(&mut self, event_loop: &ActiveEventLoop); + fn handle_event(&mut self, _event: &WindowEvent) {} /// By far a mess of a trait however it works. /// /// This struct allows you to add in a SceneCommand enum and send it to the scene management for them @@ -168,6 +170,14 @@ impl Manager { } } + pub fn handle_event(&mut self, event: &WindowEvent) { + if let Some(scene_name) = &self.current_scene + && let Some(scene) = self.scenes.get_mut(scene_name) + { + scene.write().handle_event(event); + } + } + pub fn has_scene(&self) -> bool { self.current_scene.is_some() } @@ -3,7 +3,7 @@ use std::ops::Deref; use crate::graphics::SharedGraphicsContext; use std::sync::Arc; -use slank::{compiled::CompiledSlangShader, utils::WgpuUtils}; +use slank::{CompiledSlangShader, utils::WgpuUtils}; use wgpu::ShaderModule; /// A nice little struct that stored basic information about a WGPU shaders. @@ -48,7 +48,7 @@ impl Shader { log::debug!("Created new shaders under the label: {:?}", label); - slank::compiled::CompiledSlangShader::from_bytes("light cube", slank::include_slang!("light_cube")); + CompiledSlangShader::from_bytes("light cube", slank::include_slang!("light_cube")); Self { label: match label { @@ -30,8 +30,6 @@ pub struct UIComponent { pub ui_file: ResourceReference, } -// note for tomorrow: use UIInstruction like that of asm - #[derive(Clone, Copy, Debug, Default)] pub struct WidgetState { pub clicked: bool, @@ -60,21 +58,13 @@ impl NativeWidget for WrapperWidget<yakui::widgets::Button> { pub trait WidgetParser: Send + Sync { fn parse(&self, env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Option<Box<dyn NativeWidget>>>; + fn name(&self) -> String; } -static PARSERS: std::sync::OnceLock<Mutex<Vec<Box<dyn WidgetParser>>>> = std::sync::OnceLock::new(); - pub fn register_widget_parser<P: WidgetParser + 'static>(parser: P) { - let parsers = PARSERS.get_or_init(|| Mutex::new(Vec::new())); - parsers.lock().push(Box::new(parser)); -} - -fn get_parsers() -> &'static Mutex<Vec<Box<dyn WidgetParser>>> { - PARSERS.get_or_init(|| { - let mut vec: Vec<Box<dyn WidgetParser>> = Vec::new(); - vec.push(Box::new(ButtonParser)); - Mutex::new(vec) - }) + UI_CONTEXT.with(|v| { + v.borrow().parsers.lock().push(Box::new(parser)); + }); } struct ButtonParser; @@ -84,6 +74,7 @@ impl WidgetParser for ButtonParser { let class = env.get_object_class(obj)?; let name_str_obj = env.call_method(class, "getName", "()Ljava/lang/String;", &[])?.l()?; let name_string: String = env.get_string(&name_str_obj.into())?.into(); + // println!("ButtonParser obj get_string result: {}", name_string); if name_string.contains("ButtonInstruction$Button") { let button_obj = env.get_field(obj, "button", "Lcom/dropbear/ui/widgets/Button;")?.l()?; @@ -100,6 +91,10 @@ impl WidgetParser for ButtonParser { Ok(None) } + + fn name(&self) -> String { + String::from("ButtonParser") + } } @@ -107,6 +102,7 @@ pub struct UiContext { pub yakui_state: Mutex<Yakui>, pub instruction_set: Mutex<Vec<Box<dyn NativeWidget>>>, pub widget_states: Mutex<HashMap<i64, WidgetState>>, + pub parsers: Mutex<Vec<Box<dyn WidgetParser>>>, } pub fn poll() { @@ -114,11 +110,7 @@ pub fn poll() { let ctx = v.borrow(); let mut instructions = ctx.instruction_set.lock(); let mut widget_states = ctx.widget_states.lock(); - // Clear previous states before rebuild? - // Or yakui persistent state implies we should keep? - // If we clear, and script runs before poll, it might see empty. - // But script reads states from PREVIOUS frame usually. - // Let's clear to avoid stale data from removed widgets. + widget_states.clear(); let current_instructions = instructions.drain(..).collect::<Vec<Box<dyn NativeWidget>>>(); @@ -130,10 +122,17 @@ pub fn poll() { impl UiContext { pub fn new() -> Self { + let mut parsers: Vec<Box<dyn WidgetParser>> = Vec::new(); + + parsers.push(Box::new(ButtonParser)); + + let yakui = Yakui::new(); + Self { - yakui_state: Mutex::new(Yakui::new()), + yakui_state: Mutex::new(yakui), instruction_set: Default::default(), widget_states: Default::default(), + parsers: Mutex::new(parsers), } } } @@ -148,11 +147,11 @@ pub trait UiWidgetType: FromJObject { pub mod jni { #![allow(non_snake_case)] - use jni::sys::jlong; + use jni::sys::{jboolean, jlong}; use jni::objects::{JClass, JObjectArray}; use jni::JNIEnv; use crate::convert_ptr; - use crate::ui::{UiContext, get_parsers}; + use crate::ui::{UiContext}; #[unsafe(no_mangle)] pub extern "system" fn Java_com_dropbear_ui_UINative_renderUI( @@ -161,12 +160,12 @@ pub mod jni { ui_buf_ptr: jlong, instructions: JObjectArray, ) { - println!("[Java_com_dropbear_ui_UINative_renderUI] received new renderUI request"); + // println!("[Java_com_dropbear_ui_UINative_renderUI] received new renderUI request"); let ui = convert_ptr!(ui_buf_ptr => UiContext); let mut rust_instructions = Vec::new(); let count = env.get_array_length(&instructions).unwrap_or(0); - let parsers_guard = get_parsers().lock(); + let parsers_guard = ui.parsers.lock(); for i in 0..count { let obj = match env.get_object_array_element(&instructions, i) { @@ -178,13 +177,13 @@ pub mod jni { for parser in parsers_guard.iter() { match parser.parse(&mut env, &obj) { Ok(Some(widget)) => { - println!("[Java_com_dropbear_ui_UINative_renderUI] successfully located widget: {:?}", widget); + // println!("Received widget: {:?}", widget); rust_instructions.push(widget); break; }, Ok(None) => {println!("[Java_com_dropbear_ui_UINative_renderUI] Ok but None"); continue}, Err(e) => { - eprintln!("Error converting UI instruction: {:?}", e); + eprintln!("[Java_com_dropbear_ui_UINative_renderUI] Error converting UI instruction: {:?}", e); } } } @@ -199,10 +198,10 @@ pub mod jni { _class: JClass, ui_buf_ptr: jlong, id: jlong, - ) -> bool { + ) -> jboolean { let ui = convert_ptr!(ui_buf_ptr => UiContext); let states = ui.widget_states.lock(); - states.get(&id).map(|s| s.clicked).unwrap_or(false) + states.get(&id).map(|s| s.clicked).unwrap_or(false).into() } #[unsafe(no_mangle)] @@ -211,9 +210,9 @@ pub mod jni { _class: JClass, ui_buf_ptr: jlong, id: jlong, - ) -> bool { + ) -> jboolean { let ui = convert_ptr!(ui_buf_ptr => UiContext); let states = ui.widget_states.lock(); - states.get(&id).map(|s| s.hovering).unwrap_or(false) + states.get(&id).map(|s| s.hovering).unwrap_or(false).into() } } @@ -12,14 +12,14 @@ impl FromJObject for Button { let text_jstring = text_field.l()?.into(); let text: String = env.get_string(&text_jstring)?.into(); - let f = env.get_field(obj, "padding", "Lcom/dropbear/ui/styling/Padding;")?.l()?; - let padding = Pad::from_jobject( + let f = env.get_field(obj, "alignment", "Lcom/dropbear/ui/styling/Alignment;")?.l()?; + let alignment = Alignment::from_jobject( env, &f )?; - let f = env.get_field(obj, "alignment", "Lcom/dropbear/ui/styling/Alignment;")?.l()?; - let alignment = Alignment::from_jobject( + let f = env.get_field(obj, "padding", "Lcom/dropbear/ui/styling/Padding;")?.l()?; + let padding = Pad::from_jobject( env, &f )?; @@ -2,11 +2,11 @@ use jni::JNIEnv; use jni::objects::{JObject, JByteArray}; use crate::scripting::jni::utils::FromJObject; use crate::scripting::result::DropbearNativeResult; -use yakui::Color; +use yakui::{Border, Color}; use yakui::widgets::{Pad, DynamicButtonStyle}; use yakui::{Alignment, BorderRadius}; use yakui::style::{TextStyle, TextAlignment}; -use yakui::cosmic_text::{Attrs, AttrsOwned, FamilyOwned, Weight, Style, Stretch, CacheKeyFlags, FontFeatures, Feature, FeatureTag}; +use yakui::cosmic_text::{Attrs, AttrsOwned, FamilyOwned, Weight, Style, Stretch, CacheKeyFlags, FontFeatures, Feature, FeatureTag, Metrics, CacheMetrics}; impl FromJObject for FeatureTag { fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> { @@ -54,6 +54,30 @@ impl FromJObject for FontFeatures { } } +impl FromJObject for CacheMetrics { + fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> { + let font_size = env.get_field(obj, "fontSize", "D")?.d()? as f32; + let line_height = env.get_field(obj, "lineHeight", "D")?.d()? as f32; + + Ok(CacheMetrics::from(Metrics { + font_size, + line_height, + })) + } +} + +impl FromJObject for Border { + fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> { + let color_obj = env.get_field(obj, "colour", "Lcom/dropbear/utils/Colour;")?.l()?; + let color = Color::from_jobject(env, &color_obj)?; + let width = env.get_field(obj, "width", "D")?.d()? as f32; + Ok(Border { + color, + width, + }) + } +} + impl FromJObject for Color { fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> { let r = env.get_field(obj, "r", "B")?.b()? as u8; @@ -214,6 +238,16 @@ impl FromJObject for AttrsOwned { FontFeatures::default() }; + let cache_key_flags_val = env.get_field(obj, "cacheKeyFlags", "I")?.i()? as u32; + let cache_key_flags = CacheKeyFlags::from_bits_truncate(cache_key_flags_val); + + let metrics_obj = env.get_field(obj, "metricsOptions", "Lcom/dropbear/ui/styling/fonts/CacheMetrics;")?.l()?; + let metrics_opt = if !metrics_obj.is_null() { + Some(CacheMetrics::from_jobject(env, &metrics_obj)?) + } else { + None + }; + Ok(AttrsOwned::new(&Attrs { family, stretch, @@ -221,8 +255,8 @@ impl FromJObject for AttrsOwned { weight, metadata, color_opt, - cache_key_flags: CacheKeyFlags::empty(), - metrics_opt: None, + cache_key_flags, + metrics_opt, letter_spacing_opt, font_features, })) @@ -243,11 +277,15 @@ impl FromJObject for TextStyle { Color::WHITE }; + let attrs_obj = env.get_field(obj, "attrs", "Lcom/dropbear/ui/styling/fonts/FontAttributes;")?.l()?; + let attrs = AttrsOwned::from_jobject(env, &attrs_obj)?; + Ok(TextStyle { align, font_size, + line_height_override: None, color, - ..TextStyle::default() + attrs, }) } } @@ -258,6 +296,7 @@ impl FromJObject for DynamicButtonStyle { let text = if !text_obj.is_null() { TextStyle::from_jobject(env, &text_obj)? } else { + println!("Text is null, setting to default"); TextStyle::default() }; @@ -268,10 +307,17 @@ impl FromJObject for DynamicButtonStyle { Color::GRAY }; + let border_obj = env.get_field(obj, "border", "Lcom/dropbear/ui/styling/Border;")?.l()?; + let border = if !border_obj.is_null() { + Some(Border::from_jobject(env, &border_obj)?) + } else { + None + }; + Ok(DynamicButtonStyle { text, fill, - border: None, + border, }) } } @@ -28,12 +28,13 @@ serde.workspace = true crossbeam-channel.workspace = true gilrs.workspace = true futures.workspace = true +yakui-winit.workspace = true +yakui.workspace = true +egui.workspace = true +egui_extras.workspace = true glam.workspace = true wgpu.workspace = true -egui.workspace = true -yakui.workspace = true yakui-wgpu.workspace = true -egui_extras.workspace = true [features] debug = [] @@ -25,6 +25,7 @@ use eucalyptus_core::command::COMMAND_BUFFER; use eucalyptus_core::scene::loading::IsSceneLoaded; use std::collections::HashMap; use std::path::PathBuf; +use yakui_winit::YakuiWinit; use eucalyptus_core::physics::PhysicsState; use eucalyptus_core::rapier3d::prelude::*; use eucalyptus_core::register_components; @@ -109,6 +110,9 @@ pub struct PlayMode { collider_wireframe_geometry_cache: HashMap<ColliderShapeKey, WireframeGeometry>, collider_instance_buffer: Option<ResizableBuffer<ColliderInstanceRaw>>, viewport_offset: (f32, f32), + + // ui + yakui_winit: Option<YakuiWinit>, } impl PlayMode { @@ -155,6 +159,7 @@ impl PlayMode { collision_event_receiver: Some(ce_r), collision_force_event_receiver: Some(cfe_r), event_collector, + yakui_winit: None, }; log::debug!("Created new play mode instance"); @@ -12,6 +12,8 @@ use hecs::Entity; use wgpu::{Color}; use wgpu::util::DeviceExt; use winit::event_loop::ActiveEventLoop; +use winit::event::WindowEvent; +use yakui::font::Fonts; use yakui_wgpu::SurfaceInfo; use dropbear_engine::camera::Camera; use dropbear_engine::buffer::ResizableBuffer; @@ -37,6 +39,11 @@ use eucalyptus_core::ui::UI_CONTEXT; impl Scene for PlayMode { fn load(&mut self, graphics: Arc<SharedGraphicsContext>) { + let mut yak = yakui_winit::YakuiWinit::new(&graphics.window); + yak.set_automatic_viewport(false); + yak.set_automatic_scale_factor(false); + self.yakui_winit = Some(yak); + if self.current_scene.is_none() { let initial_scene = if let Some(s) = &self.initial_scene { s.clone() @@ -461,6 +468,11 @@ impl Scene for PlayMode { yakui.set_surface_size(yakui::geometry::Vec2::new(display_width, display_height)); yakui.start(); + let fonts = yakui.dom().get_global_or_init(Fonts::default); + fonts.with_system(|v| { + log_once::debug_once!("font len: {}", v.db().len()); + }); + eucalyptus_core::ui::poll(); // Layer::new().show(|| { @@ -869,6 +881,17 @@ impl Scene for PlayMode { } } + fn handle_event(&mut self, event: &WindowEvent) { + UI_CONTEXT.with(|yakui_cell| { + let yak = yakui_cell.borrow(); + let mut yakui = yak.yakui_state.lock(); + if let Some(yak) = &mut self.yakui_winit { + yak.handle_window_event(&mut yakui, event); + + } + }); + } + fn exit(&mut self, _event_loop: &ActiveEventLoop) {} fn run_command(&mut self) -> SceneCommand { @@ -1,6 +1,6 @@ [package] name = "slank" -version = "0.1.0" +version.workspace = true edition.workspace = true license.workspace = true repository.workspace = true @@ -1,14 +1,13 @@ package com.dropbear.ui.styling -class BorderRadius( - topLeft: Double = 0.0, - topRight: Double = 0.0, - bottomLeft: Double = 0.0, - bottomRight: Double = 0.0 +data class BorderRadius( + var topLeft: Double = 0.0, + var topRight: Double = 0.0, + var bottomLeft: Double = 0.0, + var bottomRight: Double = 0.0 ) { companion object { fun uniform(value: Double): BorderRadius { - UInt return BorderRadius( value, value, @@ -1,9 +1,10 @@ package com.dropbear.ui.styling +import com.dropbear.ui.styling.fonts.TextAlignment import com.dropbear.utils.Colour data class DynamicButtonStyle( - var text: TextStyle = TextStyle.label(), + var text: TextStyle = TextStyle(align = TextAlignment.Center), var fill: Colour = Colour.GRAY, var border: Border? = null, ) @@ -1,30 +1,23 @@ package com.dropbear.ui.styling +import com.dropbear.ui.styling.fonts.Family import com.dropbear.ui.styling.fonts.FontAttributes import com.dropbear.ui.styling.fonts.FontName import com.dropbear.ui.styling.fonts.TextAlignment import com.dropbear.utils.Colour data class TextStyle( - var font: FontName, - var fontSize: Double, - var colour: Colour, - var align: TextAlignment, - var attrs: FontAttributes, + var fontSize: Double = 14.0, + var lineHeightOverride: Double? = null, + var colour: Colour = Colour.WHITE, + var align: TextAlignment = TextAlignment.Start, + var attrs: FontAttributes = FontAttributes( + family = Family.SansSerif, + ), ) { companion object { fun label(): TextStyle { - return TextStyle( - font = FontName("default"), - fontSize = 14.0, - colour = Colour.WHITE, - align = TextAlignment.Start, - attrs = FontAttributes() - ) + return TextStyle() } } - - override fun toString(): String { - return "TextStyle(font=$font, fontSize=$fontSize, colour=$colour)" - } } @@ -1,6 +1,6 @@ package com.dropbear.ui.styling.fonts class CacheMetrics( - val fontSizeBits: UInt, - val lineHeightBits: UInt, + val fontSize: Double, + val lineHeight: Double, ) @@ -4,7 +4,7 @@ import com.dropbear.utils.Colour class FontAttributes( var colourOptions: Colour? = null, - var family: Family = Family.SansSerif, + var family: Family = Family.Name("default"), var stretch: Stretch = Stretch.Normal, var style: FontStyle = FontStyle.Normal, var weight: FontWeight = FontWeight.NORMAL, @@ -5,9 +5,12 @@ import com.dropbear.ui.UIInstruction import com.dropbear.ui.Widget import com.dropbear.ui.WidgetId import com.dropbear.ui.styling.Alignment +import com.dropbear.ui.styling.Border import com.dropbear.ui.styling.BorderRadius import com.dropbear.ui.styling.DynamicButtonStyle import com.dropbear.ui.styling.Padding +import com.dropbear.ui.styling.TextStyle +import com.dropbear.ui.styling.fonts.TextAlignment import com.dropbear.utils.Colour class Button( @@ -28,23 +31,45 @@ class Button( get() = getHovering() companion object { - fun styled(text: String) : Button { + fun styled(text: String, id: String = text) : Button { + val style = DynamicButtonStyle( + fill = Colour.BACKGROUND_3, + text = TextStyle( + colour = Colour.WHITE.adjust(0.8), + align = TextAlignment.Center + ), + border = Border( + colour = Colour.BACKGROUND_1, + width = 1.0 + ) + ) + + val hoverStyle = DynamicButtonStyle( + fill = Colour.BACKGROUND_3.adjust(1.2), + border = Border(Colour.WHITE.adjust(0.75), 1.0), + ) + + val downStyle = DynamicButtonStyle( + fill = Colour.BACKGROUND_3.adjust(0.8), + border = Border(Colour.WHITE, 1.0) + ) + val result = Button( text = text, alignment = Alignment.CENTER, padding = Padding.balanced(20.0, 10.0), borderRadius = BorderRadius.uniform(6.0), - style = DynamicButtonStyle(fill = Colour.BACKGROUND_3), - hoverStyle = DynamicButtonStyle(fill = Colour.BACKGROUND_3.adjust(1.2)), - downStyle = DynamicButtonStyle(fill = Colour.BACKGROUND_3.adjust(0.8)), + style = style, + hoverStyle = hoverStyle, + downStyle = downStyle, ) - result.id = WidgetId(result.hashCode().toLong()) + result.id = WidgetId(id.hashCode().toLong()) return result } - fun unstyled(text: String) : Button { + fun unstyled(text: String, id: String = text) : Button { val result = Button( text = text, alignment = Alignment.CENTER, @@ -55,7 +80,7 @@ class Button( downStyle = DynamicButtonStyle(), ) - result.id = WidgetId(result.hashCode().toLong()) + result.id = WidgetId(id.hashCode().toLong()) return result } @@ -26,8 +26,8 @@ class Colour( val FUCHSIA = Colour.rgb(255u, 255u, 0u) val GRAY = Colour.rgb(127u, 127u, 127u) val TRANSPARENT = Colour(0u, 0u, 0u, 0u) - val WHITE = Colour.rgb(0u, 0u, 0u) - val BLACK = Colour.rgb(255u, 255u, 255u) + val WHITE = Colour.rgb(255u, 255u, 255u) + val BLACK = Colour.rgb(0u, 0u, 0u) val BACKGROUND_1 = Colour.rgb(31u, 31u, 31u) val BACKGROUND_2 = Colour.rgb(42u, 42u, 42u) @@ -63,10 +63,10 @@ class Colour( */ fun normalize(): Vector4d { return Vector4d( - x=(r/ 255u).toDouble(), - y=(g/ 255u).toDouble(), - z=(b/ 255u).toDouble(), - w=(a/ 255u).toDouble(), + x=(r.toDouble() / 255.0), + y=(g.toDouble() / 255.0), + z=(b.toDouble() / 255.0), + w=(a.toDouble() / 255.0), ) } @@ -1,5 +1,6 @@ package com.dropbear +import com.dropbear.logging.Logger import com.dropbear.ui.UIInstruction import com.dropbear.ui.UINative @@ -16,5 +17,6 @@ internal actual fun quit() { } internal actual fun renderUI(instructions: List<UIInstruction>) { + Logger.debug("instructions: $instructions") UINative.renderUI(DropbearEngine.native.uiBufferHandle, instructions.toTypedArray()) }