Skip to content

Commit

Permalink
Merge pull request #2 from CommanderStorm/sprite-dataformat
Browse files Browse the repository at this point in the history
TEST IF THIS PRODUCES A DOCKER IMAGE
  • Loading branch information
CommanderStorm authored Sep 26, 2024
2 parents 55a6f29 + 947bc6e commit 2f898b5
Show file tree
Hide file tree
Showing 19 changed files with 212 additions and 17 deletions.
1 change: 1 addition & 0 deletions debian/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ cache_size_mb: 512
# - /path/to/sprites_dir
# sources:
# sprite1: /path/to/sprites_dir2
# make_sdf: false

# fonts:
# - /path/to/font/file.ttf
Expand Down
1 change: 1 addition & 0 deletions docs/src/config-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ sprites:
sources:
# SVG images in this directory will be published as a "my_sprites" sprite source
my_sprites: /path/to/some_dir
make_sdf: false

# Font configuration
fonts:
Expand Down
11 changes: 11 additions & 0 deletions docs/src/sources-sprites.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ configuration to the config file.
martin --sprite /path/to/sprite_a --sprite /path/to/other/sprite_b
```

To use generate Signed Distance Fields (SDFs) images instead, the `--make_sdf` Option can be added.
SDF Images allow their color to be set at runtime in the map rendering engine.

```bash
martin --sprite /path/to/sprite_a --sprite /path/to/other/sprite_b --make_sdf
```

### Configuring with Config File

A sprite directory can be configured from the config file with the `sprite` key, similar to
Expand All @@ -71,6 +78,10 @@ sprites:
sources:
# SVG images in this directory will be published under the sprite_id "my_sprites"
my_sprites: /path/to/some_dir
# Tells Martin to handle sprites as Signed Distance Fields (SDFs)
# SDF Images allow their color to be set at runtime in the map rendering engine.
# Defaults to `false`.
make_sdf: false
```
The sprites are now avaliable at `/sprite/my_images,some_dir.png`/ ...
15 changes: 14 additions & 1 deletion martin/src/args/root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ pub struct ExtraArgs {
/// Export a directory with SVG files as a sprite source. Can be specified multiple times.
#[arg(short, long)]
pub sprite: Vec<PathBuf>,
/// Tells Martin to handle sprites as Signed Distance Fields (SDFs)
/// SDF Images allow their color to be set at runtime in the map rendering engine.
///
/// Defaults to `false`.
#[arg(long)]
pub make_sdf: bool,
/// Export a font file or a directory with font files as a font source (recursive). Can be specified multiple times.
#[arg(short, long)]
pub font: Vec<PathBuf>,
Expand Down Expand Up @@ -109,7 +115,14 @@ impl Args {

#[cfg(feature = "sprites")]
if !self.extras.sprite.is_empty() {
config.sprites = FileConfigEnum::new(self.extras.sprite);
config.sprites = FileConfigEnum::new_extended(
self.extras.sprite,
std::collections::BTreeMap::new(),
crate::sprites::SpriteConfig {
make_sdf: self.extras.make_sdf,
..Default::default()
},
);
}

if !self.extras.font.is_empty() {
Expand Down
59 changes: 43 additions & 16 deletions martin/src/sprites/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ pub type SpriteCatalog = BTreeMap<String, CatalogSpriteEntry>;

#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct SpriteConfig {
/// Tells Martin to handle sprites as Signed Distance Fields (SDFs)
/// SDF Images allow their color to be set at runtime in the map rendering engine.
///
/// Defaults to `false`.
pub make_sdf: bool,
#[serde(flatten)]
pub unrecognized: UnrecognizedValues,
}
Expand All @@ -71,15 +76,25 @@ impl ConfigExtras for SpriteConfig {
}

#[derive(Debug, Clone, Default)]
pub struct SpriteSources(HashMap<String, SpriteSource>);
pub struct SpriteSources {
sources: HashMap<String, SpriteSource>,
/// Tells Martin to handle sprites as Signed Distance Fields (SDFs)
/// SDF Images allow their color to be set at runtime in the map rendering engine.
///
/// Defaults to `false`.
make_sdf: bool,
}

impl SpriteSources {
pub fn resolve(config: &mut FileConfigEnum<SpriteConfig>) -> FileResult<Self> {
let Some(cfg) = config.extract_file_config(None)? else {
return Ok(Self::default());
};

let mut results = Self::default();
let mut results = Self {
make_sdf: cfg.custom.make_sdf,
..Default::default()
};
let mut directories = Vec::new();
let mut configs = BTreeMap::new();

Expand Down Expand Up @@ -110,7 +125,7 @@ impl SpriteSources {
pub fn get_catalog(&self) -> SpriteResult<SpriteCatalog> {
// TODO: all sprite generation should be pre-cached
let mut entries = SpriteCatalog::new();
for (id, source) in &self.0 {
for (id, source) in &self.sources {
let paths = get_svg_input_paths(&source.path, true)
.map_err(|e| SpriteProcessingError(e, source.path.clone()))?;
let mut images = Vec::with_capacity(paths.len());
Expand All @@ -131,7 +146,7 @@ impl SpriteSources {
if path.is_file() {
warn!("Ignoring non-directory sprite source {id} from {disp_path}");
} else {
match self.0.entry(id) {
match self.sources.entry(id) {
Entry::Occupied(v) => {
warn!("Ignoring duplicate sprite source {} from {disp_path} because it was already configured for {}",
v.key(), v.get().path.display());
Expand All @@ -156,13 +171,13 @@ impl SpriteSources {
let sprite_ids = ids
.split(',')
.map(|id| {
self.0
self.sources
.get(id)
.ok_or_else(|| SpriteError::SpriteNotFound(id.to_string()))
})
.collect::<SpriteResult<Vec<_>>>()?;

get_spritesheet(sprite_ids.into_iter(), dpi).await
get_spritesheet(sprite_ids.into_iter(), dpi, self.make_sdf).await
}
}

Expand Down Expand Up @@ -194,6 +209,7 @@ async fn parse_sprite(
pub async fn get_spritesheet(
sources: impl Iterator<Item = &SpriteSource>,
pixel_ratio: u8,
make_sdf: bool,
) -> SpriteResult<Spritesheet> {
// Asynchronously load all SVG files from the given sources
let mut futures = Vec::new();
Expand All @@ -208,6 +224,9 @@ pub async fn get_spritesheet(
}
let sprites = try_join_all(futures).await?;
let mut builder = SpritesheetBuilder::new();
if make_sdf {
builder.make_sdf();
}
builder.sprites(sprites.into_iter().collect());

// TODO: decide if this is needed and/or configurable
Expand All @@ -231,27 +250,35 @@ mod tests {
PathBuf::from("../tests/fixtures/sprites/src2"),
]);

let sprites = SpriteSources::resolve(&mut cfg).unwrap().0;
let sprites = SpriteSources::resolve(&mut cfg).unwrap().sources;
assert_eq!(sprites.len(), 2);

test_src(sprites.values(), 1, "all_1").await;
test_src(sprites.values(), 2, "all_2").await;
//.sdf => generate sdf from png, add sdf == true
//- => does not generate sdf, omits sdf == true
for extension in ["_sdf", ""] {
test_src(sprites.values(), 1, "all_1", extension).await;
test_src(sprites.values(), 2, "all_2", extension).await;

test_src(sprites.get("src1").into_iter(), 1, "src1_1").await;
test_src(sprites.get("src1").into_iter(), 2, "src1_2").await;
test_src(sprites.get("src1").into_iter(), 1, "src1_1", extension).await;
test_src(sprites.get("src1").into_iter(), 2, "src1_2", extension).await;

test_src(sprites.get("src2").into_iter(), 1, "src2_1").await;
test_src(sprites.get("src2").into_iter(), 2, "src2_2").await;
test_src(sprites.get("src2").into_iter(), 1, "src2_1", extension).await;
test_src(sprites.get("src2").into_iter(), 2, "src2_2", extension).await;
}
}

async fn test_src(
sources: impl Iterator<Item = &SpriteSource>,
pixel_ratio: u8,
filename: &str,
extension: &str,
) {
let path = PathBuf::from(format!("../tests/fixtures/sprites/expected/{filename}"));

let sprites = get_spritesheet(sources, pixel_ratio).await.unwrap();
let path = PathBuf::from(format!(
"../tests/fixtures/sprites/expected/{filename}{extension}"
));
let sprites = get_spritesheet(sources, pixel_ratio, extension == "_sdf")
.await
.unwrap();
let mut json = serde_json::to_string_pretty(sprites.get_index()).unwrap();
json.push('\n');
let png = sprites.encode_png().unwrap();
Expand Down
1 change: 1 addition & 0 deletions tests/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ sprites:
paths: tests/fixtures/sprites/src1
sources:
mysrc: tests/fixtures/sprites/src2
make_sdf: false

fonts:
- tests/fixtures/fonts/overpass-mono-regular.ttf
Expand Down
1 change: 1 addition & 0 deletions tests/expected/configured/save_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ sprites:
paths: tests/fixtures/sprites/src1
sources:
mysrc: tests/fixtures/sprites/src2
make_sdf: false
fonts:
- tests/fixtures/fonts/overpass-mono-regular.ttf
- tests/fixtures/fonts
34 changes: 34 additions & 0 deletions tests/fixtures/sprites/expected/all_1_sdf.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"another_bicycle": {
"height": 15,
"pixelRatio": 1,
"width": 15,
"x": 20,
"y": 16,
"sdf": true
},
"bear": {
"height": 16,
"pixelRatio": 1,
"width": 16,
"x": 20,
"y": 0,
"sdf": true
},
"bicycle": {
"height": 15,
"pixelRatio": 1,
"width": 15,
"x": 35,
"y": 16,
"sdf": true
},
"sub/circle": {
"height": 20,
"pixelRatio": 1,
"width": 20,
"x": 0,
"y": 0,
"sdf": true
}
}
Binary file added tests/fixtures/sprites/expected/all_1_sdf.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 34 additions & 0 deletions tests/fixtures/sprites/expected/all_2_sdf.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"another_bicycle": {
"height": 30,
"pixelRatio": 2,
"width": 30,
"x": 40,
"y": 32,
"sdf": true
},
"bear": {
"height": 32,
"pixelRatio": 2,
"width": 32,
"x": 40,
"y": 0,
"sdf": true
},
"bicycle": {
"height": 30,
"pixelRatio": 2,
"width": 30,
"x": 70,
"y": 32,
"sdf": true
},
"sub/circle": {
"height": 40,
"pixelRatio": 2,
"width": 40,
"x": 0,
"y": 0,
"sdf": true
}
}
Binary file added tests/fixtures/sprites/expected/all_2_sdf.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions tests/fixtures/sprites/expected/src1_1_sdf.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"another_bicycle": {
"height": 15,
"pixelRatio": 1,
"width": 15,
"x": 20,
"y": 16,
"sdf": true
},
"bear": {
"height": 16,
"pixelRatio": 1,
"width": 16,
"x": 20,
"y": 0,
"sdf": true
},
"sub/circle": {
"height": 20,
"pixelRatio": 1,
"width": 20,
"x": 0,
"y": 0,
"sdf": true
}
}
Binary file added tests/fixtures/sprites/expected/src1_1_sdf.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions tests/fixtures/sprites/expected/src1_2_sdf.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"another_bicycle": {
"height": 30,
"pixelRatio": 2,
"width": 30,
"x": 40,
"y": 32,
"sdf": true
},
"bear": {
"height": 32,
"pixelRatio": 2,
"width": 32,
"x": 40,
"y": 0,
"sdf": true
},
"sub/circle": {
"height": 40,
"pixelRatio": 2,
"width": 40,
"x": 0,
"y": 0,
"sdf": true
}
}
Binary file added tests/fixtures/sprites/expected/src1_2_sdf.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions tests/fixtures/sprites/expected/src2_1_sdf.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"bicycle": {
"height": 15,
"pixelRatio": 1,
"width": 15,
"x": 0,
"y": 0,
"sdf": true
}
}
Binary file added tests/fixtures/sprites/expected/src2_1_sdf.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions tests/fixtures/sprites/expected/src2_2_sdf.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"bicycle": {
"height": 30,
"pixelRatio": 2,
"width": 30,
"x": 0,
"y": 0,
"sdf": true
}
}
Binary file added tests/fixtures/sprites/expected/src2_2_sdf.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 2f898b5

Please sign in to comment.