~starkingdoms/starkingdoms

00049e064ff12a9c9b93674670410045b4ddaa7c — ghostly_zsh 10 months ago ce2ff9e
svg support
M Cargo.lock => Cargo.lock +244 -8
@@ 1502,7 1502,7 @@ dependencies = [
 "fs4",
 "hex",
 "is_executable",
 "siphasher",
 "siphasher 0.3.11",
 "tar",
 "ureq",
 "zip",


@@ 1732,9 1732,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"

[[package]]
name = "bytes"
version = "1.7.1"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50"
checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"

[[package]]
name = "bytestring"


@@ 2201,6 2201,15 @@ dependencies = [
]

[[package]]
name = "core_maths"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b02505ccb8c50b0aa21ace0fc08c3e53adebd4e58caa18a36152803c7709a3"
dependencies = [
 "libm",
]

[[package]]
name = "cpufeatures"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 2365,6 2374,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2"

[[package]]
name = "data-url"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a"

[[package]]
name = "deflate64"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 2872,6 2887,12 @@ dependencies = [
]

[[package]]
name = "float-cmp"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"

[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 2884,6 2905,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"

[[package]]
name = "fontconfig-parser"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1fcfcd44ca6e90c921fee9fa665d530b21ef1327a4c1a6c5250ea44b776ada7"
dependencies = [
 "roxmltree",
]

[[package]]
name = "fontdb"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3a6f9af55fb97ad673fb7a69533eb2f967648a06fa21f8c9bb2cd6d33975716"
dependencies = [
 "fontconfig-parser",
 "log",
 "memmap2",
 "slotmap",
 "tinyvec",
 "ttf-parser 0.24.1",
]

[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 3579,7 3623,7 @@ dependencies = [
 "color_quant",
 "exr",
 "gif",
 "image-webp",
 "image-webp 0.2.0",
 "num-traits",
 "png",
 "qoi",


@@ 3593,6 3637,16 @@ dependencies = [

[[package]]
name = "image-webp"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f79afb8cbee2ef20f59ccd477a218c12a93943d075b492015ecb1bb81f8ee904"
dependencies = [
 "byteorder-lite",
 "quick-error",
]

[[package]]
name = "image-webp"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e031e8e3d94711a9ccb5d6ea357439ef3dcbed361798bd4071dc4d9793fbe22f"


@@ 3602,6 3656,12 @@ dependencies = [
]

[[package]]
name = "imagesize"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285"

[[package]]
name = "imgref"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 3830,6 3890,16 @@ dependencies = [
]

[[package]]
name = "kurbo"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89234b2cc610a7dd927ebde6b41dd1a5d4214cffaef4cf1fb2195d592f92518f"
dependencies = [
 "arrayvec",
 "smallvec",
]

[[package]]
name = "language-tags"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 4860,7 4930,7 @@ version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec719bbf3b2a81c109a4e20b1f129b5566b7dce654bc3872f6a05abf82b2c4"
dependencies = [
 "ttf-parser",
 "ttf-parser 0.25.1",
]

[[package]]


@@ 4978,10 5048,16 @@ version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
dependencies = [
 "siphasher",
 "siphasher 0.3.11",
]

[[package]]
name = "pico-args"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"

[[package]]
name = "pin-project"
version = "1.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 5507,10 5583,30 @@ dependencies = [
]

[[package]]
name = "resvg"
version = "0.44.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a325d5e8d1cebddd070b13f44cec8071594ab67d1012797c121f27a669b7958"
dependencies = [
 "gif",
 "image-webp 0.1.3",
 "log",
 "pico-args",
 "rgb",
 "svgtypes",
 "tiny-skia",
 "usvg",
 "zune-jpeg",
]

[[package]]
name = "rgb"
version = "0.8.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a"
dependencies = [
 "bytemuck",
]

[[package]]
name = "ring"


@@ 5568,6 5664,12 @@ dependencies = [
]

[[package]]
name = "roxmltree"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97"

[[package]]
name = "rs-snowflake"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 5655,6 5757,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"

[[package]]
name = "rustybuzz"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c85d1ccd519e61834798eb52c4e886e8c2d7d698dd3d6ce0b1b47eb8557f1181"
dependencies = [
 "bitflags 2.6.0",
 "bytemuck",
 "core_maths",
 "log",
 "smallvec",
 "ttf-parser 0.24.1",
 "unicode-bidi-mirroring",
 "unicode-ccc",
 "unicode-properties",
 "unicode-script",
]

[[package]]
name = "ryu"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 5904,12 6024,27 @@ dependencies = [
]

[[package]]
name = "simplecss"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a9c6883ca9c3c7c90e888de77b7a5c849c779d25d74a1269b0218b14e8b136c"
dependencies = [
 "log",
]

[[package]]
name = "siphasher"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"

[[package]]
name = "siphasher"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"

[[package]]
name = "slab"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 6075,6 6210,7 @@ version = "0.1.0"
dependencies = [
 "bevy_ecs 0.15.1",
 "console_error_panic_hook",
 "crossbeam",
 "egui",
 "egui-wgpu",
 "egui-winit",


@@ 6083,6 6219,7 @@ dependencies = [
 "nalgebra 0.33.2",
 "pollster",
 "reqwest",
 "resvg",
 "serde",
 "serde_json",
 "starkingdoms-common",


@@ 6090,6 6227,7 @@ dependencies = [
 "tracing",
 "tracing-subscriber",
 "tracing-web",
 "tungstenite 0.26.1",
 "wasm-bindgen",
 "wasm-bindgen-futures",
 "web-sys",


@@ 6135,7 6273,7 @@ dependencies = [
 "toml 0.8.19",
 "tracing-subscriber",
 "tracing-tracy",
 "tungstenite",
 "tungstenite 0.21.0",
]

[[package]]


@@ 6149,6 6287,9 @@ name = "strict-num"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
dependencies = [
 "float-cmp",
]

[[package]]
name = "stringprep"


@@ 6186,6 6327,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20e16a0f46cf5fd675563ef54f26e83e20f2366bcf027bcb3cc3ed2b98aaf2ca"

[[package]]
name = "svgtypes"
version = "0.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68c7541fff44b35860c1a7a47a7cadf3e4a304c457b58f9870d9706ece028afc"
dependencies = [
 "kurbo",
 "siphasher 1.0.1",
]

[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 6436,6 6587,7 @@ dependencies = [
 "bytemuck",
 "cfg-if",
 "log",
 "png",
 "tiny-skia-path",
]



@@ 6775,6 6927,15 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"

[[package]]
name = "ttf-parser"
version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5be21190ff5d38e8b4a2d3b6a3ae57f612cc39c96e83cedeaf7abc338a8bac4a"
dependencies = [
 "core_maths",
]

[[package]]
name = "ttf-parser"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"


@@ 6799,6 6960,24 @@ dependencies = [
]

[[package]]
name = "tungstenite"
version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413083a99c579593656008130e29255e54dcaae495be556cc26888f211648c24"
dependencies = [
 "byteorder",
 "bytes",
 "data-encoding",
 "http 1.1.0",
 "httparse",
 "log",
 "rand",
 "sha1",
 "thiserror 2.0.9",
 "utf-8",
]

[[package]]
name = "type-map"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 6826,6 7005,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"

[[package]]
name = "unicode-bidi-mirroring"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64af057ad7466495ca113126be61838d8af947f41d93a949980b2389a118082f"

[[package]]
name = "unicode-ccc"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "260bc6647b3893a9a90668360803a15f96b85a5257b1c3a0c3daf6ae2496de42"

[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 6847,12 7038,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291"

[[package]]
name = "unicode-script"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f"

[[package]]
name = "unicode-segmentation"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"

[[package]]
name = "unicode-vo"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94"

[[package]]
name = "unicode-width"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 6907,6 7110,33 @@ dependencies = [
]

[[package]]
name = "usvg"
version = "0.44.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7447e703d7223b067607655e625e0dbca80822880248937da65966194c4864e6"
dependencies = [
 "base64 0.22.1",
 "data-url",
 "flate2",
 "fontdb",
 "imagesize",
 "kurbo",
 "log",
 "pico-args",
 "roxmltree",
 "rustybuzz",
 "simplecss",
 "siphasher 1.0.1",
 "strict-num",
 "svgtypes",
 "tiny-skia-path",
 "unicode-bidi",
 "unicode-script",
 "unicode-vo",
 "xmlwriter",
]

[[package]]
name = "utf-8"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 7085,7 7315,7 @@ dependencies = [
 "serde_derive",
 "serde_ignored",
 "serde_json",
 "siphasher",
 "siphasher 0.3.11",
 "strsim 0.10.0",
 "toml 0.7.8",
 "ureq",


@@ 8069,6 8299,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "539a77ee7c0de333dcc6da69b177380a0b81e0dacfa4f7344c465a36871ee601"

[[package]]
name = "xmlwriter"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9"

[[package]]
name = "xtask"
version = "0.1.0"
dependencies = [

M crates/client/Cargo.toml => crates/client/Cargo.toml +1 -0
@@ 25,6 25,7 @@ starkingdoms-common = { version = "0.1", path = "../common" }
serde = "1"
serde_json = "1"
crossbeam = "0.8.4"
resvg = "0.44.0"

# WASM dependencies
[target.'cfg(target_arch = "wasm32")'.dependencies]

M crates/client/src/lib.rs => crates/client/src/lib.rs +1 -1
@@ 81,7 81,7 @@ pub fn start() {
            radians: 45.0_f32.to_radians()
        },
        texture: SpriteTexture {
            texture: "happy-tree".to_string(),
            texture: "hearty".to_string(),
        },
    });


M crates/client/src/rendering/assets_wasm.rs => crates/client/src/rendering/assets_wasm.rs +43 -9
@@ 1,13 1,11 @@
use std::{collections::HashMap, fmt::Display, sync::{Arc, Mutex}};

use bevy_ecs::system::Resource;
use futures::channel::oneshot::{Receiver, Sender};
use futures::channel::oneshot::Receiver;
use image::EncodableLayout;
use tracing::info;
use resvg::{tiny_skia, usvg};
use wasm_bindgen_futures::spawn_local;

use super::texture::{self, Texture};

#[derive(Debug, Clone)]
pub enum AssetError {
    AssetNotFound,


@@ 23,10 21,17 @@ impl Display for AssetError {
}
impl std::error::Error for AssetError {}

#[derive(Debug, Clone)]
pub struct ImgData {
    pub bytes: Vec<u8>,
    pub width: u32,
    pub height: u32,
}

#[derive(Resource)]
pub struct Assets {
    texture_receivers: Arc<Mutex<HashMap<String, Receiver<Vec<u8>>>>>,
    textures: Arc<Mutex<HashMap<String, Vec<u8>>>>,
    texture_receivers: Arc<Mutex<HashMap<String, Receiver<ImgData>>>>,
    textures: Arc<Mutex<HashMap<String, ImgData>>>,
}

impl Assets {


@@ 36,7 41,7 @@ impl Assets {
            texture_receivers: Arc::new(Mutex::new(HashMap::new())),
        }
    }
    pub fn get(&self, local_path: impl Into<String>) -> Option<Vec<u8>> {
    pub fn get(&self, local_path: impl Into<String>) -> Option<ImgData> {
        let (tx, rx) = futures::channel::oneshot::channel();
        let local_path = local_path.into();
        let contains_texture = {


@@ 73,8 78,37 @@ impl Assets {
                    Ok(bytes) => bytes,
                    Err(e) => todo!(),
                }.to_vec();
                textures.lock().unwrap().insert(local_path, bytes.clone());
                tx.send(bytes).unwrap();
                if local_path.ends_with(".svg") {
                    let opt = usvg::Options {
                        default_size: usvg::Size::from_wh(20.0, 20.0).unwrap(),
                        ..Default::default()
                    };
                    let tree = usvg::Tree::from_data(&bytes, &opt).expect("Couldn't parse svg");
                    let tree_size = tree.size().to_int_size();
                    let size = usvg::Size::from_wh(1000.0, 1000.0).unwrap().to_int_size();
                    assert!(size.width() > 0 && size.height() > 0);
                    tracing::warn!("{:?}", size);
                    let mut pixmap = tiny_skia::Pixmap::new(size.width(), size.height()).expect("Failed to construct pixmap");
                    resvg::render(&tree, tiny_skia::Transform::from_scale((size.width() as f32)/(tree_size.height() as f32), (size.height() as f32)/(tree_size.height() as f32)), &mut pixmap.as_mut());
                    let data = ImgData {
                        bytes: pixmap.data().to_vec(),
                        width: size.width(),
                        height: size.height(),
                    };
                    
                    textures.lock().unwrap().insert(local_path, data.clone());
                    tx.send(data).unwrap();
                } else if local_path.ends_with(".png") {
                    let img = image::load_from_memory(&bytes).unwrap();
                    let rgba = img.to_rgba8();
                    let data = ImgData {
                        bytes: rgba.as_bytes().to_vec(),
                        width: rgba.width(),
                        height: rgba.height(),
                    };
                    textures.lock().unwrap().insert(local_path, data.clone());
                    tx.send(data).unwrap();
                }
            });
            None
        } else if !contains_texture {

M crates/client/src/rendering/renderer.rs => crates/client/src/rendering/renderer.rs +5 -1
@@ 303,6 303,10 @@ impl<T: UiRenderable> Renderer<T> {
                        Some(b) => b,
                        None => continue,
                    }
                    "hearty" => match assets.get("hearty.svg") {
                        Some(b) => b,
                        None => continue,
                    }
                    u => panic!("unknown texture {u}, has it been added in rendering::renderer::<impl Renderer>::render()?")
                };
                /*let b: &[u8] = match tex.texture.as_str() {


@@ 312,7 316,7 @@ impl<T: UiRenderable> Renderer<T> {
                    u => panic!("unknown texture {u}, has it been added in rendering::renderer::<impl Renderer>::render()?")
                };*/
                texture::Texture::new(
                    &b,
                    b,
                    &tex.texture,
                    &self.device,
                    &self.queue,

M crates/client/src/rendering/texture.rs => crates/client/src/rendering/texture.rs +11 -12
@@ 5,6 5,8 @@ use wgpu::{
    SamplerDescriptor, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages,
};

use super::assets::ImgData;

#[derive(Debug)]
pub struct Texture {
    pub texture: wgpu::Texture,


@@ 12,24 14,21 @@ pub struct Texture {
}
impl Texture {
    pub fn new(
        bytes: &[u8],
        rgba: ImgData,
        label: &str,
        device: &Device,
        queue: &Queue,
        mip_generator: &mut MipGenerator,
    ) -> Self {
        let img = image::load_from_memory(bytes).unwrap();
        let rgba = img.to_rgba8();

        let max_size = rgba.width().max(rgba.height());
        let max_size = rgba.width.max(rgba.height);
        let log_factor = if max_size == 0 { 0 } else { max_size.ilog2() };
        let optimal_mip_levels = 1 + log_factor;

        let texture = device.create_texture(&TextureDescriptor {
            label: Some(label),
            size: Extent3d {
                width: rgba.width(),
                height: rgba.height(),
                width: rgba.width,
                height: rgba.height,
                depth_or_array_layers: 1,
            },
            mip_level_count: optimal_mip_levels,


@@ 48,15 47,15 @@ impl Texture {
                origin: Origin3d::ZERO,
                aspect: Default::default(),
            },
            rgba.as_bytes(),
            &rgba.bytes,
            ImageDataLayout {
                offset: 0,
                bytes_per_row: Some(rgba.width() * 4),
                rows_per_image: Some(rgba.height()),
                bytes_per_row: Some(rgba.width * 4),
                rows_per_image: Some(rgba.height),
            },
            Extent3d {
                width: rgba.width(),
                height: rgba.height(),
                width: rgba.width,
                height: rgba.height,
                depth_or_array_layers: 1,
            },
        );

A crates/client/src/textures/hearty.svg => crates/client/src/textures/hearty.svg +278 -0
@@ 0,0 1,278 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
   width="512"
   height="512"
   viewBox="0 0 135.46666 135.46667"
   version="1.1"
   id="svg5"
   inkscape:export-filename="/home/tm85/prj/stk_sprites/hearty.png"
   inkscape:export-xdpi="96"
   inkscape:export-ydpi="96"
   inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
   sodipodi:docname="hearty.ink.svg"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:svg="http://www.w3.org/2000/svg">
  <sodipodi:namedview
     id="namedview7"
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1.0"
     inkscape:pageshadow="2"
     inkscape:pageopacity="0.0"
     inkscape:pagecheckerboard="0"
     inkscape:document-units="mm"
     showgrid="false"
     units="px"
     width="512px"
     showguides="true"
     inkscape:snap-object-midpoints="true"
     inkscape:snap-global="true"
     inkscape:guide-bbox="true"
     inkscape:zoom="2"
     inkscape:cx="191.75"
     inkscape:cy="253.75"
     inkscape:window-width="2548"
     inkscape:window-height="1412"
     inkscape:window-x="4"
     inkscape:window-y="20"
     inkscape:window-maximized="1"
     inkscape:current-layer="layer1" />
  <defs
     id="defs2">
    <inkscape:path-effect
       effect="fillet_chamfer"
       id="path-effect17083"
       is_visible="true"
       lpeversion="1"
       satellites_param="F,0,0,1,0,2.1166667,0,1 @ F,0,0,1,0,2.1166667,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
       unit="px"
       method="auto"
       mode="F"
       radius="8"
       chamfer_steps="1"
       flexible="false"
       use_knot_distance="true"
       apply_no_radius="true"
       apply_with_radius="true"
       only_selected="false"
       hide_knots="false" />
    <inkscape:path-effect
       effect="fillet_chamfer"
       id="path-effect16803"
       is_visible="true"
       lpeversion="1"
       satellites_param="F,0,0,1,0,2.1166667,0,1 @ F,0,0,1,0,2.1166667,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
       unit="px"
       method="auto"
       mode="F"
       radius="8"
       chamfer_steps="1"
       flexible="false"
       use_knot_distance="true"
       apply_no_radius="true"
       apply_with_radius="true"
       only_selected="false"
       hide_knots="false" />
    <inkscape:path-effect
       effect="fillet_chamfer"
       id="path-effect15774"
       is_visible="true"
       lpeversion="1"
       satellites_param="F,0,0,1,0,4.2333333,0,1 @ F,0,0,1,0,4.2333333,0,1 @ F,0,0,1,0,4.2333333,0,1 @ F,0,0,1,0,4.2333333,0,1"
       unit="px"
       method="auto"
       mode="F"
       radius="16"
       chamfer_steps="1"
       flexible="false"
       use_knot_distance="true"
       apply_no_radius="true"
       apply_with_radius="true"
       only_selected="false"
       hide_knots="false" />
    <inkscape:path-effect
       effect="fillet_chamfer"
       id="path-effect15612"
       is_visible="true"
       lpeversion="1"
       satellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
       unit="px"
       method="auto"
       mode="F"
       radius="16"
       chamfer_steps="1"
       flexible="false"
       use_knot_distance="true"
       apply_no_radius="true"
       apply_with_radius="true"
       only_selected="false"
       hide_knots="false" />
    <inkscape:path-effect
       effect="fillet_chamfer"
       id="path-effect15006"
       is_visible="true"
       lpeversion="1"
       satellites_param="F,0,0,1,0,2.1166667,0,1 @ F,0,0,1,0,2.1166667,0,1 @ F,0,0,1,0,2.1166667,0,1 @ F,0,0,1,0,2.1166667,0,1"
       unit="px"
       method="auto"
       mode="F"
       radius="16"
       chamfer_steps="1"
       flexible="false"
       use_knot_distance="true"
       apply_no_radius="true"
       apply_with_radius="true"
       only_selected="false"
       hide_knots="false" />
    <inkscape:path-effect
       effect="fillet_chamfer"
       id="path-effect12397"
       is_visible="true"
       lpeversion="1"
       satellites_param="F,0,0,1,0,2.6458333,0,5 @ F,0,0,1,0,2.6458333,0,5 @ F,0,0,1,0,2.6458333,0,5 | F,0,0,1,0,2.6458333,0,5 @ F,0,0,1,0,2.6458333,0,5 @ F,0,0,1,0,2.6458333,0,5"
       unit="px"
       method="auto"
       mode="F"
       radius="10"
       chamfer_steps="5"
       flexible="false"
       use_knot_distance="true"
       apply_no_radius="true"
       apply_with_radius="true"
       only_selected="false"
       hide_knots="false" />
    <inkscape:path-effect
       effect="fillet_chamfer"
       id="path-effect12289"
       is_visible="true"
       lpeversion="1"
       satellites_param="C,0,0,1,0,2.6458333,0,5 @ C,0,0,1,0,2.6458333,0,5 @ C,0,0,1,0,2.6458333,0,5 | C,0,0,1,0,2.6458333,0,5 @ C,0,0,1,0,2.6458333,0,5 @ C,0,0,1,0,2.6458333,0,5"
       unit="px"
       method="auto"
       mode="F"
       radius="10"
       chamfer_steps="5"
       flexible="false"
       use_knot_distance="true"
       apply_no_radius="true"
       apply_with_radius="true"
       only_selected="false"
       hide_knots="false" />
    <inkscape:path-effect
       effect="fillet_chamfer"
       id="path-effect12074"
       is_visible="true"
       lpeversion="1"
       satellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
       unit="px"
       method="auto"
       mode="F"
       radius="0"
       chamfer_steps="1"
       flexible="false"
       use_knot_distance="true"
       apply_no_radius="true"
       apply_with_radius="true"
       only_selected="false"
       hide_knots="false" />
    <filter
       inkscape:menu-tooltip="In and out glow with a possible offset and colorizable flood"
       inkscape:menu="Shadows and Glows"
       inkscape:label="Cutout Glow"
       style="color-interpolation-filters:sRGB;"
       id="filter13281"
       x="-0.23629366"
       y="-0.23629366"
       width="1.4725873"
       height="1.4725873">
      <feGaussianBlur
         stdDeviation="29.536707281068317"
         result="blur"
         id="feGaussianBlur13273" />
      <feComposite
         in="flood"
         in2="SourceGraphic"
         operator="in"
         result="composite"
         id="feComposite13277" />
      <feBlend
         in="blur"
         in2="composite"
         mode="normal"
         id="feBlend13279" />
    </filter>
  </defs>
  <g
     inkscape:groupmode="layer"
     id="layer2"
     inkscape:label="Thrusters"
     style="display:inline">
    <path
       id="rect3826"
       style="display:inline;fill:#444444;stroke-width:0.149461"
       d="m 1e-5,1e-6 h 25.4 V 21.166667 L 12.7,21.166664 Z"
       sodipodi:nodetypes="ccccc" />
    <path
       id="rect3826-3"
       style="display:inline;fill:#444444;stroke-width:0.149461"
       d="m 135.46667,0 h -25.4 v 21.166666 l 12.70001,-3e-6 z"
       sodipodi:nodetypes="ccccc" />
    <path
       id="rect3826-3-6"
       style="display:inline;fill:#444444;stroke-width:0.149461"
       d="m 135.46667,135.46666 h -25.4 V 114.3 h 12.70001 z"
       sodipodi:nodetypes="ccccc" />
    <path
       id="rect3826-3-6-7"
       style="display:inline;fill:#444444;stroke-width:0.149461"
       d="M 0,135.46666 H 25.4 V 114.3 H 12.69999 Z"
       sodipodi:nodetypes="ccccc" />
  </g>
  <g
     inkscape:label="Body"
     inkscape:groupmode="layer"
     id="layer1"
     style="display:inline">
    <rect
       style="fill:#777777;fill-opacity:1;stroke-width:0.325266"
       id="rect2738"
       width="135.46666"
       height="135.46666"
       x="0"
       y="0"
       rx="33.866665"
       ry="33.866665" />
    <rect
       style="fill:#444444;fill-opacity:1;stroke-width:0.23373;stroke-miterlimit:4;stroke-dasharray:none"
       id="rect55-3"
       width="110.06667"
       height="110.06667"
       x="12.7"
       y="12.7"
       rx="21.166666"
       ry="21.166666"
       inkscape:export-filename="/home/tm85/prj/stk_sprites/hearty.png"
       inkscape:export-xdpi="96"
       inkscape:export-ydpi="96" />
    <g
       id="use12910"
       transform="matrix(-0.14028033,-0.14028033,0.14028033,-0.14028033,67.733335,98.694702)"
       style="fill:#ff0000;stroke:none;stroke-width:0">
      <path
         d="M 0,200 V 0 h 200 a 100,100 90 0 1 0,200 100,100 90 0 1 -200,0 z"
         id="path13158" />
    </g>
    <g
       id="use12910-2"
       transform="matrix(-0.14028033,-0.14028033,0.14028033,-0.14028033,67.733335,98.694702)"
       style="display:inline;fill:#ff0000;stroke:none;stroke-width:0;filter:url(#filter13281)">
      <path
         d="M 0,200 V 0 h 200 a 100,100 90 0 1 0,200 100,100 90 0 1 -200,0 z"
         id="path13158-7" />
    </g>
  </g>
</svg>