Rust rendering library built on top of Raylib
0

Configure Feed

Select the types of activity you want to include in your feed.

rename crates, add UTF-8 text drawing, and add a timer struct

+208 -34
+10
.editorconfig
··· 1 + root = true 2 + 3 + [*] 4 + end_of_line = lf 5 + insert_final_newline = true 6 + charset = utf-8 7 + 8 + [*.rs] 9 + indent_style = space 10 + indent_size = 4
+20 -20
Cargo.lock
··· 95 95 ] 96 96 97 97 [[package]] 98 - name = "core" 99 - version = "0.1.0" 100 - dependencies = [ 101 - "anyhow", 102 - "num-traits", 103 - "serde", 104 - "serde-lexpr", 105 - "thiserror", 106 - ] 107 - 108 - [[package]] 109 98 name = "either" 110 99 version = "1.16.0" 111 100 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 122 111 version = "0.3.3" 123 112 source = "registry+https://github.com/rust-lang/crates.io-index" 124 113 checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" 125 - 126 - [[package]] 127 - name = "graphics" 128 - version = "0.1.0" 129 - dependencies = [ 130 - "core", 131 - "num-traits", 132 - "raylib-ffi", 133 - ] 134 114 135 115 [[package]] 136 116 name = "itertools" ··· 303 283 version = "0.8.11" 304 284 source = "registry+https://github.com/rust-lang/crates.io-index" 305 285 checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" 286 + 287 + [[package]] 288 + name = "ren-core" 289 + version = "0.1.0" 290 + dependencies = [ 291 + "anyhow", 292 + "num-traits", 293 + "serde", 294 + "serde-lexpr", 295 + "thiserror", 296 + ] 297 + 298 + [[package]] 299 + name = "ren-graphics" 300 + version = "0.1.0" 301 + dependencies = [ 302 + "num-traits", 303 + "raylib-ffi", 304 + "ren-core", 305 + ] 306 306 307 307 [[package]] 308 308 name = "rustc-hash"
+1 -1
crates/core/Cargo.toml crates/ren-core/Cargo.toml
··· 1 1 [package] 2 - name = "core" 2 + name = "ren-core" 3 3 version = "0.1.0" 4 4 edition = "2024" 5 5
-1
crates/core/src/lib.rs
··· 1 - pub mod math;
crates/core/src/math/mod.rs crates/ren-core/src/math/mod.rs
crates/core/src/math/rect.rs crates/ren-core/src/math/rect.rs
crates/core/src/math/vec2.rs crates/ren-core/src/math/vec2.rs
crates/core/src/math/vec3.rs crates/ren-core/src/math/vec3.rs
crates/core/src/math/vec4.rs crates/ren-core/src/math/vec4.rs
+2 -2
crates/graphics/Cargo.toml crates/ren-graphics/Cargo.toml
··· 1 1 [package] 2 - name = "graphics" 2 + name = "ren-graphics" 3 3 version = "0.1.0" 4 4 edition = "2024" 5 5 6 6 [dependencies] 7 7 raylib-ffi = "5.5.1" 8 8 num-traits = "0.2.19" 9 - core = { path = "../core" } 9 + ren-core = { path = "../ren-core" }
+1 -1
crates/graphics/src/_lib/camera.rs crates/ren-graphics/src/_lib/camera.rs
··· 1 - use core::math::Vec2; 1 + use ren_core::math::Vec2; 2 2 3 3 use raylib_ffi::{self as rl, Camera2D, Vector2}; 4 4
crates/graphics/src/_lib/canvas.rs crates/ren-graphics/src/_lib/canvas.rs
crates/graphics/src/_lib/colours.rs crates/ren-graphics/src/_lib/colours.rs
+1 -1
crates/graphics/src/_lib/data_sampler.rs crates/ren-graphics/src/_lib/data_sampler.rs
··· 1 - use core::math::Vec4; 1 + use ren_core::math::Vec4; 2 2 3 3 use raylib_ffi::{self as rl, Color, Image, Texture2D, colors}; 4 4
+1 -1
crates/graphics/src/_lib/drawing.rs crates/ren-graphics/src/_lib/drawing.rs
··· 2 2 3 3 use std::ffi::CString; 4 4 5 - use core::math::{Rect, Vec2}; 5 + use ren_core::math::{Rect, Vec2}; 6 6 7 7 use crate::{Sprite, Spritesheet, colours}; 8 8
crates/graphics/src/_lib/input.rs crates/ren-graphics/src/_lib/input.rs
+2
crates/graphics/src/_lib/mod.rs crates/ren-graphics/src/_lib/mod.rs
··· 6 6 mod input; 7 7 mod shader; 8 8 mod sprite; 9 + mod text; 9 10 mod window; 10 11 11 12 pub use camera::*; ··· 16 17 pub use input::*; 17 18 pub use shader::*; 18 19 pub use sprite::*; 20 + pub use text::*; 19 21 pub use window::*;
crates/graphics/src/_lib/shader.rs crates/ren-graphics/src/_lib/shader.rs
+1 -1
crates/graphics/src/_lib/sprite.rs crates/ren-graphics/src/_lib/sprite.rs
··· 1 - use core::math::Vec2; 1 + use ren_core::math::Vec2; 2 2 use std::ffi::CString; 3 3 4 4 use num_traits::{Num, NumCast};
+2 -2
crates/graphics/src/_lib/window.rs crates/ren-graphics/src/_lib/window.rs
··· 1 - use core::math::Vec2; 1 + use ren_core::{math::Vec2, time::Delta}; 2 2 use std::{ffi::CString, path::PathBuf}; 3 3 4 4 use raylib_ffi::{ ··· 65 65 } 66 66 67 67 /* get delta time in seconds */ 68 - pub fn get_delta_time(&self) -> f64 { 68 + pub fn get_delta_time(&self) -> Delta { 69 69 unsafe { rl::GetFrameTime() as f64 } 70 70 } 71 71
crates/graphics/src/lib.rs crates/ren-graphics/src/lib.rs
+1 -1
crates/graphics/src/renderers/debug_renderer.rs crates/ren-graphics/src/renderers/debug_renderer.rs
··· 11 11 12 12 pub fn line(&mut self, renderer: &Renderer, drawer: &mut impl IGraphicsDrawer, text: String) { 13 13 drawer.text( 14 - renderer.get_default_font(), 14 + renderer.get_font(), 15 15 text.as_str(), 16 16 0, 17 17 self.y,
crates/graphics/src/renderers/mod.rs crates/ren-graphics/src/renderers/mod.rs
+35 -3
crates/graphics/src/renderers/renderer.rs crates/ren-graphics/src/renderers/renderer.rs
··· 1 - use core::math::Vec2; 1 + use std::{ffi::CString, path::PathBuf}; 2 + 3 + use ren_core::math::Vec2; 2 4 3 5 use raylib_ffi::{Font, Rectangle}; 4 6 5 7 use crate::{Camera, Canvas, Resolution, Spritesheet, Window}; 6 8 9 + pub const BASE_FONT_SIZE: i32 = 32; 10 + 7 11 pub struct Renderer { 12 + font: Option<Font>, 8 13 pub resolution: Resolution, 9 14 pub camera: Camera, 10 15 pub cursor_spritesheet: Option<Spritesheet>, ··· 25 30 cursor_spritesheet: Option<Spritesheet>, 26 31 ) -> Self { 27 32 let mut s = Self { 33 + font: None, 28 34 resolution, 29 35 camera: Camera::new(Vec2 { 30 36 x: resolution.width as f32 / 2.0, ··· 53 59 ) 54 60 } 55 61 56 - pub fn get_default_font(&self) -> Font { 57 - unsafe { raylib_ffi::GetFontDefault() } 62 + pub fn set_font(&mut self, font_path: PathBuf, codepoints: Option<String>) { 63 + if let Some(font) = self.font { 64 + unsafe { 65 + raylib_ffi::UnloadFont(font); 66 + } 67 + } 68 + self.font = Some(unsafe { 69 + if let Some(c) = &codepoints { 70 + let mut codepoints_len = 0; 71 + let codepoints = raylib_ffi::LoadCodepoints( 72 + CString::new(c.as_str()).unwrap().as_ptr(), 73 + &mut codepoints_len, 74 + ); 75 + raylib_ffi::LoadFontEx( 76 + CString::new(font_path.to_str().unwrap()).unwrap().as_ptr(), 77 + BASE_FONT_SIZE, 78 + codepoints, 79 + codepoints_len, 80 + ) 81 + } else { 82 + raylib_ffi::LoadFont(CString::new(font_path.to_str().unwrap()).unwrap().as_ptr()) 83 + } 84 + }); 85 + } 86 + 87 + pub fn get_font(&self) -> Font { 88 + self.font 89 + .unwrap_or_else(|| unsafe { raylib_ffi::GetFontDefault() }) 58 90 } 59 91 60 92 /* recenter and resize the canvas_rect. called when the window is resized */
crates/graphics/src/ui/mod.rs crates/ren-graphics/src/ui/mod.rs
+2
crates/ren-core/src/lib.rs
··· 1 + pub mod math; 2 + pub mod time;
+33
crates/ren-core/src/time.rs
··· 1 + /* Represents the delta time in seconds. */ 2 + pub type Delta = f64; 3 + 4 + pub struct Timer { 5 + pub repeating: bool, 6 + pub duration: f64, 7 + pub progress: f64, 8 + pub callback: Option<fn()>, 9 + } 10 + 11 + impl Timer { 12 + pub fn tick(&mut self, dt: Delta) -> bool { 13 + let mut finished = false; 14 + self.progress += dt; 15 + 16 + if self.progress >= self.duration { 17 + if self.repeating { 18 + self.progress = 0.0; 19 + finished = true; 20 + } 21 + 22 + if let Some(cb) = self.callback { 23 + cb(); 24 + } 25 + } 26 + 27 + finished 28 + } 29 + 30 + pub fn is_done(&self) -> bool { 31 + self.progress >= self.duration 32 + } 33 + }
+96
crates/ren-graphics/src/_lib/text.rs
··· 1 + use std::ffi::CString; 2 + 3 + use raylib_ffi::{Color, Font, Vector2}; 4 + use ren_core::math::{Rect, Vec2}; 5 + 6 + /* 7 + Codepoints that should be able to represent Latin and Cyrillic scripts, maybe a few others? 8 + For CJK, you should only load the needed codepoints, otherwise you could use an excessive amount of memory. 9 + */ 10 + pub const RECOMMENDED_CODEPOINTS: &'static str = { 11 + " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ 12 + ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ 13 + ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžƒǍǎȘșȚț 14 + ʼˆˇˉ˘˙˚˛˜˝ʹ͵ͺͻͼͽ;΄ 15 + ΅Ά·ΈΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώϕ 16 + ϲϴϵ϶ϽϾϿЀЁЃЄІЇАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёѓєіїҐґ 17 + –—‘’‚“”„•…‹›‽⁄⁰⁴⁵⁶⁷⁸⁹⁺⁻⁼ⁿ₤₧€₲₵№™←↑→↓↔↕↖↗↘↙−∕∙√∞∟∩≈≠≡≤≥⌂⌐▲▶▼◀♀♂♥♦✓✝" 18 + }; 19 + 20 + pub const LETTER_SPACING: f32 = 2.0; 21 + 22 + #[inline] 23 + pub fn draw_char(font: Font, ch: char, x: i32, y: i32, size: f32, colour: Color) { 24 + unsafe { 25 + let mut codepoint_size = 0; 26 + let codepoint = raylib_ffi::GetCodepoint( 27 + CString::new(ch.to_string()).unwrap().as_ptr(), 28 + &mut codepoint_size, 29 + ); 30 + raylib_ffi::DrawTextCodepoint( 31 + font, 32 + codepoint, 33 + Vector2 { 34 + x: x as f32, 35 + y: y as f32, 36 + }, 37 + size, 38 + colour, 39 + ); 40 + } 41 + } 42 + 43 + pub fn measure_char(font: Font, ch: char, size: f32) -> f32 { 44 + let base_size = font.baseSize; 45 + let scale_factor = size / base_size as f32; 46 + 47 + unsafe { 48 + let mut codepoint_size = 0; 49 + let codepoint = raylib_ffi::GetCodepoint( 50 + CString::new(ch.to_string()).unwrap().as_ptr(), 51 + &mut codepoint_size, 52 + ); 53 + let index = raylib_ffi::GetGlyphIndex(font, codepoint) as isize; 54 + if (*font.glyphs.offset(index)).advanceX == 0 { 55 + (*font.recs.offset(index)).width * scale_factor 56 + } else { 57 + (*font.glyphs.offset(index)).advanceX as f32 * scale_factor 58 + } 59 + } 60 + } 61 + 62 + pub fn draw_text(font: Font, text: &String, x: i32, y: i32, size: f32, colour: Color) { 63 + let mut offset = Vec2::new(0.0, 0.0); 64 + text.chars().for_each(|ch| { 65 + let x = x + offset.x as i32; 66 + let y = y + offset.y as i32; 67 + draw_char(font, ch, x, y, size, colour); 68 + offset.x += measure_char(font, ch, size) + LETTER_SPACING; 69 + }); 70 + } 71 + 72 + pub fn measure_text(font: Font, text: &String, size: f32) -> f32 { 73 + text.chars().map(|ch| measure_char(font, ch, size)).sum() 74 + } 75 + 76 + pub fn draw_text_boxed(font: Font, text: &String, rect: Rect<i32>, size: f32, colour: Color) { 77 + let mut offset = Vec2::new(0.0, 0.0); 78 + text.split_inclusive(|c: char| c.is_whitespace()) 79 + .for_each(|word| { 80 + let str = &word.to_string(); 81 + let m = measure_text(font, str, size); 82 + if offset.x + m >= rect.w as f32 { 83 + offset.x = 0.0; 84 + offset.y += size + LETTER_SPACING; 85 + } 86 + if offset.y >= rect.h as f32 { 87 + return; 88 + } 89 + str.chars().for_each(|ch| { 90 + let x = rect.x + offset.x as i32; 91 + let y = rect.y + offset.y as i32; 92 + draw_char(font, ch, x, y, size, colour); 93 + offset.x += measure_char(font, ch, size) + LETTER_SPACING; 94 + }); 95 + }); 96 + }