Files
OneCAD-Draft/src/scene/model/visual_style_model.rs
T

287 lines
9.7 KiB
Rust

use acadrust::objects::{
ObjectType, VisualStyle, VisualStyleProperty, VisualStylePropertyValue,
};
use acadrust::{CadDocument, EntityType, Handle};
#[derive(Clone, Debug)]
pub struct MeshVisualStyle {
pub full_handle: Option<Handle>,
pub face_handle: Option<Handle>,
pub edge_handle: Option<Handle>,
pub description: String,
pub style_type: i16,
pub face_lighting_model: i16,
pub face_lighting_quality: i16,
pub face_color_mode: i16,
pub face_modifier: i32,
pub face_opacity: f32,
pub face_specular: f32,
pub mono_color: Option<[f32; 4]>,
pub edge_model: i32,
pub edge_style: i32,
pub edge_color: Option<[f32; 4]>,
pub edge_opacity: f32,
pub edge_width: f32,
pub edge_overhang: i32,
pub edge_jitter: i32,
pub silhouette_color: Option<[f32; 4]>,
pub silhouette_width: i32,
pub halo_gap: i32,
pub isoline_count: i32,
pub hide_precision: bool,
pub display_settings: i32,
pub brightness: f32,
pub shadow_type: i32,
pub extended_lighting_model: i16,
pub internal_use_only: bool,
}
fn core_property(style: &VisualStyle, index: usize) -> Option<&VisualStyleProperty> {
if style.properties.len() >= 28 {
return style.properties.get(index);
}
if style.properties.len() == 24 {
let legacy = match index {
4 => 0,
5 => 1,
6 => 2,
9 => 3,
10 => 4,
11 => 5,
13 => 6,
14 => 7,
15 => 8,
16 => 9,
17 => 10,
18 => 11,
19 => 12,
20 => 13,
21 => 14,
22 => 15,
23 => 16,
24 => 17,
12 => 19,
25 => 20,
26 => 21,
27 => 22,
_ => return None,
};
return style.properties.get(legacy);
}
style.properties.get(index)
}
fn property_double(style: &VisualStyle, index: usize, fallback: f64) -> f64 {
let Some(property) = core_property(style, index) else {
return fallback;
};
match property.value {
VisualStylePropertyValue::Short(value) => value as f64,
VisualStylePropertyValue::Long(value) => value as f64,
VisualStylePropertyValue::Double(value) => value,
VisualStylePropertyValue::Bool(value) => value as u8 as f64,
_ => fallback,
}
}
fn property_long(style: &VisualStyle, index: usize, fallback: i32) -> i32 {
property_double(style, index, fallback as f64) as i32
}
fn property_bool(style: &VisualStyle, index: usize, fallback: bool) -> bool {
property_double(style, index, fallback as u8 as f64) != 0.0
}
fn property_color(style: &VisualStyle, index: usize) -> Option<[f32; 4]> {
let property = core_property(style, index)?;
if property.enabled == 0 {
return None;
}
let VisualStylePropertyValue::Color(color) = &property.value else {
return None;
};
if matches!(
color,
acadrust::types::Color::ByLayer | acadrust::types::Color::ByBlock
) {
return None;
}
Some(crate::scene::convert::tess_util::aci_to_rgba(color))
}
impl MeshVisualStyle {
pub(crate) fn from_dwg(handle: Handle, style: &VisualStyle) -> Self {
Self {
full_handle: Some(handle),
face_handle: None,
edge_handle: None,
description: style.description.clone(),
style_type: style.style_type,
face_lighting_model: style.face_lighting_model,
face_lighting_quality: style.face_lighting_quality,
face_color_mode: style.face_color_mode,
face_modifier: style.face_modifier,
face_opacity: property_double(style, 4, 1.0).clamp(0.0, 1.0) as f32,
face_specular: property_double(style, 5, 0.0).max(0.0) as f32,
mono_color: property_color(style, 6),
edge_model: style.edge_model,
edge_style: style.edge_style,
edge_color: property_color(style, 15),
edge_opacity: property_double(style, 16, 1.0).clamp(0.0, 1.0) as f32,
edge_width: property_double(style, 17, 1.0).max(0.0) as f32,
edge_overhang: property_long(style, 18, 0),
edge_jitter: property_long(style, 19, 0),
silhouette_color: property_color(style, 20),
silhouette_width: property_long(style, 21, 0),
halo_gap: property_long(style, 22, 0),
isoline_count: property_long(style, 23, 0),
hide_precision: property_bool(style, 24, false),
display_settings: property_long(style, 25, 0),
brightness: property_double(style, 26, 0.0) as f32,
shadow_type: if style.properties.len() == 24 {
style
.properties
.get(23)
.map_or(0, |property| match property.value {
VisualStylePropertyValue::Short(value) => value as i32,
VisualStylePropertyValue::Long(value) => value,
VisualStylePropertyValue::Double(value) => value as i32,
VisualStylePropertyValue::Bool(value) => value as i32,
_ => 0,
})
} else {
property_long(style, 27, 0)
},
extended_lighting_model: style.extended_lighting_model,
internal_use_only: style.internal_use_only,
}
}
fn override_face(&mut self, handle: Handle, style: &VisualStyle) {
let source = Self::from_dwg(handle, style);
self.face_handle = Some(handle);
self.face_lighting_model = source.face_lighting_model;
self.face_lighting_quality = source.face_lighting_quality;
self.face_color_mode = source.face_color_mode;
self.face_modifier = source.face_modifier;
self.face_opacity = source.face_opacity;
self.face_specular = source.face_specular;
self.mono_color = source.mono_color;
self.brightness = source.brightness;
self.extended_lighting_model = source.extended_lighting_model;
}
fn override_edge(&mut self, handle: Handle, style: &VisualStyle) {
let source = Self::from_dwg(handle, style);
self.edge_handle = Some(handle);
self.edge_model = source.edge_model;
self.edge_style = source.edge_style;
self.edge_color = source.edge_color;
self.edge_opacity = source.edge_opacity;
self.edge_width = source.edge_width;
self.edge_overhang = source.edge_overhang;
self.edge_jitter = source.edge_jitter;
self.silhouette_color = source.silhouette_color;
self.silhouette_width = source.silhouette_width;
self.halo_gap = source.halo_gap;
self.isoline_count = source.isoline_count;
self.hide_precision = source.hide_precision;
}
pub fn face_visible(&self) -> bool {
self.face_lighting_model != 0 && self.face_color_mode != 0
}
pub fn edges_visible(&self) -> bool {
self.edge_model != 0
}
pub fn face_color(&self, base: [f32; 4]) -> [f32; 4] {
let mut color = match self.face_color_mode {
3 | 4 => self.mono_color.unwrap_or(base),
5 => {
let tint = self.mono_color.unwrap_or(base);
[
(base[0] + tint[0]) * 0.5,
(base[1] + tint[1]) * 0.5,
(base[2] + tint[2]) * 0.5,
base[3],
]
}
6 => {
let luminance = base[0] * 0.2126 + base[1] * 0.7152 + base[2] * 0.0722;
[
base[0] * 0.7 + luminance * 0.3,
base[1] * 0.7 + luminance * 0.3,
base[2] * 0.7 + luminance * 0.3,
base[3],
]
}
_ => base,
};
if self.face_modifier & 1 != 0 {
color[3] *= self.face_opacity;
}
color
}
pub fn edge_color(&self, base: [f32; 4]) -> [f32; 4] {
let mut color = self.edge_color.unwrap_or(base);
color[3] *= self.edge_opacity;
color
}
}
pub(crate) fn resolve_visual_style_handle(
document: &CadDocument,
handle: Handle,
) -> Option<MeshVisualStyle> {
visual_style(document, Some(handle))
.map(|(handle, style)| MeshVisualStyle::from_dwg(handle, style))
}
fn visual_style(
document: &CadDocument,
handle: Option<Handle>,
) -> Option<(Handle, &VisualStyle)> {
let handle = handle.filter(|handle| handle.is_valid())?;
match document.objects.get(&handle) {
Some(ObjectType::VisualStyle(style)) => Some((handle, style)),
_ => None,
}
}
pub fn resolve_mesh_visual_style(
document: &CadDocument,
entity: &EntityType,
) -> Option<MeshVisualStyle> {
let common = entity.common();
let full = visual_style(document, common.full_visual_style_handle);
let face = visual_style(document, common.face_visual_style_handle);
let edge = visual_style(document, common.edge_visual_style_handle);
let mut result = full
.map(|(handle, style)| MeshVisualStyle::from_dwg(handle, style))
.or_else(|| {
face.or(edge)
.map(|(handle, style)| MeshVisualStyle::from_dwg(handle, style))
})?;
if full.is_none() {
result.full_handle = None;
}
if let Some((handle, style)) = face {
result.override_face(handle, style);
}
if let Some((handle, style)) = edge {
result.override_edge(handle, style);
}
Some(result)
}
pub fn apply_mesh_visual_style(
set: &mut super::mesh_model::MeshLodSet,
document: &CadDocument,
entity: &EntityType,
) {
set.visual_style = resolve_mesh_visual_style(document, entity);
}