mirror of https://github.com/Leinnan/rpack.git
Start work on real version
This commit is contained in:
parent
7d70ead8f6
commit
f0cfe7cb8a
|
|
@ -3,19 +3,18 @@ on: [push, pull_request]
|
||||||
name: CI
|
name: CI
|
||||||
|
|
||||||
env:
|
env:
|
||||||
# This is required to enable the web_sys clipboard API which egui_web uses
|
# --cfg=web_sys_unstable_apis is required to enable the web_sys clipboard API which egui_web uses
|
||||||
# https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.Clipboard.html
|
# https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.Clipboard.html
|
||||||
# https://rustwasm.github.io/docs/wasm-bindgen/web-sys/unstable-apis.html
|
# https://rustwasm.github.io/docs/wasm-bindgen/web-sys/unstable-apis.html
|
||||||
RUSTFLAGS: --cfg=web_sys_unstable_apis
|
RUSTFLAGS: -D warnings --cfg=web_sys_unstable_apis
|
||||||
|
RUSTDOCFLAGS: -D warnings
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check:
|
check:
|
||||||
name: Check
|
name: Check
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: "[Ubuntu] install dependencies"
|
|
||||||
run: sudo apt update && sudo apt install libgtk-3-dev
|
|
||||||
- uses: actions-rs/toolchain@v1
|
- uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
profile: minimal
|
profile: minimal
|
||||||
|
|
@ -30,7 +29,7 @@ jobs:
|
||||||
name: Check wasm32
|
name: Check wasm32
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions-rs/toolchain@v1
|
- uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
profile: minimal
|
profile: minimal
|
||||||
|
|
@ -46,9 +45,7 @@ jobs:
|
||||||
name: Test Suite
|
name: Test Suite
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: "[Ubuntu] install dependencies"
|
|
||||||
run: sudo apt update && sudo apt install libgtk-3-dev
|
|
||||||
- uses: actions-rs/toolchain@v1
|
- uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
profile: minimal
|
profile: minimal
|
||||||
|
|
@ -64,7 +61,7 @@ jobs:
|
||||||
name: Rustfmt
|
name: Rustfmt
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions-rs/toolchain@v1
|
- uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
profile: minimal
|
profile: minimal
|
||||||
|
|
@ -80,9 +77,7 @@ jobs:
|
||||||
name: Clippy
|
name: Clippy
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: "[Ubuntu] install dependencies"
|
|
||||||
run: sudo apt update && sudo apt install libgtk-3-dev
|
|
||||||
- uses: actions-rs/toolchain@v1
|
- uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
profile: minimal
|
profile: minimal
|
||||||
|
|
@ -98,13 +93,11 @@ jobs:
|
||||||
name: trunk
|
name: trunk
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: "[Ubuntu] install dependencies"
|
|
||||||
run: sudo apt update && sudo apt install libgtk-3-dev
|
|
||||||
- uses: actions-rs/toolchain@v1
|
- uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
profile: minimal
|
profile: minimal
|
||||||
toolchain: 1.72.0
|
toolchain: 1.81.0
|
||||||
target: wasm32-unknown-unknown
|
target: wasm32-unknown-unknown
|
||||||
override: true
|
override: true
|
||||||
- name: Download and install Trunk binary
|
- name: Download and install Trunk binary
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
110
src/app.rs
110
src/app.rs
|
|
@ -2,7 +2,6 @@ use std::{collections::HashMap, io::Cursor};
|
||||||
|
|
||||||
use egui::{CollapsingHeader, Color32, DroppedFile, FontFamily, FontId, Image, RichText, Vec2};
|
use egui::{CollapsingHeader, Color32, DroppedFile, FontFamily, FontId, Image, RichText, Vec2};
|
||||||
use image::DynamicImage;
|
use image::DynamicImage;
|
||||||
|
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use texture_packer::{importer::ImageImporter, TexturePacker, TexturePackerConfig};
|
use texture_packer::{importer::ImageImporter, TexturePacker, TexturePackerConfig};
|
||||||
pub const MY_ACCENT_COLOR32: Color32 = Color32::from_rgb(230, 102, 1);
|
pub const MY_ACCENT_COLOR32: Color32 = Color32::from_rgb(230, 102, 1);
|
||||||
|
|
@ -11,11 +10,24 @@ pub const HEADER_HEIGHT: f32 = 45.0;
|
||||||
pub const TOP_BUTTON_WIDTH: f32 = 150.0;
|
pub const TOP_BUTTON_WIDTH: f32 = 150.0;
|
||||||
pub const GIT_HASH: &str = env!("GIT_HASH");
|
pub const GIT_HASH: &str = env!("GIT_HASH");
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||||
|
pub struct AtlasFrame {
|
||||||
|
pub key: String,
|
||||||
|
pub frame: SerializableRect,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||||
|
pub struct AtlasAsset {
|
||||||
|
pub size: [u32; 2],
|
||||||
|
pub name: String,
|
||||||
|
pub frames: Vec<AtlasFrame>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Spritesheet {
|
pub struct Spritesheet {
|
||||||
pub data: Vec<u8>,
|
pub data: Vec<u8>,
|
||||||
pub frames: HashMap<String, texture_packer::Frame<String>>,
|
pub frames: HashMap<String, texture_packer::Frame<String>>,
|
||||||
pub frames_json: Value,
|
pub atlas_asset_json: Value,
|
||||||
pub size: (u32, u32),
|
pub size: (u32, u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,11 +102,6 @@ impl From<texture_packer::Rect> for SerializableRect {
|
||||||
#[derive(serde::Deserialize, serde::Serialize)]
|
#[derive(serde::Deserialize, serde::Serialize)]
|
||||||
#[serde(default)] // if we add new fields, give them default values when deserializing old state
|
#[serde(default)] // if we add new fields, give them default values when deserializing old state
|
||||||
pub struct TemplateApp {
|
pub struct TemplateApp {
|
||||||
// Example stuff:
|
|
||||||
label: String,
|
|
||||||
|
|
||||||
#[serde(skip)] // This how you opt-out of serialization of a field
|
|
||||||
value: f32,
|
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
dropped_files: Vec<DroppedFile>,
|
dropped_files: Vec<DroppedFile>,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
|
|
@ -113,9 +120,6 @@ pub struct TemplateApp {
|
||||||
impl Default for TemplateApp {
|
impl Default for TemplateApp {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
// Example stuff:
|
|
||||||
label: "Hello World!".to_owned(),
|
|
||||||
value: 2.7,
|
|
||||||
dropped_files: vec![],
|
dropped_files: vec![],
|
||||||
config: TexturePackerConfig {
|
config: TexturePackerConfig {
|
||||||
max_width: 512,
|
max_width: 512,
|
||||||
|
|
@ -149,12 +153,38 @@ impl TemplateApp {
|
||||||
|
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
fn get_common_prefix(paths: &[DroppedFile]) -> String {
|
||||||
|
if paths.is_empty() {
|
||||||
|
return String::new();
|
||||||
|
}
|
||||||
|
let mut prefix = file_path(&paths[0]);
|
||||||
|
|
||||||
|
for s in paths.iter().skip(1) {
|
||||||
|
let s = file_path(s);
|
||||||
|
while !s.starts_with(&prefix) {
|
||||||
|
prefix.pop(); // Remove the last character of the prefix
|
||||||
|
if prefix.is_empty() {
|
||||||
|
return String::new();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix
|
||||||
|
}
|
||||||
|
|
||||||
fn build_atlas(&mut self, ctx: &egui::Context) {
|
fn build_atlas(&mut self, ctx: &egui::Context) {
|
||||||
self.error = None;
|
self.error = None;
|
||||||
let mut packer = TexturePacker::new_skyline(self.config);
|
let mut packer = TexturePacker::new_skyline(self.config);
|
||||||
|
let prefix = Self::get_common_prefix(&self.dropped_files);
|
||||||
|
println!("Prefix: {}", prefix);
|
||||||
for file in &self.dropped_files {
|
for file in &self.dropped_files {
|
||||||
let id = id_for_file(file);
|
let base_id = file_path(file);
|
||||||
|
let id = base_id
|
||||||
|
.strip_prefix(&prefix)
|
||||||
|
.unwrap_or(&base_id)
|
||||||
|
.to_owned()
|
||||||
|
.replace("\\", "/");
|
||||||
|
println!("Base id: {}, ID: {}", &base_id, &id);
|
||||||
let texture = dynamic_image_from_file(file);
|
let texture = dynamic_image_from_file(file);
|
||||||
let can_pack = packer.can_pack(&texture);
|
let can_pack = packer.can_pack(&texture);
|
||||||
|
|
||||||
|
|
@ -178,19 +208,33 @@ impl TemplateApp {
|
||||||
|
|
||||||
img.write_to(&mut Cursor::new(&mut out_vec), image::ImageFormat::Png)
|
img.write_to(&mut Cursor::new(&mut out_vec), image::ImageFormat::Png)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let atlas = AtlasAsset {
|
||||||
|
size: [img.width(), img.height()],
|
||||||
|
name: "Atlas".to_owned(),
|
||||||
|
frames: packer
|
||||||
|
.get_frames()
|
||||||
|
.values()
|
||||||
|
.map(|v| -> AtlasFrame {
|
||||||
|
AtlasFrame {
|
||||||
|
key: v.key.clone(),
|
||||||
|
frame: SerializableRect {
|
||||||
|
x: v.frame.x,
|
||||||
|
y: v.frame.y,
|
||||||
|
w: v.frame.w,
|
||||||
|
h: v.frame.h,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
|
let frames_string = serde_json::to_string_pretty(&atlas).unwrap();
|
||||||
|
|
||||||
let frames_info: Vec<SerializableFrame> = packer
|
let atlas_asset_json = serde_json::from_str(&frames_string).unwrap();
|
||||||
.get_frames()
|
|
||||||
.values()
|
|
||||||
.map(|v| -> SerializableFrame { (*v).clone().into() })
|
|
||||||
.collect();
|
|
||||||
let frames_string = serde_json::to_string_pretty(&frames_info).unwrap();
|
|
||||||
let frames_json = serde_json::from_str(&frames_string).unwrap();
|
|
||||||
self.data = Some(Spritesheet {
|
self.data = Some(Spritesheet {
|
||||||
data: out_vec.clone(),
|
data: out_vec.clone(),
|
||||||
frames: packer.get_frames().clone(),
|
frames: packer.get_frames().clone(),
|
||||||
size: (img.width(), img.height()),
|
size: (img.width(), img.height()),
|
||||||
frames_json,
|
atlas_asset_json,
|
||||||
});
|
});
|
||||||
let id = format!("bytes://output_{}.png", self.counter);
|
let id = format!("bytes://output_{}.png", self.counter);
|
||||||
self.image = None;
|
self.image = None;
|
||||||
|
|
@ -343,9 +387,15 @@ impl eframe::App for TemplateApp {
|
||||||
});
|
});
|
||||||
ctx.input(|i| {
|
ctx.input(|i| {
|
||||||
if !i.raw.dropped_files.is_empty() {
|
if !i.raw.dropped_files.is_empty() {
|
||||||
self.dropped_files = i.raw.dropped_files.clone();
|
let mut extra = i.raw.dropped_files.clone();
|
||||||
|
self.dropped_files.append(&mut extra);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
egui::TopBottomPanel::bottom("bottom_panel")
|
||||||
|
.frame(egui::Frame::canvas(&ctx.style()))
|
||||||
|
.show(ctx, |ui| {
|
||||||
|
powered_by_egui_and_eframe(ui);
|
||||||
|
});
|
||||||
|
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
if let Some(error) = &self.error {
|
if let Some(error) = &self.error {
|
||||||
|
|
@ -390,12 +440,12 @@ impl eframe::App for TemplateApp {
|
||||||
ui.label(format!("{} frames, size: {}x{}",data.frames.len(),data.size.0,data.size.1));
|
ui.label(format!("{} frames, size: {}x{}",data.frames.len(),data.size.0,data.size.1));
|
||||||
});
|
});
|
||||||
ui.label(RichText::new("Frames JSON").strong());
|
ui.label(RichText::new("Frames JSON").strong());
|
||||||
egui_json_tree::JsonTree::new("simple-tree", &data.frames_json).show(ui);
|
egui_json_tree::JsonTree::new("simple-tree", &data.atlas_asset_json).show(ui);
|
||||||
if ui
|
if ui
|
||||||
.add(egui::Button::new("Copy JSON to Clipboard"))
|
.add(egui::Button::new("Copy JSON to Clipboard"))
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
ui.output_mut(|o| o.copied_text = data.frames_json.to_string());
|
ui.output_mut(|o| o.copied_text = data.atlas_asset_json.to_string());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
@ -439,25 +489,15 @@ impl eframe::App for TemplateApp {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
egui::TopBottomPanel::bottom("bottom_panel")
|
|
||||||
.frame(egui::Frame::canvas(&ctx.style()))
|
|
||||||
.show(ctx, |ui| {
|
|
||||||
powered_by_egui_and_eframe(ui);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn id_for_file(file: &DroppedFile) -> String {
|
fn file_path(file: &DroppedFile) -> String {
|
||||||
let id;
|
let id;
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
{
|
{
|
||||||
let path = file.path.as_ref().unwrap().clone();
|
let path = file.path.as_ref().unwrap().clone();
|
||||||
id = path
|
id = path.to_str().unwrap().to_owned();
|
||||||
.file_name()
|
|
||||||
.unwrap()
|
|
||||||
.to_os_string()
|
|
||||||
.into_string()
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue