mirror of
https://github.com/enso-org/enso.git
synced 2024-12-19 15:12:26 +03:00
Enable alpha blending for ID pass (https://github.com/enso-org/ide/pull/364)
* Enable working alpha blending for ID pass via bit encoding of IDs in a RGB8 texture..
* Add facilities to change texture parameters.
Original commit: b46012e3fa
This commit is contained in:
parent
c1a399804f
commit
3e2c8bef84
@ -109,7 +109,8 @@ impl ComposerPass {
|
||||
let name = format!("pass_{}",output.name());
|
||||
let args = (self.width,self.height);
|
||||
let texture = uniform::get_or_add_gpu_texture_dyn
|
||||
(&self.context,&self.variables,&name,output.internal_format,output.item_type,args);
|
||||
(&self.context,&self.variables,&name,output.internal_format,output.item_type,args,
|
||||
Some(output.texture_parameters));
|
||||
self.add_output(texture);
|
||||
}
|
||||
}
|
||||
|
@ -31,16 +31,21 @@ impl SymbolsRenderPass {
|
||||
|
||||
impl RenderPass for SymbolsRenderPass {
|
||||
fn outputs(&self) -> Vec<RenderPassOutput> {
|
||||
vec![ RenderPassOutput::new("color",texture::Rgba,texture::item_type::u8)
|
||||
, RenderPassOutput::new("id",texture::Rgba32ui,texture::item_type::u32)
|
||||
let color_parameters = texture::Parameters::default();
|
||||
let id_parameters = texture::Parameters {
|
||||
min_filter : texture::MinFilter::Nearest,
|
||||
mag_filter : texture::MagFilter::Nearest,
|
||||
..default()
|
||||
};
|
||||
vec![ RenderPassOutput::new("color",texture::Rgba,texture::item_type::u8,color_parameters)
|
||||
, RenderPassOutput::new("id",texture::Rgba,texture::item_type::u8,id_parameters)
|
||||
]
|
||||
}
|
||||
|
||||
fn run(&mut self, context:&Context, _:&UniformScope) {
|
||||
let arr = vec![0.0,0.0,0.0,0.0];
|
||||
let arr2 = vec![0,0,0,0];
|
||||
context.clear_bufferfv_with_f32_array(Context::COLOR,0,&arr);
|
||||
context.clear_bufferuiv_with_u32_array(Context::COLOR,1,&arr2);
|
||||
context.clear_bufferfv_with_f32_array(Context::COLOR,1,&arr);
|
||||
self.target.set_camera(&self.views.main.camera);
|
||||
self.target.render_by_ids(&self.views.main.symbols());
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
use crate::system::gpu::types::*;
|
||||
use crate::system::gpu::texture::*;
|
||||
use crate::system::gpu::texture;
|
||||
|
||||
|
||||
|
||||
@ -53,19 +53,21 @@ pub struct RenderPassOutput {
|
||||
/// Name of the pass.
|
||||
pub name : String,
|
||||
/// Internal texture format of the pass framebuffer's attachment.
|
||||
pub internal_format : AnyInternalFormat,
|
||||
pub internal_format : texture::AnyInternalFormat,
|
||||
/// Item texture type of the pass framebuffer's attachment.
|
||||
pub item_type : AnyItemType,
|
||||
pub item_type : texture::AnyItemType,
|
||||
/// Texture parameters that will be set when binding the texture.
|
||||
pub texture_parameters : texture::Parameters,
|
||||
}
|
||||
|
||||
impl RenderPassOutput {
|
||||
/// Constructor.
|
||||
pub fn new<Name:Str,F:Into<AnyInternalFormat>,T:Into<AnyItemType>>
|
||||
(name:Name, internal_format:F, item_type:T) -> Self {
|
||||
pub fn new<Name:Str,F:Into<texture::AnyInternalFormat>,T:Into<texture::AnyItemType>>
|
||||
(name:Name, internal_format:F, item_type:T, texture_parameters:texture::Parameters) -> Self {
|
||||
let name = name.into();
|
||||
let internal_format = internal_format.into();
|
||||
let item_type = item_type.into();
|
||||
Self {name,internal_format,item_type}
|
||||
Self {name,internal_format,item_type,texture_parameters}
|
||||
}
|
||||
|
||||
/// Getter.
|
||||
|
@ -109,6 +109,15 @@ impl {
|
||||
// === Target ===
|
||||
// ==============
|
||||
|
||||
/// Result of a Decoding operation in the Target.
|
||||
#[derive(Debug,Clone,Copy,Eq,PartialEq)]
|
||||
enum DecodingResult{
|
||||
/// Values had to be truncated.
|
||||
Truncated(u8,u8,u8),
|
||||
/// Values have been encoded successfully.
|
||||
Ok(u8,u8,u8)
|
||||
}
|
||||
|
||||
/// Mouse target. Contains a path to an object pointed by mouse.
|
||||
#[derive(Debug,Clone,Copy,Eq,PartialEq)]
|
||||
pub enum Target {
|
||||
@ -120,23 +129,82 @@ pub enum Target {
|
||||
}
|
||||
|
||||
impl Target {
|
||||
fn to_internal(&self) -> Vector4<u32> {
|
||||
|
||||
/// Encode two u32 values into three u8 values.
|
||||
///
|
||||
/// This is the same encoding that is used in the `fragment_runner`. This encoding is lossy and
|
||||
/// can only encode values up to 12^2=4096 each
|
||||
///
|
||||
/// We use 12 bits from each value and pack them into the 3 output bytes like described in the
|
||||
/// following diagram.
|
||||
///
|
||||
/// ```text
|
||||
/// Input
|
||||
///
|
||||
/// value1 (v1) as bytes value2 (v2) as bytes
|
||||
/// +-----+-----+-----+-----+ +-----+-----+-----+-----+
|
||||
/// | | | | | | | | | |
|
||||
/// +-----+-----+-----+-----+ +-----+-----+-----+-----+
|
||||
/// 32 24 16 8 0 32 24 16 8 0 <- Bit index
|
||||
///
|
||||
///
|
||||
/// Output
|
||||
///
|
||||
/// byte1 byte2 byte3
|
||||
/// +-----------+ +----------------------+ +------------+
|
||||
/// | v ]12..4] | | v1 ]4..0] v2 ]4..0] | | v2 ]12..4] |
|
||||
/// +-----------+ +----------------------+ +------------+
|
||||
///
|
||||
/// Ranges use mathematical notation for inclusion/exclusion.
|
||||
/// ```
|
||||
fn encode(value1:u32, value2:u32) -> DecodingResult {
|
||||
let chunk1 = (value1 >> 4u32) & 0x00FFu32;
|
||||
let chunk2 = (value1 & 0x000Fu32) << 4u32;
|
||||
let chunk2 = chunk2 | ((value2 & 0x0F00u32) >> 8u32);
|
||||
let chunk3 = value2 & 0x00FFu32;
|
||||
|
||||
if value1 > 2u32.pow(12) ||value2 > 2u32.pow(12) {
|
||||
DecodingResult::Truncated(chunk1 as u8, chunk2 as u8, chunk3 as u8)
|
||||
}else{
|
||||
DecodingResult::Ok(chunk1 as u8, chunk2 as u8, chunk3 as u8)
|
||||
}
|
||||
}
|
||||
|
||||
/// Decode the symbol_id and instance_id that was encoded in the `fragment_runner`.
|
||||
///
|
||||
/// See the `encode` method for more information on the encoding.
|
||||
fn decode(chunk1:u32, chunk2:u32, chunk3:u32) -> (u32, u32) {
|
||||
let value1 = (chunk1 << 4) + (chunk2 >> 4);
|
||||
let value2 = chunk3 + ((chunk2 & 0x000F) << 8);
|
||||
(value1, value2)
|
||||
}
|
||||
|
||||
fn to_internal(&self, logger:&Logger) -> Vector4<u32> {
|
||||
match self {
|
||||
Self::Background => Vector4::new(0,0,0,0),
|
||||
Self::Symbol {symbol_id,instance_id} => Vector4::new(*symbol_id,*instance_id,0,1),
|
||||
Self::Symbol {symbol_id,instance_id} => {
|
||||
match Self::encode(*symbol_id,*instance_id) {
|
||||
DecodingResult::Truncated(pack0,pack1,pack2) => {
|
||||
warning!(logger,"Target values too big to encode: \
|
||||
({symbol_id},{instance_id}).");
|
||||
Vector4::new(pack0.into(),pack1.into(),pack2.into(),1)
|
||||
},
|
||||
DecodingResult::Ok(pack0,pack1,pack2) => {
|
||||
Vector4::new(pack0.into(),pack1.into(),pack2.into(),1)
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn from_internal(v:Vector4<u32>) -> Self {
|
||||
if v.z != 0 {
|
||||
panic!("Wrong internal format for mouse target.")
|
||||
}
|
||||
if v.w == 0 {
|
||||
Self::Background
|
||||
}
|
||||
else if v.w == 1 {
|
||||
let symbol_id = v.x;
|
||||
let instance_id = v.y;
|
||||
else if v.w == 255 {
|
||||
let decoded = Self::decode(v.x,v.y,v.z);
|
||||
let symbol_id = decoded.0;
|
||||
let instance_id = decoded.1;
|
||||
Self::Symbol {symbol_id,instance_id}
|
||||
} else {
|
||||
panic!("Wrong internal format alpha for mouse target.")
|
||||
@ -151,6 +219,58 @@ impl Default for Target {
|
||||
}
|
||||
|
||||
|
||||
// === Target Tests ===
|
||||
|
||||
#[cfg(test)]
|
||||
mod target_tests {
|
||||
use super::*;
|
||||
|
||||
/// Asserts that decoding encoded the given values returns the correct initial values again.
|
||||
/// That means that `decode(encode(value1,value2)) == (value1,value2)`.
|
||||
fn assert_valid_roundtrip(value1:u32, value2:u32) {
|
||||
let pack = Target::encode(value1,value2);
|
||||
match pack {
|
||||
DecodingResult::Truncated {..} => {
|
||||
panic!("Values got truncated. This is an invalid test case: {}, {}", value1, value1)
|
||||
},
|
||||
DecodingResult::Ok(pack0,pack1,pack2) => {
|
||||
let unpack = Target::decode(pack0.into(),pack1.into(),pack2.into());
|
||||
assert_eq!(unpack.0,value1);
|
||||
assert_eq!(unpack.1,value2);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_roundtrip_coding() {
|
||||
assert_valid_roundtrip( 0, 0);
|
||||
assert_valid_roundtrip( 0, 5);
|
||||
assert_valid_roundtrip( 512, 0);
|
||||
assert_valid_roundtrip(1024, 64);
|
||||
assert_valid_roundtrip(1024, 999);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encoding() {
|
||||
let pack = Target::encode(0,0);
|
||||
assert_eq!(pack,DecodingResult::Ok(0,0,0));
|
||||
|
||||
let pack = Target::encode(3,7);
|
||||
assert_eq!(pack,DecodingResult::Ok(0,48,7));
|
||||
|
||||
let pack = Target::encode(3,256);
|
||||
assert_eq!(pack,DecodingResult::Ok(0,49,0));
|
||||
|
||||
let pack = Target::encode(255,356);
|
||||
assert_eq!(pack,DecodingResult::Ok(15,241,100));
|
||||
|
||||
let pack = Target::encode(256,356);
|
||||
assert_eq!(pack,DecodingResult::Ok(16,1,100));
|
||||
|
||||
let pack = Target::encode(31256,0);
|
||||
assert_eq!(pack,DecodingResult::Truncated(161,128,0));
|
||||
}
|
||||
}
|
||||
|
||||
// =============
|
||||
// === Mouse ===
|
||||
@ -176,14 +296,15 @@ pub struct Mouse {
|
||||
pub target : Rc<Cell<Target>>,
|
||||
pub handles : Rc<Vec<callback::Handle>>,
|
||||
pub frp : enso_frp::io::Mouse,
|
||||
pub logger : Logger
|
||||
}
|
||||
|
||||
impl Mouse {
|
||||
pub fn new(shape:&web::dom::Shape, variables:&UniformScope) -> Self {
|
||||
pub fn new(shape:&web::dom::Shape, variables:&UniformScope, logger:Logger) -> Self {
|
||||
|
||||
let target = Target::default();
|
||||
let position = variables.add_or_panic("mouse_position",Vector2::new(0,0));
|
||||
let hover_ids = variables.add_or_panic("mouse_hover_ids",target.to_internal());
|
||||
let hover_ids = variables.add_or_panic("mouse_hover_ids",target.to_internal(&logger));
|
||||
let button0_pressed = variables.add_or_panic("mouse_button0_pressed",false);
|
||||
let button1_pressed = variables.add_or_panic("mouse_button1_pressed",false);
|
||||
let button2_pressed = variables.add_or_panic("mouse_button2_pressed",false);
|
||||
@ -255,7 +376,7 @@ impl Mouse {
|
||||
}).forget();
|
||||
|
||||
Self {mouse_manager,position,hover_ids,button0_pressed,button1_pressed,button2_pressed
|
||||
,button3_pressed,button4_pressed,target,handles,frp}
|
||||
,button3_pressed,button4_pressed,target,handles,frp,logger}
|
||||
}
|
||||
}
|
||||
|
||||
@ -619,7 +740,8 @@ impl SceneData {
|
||||
let symbols_dirty = dirty_flag;
|
||||
let views = Views::mk(&logger,width,height);
|
||||
let stats = stats.clone();
|
||||
let mouse = Mouse::new(&dom.shape(),&variables);
|
||||
let mouse_logger = logger.sub("mouse");
|
||||
let mouse = Mouse::new(&dom.shape(),&variables,mouse_logger);
|
||||
let shapes = ShapeRegistry::default();
|
||||
let uniforms = Uniforms::new(&variables);
|
||||
let dirty = Dirty {symbols:symbols_dirty,shape:shape_dirty};
|
||||
|
@ -4,13 +4,28 @@ Env env = Env(1);
|
||||
vec2 position = input_local.xy ;
|
||||
Shape shape = run(env,position);
|
||||
float alpha = shape.color.color.raw.a;
|
||||
uint alpha_no_aa = alpha > 0.5 ? uint(1) : uint(0);
|
||||
|
||||
output_id = uvec4(input_symbol_id,input_instance_id,0,alpha_no_aa);
|
||||
|
||||
|
||||
// ===========================
|
||||
// === Object ID Rendering ===
|
||||
// ===========================
|
||||
|
||||
uvec3 chunks = encode(input_symbol_id,input_instance_id);
|
||||
|
||||
float alpha_no_aa = alpha > 0.5 ? 1.0 : 0.0;
|
||||
|
||||
output_id = vec4(as_float_u8(chunks.x),as_float_u8(chunks.y),as_float_u8(chunks.z),alpha_no_aa);
|
||||
output_id.r *= alpha_no_aa;
|
||||
output_id.g *= alpha_no_aa;
|
||||
output_id.b *= alpha_no_aa;
|
||||
|
||||
|
||||
|
||||
// =======================
|
||||
// === Color Rendering ===
|
||||
// =======================
|
||||
|
||||
if (input_display_mode == 0) {
|
||||
output_color = srgba(unpremultiply(shape.color)).raw;
|
||||
output_color.rgb *= alpha;
|
||||
|
@ -178,3 +178,22 @@ float mul(float a, float b) {
|
||||
float neg(float a) {
|
||||
return -a;
|
||||
}
|
||||
|
||||
|
||||
// === Encode ===
|
||||
|
||||
// This encoding must correspond to the decoding in the `Target` struct in
|
||||
// src\rust\ensogl\src\display\scene.rs See there for more explanation.
|
||||
uvec3 encode(int value1, int value2) {
|
||||
uint chunk1 = (uint(value1) >> 4u) & 0x00FFu;
|
||||
uint chunk2 = (uint(value1) & 0x000Fu) << 4u;
|
||||
chunk2 = chunk2 + ((uint(value2) & 0x0F00u) >> 8u);
|
||||
uint chunk3 = uint(value2) & 0x00FFu;
|
||||
return uvec3(chunk1,chunk2,chunk3);
|
||||
}
|
||||
|
||||
// Encodes a uint values so it can be stored in a u8 encoded float. Will clamp values that are
|
||||
// out of range.
|
||||
float as_float_u8(uint value) {
|
||||
return clamp(float(value) / 255.0);
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ impl ShapeSystem {
|
||||
material.add_input ("time" , 0.0);
|
||||
material.add_input ("symbol_id" , 0);
|
||||
material.add_input ("display_mode" , 0);
|
||||
material.add_output ("id" , Vector4::<u32>::new(0,0,0,0));
|
||||
material.add_output ("id" , Vector4::<f32>::zero());
|
||||
material
|
||||
}
|
||||
|
||||
|
@ -258,7 +258,7 @@ impl GlyphSystem {
|
||||
// FIXME outputs as the number of attachments to framebuffer. We should manage this more
|
||||
// FIXME intelligent. For example, we could allow defining output shader fragments,
|
||||
// FIXME which will be enabled only if pass of given attachment type was enabled.
|
||||
material.add_output("id", Vector4::<u32>::new(0,0,0,0));
|
||||
material.add_output("id", Vector4::<f32>::new(0.0,0.0,0.0,0.0));
|
||||
|
||||
let code = CodeTemplate::new(BEFORE_MAIN.to_string(),MAIN.to_string(),"".to_string());
|
||||
material.set_code(code);
|
||||
|
@ -348,6 +348,18 @@ impl Symbol {
|
||||
let count = self.surface.point_scope().size() as i32;
|
||||
let instance_count = self.surface.instance_scope().size() as i32;
|
||||
|
||||
// Check if we are ready to render. If we don't assert here we wil only get a warning
|
||||
// that won't tell us where things went wrong.
|
||||
{
|
||||
let framebuffer_status = context.check_framebuffer_status(Context::FRAMEBUFFER);
|
||||
debug_assert_eq!(
|
||||
framebuffer_status,
|
||||
Context::FRAMEBUFFER_COMPLETE,
|
||||
"Framebuffer incomplete (status: {}).",
|
||||
framebuffer_status
|
||||
)
|
||||
}
|
||||
|
||||
self.stats.inc_draw_call_count();
|
||||
if instance_count > 0 {
|
||||
self.context.draw_arrays_instanced(mode,first,count,instance_count);
|
||||
|
@ -314,7 +314,7 @@ impl SpriteSystem {
|
||||
// FIXME outputs as the number of attachments to framebuffer. We should manage this more
|
||||
// FIXME intelligent. For example, we could allow defining output shader fragments,
|
||||
// FIXME which will be enabled only if pass of given attachment type was enabled.
|
||||
material.add_output ("id", Vector4::<u32>::new(0,0,0,0));
|
||||
material.add_output ("id", Vector4::<f32>::new(0.0,0.0,0.0,0.0));
|
||||
material.set_main("output_color = vec4(0.0,0.0,0.0,1.0); output_id=uvec4(0,0,0,0);");
|
||||
material
|
||||
}
|
||||
|
@ -142,9 +142,9 @@ impl World {
|
||||
|
||||
fn init_composer(&self) {
|
||||
let mouse_hover_ids = self.scene.mouse.hover_ids.clone_ref();
|
||||
let mut pixel_read_pass = PixelReadPass::<u32>::new(&self.scene.mouse.position);
|
||||
let mut pixel_read_pass = PixelReadPass::<u8>::new(&self.scene.mouse.position);
|
||||
pixel_read_pass.set_callback(move |v| {
|
||||
mouse_hover_ids.set(Vector4::from_iterator(v))
|
||||
mouse_hover_ids.set(Vector4::from_iterator(v.iter().map(|value| *value as u32)))
|
||||
});
|
||||
// TODO: We may want to enable it on weak hardware.
|
||||
// pixel_read_pass.set_threshold(1);
|
||||
|
@ -45,6 +45,106 @@ impl Drop for TextureBindGuard {
|
||||
|
||||
|
||||
|
||||
// ==================
|
||||
// === Parameters ===
|
||||
// ==================
|
||||
|
||||
/// Helper struct to specify texture parameters that need to be set when binding a texture.
|
||||
///
|
||||
/// The essential parameters that need to be set are about how the texture will be samples, i.e.,
|
||||
/// how the values of the texture are interpolated at various resolutions, and how out of bounds
|
||||
/// samples are handled.
|
||||
///
|
||||
/// For more background see: https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/texParameter
|
||||
///
|
||||
#[derive(Copy,Clone,Debug,Default)]
|
||||
pub struct Parameters {
|
||||
/// Specifies the setting for the texture magnification filter (`Context::TEXTURE_MIN_FILTER`).
|
||||
pub min_filter : MinFilter,
|
||||
/// Specifies the setting for the texture minification filter (`Context::TEXTURE_MAG_FILTER`).
|
||||
pub mag_filter : MagFilter,
|
||||
/// Specifies the setting for the wrapping function for texture coordinate s
|
||||
/// (`Context::TEXTURE_WRAP_S`).
|
||||
pub wrap_s : Wrap,
|
||||
/// Specifies the setting for the wrapping function for texture coordinate t
|
||||
/// (`Context::TEXTURE_WRAP_T`).
|
||||
pub wrap_t : Wrap,
|
||||
}
|
||||
|
||||
impl Parameters {
|
||||
/// Applies the context parameters in the given context.
|
||||
pub fn apply_parameters(self, context:&Context) {
|
||||
let target = Context::TEXTURE_2D;
|
||||
context.tex_parameteri(target,Context::TEXTURE_MIN_FILTER,self.min_filter as i32);
|
||||
context.tex_parameteri(target,Context::TEXTURE_MIN_FILTER,self.mag_filter as i32);
|
||||
context.tex_parameteri(target,Context::TEXTURE_WRAP_S,self.wrap_s as i32);
|
||||
context.tex_parameteri(target,Context::TEXTURE_WRAP_T,self.wrap_t as i32);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// === Parameter Types ===
|
||||
|
||||
/// Valid Parameters for the `gl.TEXTURE_MAG_FILTER` texture setting.
|
||||
///
|
||||
/// Specifies how values are interpolated if the texture is rendered at a resolution that is
|
||||
/// lower than its native resolution.
|
||||
#[derive(Copy,Clone,Debug)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum MagFilter {
|
||||
Linear = Context::LINEAR as isize,
|
||||
Nearest = Context::NEAREST as isize,
|
||||
}
|
||||
|
||||
// Note: The parameters implement our own default, not the WebGL one.
|
||||
impl Default for MagFilter {
|
||||
fn default() -> Self {
|
||||
Self::Linear
|
||||
}
|
||||
}
|
||||
|
||||
/// Valid Parameters for the `gl.TEXTURE_MIN_FILTER` texture setting.
|
||||
///
|
||||
/// Specifies how values are interpolated if the texture is rendered at a resolution that is
|
||||
/// lower than its native resolution.
|
||||
#[derive(Copy,Clone,Debug)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum MinFilter {
|
||||
Linear = Context::LINEAR as isize,
|
||||
Nearest = Context::NEAREST as isize,
|
||||
NearestMipmapNearest = Context::NEAREST_MIPMAP_NEAREST as isize,
|
||||
LinearMipmapNearest = Context::LINEAR_MIPMAP_NEAREST as isize,
|
||||
NearestMipmapLinear = Context::NEAREST_MIPMAP_LINEAR as isize,
|
||||
LinearMipmapLinear = Context::LINEAR_MIPMAP_LINEAR as isize,
|
||||
}
|
||||
|
||||
// Note: The parameters implement our own default, not the WebGL one.
|
||||
impl Default for MinFilter {
|
||||
fn default() -> Self {
|
||||
Self::Linear
|
||||
}
|
||||
}
|
||||
|
||||
/// Valid Parameters for the `gl.TEXTURE_WRAP_S` and `gl.TEXTURE_WRAP_T` texture setting.
|
||||
///
|
||||
/// Specifies what happens if a texture is sampled out of bounds.
|
||||
#[derive(Copy,Clone,Debug)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum Wrap {
|
||||
Repeat = Context::REPEAT as isize,
|
||||
ClampToEdge = Context::CLAMP_TO_EDGE as isize,
|
||||
MirroredRepeat = Context::MIRRORED_REPEAT as isize,
|
||||
}
|
||||
|
||||
// Note: The parameters implement our own default, not the WebGL one.
|
||||
impl Default for Wrap {
|
||||
fn default() -> Self {
|
||||
Self::ClampToEdge
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ===============
|
||||
// === Texture ===
|
||||
// ===============
|
||||
@ -58,6 +158,7 @@ where Storage: StorageRelation<InternalFormat,ItemType> {
|
||||
storage : StorageOf<Storage,InternalFormat,ItemType>,
|
||||
gl_texture : WebGlTexture,
|
||||
context : Context,
|
||||
parameters : Parameters
|
||||
}
|
||||
|
||||
|
||||
@ -125,6 +226,23 @@ where S:StorageRelation<I,T> {
|
||||
pub fn storage(&self) -> &StorageOf<S,I,T> {
|
||||
&self.storage
|
||||
}
|
||||
|
||||
/// Getter.
|
||||
pub fn parameters(&self) -> &Parameters {
|
||||
&self.parameters
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// === Setters ===
|
||||
|
||||
impl<S,I,T> Texture<S,I,T>
|
||||
where S:StorageRelation<I,T> {
|
||||
|
||||
/// Setter.
|
||||
pub fn set_parameters(&mut self, parameters: Parameters) {
|
||||
self.parameters = parameters;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -161,16 +279,13 @@ where S:StorageRelation<I,T> {
|
||||
let storage = storage.into();
|
||||
let context = context.clone();
|
||||
let gl_texture = context.create_texture().unwrap();
|
||||
Self {storage,gl_texture,context}
|
||||
let parameters = default();
|
||||
Self {storage,gl_texture,context,parameters}
|
||||
}
|
||||
|
||||
/// Sets the texture wrapping parameters.
|
||||
pub fn set_texture_parameters(context:&Context) {
|
||||
let target = Context::TEXTURE_2D;
|
||||
let wrap = Context::CLAMP_TO_EDGE as i32;
|
||||
context.tex_parameteri(target,Context::TEXTURE_MIN_FILTER,Context::LINEAR as i32);
|
||||
context.tex_parameteri(target,Context::TEXTURE_WRAP_S,wrap);
|
||||
context.tex_parameteri(target,Context::TEXTURE_WRAP_T,wrap);
|
||||
/// Applies this textures' parameters in the given context.
|
||||
pub fn apply_texture_parameters(&self, context:&Context) {
|
||||
self.parameters.apply_parameters(context);
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,7 +314,7 @@ where S : StorageRelation<I,T>,
|
||||
result.unwrap();
|
||||
}
|
||||
|
||||
Self::set_texture_parameters(&self.context);
|
||||
self.apply_texture_parameters(&self.context);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ TextureReload for Texture<GpuOnly,I,T> {
|
||||
self.context().tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_opt_u8_array
|
||||
(target,level,internal_format,width,height,border,format,elem_type,None).unwrap();
|
||||
|
||||
Self::set_texture_parameters(self.context());
|
||||
self.apply_texture_parameters(self.context());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,6 +82,7 @@ TextureReload for Texture<RemoteImage,I,T> {
|
||||
let image_ref_opt = image_ref.clone();
|
||||
let context = self.context().clone();
|
||||
let gl_texture = self.gl_texture().clone();
|
||||
let parameters = *self.parameters();
|
||||
let callback: Closure<dyn FnMut()> = Closure::once(move || {
|
||||
let _keep_alive = callback_ref2;
|
||||
let image = image_ref_opt.borrow();
|
||||
@ -94,7 +95,7 @@ TextureReload for Texture<RemoteImage,I,T> {
|
||||
context.tex_image_2d_with_u32_and_u32_and_html_image_element
|
||||
(target,level,internal_format,format,elem_type,&image).unwrap();
|
||||
|
||||
Self::set_texture_parameters(&context);
|
||||
parameters.apply_parameters(&context);
|
||||
});
|
||||
let js_callback = callback.as_ref().unchecked_ref();
|
||||
let image = image_ref.borrow();
|
||||
|
@ -25,6 +25,11 @@
|
||||
/// currently stored pixel. Blending applies only in RGBA mode and only if the color buffer has a
|
||||
/// fixed-point or floating-point format; in color index mode or if the color buffer has an
|
||||
/// integer format, it is bypassed.
|
||||
///
|
||||
/// The features of some texture formats can be modified through extensions. For example, the
|
||||
/// the extension `EXT_color_buffer_float` can make the group of float texture (e.g., `Rgba32f`)
|
||||
/// color renderable.
|
||||
///
|
||||
#[macro_export]
|
||||
macro_rules! with_texture_format_relations { ($f:ident $args:tt) => { $crate::$f! { $args
|
||||
// INTERNAL_FORMAT FORMAT SAMPLER COL FILT BLEND [POSSIBLE_TYPE:BYTES_PER_TEXTURE_ELEM]
|
||||
|
@ -334,12 +334,16 @@ macro_rules! define_get_or_add_gpu_texture_dyn {
|
||||
, internal_format : AnyInternalFormat
|
||||
, item_type : AnyItemType
|
||||
, provider : P
|
||||
, parameters : Option<Parameters>
|
||||
) -> AnyTextureUniform {
|
||||
let provider = provider.into();
|
||||
match (internal_format,item_type) {
|
||||
$((AnyInternalFormat::$internal_format, AnyItemType::$item_type) => {
|
||||
let texture = Texture::<GpuOnly,$internal_format,$item_type>
|
||||
let mut texture = Texture::<GpuOnly,$internal_format,$item_type>
|
||||
::new(&context,provider);
|
||||
if let Some(parameters) = parameters {
|
||||
texture.set_parameters(parameters);
|
||||
}
|
||||
let uniform = scope.get_or_add(name,texture).unwrap();
|
||||
uniform.into()
|
||||
})*
|
||||
|
@ -204,7 +204,8 @@ pub fn get_webgl2_context(canvas:&HtmlCanvasElement) -> WebGl2RenderingContext {
|
||||
let options = js_sys::Object::new();
|
||||
js_sys::Reflect::set(&options, &"antialias".into(), &false.into()).unwrap();
|
||||
let context = canvas.get_context_with_context_options("webgl2",&options).unwrap().unwrap();
|
||||
context.dyn_into().unwrap()
|
||||
let context : WebGl2RenderingContext = context.dyn_into().unwrap();
|
||||
context
|
||||
}
|
||||
|
||||
pub fn try_request_animation_frame(f:&Closure<dyn FnMut(f64)>) -> Result<i32> {
|
||||
|
Loading…
Reference in New Issue
Block a user