diff --git a/resources/characters/characters.yaml b/resources/characters/characters.yaml
index 0db48347..4b476c5a 100644
--- a/resources/characters/characters.yaml
+++ b/resources/characters/characters.yaml
@@ -14,6 +14,10 @@
pants:
style: Regular
color: Blue
+ shirt:
+ sleeve_style: Long
+ neckline: Crew
+ color: White
head:
ears:
type: Normal
@@ -164,6 +168,10 @@
pants:
style: Balloon
color: Red
+ shirt:
+ sleeve_style: Long
+ neckline: DeepV
+ color: Red
head:
ears:
type: Normal
@@ -221,7 +229,11 @@
clothing:
type: Simple
pants:
- style: Regular
+ style: Shorts
+ color: Purple
+ shirt:
+ sleeve_style: None
+ neckline: Crew
color: Purple
head:
ears:
@@ -270,6 +282,10 @@
pants:
style: Regular
color: Gray
+ shirt:
+ sleeve_style: Short
+ neckline: Crew
+ color: Gray
head:
ears:
type: Normal
diff --git a/resources/templates/appearance_edit.html.tera b/resources/templates/appearance_edit.html.tera
index 00f7aef6..94118e13 100644
--- a/resources/templates/appearance_edit.html.tera
+++ b/resources/templates/appearance_edit.html.tera
@@ -453,6 +453,20 @@
+
+ Shirt
+
+ -
+ Sleeve Style: {{ macros::add_select(name="appearance.body.clothing.shirt.sleeve_style", options=[ "Long","None","Short" ], selected=appearance.body.clothing.shirt.sleeve_style, update=true) }}
+
+ -
+ Neckline: {{ macros::add_select(name="appearance.body.clothing.shirt.neckline", options=[ "Boat","Crew","DeepV","None","Scoop","V" ], selected=appearance.body.clothing.shirt.neckline, update=true) }}
+
+ -
+ Color: {{ macros::add_select(name="appearance.body.clothing.shirt.color", options=[ "Aqua","Black","Blue","Fuchsia","Gray","Green","Lime","Maroon","Navy","Olive","Orange","Purple","Red","SaddleBrown","Silver","Teal","White","Yellow" ], selected=appearance.body.clothing.shirt.color, update=true) }}
+
+
+
{% endif %}
diff --git a/resources/templates/character.html.tera b/resources/templates/character.html.tera
index 4f5888e1..f9814ca8 100644
--- a/resources/templates/character.html.tera
+++ b/resources/templates/character.html.tera
@@ -454,6 +454,20 @@
+
+ Shirt
+
+ -
+ Sleeve Style: {{ appearance.body.clothing.shirt.sleeve_style }}
+
+ -
+ Neckline: {{ appearance.body.clothing.shirt.neckline }}
+
+ -
+ Color: {{ appearance.body.clothing.shirt.color }}
+
+
+
{% endif %}
diff --git a/rpg_tools_core/src/model/equipment/appearance/mod.rs b/rpg_tools_core/src/model/equipment/appearance/mod.rs
index 03c3a92f..c398d23d 100644
--- a/rpg_tools_core/src/model/equipment/appearance/mod.rs
+++ b/rpg_tools_core/src/model/equipment/appearance/mod.rs
@@ -1,8 +1,10 @@
use crate::model::equipment::appearance::pants::Pants;
+use crate::model::equipment::appearance::shirt::Shirt;
use macro_ui::ui;
use serde::{Deserialize, Serialize};
pub mod pants;
+pub mod shirt;
#[derive(ui, Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "type")]
@@ -11,5 +13,6 @@ pub enum Clothing {
None,
Simple {
pants: Pants,
+ shirt: Shirt,
},
}
diff --git a/rpg_tools_core/src/model/equipment/appearance/pants.rs b/rpg_tools_core/src/model/equipment/appearance/pants.rs
index 599776b3..6c1d3ed2 100644
--- a/rpg_tools_core/src/model/equipment/appearance/pants.rs
+++ b/rpg_tools_core/src/model/equipment/appearance/pants.rs
@@ -3,14 +3,14 @@ use macro_convert::Convert;
use macro_ui::ui;
use serde::{Deserialize, Serialize};
-/// Clothing for the lower body.
+/// The pants of the [`character`](crate::model::character::Character).
#[derive(ui, Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct Pants {
pub style: PantsStyle,
pub color: Color,
}
-/// What style of pants?
+/// What style of [`pants`](Pants)?
#[derive(Convert, ui, Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub enum PantsStyle {
Balloon,
diff --git a/rpg_tools_core/src/model/equipment/appearance/shirt.rs b/rpg_tools_core/src/model/equipment/appearance/shirt.rs
new file mode 100644
index 00000000..b0a6c2d7
--- /dev/null
+++ b/rpg_tools_core/src/model/equipment/appearance/shirt.rs
@@ -0,0 +1,33 @@
+use crate::model::color::Color;
+use macro_convert::Convert;
+use macro_ui::ui;
+use serde::{Deserialize, Serialize};
+
+/// The shirt of the [`character`](crate::model::character::Character).
+#[derive(ui, Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
+pub struct Shirt {
+ pub sleeve_style: SleeveStyle,
+ pub neckline: Neckline,
+ pub color: Color,
+}
+
+/// What style of neckline?
+#[derive(Convert, ui, Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
+pub enum Neckline {
+ Boat,
+ Crew,
+ DeepV,
+ #[default]
+ None,
+ Scoop,
+ V,
+}
+
+/// What style of sleeves?
+#[derive(Convert, ui, Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
+pub enum SleeveStyle {
+ #[default]
+ Long,
+ None,
+ Short,
+}
diff --git a/rpg_tools_rendering/examples/pants.rs b/rpg_tools_rendering/examples/pants.rs
index a4756a2a..9b19d7bd 100644
--- a/rpg_tools_rendering/examples/pants.rs
+++ b/rpg_tools_rendering/examples/pants.rs
@@ -3,13 +3,11 @@ extern crate rpg_tools_rendering;
use crate::utils::render::render_2_sets;
use rpg_tools_core::model::character::appearance::body::{Body, BodyShape};
-use rpg_tools_core::model::character::appearance::head::Head;
use rpg_tools_core::model::character::appearance::Appearance;
use rpg_tools_core::model::color::Color;
use rpg_tools_core::model::equipment::appearance::pants::{Pants, PantsStyle};
use rpg_tools_core::model::equipment::appearance::Clothing;
use rpg_tools_core::model::length::Length;
-use rpg_tools_core::model::width::Width;
pub mod utils;
@@ -40,11 +38,14 @@ fn create_appearance(height: Length, pants: &Pants, shape: &BodyShape) -> Appear
Appearance::humanoid(
Body {
shape: *shape,
- width: Width::default(),
+ width: Default::default(),
skin: Default::default(),
- clothing: Clothing::Simple { pants: *pants },
+ clothing: Clothing::Simple {
+ pants: *pants,
+ shirt: Default::default(),
+ },
},
- Head::default(),
+ Default::default(),
height,
)
}
diff --git a/rpg_tools_rendering/examples/shirts.rs b/rpg_tools_rendering/examples/shirts.rs
new file mode 100644
index 00000000..200ed3ea
--- /dev/null
+++ b/rpg_tools_rendering/examples/shirts.rs
@@ -0,0 +1,50 @@
+extern crate rpg_tools_core;
+extern crate rpg_tools_rendering;
+
+use crate::utils::render::render_2_sets;
+use rpg_tools_core::model::character::appearance::body::{Body, BodyShape};
+use rpg_tools_core::model::character::appearance::Appearance;
+use rpg_tools_core::model::color::Color;
+use rpg_tools_core::model::equipment::appearance::shirt::{Neckline, Shirt, SleeveStyle};
+use rpg_tools_core::model::equipment::appearance::Clothing;
+use rpg_tools_core::model::length::Length;
+
+pub mod utils;
+
+fn main() {
+ let mut shirts = vec![];
+
+ for neckline in Neckline::get_all() {
+ for sleeve_style in SleeveStyle::get_all() {
+ shirts.push(Shirt {
+ sleeve_style,
+ neckline,
+ color: Color::Aqua,
+ })
+ }
+ }
+
+ render_2_sets(
+ "shirts.svg",
+ shirts,
+ BodyShape::get_all(),
+ create_appearance,
+ false,
+ );
+}
+
+fn create_appearance(height: Length, shirt: &Shirt, shape: &BodyShape) -> Appearance {
+ Appearance::humanoid(
+ Body {
+ shape: *shape,
+ width: Default::default(),
+ skin: Default::default(),
+ clothing: Clothing::Simple {
+ pants: Default::default(),
+ shirt: *shirt,
+ },
+ },
+ Default::default(),
+ height,
+ )
+}
diff --git a/rpg_tools_rendering/src/rendering/body/mod.rs b/rpg_tools_rendering/src/rendering/body/mod.rs
index 243e6ee1..8a2698b1 100644
--- a/rpg_tools_rendering/src/rendering/body/mod.rs
+++ b/rpg_tools_rendering/src/rendering/body/mod.rs
@@ -1,11 +1,12 @@
use crate::math::aabb2d::{get_end_x, get_start_x, AABB};
use crate::math::orientation::Orientation;
use crate::math::point2d::Point2d;
-use crate::math::polygon2d::Polygon2d;
+use crate::math::polygon2d::builder::Polygon2dBuilder;
use crate::math::size2d::Size2d;
use crate::renderer::{RenderOptions, Renderer};
use crate::rendering::body::torso::render_torso;
use crate::rendering::config::RenderConfig;
+use crate::rendering::equipment::pants::interpolate;
use rpg_tools_core::model::character::appearance::body::Body;
use std::ops::Mul;
@@ -15,8 +16,7 @@ pub fn render_body(renderer: &mut dyn Renderer, config: &RenderConfig, aabb: &AA
let options = config.get_skin_options(&body.skin);
render_legs(renderer, config, aabb, body, &options);
- render_arms(renderer, config, &aabb, body, &options);
- render_hands(renderer, config, aabb, body, &options);
+ render_arms(renderer, config, aabb, body, &options);
render_torso(renderer, config, aabb, body, &options);
}
@@ -50,67 +50,65 @@ fn render_legs(
renderer.render_circle_arc(&right_foot_start, foot_radius, offset, angle, options);
}
-fn render_hands(
- renderer: &mut dyn Renderer,
- config: &RenderConfig,
- aabb: &AABB,
- body: &Body,
- options: &RenderOptions,
-) {
+pub fn render_hands(renderer: &mut dyn Renderer, config: &RenderConfig, aabb: &AABB, body: &Body) {
+ let options = config.get_skin_options(&body.skin);
let hand_radius = config.body.get_hand_radius(body, aabb);
- let distance_between_hands = config.body.get_shoulder_width(body)
- + config.body.get_arm_width(body)
- + config.body.get_fat_offset_factor(body);
+ let distance_between_hands =
+ config.body.get_distance_between_hands(body) + config.body.get_hand_radius_factor(body);
let hand_y = config.body.get_arm_y() + config.body.height_arm;
let (left_hand_center, right_hand_center) =
aabb.get_mirrored_points(distance_between_hands, hand_y);
- renderer.render_circle(&left_hand_center, hand_radius, options);
- renderer.render_circle(&right_hand_center, hand_radius, options);
+ renderer.render_circle(&left_hand_center, hand_radius, &options);
+ renderer.render_circle(&right_hand_center, hand_radius, &options);
}
fn render_arms(
renderer: &mut dyn Renderer,
config: &RenderConfig,
- aabb: &&AABB,
+ aabb: &AABB,
body: &Body,
options: &RenderOptions,
) {
- let arm_size = aabb
- .size()
- .scale(config.body.get_arm_width(body), config.body.height_arm);
- let arm_start_x = get_start_x(config.body.get_shoulder_width(body));
- let right_arm_start = aabb.get_point(
- arm_start_x - config.body.get_arm_width(body),
- config.body.get_arm_y(),
- );
- let fat_offset = aabb.convert_to_height(config.body.get_fat_offset_factor(body) / 2.0);
- let polygon = create_arm(arm_size, right_arm_start, fat_offset as i32);
+ let polygon = get_left_arm(config, aabb, body).build();
renderer.render_rounded_polygon(&polygon, options);
renderer.render_rounded_polygon(&aabb.mirrored(&polygon), options);
}
-fn create_arm(arm_size: Size2d, right_arm_start: Point2d, offset: i32) -> Polygon2d {
- let right_arm = AABB::new(right_arm_start, arm_size);
- let mut polygon: Polygon2d = (&right_arm).into();
-
- if offset != 0 {
- let corners = polygon.corners_mut();
-
- update_corner(corners, 2, offset);
- update_corner(corners, 3, offset);
- }
+pub fn get_left_arm(config: &RenderConfig, aabb: &AABB, body: &Body) -> Polygon2dBuilder {
+ let mut builder = get_left_arm_short(config, aabb, body, false);
+ let width = config.body.get_arm_width(body);
+ let bottom_x = get_end_x(config.body.get_distance_between_hands(body));
+ let y = config.body.get_arm_y() + config.body.height_arm;
- polygon.create_sharp_corner(1);
+ builder.add_point(aabb.get_point(bottom_x, y), false);
+ builder.add_point_cw(aabb.get_point(bottom_x + width, y), false);
- polygon
+ builder
}
-fn update_corner(corners: &mut [Point2d], index: usize, offset: i32) {
- if let Some(p) = corners.get_mut(index) {
- p.x -= offset;
- }
+pub fn get_left_arm_short(
+ config: &RenderConfig,
+ aabb: &AABB,
+ body: &Body,
+ bottom_sharp: bool,
+) -> Polygon2dBuilder {
+ let mut builder = Polygon2dBuilder::new();
+ let width = config.body.get_arm_width(body);
+ let top_x = get_end_x(config.body.get_shoulder_width(body) * 0.94);
+ let bottom_x = get_end_x(config.body.get_distance_between_hands(body));
+ let bottom_x = interpolate(top_x, bottom_x, 0.7);
+ let y = config.body.get_arm_y();
+ let mid_y = y + 0.2;
+
+ builder.add_point(aabb.get_point(top_x, y), true);
+ builder.add_point_cw(aabb.get_point(top_x + width, y), false);
+ builder.add_point(aabb.get_point(top_x, y + 0.1), true);
+ builder.add_point(aabb.get_point(bottom_x, mid_y), bottom_sharp);
+ builder.add_point_cw(aabb.get_point(bottom_x + width, mid_y), bottom_sharp);
+
+ builder
}
fn render_leg(renderer: &mut dyn Renderer, options: &RenderOptions, start: Point2d, size: Size2d) {
diff --git a/rpg_tools_rendering/src/rendering/body/torso.rs b/rpg_tools_rendering/src/rendering/body/torso.rs
index 0b7ac964..f7f9fdb2 100644
--- a/rpg_tools_rendering/src/rendering/body/torso.rs
+++ b/rpg_tools_rendering/src/rendering/body/torso.rs
@@ -1,5 +1,5 @@
use crate::math::aabb2d::AABB;
-use crate::math::polygon2d::Polygon2d;
+use crate::math::polygon2d::builder::Polygon2dBuilder;
use crate::renderer::{RenderOptions, Renderer};
use crate::rendering::config::body::torso::TorsoConfig;
use crate::rendering::config::body::BodyConfig;
@@ -18,27 +18,19 @@ pub fn render_torso(
&torso_aabb,
&config.body,
config.body.get_torso_config(body.shape),
- );
+ )
+ .build();
renderer.render_rounded_polygon(&polygon, options);
}
-fn create_torso(aabb: &AABB, config: &BodyConfig, torso: &TorsoConfig) -> Polygon2d {
- let (top_left, top_right) = aabb.get_mirrored_points(torso.shoulder_width, 0.0);
- let (upper_left, upper_right) = aabb.get_mirrored_points(torso.shoulder_width, config.y_upper);
- let (waist_left, waist_right) = aabb.get_mirrored_points(torso.waist_width, config.y_waist);
- let (lower_left, lower_right) = aabb.get_mirrored_points(torso.hip_width, config.y_lower);
- let (bottom_left, bottom_right) = aabb.get_mirrored_points(torso.hip_width, 1.0);
+pub fn create_torso(aabb: &AABB, config: &BodyConfig, torso: &TorsoConfig) -> Polygon2dBuilder {
+ let mut builder = Polygon2dBuilder::new();
- Polygon2d::new(vec![
- top_left,
- upper_left,
- waist_left,
- lower_left,
- bottom_left,
- bottom_right,
- lower_right,
- waist_right,
- upper_right,
- top_right,
- ])
+ builder.add_mirrored_points(aabb, torso.hip_width, 1.0, false);
+ builder.add_mirrored_points(aabb, torso.hip_width, config.y_lower, false);
+ builder.add_mirrored_points(aabb, torso.waist_width, config.y_waist, false);
+ builder.add_mirrored_points(aabb, torso.shoulder_width, config.y_upper, false);
+ builder.add_mirrored_points(aabb, torso.shoulder_width, 0.0, false);
+
+ builder
}
diff --git a/rpg_tools_rendering/src/rendering/character.rs b/rpg_tools_rendering/src/rendering/character.rs
index 5bd885f3..e52f09b9 100644
--- a/rpg_tools_rendering/src/rendering/character.rs
+++ b/rpg_tools_rendering/src/rendering/character.rs
@@ -1,7 +1,7 @@
use crate::math::aabb2d::AABB;
use crate::math::size2d::Size2d;
use crate::renderer::Renderer;
-use crate::rendering::body::{calculate_head_aabb, render_body};
+use crate::rendering::body::{calculate_head_aabb, render_body, render_hands};
use crate::rendering::config::RenderConfig;
use crate::rendering::ear::render_ears;
use crate::rendering::equipment::render_clothing;
@@ -39,7 +39,8 @@ pub fn render_character_from_front(
let head_aabb = calculate_head_aabb(config, &inner);
render_head_behind_body_from_front(renderer, config, head, &head_aabb);
render_body(renderer, config, &inner, body);
- render_clothing(renderer, config, &inner, body);
+ render_clothing(renderer, config, &inner, body, true);
+ render_hands(renderer, config, &inner, body);
render_head_before_body_from_front(renderer, config, head, &head_aabb);
}
}
@@ -59,7 +60,8 @@ pub fn render_character_from_back(
}
Appearance::Humanoid { body, head, .. } => {
render_body(renderer, config, &inner, &body);
- render_clothing(renderer, config, &inner, &body);
+ render_clothing(renderer, config, &inner, &body, false);
+ render_hands(renderer, config, &inner, &body);
let head_aabb = calculate_head_aabb(config, &inner);
render_head_from_back(renderer, config, &head, &head_aabb);
}
diff --git a/rpg_tools_rendering/src/rendering/config/body/mod.rs b/rpg_tools_rendering/src/rendering/config/body/mod.rs
index 8f8ba2b7..3779a0de 100644
--- a/rpg_tools_rendering/src/rendering/config/body/mod.rs
+++ b/rpg_tools_rendering/src/rendering/config/body/mod.rs
@@ -84,23 +84,23 @@ impl BodyConfig {
}
pub fn get_arm_y(&self) -> f32 {
- self.y_torso + 0.05
+ self.y_torso + 0.02
}
pub fn get_leg_y(&self) -> f32 {
self.get_torso_bottom() - 0.05
}
- pub fn get_fat_offset_factor(&self, body: &Body) -> f32 {
- if body.shape == BodyShape::Fat {
- self.get_hip_width(body) - self.get_shoulder_width(body)
- } else {
- 0.0
- }
+ pub fn get_distance_between_hands(&self, body: &Body) -> f32 {
+ self.get_torso_width(body) + 0.08
}
pub fn get_hand_radius(&self, body: &Body, aabb: &AABB) -> u32 {
- aabb.convert_to_height(self.hand_factor * self.get_width_factor(body))
+ aabb.convert_to_height(self.get_hand_radius_factor(body))
+ }
+
+ pub fn get_hand_radius_factor(&self, body: &Body) -> f32 {
+ self.hand_factor * self.get_width_factor(body)
}
pub fn get_foot_radius(&self, body: &Body, aabb: &AABB) -> u32 {
diff --git a/rpg_tools_rendering/src/rendering/config/equipment/mod.rs b/rpg_tools_rendering/src/rendering/config/equipment/mod.rs
index 9cb84244..cd7eb969 100644
--- a/rpg_tools_rendering/src/rendering/config/equipment/mod.rs
+++ b/rpg_tools_rendering/src/rendering/config/equipment/mod.rs
@@ -1 +1,2 @@
pub mod pants;
+pub mod shirt;
diff --git a/rpg_tools_rendering/src/rendering/config/equipment/shirt.rs b/rpg_tools_rendering/src/rendering/config/equipment/shirt.rs
new file mode 100644
index 00000000..3887b41e
--- /dev/null
+++ b/rpg_tools_rendering/src/rendering/config/equipment/shirt.rs
@@ -0,0 +1,12 @@
+/// The rendering config of the [`shirts`](rpg_tools_core::model::equipment::appearance::shirt::Shirt).
+#[derive(Debug, PartialEq)]
+pub struct ShirtConfig {
+ pub boat_depth: f32,
+ pub boat_width: f32,
+ pub crew_depth: f32,
+ pub crew_width: f32,
+ pub deep_v_depth: f32,
+ pub scoop_depth: f32,
+ pub scoop_width: f32,
+ pub v_depth: f32,
+}
diff --git a/rpg_tools_rendering/src/rendering/config/example.rs b/rpg_tools_rendering/src/rendering/config/example.rs
index 4f51fd2a..6fd9147a 100644
--- a/rpg_tools_rendering/src/rendering/config/example.rs
+++ b/rpg_tools_rendering/src/rendering/config/example.rs
@@ -6,6 +6,7 @@ use crate::rendering::config::body::torso::TorsoConfig;
use crate::rendering::config::body::BodyConfig;
use crate::rendering::config::ear::EarConfig;
use crate::rendering::config::equipment::pants::PantsConfig;
+use crate::rendering::config::equipment::shirt::ShirtConfig;
use crate::rendering::config::eye::eyebrow::EyebrowConfig;
use crate::rendering::config::eye::EyeConfig;
use crate::rendering::config::hair::hairline::HairlineConfig;
@@ -127,6 +128,16 @@ pub fn create_config() -> RenderConfig {
width_padding: 0.05,
balloon_padding: 0.2,
},
+ shirt: ShirtConfig {
+ boat_depth: 0.05,
+ boat_width: 0.7,
+ crew_depth: 0.1,
+ crew_width: 0.3,
+ deep_v_depth: 0.4,
+ scoop_depth: 0.2,
+ scoop_width: 0.5,
+ v_depth: 0.2,
+ },
}
}
diff --git a/rpg_tools_rendering/src/rendering/config/mod.rs b/rpg_tools_rendering/src/rendering/config/mod.rs
index b04bbf93..3d3b9b07 100644
--- a/rpg_tools_rendering/src/rendering/config/mod.rs
+++ b/rpg_tools_rendering/src/rendering/config/mod.rs
@@ -3,6 +3,7 @@ use crate::renderer::RenderOptions;
use crate::rendering::config::body::BodyConfig;
use crate::rendering::config::ear::EarConfig;
use crate::rendering::config::equipment::pants::PantsConfig;
+use crate::rendering::config::equipment::shirt::ShirtConfig;
use crate::rendering::config::eye::EyeConfig;
use crate::rendering::config::hair::HairConfig;
use crate::rendering::config::head::HeadConfig;
@@ -35,6 +36,7 @@ pub struct RenderConfig {
pub head: HeadConfig,
pub mouth: MouthConfig,
pub pants: PantsConfig,
+ pub shirt: ShirtConfig,
}
impl RenderConfig {
diff --git a/rpg_tools_rendering/src/rendering/equipment/mod.rs b/rpg_tools_rendering/src/rendering/equipment/mod.rs
index 86545cba..0d2d7193 100644
--- a/rpg_tools_rendering/src/rendering/equipment/mod.rs
+++ b/rpg_tools_rendering/src/rendering/equipment/mod.rs
@@ -2,18 +2,22 @@ use crate::math::aabb2d::AABB;
use crate::renderer::Renderer;
use crate::rendering::config::RenderConfig;
use crate::rendering::equipment::pants::render_pants;
+use crate::rendering::equipment::shirt::render_shirt;
use rpg_tools_core::model::character::appearance::body::Body;
use rpg_tools_core::model::equipment::appearance::Clothing;
pub mod pants;
+pub mod shirt;
pub fn render_clothing(
renderer: &mut dyn Renderer,
config: &RenderConfig,
aabb: &AABB,
body: &Body,
+ from_front: bool,
) {
- if let Clothing::Simple { pants } = &body.clothing {
- render_pants(renderer, config, aabb, body, pants)
+ if let Clothing::Simple { pants, shirt } = &body.clothing {
+ render_shirt(renderer, config, aabb, body, shirt, from_front);
+ render_pants(renderer, config, aabb, body, pants);
}
}
diff --git a/rpg_tools_rendering/src/rendering/equipment/pants.rs b/rpg_tools_rendering/src/rendering/equipment/pants.rs
index e18fb44e..9fd0485a 100644
--- a/rpg_tools_rendering/src/rendering/equipment/pants.rs
+++ b/rpg_tools_rendering/src/rendering/equipment/pants.rs
@@ -99,6 +99,6 @@ fn get_base(config: &RenderConfig, aabb: &AABB, body: &Body) -> Polygon2dBuilder
builder
}
-fn interpolate(start: f32, end: f32, factor: f32) -> f32 {
+pub fn interpolate(start: f32, end: f32, factor: f32) -> f32 {
start * (1.0 - factor) + end * factor
}
diff --git a/rpg_tools_rendering/src/rendering/equipment/shirt.rs b/rpg_tools_rendering/src/rendering/equipment/shirt.rs
new file mode 100644
index 00000000..bd779b08
--- /dev/null
+++ b/rpg_tools_rendering/src/rendering/equipment/shirt.rs
@@ -0,0 +1,104 @@
+use crate::math::aabb2d::AABB;
+use crate::math::polygon2d::builder::Polygon2dBuilder;
+use crate::renderer::Renderer;
+use crate::rendering::body::torso::create_torso;
+use crate::rendering::body::{get_left_arm, get_left_arm_short};
+use crate::rendering::config::body::torso::TorsoConfig;
+use crate::rendering::config::equipment::shirt::ShirtConfig;
+use crate::rendering::config::RenderConfig;
+use rpg_tools_core::model::character::appearance::body::Body;
+use rpg_tools_core::model::equipment::appearance::shirt::{Neckline, Shirt, SleeveStyle};
+
+pub fn render_shirt(
+ renderer: &mut dyn Renderer,
+ config: &RenderConfig,
+ aabb: &AABB,
+ body: &Body,
+ shirt: &Shirt,
+ from_front: bool,
+) {
+ render_sleeves(renderer, config, aabb, body, shirt);
+ render_torso(renderer, config, aabb, body, shirt, from_front);
+}
+
+fn render_torso(
+ renderer: &mut dyn Renderer,
+ config: &RenderConfig,
+ aabb: &AABB,
+ body: &Body,
+ shirt: &Shirt,
+ from_front: bool,
+) {
+ let options = config.get_options(shirt.color);
+ let torso_aabb = config.body.get_torso_aabb(body, aabb);
+ let torso = config.body.get_torso_config(body.shape);
+ let mut builder = create_torso(&torso_aabb, &config.body, torso);
+
+ if from_front {
+ add_neckline(&torso_aabb, &config.shirt, torso, shirt, &mut builder);
+ } else {
+ add_straight(&torso_aabb, torso, &mut builder)
+ }
+
+ let polygon = builder.build();
+ renderer.render_rounded_polygon(&polygon, &options);
+}
+
+fn render_sleeves(
+ renderer: &mut dyn Renderer,
+ config: &RenderConfig,
+ aabb: &AABB,
+ body: &Body,
+ shirt: &Shirt,
+) {
+ let options = config.get_options(shirt.color);
+
+ let polygon = match shirt.sleeve_style {
+ SleeveStyle::Long => get_left_arm(config, aabb, body),
+ SleeveStyle::None => return,
+ SleeveStyle::Short => get_left_arm_short(config, aabb, body, true),
+ }
+ .build();
+
+ renderer.render_rounded_polygon(&polygon, &options);
+ renderer.render_rounded_polygon(&aabb.mirrored(&polygon), &options);
+}
+
+fn add_neckline(
+ aabb: &AABB,
+ config: &ShirtConfig,
+ torso: &TorsoConfig,
+ shirt: &Shirt,
+ builder: &mut Polygon2dBuilder,
+) {
+ match shirt.neckline {
+ Neckline::Boat => add_round(aabb, torso, builder, config.boat_width, config.boat_depth),
+ Neckline::Crew => add_round(aabb, torso, builder, config.crew_width, config.crew_depth),
+ Neckline::DeepV => add_v(aabb, torso, builder, config.deep_v_depth),
+ Neckline::None => add_straight(aabb, torso, builder),
+ Neckline::Scoop => add_round(aabb, torso, builder, config.scoop_width, config.scoop_depth),
+ Neckline::V => add_v(aabb, torso, builder, config.v_depth),
+ }
+}
+
+fn add_round(
+ aabb: &AABB,
+ torso: &TorsoConfig,
+ builder: &mut Polygon2dBuilder,
+ width: f32,
+ depth: f32,
+) {
+ let width = torso.shoulder_width * width;
+ builder.add_mirrored_points(aabb, width, 0.0, true);
+ builder.add_mirrored_points(aabb, width * 0.7, depth, false);
+}
+
+fn add_v(aabb: &AABB, torso: &TorsoConfig, builder: &mut Polygon2dBuilder, depth: f32) {
+ add_straight(aabb, torso, builder);
+ builder.add_point(aabb.get_point(0.5, depth), true);
+}
+
+fn add_straight(aabb: &AABB, torso: &TorsoConfig, builder: &mut Polygon2dBuilder) {
+ let width = torso.shoulder_width / 3.0;
+ builder.add_mirrored_points(aabb, width, 0.0, true);
+}