use super::*;
pub(crate) fn draw_sprite_immediate(
context: &CanvasRenderingContext2d,
image: &HtmlImageElement,
source: &Rect,
transform: &Transform2D,
) {
let rotation: f64 = transform.get_rotation();
let cos: f64 = rotation.cos();
let sin: f64 = rotation.sin();
let scale_x: f64 = transform.get_scale().get_x();
let scale_y: f64 = transform.get_scale().get_y();
let _: Result<(), JsValue> = context.set_transform(
cos * scale_x,
sin * scale_x,
-sin * scale_y,
cos * scale_y,
transform.get_position().get_x(),
transform.get_position().get_y(),
);
let _: Result<(), JsValue> = context
.draw_image_with_html_image_element_and_sw_and_sh_and_dx_and_dy_and_dw_and_dh(
image,
source.get_x(),
source.get_y(),
source.get_width(),
source.get_height(),
-source.get_width() * 0.5,
-source.get_height() * 0.5,
source.get_width(),
source.get_height(),
);
let _: Result<(), JsValue> = context.set_transform(1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
}
pub(crate) fn js_error_to_string(value: &JsValue) -> String {
if let Some(s) = value.as_string() {
s
} else if value.is_undefined() {
"<undefined>".to_string()
} else if value.is_null() {
"<null>".to_string()
} else {
format!("{:?}", value)
}
}
pub(crate) fn pick_depth_format(high_precision: bool, with_stencil: bool) -> &'static str {
if with_stencil {
WEBGPU_DEPTH_FORMAT_DEPTH24_PLUS_STENCIL8
} else if high_precision {
WEBGPU_DEPTH_FORMAT_DEPTH32_FLOAT
} else if cfg!(target_arch = "wasm32") {
WEBGPU_DEPTH_FORMAT_DEPTH24_PLUS
} else {
WEBGPU_DEPTH_FORMAT_DEPTH16_UNORM
}
}
pub(crate) fn default_color_store_op(transient: bool) -> &'static str {
if transient {
WEBGPU_STORE_OP_DISCARD
} else {
WEBGPU_STORE_OP_STORE
}
}
pub(crate) fn map_mode_for(read: bool, write: bool) -> u32 {
let mut mode: u32 = 0;
if read {
mode |= WEBGPU_MAP_MODE_READ as u32;
}
if write {
mode |= WEBGPU_MAP_MODE_WRITE as u32;
}
mode
}
pub(crate) fn texture_usage(
render_target: bool,
copy_src: bool,
copy_dst: bool,
sampled: bool,
storage: bool,
) -> u32 {
let mut usage: u32 = 0;
if render_target {
usage |= WEBGPU_TEXTURE_USAGE_RENDER_ATTACHMENT as u32;
}
if copy_src {
usage |= WEBGPU_TEXTURE_USAGE_COPY_SRC as u32;
}
if copy_dst {
usage |= WEBGPU_TEXTURE_USAGE_COPY_DST as u32;
}
if sampled {
usage |= WEBGPU_TEXTURE_USAGE_TEXTURE_BINDING as u32;
}
if storage {
usage |= WEBGPU_TEXTURE_USAGE_STORAGE_BINDING as u32;
}
usage
}
pub(crate) fn cached_method_name(name: &'static str) -> JsValue {
thread_local! {
static CACHE: RefCell<Option<HashMap<&'static str, JsValue>>> =
const { RefCell::new(None) };
}
CACHE.with(|slot| {
let mut borrow: std::cell::RefMut<'_, Option<HashMap<&'static str, JsValue>>> =
slot.borrow_mut();
let map: &mut HashMap<&'static str, JsValue> = borrow.get_or_insert_with(HashMap::new);
if let Some(value) = map.get(name) {
return value.clone();
}
let value: JsValue = JsValue::from_str(name);
map.insert(name, value.clone());
value
})
}
pub(crate) fn cached_method(obj: &JsValue, method_name: &'static str) -> Result<Function, JsValue> {
thread_local! {
static FUNCTION_CACHE: RefCell<
Option<HashMap<(usize, &'static str), Function>>,
> = const { RefCell::new(None) };
}
let key: (usize, &'static str) = (obj as *const JsValue as usize, method_name);
FUNCTION_CACHE.with(|slot| {
let mut borrow: std::cell::RefMut<'_, Option<HashMap<(usize, &'static str), Function>>> =
slot.borrow_mut();
let map: &mut HashMap<(usize, &'static str), Function> =
borrow.get_or_insert_with(HashMap::new);
if let Some(func) = map.get(&key) {
return Ok(func.clone());
}
let value: Result<JsValue, JsValue> = Reflect::get(obj, &cached_method_name(method_name));
let value: JsValue = match value {
Ok(v) => v,
Err(e) => return Err(e),
};
let func: Function = value.unchecked_into();
map.insert(key, func.clone());
Ok(func)
})
}
pub(crate) fn cached_method_call(
obj: &JsValue,
method_name: &'static str,
arg: &JsValue,
) -> Result<JsValue, JsValue> {
let function: Function = cached_method(obj, method_name)?;
function.call1(obj, arg)
}