pathfinder: data binding
This commit is contained in:
parent
0dd55f2c40
commit
4eb562975f
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@ -33,11 +33,11 @@
|
|||||||
"cargo": {
|
"cargo": {
|
||||||
"args": [
|
"args": [
|
||||||
"build",
|
"build",
|
||||||
"--example=scene",
|
"--example=pathfinder",
|
||||||
"--package=bevy"
|
"--package=bevy"
|
||||||
],
|
],
|
||||||
"filter": {
|
"filter": {
|
||||||
"name": "scene",
|
"name": "pathfinder",
|
||||||
"kind": "example"
|
"kind": "example"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -2,18 +2,21 @@ use bevy_asset::{AssetStorage, Handle};
|
|||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
pass::{
|
pass::{
|
||||||
LoadOp, PassDescriptor, RenderPassColorAttachmentDescriptor,
|
LoadOp, PassDescriptor, RenderPassColorAttachmentDescriptor,
|
||||||
RenderPassDepthStencilAttachmentDescriptor, StoreOp, TextureAttachment,
|
RenderPassDepthStencilAttachmentDescriptor, StoreOp, TextureAttachment, RenderPass,
|
||||||
},
|
},
|
||||||
pipeline::{
|
pipeline::{
|
||||||
state_descriptors::{
|
state_descriptors::{
|
||||||
BlendDescriptor, BlendFactor, BlendOperation, ColorStateDescriptor, ColorWrite,
|
BlendDescriptor, BlendFactor, BlendOperation, ColorStateDescriptor, ColorWrite,
|
||||||
CompareFunction, DepthStencilStateDescriptor, StencilOperation,
|
CompareFunction, DepthStencilStateDescriptor, StencilOperation,
|
||||||
StencilStateFaceDescriptor,
|
StencilStateFaceDescriptor, RasterizationStateDescriptor, PrimitiveTopology,
|
||||||
},
|
},
|
||||||
InputStepMode, PipelineDescriptor, VertexAttributeDescriptor, VertexBufferDescriptor,
|
InputStepMode, PipelineDescriptor, VertexAttributeDescriptor, VertexBufferDescriptor,
|
||||||
VertexFormat,
|
VertexFormat,
|
||||||
},
|
},
|
||||||
render_resource::{BufferInfo, BufferUsage, RenderResource, RenderResourceAssignments},
|
render_resource::{
|
||||||
|
BufferInfo, BufferUsage, RenderResource, RenderResourceAssignment,
|
||||||
|
RenderResourceAssignments,
|
||||||
|
},
|
||||||
renderer::RenderContext,
|
renderer::RenderContext,
|
||||||
shader::{Shader, ShaderSource, ShaderStage, ShaderStages},
|
shader::{Shader, ShaderSource, ShaderStage, ShaderStages},
|
||||||
texture::{
|
texture::{
|
||||||
@ -31,7 +34,9 @@ use pathfinder_gpu::{
|
|||||||
VertexAttrClass, VertexAttrDescriptor, VertexAttrType,
|
VertexAttrClass, VertexAttrDescriptor, VertexAttrType,
|
||||||
};
|
};
|
||||||
use pathfinder_resources::ResourceLoader;
|
use pathfinder_resources::ResourceLoader;
|
||||||
use std::{borrow::Cow, cell::RefCell, collections::HashMap, mem, rc::Rc, time::Duration, ops::Range};
|
use std::{
|
||||||
|
borrow::Cow, cell::RefCell, collections::HashMap, mem, rc::Rc, time::Duration,
|
||||||
|
};
|
||||||
use zerocopy::AsBytes;
|
use zerocopy::AsBytes;
|
||||||
|
|
||||||
pub struct BevyPathfinderDevice<'a> {
|
pub struct BevyPathfinderDevice<'a> {
|
||||||
@ -40,6 +45,7 @@ pub struct BevyPathfinderDevice<'a> {
|
|||||||
samplers: RefCell<HashMap<u8, RenderResource>>,
|
samplers: RefCell<HashMap<u8, RenderResource>>,
|
||||||
main_color_texture: RenderResource,
|
main_color_texture: RenderResource,
|
||||||
main_depth_stencil_texture: RenderResource,
|
main_depth_stencil_texture: RenderResource,
|
||||||
|
default_sampler: RenderResource,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> BevyPathfinderDevice<'a> {
|
impl<'a> BevyPathfinderDevice<'a> {
|
||||||
@ -49,21 +55,182 @@ impl<'a> BevyPathfinderDevice<'a> {
|
|||||||
main_color_texture: RenderResource,
|
main_color_texture: RenderResource,
|
||||||
main_depth_stencil_texture: RenderResource,
|
main_depth_stencil_texture: RenderResource,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
let default_sampler = render_context.resources().create_sampler(&SamplerDescriptor::default());
|
||||||
BevyPathfinderDevice {
|
BevyPathfinderDevice {
|
||||||
render_context: RefCell::new(render_context),
|
render_context: RefCell::new(render_context),
|
||||||
shaders: RefCell::new(shaders),
|
shaders: RefCell::new(shaders),
|
||||||
samplers: RefCell::new(HashMap::new()),
|
samplers: RefCell::new(HashMap::new()),
|
||||||
main_color_texture,
|
main_color_texture,
|
||||||
main_depth_stencil_texture,
|
main_depth_stencil_texture,
|
||||||
|
default_sampler,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prepare_to_draw(&self, render_state: &RenderState<BevyPathfinderDevice>) {
|
pub fn setup_uniforms(
|
||||||
let pass_descriptor = self.create_pass_descriptor(render_state);
|
&self,
|
||||||
self.setup_pipline_descriptor(render_state, &pass_descriptor, &render_state.vertex_array.requested_descriptors.borrow());
|
render_state: &RenderState<BevyPathfinderDevice>,
|
||||||
// TODO: setup uniforms
|
render_resource_assignments: &mut RenderResourceAssignments,
|
||||||
let mut render_context = self.render_context.borrow_mut();
|
) {
|
||||||
let mut render_resource_assignments = RenderResourceAssignments::default();
|
let mut uniform_buffer_data = Vec::new();
|
||||||
|
let mut uniform_buffer_ranges = Vec::new();
|
||||||
|
for (bevy_uniform, uniform_data) in render_state.uniforms.iter() {
|
||||||
|
let start_index = uniform_buffer_data.len();
|
||||||
|
match *uniform_data {
|
||||||
|
UniformData::Float(value) => uniform_buffer_data
|
||||||
|
.write_f32::<NativeEndian>(value)
|
||||||
|
.unwrap(),
|
||||||
|
UniformData::IVec2(vector) => {
|
||||||
|
uniform_buffer_data
|
||||||
|
.write_i32::<NativeEndian>(vector.x())
|
||||||
|
.unwrap();
|
||||||
|
uniform_buffer_data
|
||||||
|
.write_i32::<NativeEndian>(vector.y())
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
UniformData::IVec3(values) => {
|
||||||
|
uniform_buffer_data
|
||||||
|
.write_i32::<NativeEndian>(values[0])
|
||||||
|
.unwrap();
|
||||||
|
uniform_buffer_data
|
||||||
|
.write_i32::<NativeEndian>(values[1])
|
||||||
|
.unwrap();
|
||||||
|
uniform_buffer_data
|
||||||
|
.write_i32::<NativeEndian>(values[2])
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
UniformData::Int(value) => uniform_buffer_data
|
||||||
|
.write_i32::<NativeEndian>(value)
|
||||||
|
.unwrap(),
|
||||||
|
UniformData::Mat2(matrix) => {
|
||||||
|
uniform_buffer_data
|
||||||
|
.write_f32::<NativeEndian>(matrix.x())
|
||||||
|
.unwrap();
|
||||||
|
uniform_buffer_data
|
||||||
|
.write_f32::<NativeEndian>(matrix.y())
|
||||||
|
.unwrap();
|
||||||
|
uniform_buffer_data
|
||||||
|
.write_f32::<NativeEndian>(matrix.z())
|
||||||
|
.unwrap();
|
||||||
|
uniform_buffer_data
|
||||||
|
.write_f32::<NativeEndian>(matrix.w())
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
UniformData::Mat4(matrix) => {
|
||||||
|
for column in &matrix {
|
||||||
|
uniform_buffer_data
|
||||||
|
.write_f32::<NativeEndian>(column.x())
|
||||||
|
.unwrap();
|
||||||
|
uniform_buffer_data
|
||||||
|
.write_f32::<NativeEndian>(column.y())
|
||||||
|
.unwrap();
|
||||||
|
uniform_buffer_data
|
||||||
|
.write_f32::<NativeEndian>(column.z())
|
||||||
|
.unwrap();
|
||||||
|
uniform_buffer_data
|
||||||
|
.write_f32::<NativeEndian>(column.w())
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UniformData::Vec2(vector) => {
|
||||||
|
uniform_buffer_data
|
||||||
|
.write_f32::<NativeEndian>(vector.x())
|
||||||
|
.unwrap();
|
||||||
|
uniform_buffer_data
|
||||||
|
.write_f32::<NativeEndian>(vector.y())
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
UniformData::Vec3(array) => {
|
||||||
|
uniform_buffer_data
|
||||||
|
.write_f32::<NativeEndian>(array[0])
|
||||||
|
.unwrap();
|
||||||
|
uniform_buffer_data
|
||||||
|
.write_f32::<NativeEndian>(array[1])
|
||||||
|
.unwrap();
|
||||||
|
uniform_buffer_data
|
||||||
|
.write_f32::<NativeEndian>(array[2])
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
UniformData::Vec4(vector) => {
|
||||||
|
uniform_buffer_data
|
||||||
|
.write_f32::<NativeEndian>(vector.x())
|
||||||
|
.unwrap();
|
||||||
|
uniform_buffer_data
|
||||||
|
.write_f32::<NativeEndian>(vector.y())
|
||||||
|
.unwrap();
|
||||||
|
uniform_buffer_data
|
||||||
|
.write_f32::<NativeEndian>(vector.z())
|
||||||
|
.unwrap();
|
||||||
|
uniform_buffer_data
|
||||||
|
.write_f32::<NativeEndian>(vector.w())
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
UniformData::TextureUnit(index) => {
|
||||||
|
let texture = &render_state.textures[index as usize];
|
||||||
|
render_resource_assignments.set(
|
||||||
|
&bevy_uniform.name,
|
||||||
|
RenderResourceAssignment::Texture(texture.handle),
|
||||||
|
);
|
||||||
|
let sampler_resource = if let Some(sampler_resource) = *texture.sampler_resource.borrow() {
|
||||||
|
// NOTE: this assumes theres is only one sampler
|
||||||
|
// TODO: see if we need more than one sampler
|
||||||
|
sampler_resource
|
||||||
|
} else {
|
||||||
|
self.default_sampler
|
||||||
|
};
|
||||||
|
|
||||||
|
render_resource_assignments.set(
|
||||||
|
"uSampler",
|
||||||
|
RenderResourceAssignment::Sampler(sampler_resource),
|
||||||
|
);
|
||||||
|
|
||||||
|
uniform_buffer_ranges.push(None);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
UniformData::ImageUnit(_) => panic!("image unit not currently supported"),
|
||||||
|
}
|
||||||
|
let end_index = uniform_buffer_data.len();
|
||||||
|
while uniform_buffer_data.len() % 256 != 0 {
|
||||||
|
uniform_buffer_data.push(0);
|
||||||
|
}
|
||||||
|
uniform_buffer_ranges.push(Some(start_index..end_index));
|
||||||
|
}
|
||||||
|
|
||||||
|
let buffer_resource = self
|
||||||
|
.render_context
|
||||||
|
.borrow()
|
||||||
|
.resources()
|
||||||
|
.create_buffer_with_data(
|
||||||
|
BufferInfo {
|
||||||
|
buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
&uniform_buffer_data,
|
||||||
|
);
|
||||||
|
|
||||||
|
for ((bevy_uniform, _data), range) in render_state
|
||||||
|
.uniforms
|
||||||
|
.iter()
|
||||||
|
.zip(uniform_buffer_ranges.iter())
|
||||||
|
{
|
||||||
|
if let Some(range) = range {
|
||||||
|
render_resource_assignments.set(
|
||||||
|
&bevy_uniform.name,
|
||||||
|
RenderResourceAssignment::Buffer {
|
||||||
|
dynamic_index: None,
|
||||||
|
range: range.start as u64..range.end as u64,
|
||||||
|
resource: buffer_resource,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup_vertex_buffers(
|
||||||
|
&self,
|
||||||
|
render_state: &RenderState<BevyPathfinderDevice>,
|
||||||
|
render_resource_assignments: &mut RenderResourceAssignments,
|
||||||
|
) {
|
||||||
for (i, vertex_buffer) in render_state
|
for (i, vertex_buffer) in render_state
|
||||||
.vertex_array
|
.vertex_array
|
||||||
.vertex_buffers
|
.vertex_buffers
|
||||||
@ -78,14 +245,45 @@ impl<'a> BevyPathfinderDevice<'a> {
|
|||||||
indices_resource = Some(index_buffer.handle.borrow().unwrap());
|
indices_resource = Some(index_buffer.handle.borrow().unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
render_resource_assignments.set_vertex_buffer(get_vertex_buffer_name(i), resource, indices_resource);
|
render_resource_assignments.set_vertex_buffer(
|
||||||
|
get_vertex_buffer_name(i),
|
||||||
|
resource,
|
||||||
|
indices_resource,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if let Some(ref index_buffer) = *render_state.vertex_array.index_buffer.borrow() {
|
pub fn setup_bind_groups(
|
||||||
// let resource = index_buffer.handle.borrow().unwrap();
|
&self,
|
||||||
// pass.set_index_buffer(resource, 0);
|
pipeline_descriptor: &PipelineDescriptor,
|
||||||
// }
|
render_resource_assignments: &mut RenderResourceAssignments,
|
||||||
render_context.begin_pass(
|
) {
|
||||||
|
let bind_groups = &pipeline_descriptor.get_layout().unwrap().bind_groups;
|
||||||
|
let render_context = self.render_context.borrow();
|
||||||
|
let render_resources = render_context.resources();
|
||||||
|
for bind_group in bind_groups.iter() {
|
||||||
|
render_resource_assignments.update_render_resource_set_id(bind_group);
|
||||||
|
render_resources.setup_bind_groups(pipeline_descriptor, &render_resource_assignments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw<F>(&self, render_state: &RenderState<BevyPathfinderDevice>, draw_func: F) where F: Fn(&mut dyn RenderPass) {
|
||||||
|
let pass_descriptor = self.create_pass_descriptor(render_state);
|
||||||
|
self.setup_pipline_descriptor(
|
||||||
|
render_state,
|
||||||
|
&pass_descriptor,
|
||||||
|
&render_state.vertex_array.requested_descriptors.borrow(),
|
||||||
|
);
|
||||||
|
let mut render_resource_assignments = RenderResourceAssignments::default();
|
||||||
|
self.setup_uniforms(render_state, &mut render_resource_assignments);
|
||||||
|
self.setup_bind_groups(
|
||||||
|
&render_state.program.pipeline_descriptor.borrow(),
|
||||||
|
&mut render_resource_assignments,
|
||||||
|
);
|
||||||
|
self.setup_vertex_buffers(render_state, &mut render_resource_assignments);
|
||||||
|
println!("pass {:#?}", pass_descriptor);
|
||||||
|
println!("pipeline {:#?}", render_state.program.pipeline_descriptor);
|
||||||
|
self.render_context.borrow_mut().begin_pass(
|
||||||
&pass_descriptor,
|
&pass_descriptor,
|
||||||
&render_resource_assignments,
|
&render_resource_assignments,
|
||||||
&mut |pass| {
|
&mut |pass| {
|
||||||
@ -105,6 +303,9 @@ impl<'a> BevyPathfinderDevice<'a> {
|
|||||||
|
|
||||||
let pipeline_descriptor = render_state.program.pipeline_descriptor.borrow();
|
let pipeline_descriptor = render_state.program.pipeline_descriptor.borrow();
|
||||||
pass.set_render_resources(&pipeline_descriptor, &render_resource_assignments);
|
pass.set_render_resources(&pipeline_descriptor, &render_resource_assignments);
|
||||||
|
println!("{:#?}", &render_resource_assignments);
|
||||||
|
pass.set_pipeline(render_state.program.pipeline_handle);
|
||||||
|
draw_func(pass);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -125,7 +326,7 @@ impl<'a> BevyPathfinderDevice<'a> {
|
|||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
// );
|
// );
|
||||||
Some(TextureFormat::Bgra8UnormSrgb)
|
Some(TextureFormat::Rgba16Float)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setup_pipline_descriptor(
|
pub fn setup_pipline_descriptor(
|
||||||
@ -143,14 +344,22 @@ impl<'a> BevyPathfinderDevice<'a> {
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut pipeline_descriptor = render_state.program.pipeline_descriptor.borrow_mut();
|
let mut pipeline_descriptor = render_state.program.pipeline_descriptor.borrow_mut();
|
||||||
|
pipeline_descriptor.primitive_topology = match render_state.primitive {
|
||||||
|
pathfinder_gpu::Primitive::Triangles => PrimitiveTopology::TriangleList,
|
||||||
|
pathfinder_gpu::Primitive::Lines => PrimitiveTopology::LineList,
|
||||||
|
};
|
||||||
|
pipeline_descriptor.rasterization_state = Some(RasterizationStateDescriptor::default());
|
||||||
{
|
{
|
||||||
let mut layout = pipeline_descriptor.get_layout_mut().unwrap();
|
let mut layout = pipeline_descriptor.get_layout_mut().unwrap();
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
let mut descriptors = Vec::with_capacity(requested_vertex_descriptors.len());
|
let mut descriptors = Vec::with_capacity(requested_vertex_descriptors.len());
|
||||||
loop {
|
loop {
|
||||||
if let Some(descriptor) = requested_vertex_descriptors.get(&i) {
|
if let Some(descriptor) = requested_vertex_descriptors.get(&i) {
|
||||||
descriptors.push(descriptor.clone());
|
let mut descriptor = descriptor.clone();
|
||||||
|
descriptor.attributes.sort_by_key(|a| a.shader_location);
|
||||||
|
descriptors.push(descriptor);
|
||||||
i += 1;
|
i += 1;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
@ -247,6 +456,7 @@ impl<'a> BevyPathfinderDevice<'a> {
|
|||||||
descriptor.stencil_front = stencil_descriptor.clone();
|
descriptor.stencil_front = stencil_descriptor.clone();
|
||||||
descriptor.stencil_back = stencil_descriptor;
|
descriptor.stencil_back = stencil_descriptor;
|
||||||
}
|
}
|
||||||
|
pipeline_descriptor.depth_stencil_state = Some(descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.render_context
|
self.render_context
|
||||||
@ -269,9 +479,10 @@ impl<'a> BevyPathfinderDevice<'a> {
|
|||||||
depth_texture = Some(self.main_depth_stencil_texture);
|
depth_texture = Some(self.main_depth_stencil_texture);
|
||||||
self.main_color_texture
|
self.main_color_texture
|
||||||
}
|
}
|
||||||
RenderTarget::Framebuffer(framebuffer) => framebuffer.handle,
|
RenderTarget::Framebuffer(framebuffer) => {println!("{:?} {:?}", framebuffer.texture_descriptor, framebuffer.handle); framebuffer.handle },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
println!("color main {:?} {:?}", self.main_color_texture, color_texture);
|
||||||
let mut color_attachment = RenderPassColorAttachmentDescriptor {
|
let mut color_attachment = RenderPassColorAttachmentDescriptor {
|
||||||
attachment: TextureAttachment::RenderResource(color_texture),
|
attachment: TextureAttachment::RenderResource(color_texture),
|
||||||
clear_color: Color::WHITE,
|
clear_color: Color::WHITE,
|
||||||
@ -317,114 +528,6 @@ impl<'a> BevyPathfinderDevice<'a> {
|
|||||||
sample_count: 1,
|
sample_count: 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn create_uniform_buffer(&self, uniforms: &[(&BevyUniform, UniformData)]) -> UniformBuffer {
|
|
||||||
let (mut uniform_buffer_data, mut uniform_buffer_ranges) = (vec![], vec![]);
|
|
||||||
for &(_, uniform_data) in uniforms.iter() {
|
|
||||||
let start_index = uniform_buffer_data.len();
|
|
||||||
match uniform_data {
|
|
||||||
UniformData::Float(value) => uniform_buffer_data
|
|
||||||
.write_f32::<NativeEndian>(value)
|
|
||||||
.unwrap(),
|
|
||||||
UniformData::IVec2(vector) => {
|
|
||||||
uniform_buffer_data
|
|
||||||
.write_i32::<NativeEndian>(vector.x())
|
|
||||||
.unwrap();
|
|
||||||
uniform_buffer_data
|
|
||||||
.write_i32::<NativeEndian>(vector.y())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
UniformData::IVec3(values) => {
|
|
||||||
uniform_buffer_data
|
|
||||||
.write_i32::<NativeEndian>(values[0])
|
|
||||||
.unwrap();
|
|
||||||
uniform_buffer_data
|
|
||||||
.write_i32::<NativeEndian>(values[1])
|
|
||||||
.unwrap();
|
|
||||||
uniform_buffer_data
|
|
||||||
.write_i32::<NativeEndian>(values[2])
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
UniformData::Int(value) => uniform_buffer_data
|
|
||||||
.write_i32::<NativeEndian>(value)
|
|
||||||
.unwrap(),
|
|
||||||
UniformData::Mat2(matrix) => {
|
|
||||||
uniform_buffer_data
|
|
||||||
.write_f32::<NativeEndian>(matrix.x())
|
|
||||||
.unwrap();
|
|
||||||
uniform_buffer_data
|
|
||||||
.write_f32::<NativeEndian>(matrix.y())
|
|
||||||
.unwrap();
|
|
||||||
uniform_buffer_data
|
|
||||||
.write_f32::<NativeEndian>(matrix.z())
|
|
||||||
.unwrap();
|
|
||||||
uniform_buffer_data
|
|
||||||
.write_f32::<NativeEndian>(matrix.w())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
UniformData::Mat4(matrix) => {
|
|
||||||
for column in &matrix {
|
|
||||||
uniform_buffer_data
|
|
||||||
.write_f32::<NativeEndian>(column.x())
|
|
||||||
.unwrap();
|
|
||||||
uniform_buffer_data
|
|
||||||
.write_f32::<NativeEndian>(column.y())
|
|
||||||
.unwrap();
|
|
||||||
uniform_buffer_data
|
|
||||||
.write_f32::<NativeEndian>(column.z())
|
|
||||||
.unwrap();
|
|
||||||
uniform_buffer_data
|
|
||||||
.write_f32::<NativeEndian>(column.w())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UniformData::Vec2(vector) => {
|
|
||||||
uniform_buffer_data
|
|
||||||
.write_f32::<NativeEndian>(vector.x())
|
|
||||||
.unwrap();
|
|
||||||
uniform_buffer_data
|
|
||||||
.write_f32::<NativeEndian>(vector.y())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
UniformData::Vec3(array) => {
|
|
||||||
uniform_buffer_data
|
|
||||||
.write_f32::<NativeEndian>(array[0])
|
|
||||||
.unwrap();
|
|
||||||
uniform_buffer_data
|
|
||||||
.write_f32::<NativeEndian>(array[1])
|
|
||||||
.unwrap();
|
|
||||||
uniform_buffer_data
|
|
||||||
.write_f32::<NativeEndian>(array[2])
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
UniformData::Vec4(vector) => {
|
|
||||||
uniform_buffer_data
|
|
||||||
.write_f32::<NativeEndian>(vector.x())
|
|
||||||
.unwrap();
|
|
||||||
uniform_buffer_data
|
|
||||||
.write_f32::<NativeEndian>(vector.y())
|
|
||||||
.unwrap();
|
|
||||||
uniform_buffer_data
|
|
||||||
.write_f32::<NativeEndian>(vector.z())
|
|
||||||
.unwrap();
|
|
||||||
uniform_buffer_data
|
|
||||||
.write_f32::<NativeEndian>(vector.w())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
UniformData::TextureUnit(_) | UniformData::ImageUnit(_) => {}
|
|
||||||
}
|
|
||||||
// TODO: this padding might not be necessary
|
|
||||||
let end_index = uniform_buffer_data.len();
|
|
||||||
while uniform_buffer_data.len() % 256 != 0 {
|
|
||||||
uniform_buffer_data.push(0);
|
|
||||||
}
|
|
||||||
uniform_buffer_ranges.push(start_index..end_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
UniformBuffer {
|
|
||||||
data: uniform_buffer_data,
|
|
||||||
ranges: uniform_buffer_ranges,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BevyTimerQuery {}
|
pub struct BevyTimerQuery {}
|
||||||
@ -496,7 +599,7 @@ impl<'a> Device for BevyPathfinderDevice<'a> {
|
|||||||
pathfinder_gpu::TextureFormat::RGBA16F => TextureFormat::Rgba16Float,
|
pathfinder_gpu::TextureFormat::RGBA16F => TextureFormat::Rgba16Float,
|
||||||
pathfinder_gpu::TextureFormat::RGBA32F => TextureFormat::Rgba32Float,
|
pathfinder_gpu::TextureFormat::RGBA32F => TextureFormat::Rgba32Float,
|
||||||
},
|
},
|
||||||
usage: TextureUsage::WRITE_ALL, // TODO: this might be overly safe
|
usage: TextureUsage::WRITE_ALL | TextureUsage::SAMPLED, // TODO: this might be overly safe
|
||||||
};
|
};
|
||||||
BevyTexture {
|
BevyTexture {
|
||||||
handle: self
|
handle: self
|
||||||
@ -576,6 +679,7 @@ impl<'a> Device for BevyPathfinderDevice<'a> {
|
|||||||
fragment: Some(fragment),
|
fragment: Some(fragment),
|
||||||
});
|
});
|
||||||
descriptor.reflect_layout(&self.shaders.borrow(), false, None, None);
|
descriptor.reflect_layout(&self.shaders.borrow(), false, None, None);
|
||||||
|
println!("orig {:?}", descriptor);
|
||||||
BevyProgram {
|
BevyProgram {
|
||||||
pipeline_descriptor: RefCell::new(descriptor),
|
pipeline_descriptor: RefCell::new(descriptor),
|
||||||
pipeline_handle: Handle::new(),
|
pipeline_handle: Handle::new(),
|
||||||
@ -595,6 +699,7 @@ impl<'a> Device for BevyPathfinderDevice<'a> {
|
|||||||
.find(|a| a.name == attribute_name)
|
.find(|a| a.name == attribute_name)
|
||||||
.cloned();
|
.cloned();
|
||||||
if attribute.is_some() {
|
if attribute.is_some() {
|
||||||
|
println!("pre {:?}", attribute);
|
||||||
return attribute.map(|a| BevyVertexAttr {
|
return attribute.map(|a| BevyVertexAttr {
|
||||||
attr: RefCell::new(a),
|
attr: RefCell::new(a),
|
||||||
});
|
});
|
||||||
@ -605,7 +710,7 @@ impl<'a> Device for BevyPathfinderDevice<'a> {
|
|||||||
}
|
}
|
||||||
fn get_uniform(&self, _program: &BevyProgram, name: &str) -> Self::Uniform {
|
fn get_uniform(&self, _program: &BevyProgram, name: &str) -> Self::Uniform {
|
||||||
BevyUniform {
|
BevyUniform {
|
||||||
name: name.to_string(),
|
name: format!("u{}", name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn bind_buffer(
|
fn bind_buffer(
|
||||||
@ -629,7 +734,7 @@ impl<'a> Device for BevyPathfinderDevice<'a> {
|
|||||||
bevy_attr: &BevyVertexAttr,
|
bevy_attr: &BevyVertexAttr,
|
||||||
descriptor: &VertexAttrDescriptor,
|
descriptor: &VertexAttrDescriptor,
|
||||||
) {
|
) {
|
||||||
println!("configure");
|
// println!("configure: {:?} {:?}")
|
||||||
let format = match (descriptor.class, descriptor.attr_type, descriptor.size) {
|
let format = match (descriptor.class, descriptor.attr_type, descriptor.size) {
|
||||||
(VertexAttrClass::Int, VertexAttrType::I8, 2) => VertexFormat::Char2,
|
(VertexAttrClass::Int, VertexAttrType::I8, 2) => VertexFormat::Char2,
|
||||||
// (VertexAttrClass::Int, VertexAttrType::I8, 3) => VertexFormat::Char3,
|
// (VertexAttrClass::Int, VertexAttrType::I8, 3) => VertexFormat::Char3,
|
||||||
@ -906,22 +1011,25 @@ impl<'a> Device for BevyPathfinderDevice<'a> {
|
|||||||
fn end_commands(&self) {
|
fn end_commands(&self) {
|
||||||
// NOTE: the Bevy Render Graph handles command buffer submission
|
// NOTE: the Bevy Render Graph handles command buffer submission
|
||||||
}
|
}
|
||||||
fn draw_arrays(&self, _index_count: u32, render_state: &RenderState<Self>) {
|
fn draw_arrays(&self, index_count: u32, render_state: &RenderState<Self>) {
|
||||||
self.prepare_to_draw(render_state);
|
self.draw(render_state, |pass| {
|
||||||
println!("draw_arrays");
|
pass.draw(0..index_count, 0..1);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
fn draw_elements(&self, _index_count: u32, render_state: &RenderState<Self>) {
|
fn draw_elements(&self, index_count: u32, render_state: &RenderState<Self>) {
|
||||||
self.prepare_to_draw(render_state);
|
self.draw(render_state, |pass| {
|
||||||
println!("draw_elements");
|
pass.draw_indexed( 0..index_count, 0, 0..1);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
fn draw_elements_instanced(
|
fn draw_elements_instanced(
|
||||||
&self,
|
&self,
|
||||||
_index_count: u32,
|
index_count: u32,
|
||||||
_instance_count: u32,
|
instance_count: u32,
|
||||||
render_state: &RenderState<Self>,
|
render_state: &RenderState<Self>,
|
||||||
) {
|
) {
|
||||||
self.prepare_to_draw(render_state);
|
self.draw(render_state, |pass| {
|
||||||
println!("draw_elements_instanced");
|
pass.draw_indexed( 0..index_count, 0, 0..instance_count);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
fn create_timer_query(&self) -> Self::TimerQuery {
|
fn create_timer_query(&self) -> Self::TimerQuery {
|
||||||
// TODO: maybe not needed
|
// TODO: maybe not needed
|
||||||
@ -1073,11 +1181,6 @@ impl ToBevyCompareFunction for pathfinder_gpu::StencilFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UniformBuffer {
|
|
||||||
data: Vec<u8>,
|
|
||||||
ranges: Vec<Range<usize>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const PATHFINDER_VERTEX_BUFFER_0: &'static str = "P0";
|
pub const PATHFINDER_VERTEX_BUFFER_0: &'static str = "P0";
|
||||||
pub const PATHFINDER_VERTEX_BUFFER_1: &'static str = "P1";
|
pub const PATHFINDER_VERTEX_BUFFER_1: &'static str = "P1";
|
||||||
pub const PATHFINDER_VERTEX_BUFFER_2: &'static str = "P2";
|
pub const PATHFINDER_VERTEX_BUFFER_2: &'static str = "P2";
|
||||||
|
|||||||
@ -1,12 +1,14 @@
|
|||||||
use super::{LoadOp, StoreOp};
|
use super::{LoadOp, StoreOp};
|
||||||
use crate::{render_resource::RenderResource, Color};
|
use crate::{render_resource::RenderResource, Color};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub enum TextureAttachment {
|
pub enum TextureAttachment {
|
||||||
RenderResource(RenderResource),
|
RenderResource(RenderResource),
|
||||||
Name(String),
|
Name(String),
|
||||||
Input(String),
|
Input(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct RenderPassColorAttachmentDescriptor {
|
pub struct RenderPassColorAttachmentDescriptor {
|
||||||
/// The actual color attachment.
|
/// The actual color attachment.
|
||||||
pub attachment: TextureAttachment,
|
pub attachment: TextureAttachment,
|
||||||
@ -24,6 +26,7 @@ pub struct RenderPassColorAttachmentDescriptor {
|
|||||||
pub clear_color: Color,
|
pub clear_color: Color,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct RenderPassDepthStencilAttachmentDescriptor {
|
pub struct RenderPassDepthStencilAttachmentDescriptor {
|
||||||
pub attachment: TextureAttachment,
|
pub attachment: TextureAttachment,
|
||||||
pub depth_load_op: LoadOp,
|
pub depth_load_op: LoadOp,
|
||||||
@ -35,6 +38,7 @@ pub struct RenderPassDepthStencilAttachmentDescriptor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// A set of pipeline bindings and draw calls with color and depth outputs
|
// A set of pipeline bindings and draw calls with color and depth outputs
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct PassDescriptor {
|
pub struct PassDescriptor {
|
||||||
pub color_attachments: Vec<RenderPassColorAttachmentDescriptor>,
|
pub color_attachments: Vec<RenderPassColorAttachmentDescriptor>,
|
||||||
pub depth_stencil_attachment: Option<RenderPassDepthStencilAttachmentDescriptor>,
|
pub depth_stencil_attachment: Option<RenderPassDepthStencilAttachmentDescriptor>,
|
||||||
|
|||||||
@ -13,6 +13,7 @@ pub trait RenderPass {
|
|||||||
fn set_pipeline(&mut self, pipeline_handle: Handle<PipelineDescriptor>);
|
fn set_pipeline(&mut self, pipeline_handle: Handle<PipelineDescriptor>);
|
||||||
fn set_viewport(&mut self, x: f32, y: f32, w: f32, h: f32, min_depth: f32, max_depth: f32);
|
fn set_viewport(&mut self, x: f32, y: f32, w: f32, h: f32, min_depth: f32, max_depth: f32);
|
||||||
fn set_stencil_reference(&mut self, reference: u32);
|
fn set_stencil_reference(&mut self, reference: u32);
|
||||||
|
fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>);
|
||||||
fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
|
fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
|
||||||
// TODO: try to somehow take into account the "set" pipeline instead of passing it in here
|
// TODO: try to somehow take into account the "set" pipeline instead of passing it in here
|
||||||
fn set_render_resources(
|
fn set_render_resources(
|
||||||
|
|||||||
@ -7,10 +7,7 @@ use super::{
|
|||||||
BindType, PipelineLayout, VertexBufferDescriptors,
|
BindType, PipelineLayout, VertexBufferDescriptors,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
render_resource::{
|
render_resource::{RenderResourceAssignment, RenderResourceAssignments},
|
||||||
BufferInfo, RenderResourceAssignment, RenderResourceAssignments, ResourceInfo,
|
|
||||||
},
|
|
||||||
renderer::RenderResourceContext,
|
|
||||||
shader::{Shader, ShaderStages},
|
shader::{Shader, ShaderStages},
|
||||||
texture::TextureFormat,
|
texture::TextureFormat,
|
||||||
};
|
};
|
||||||
@ -170,16 +167,17 @@ impl PipelineDescriptor {
|
|||||||
layout.sync_vertex_buffer_descriptors(vertex_buffer_descriptors);
|
layout.sync_vertex_buffer_descriptors(vertex_buffer_descriptors);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(render_resource_assignments) = render_resource_assignments
|
if let Some(render_resource_assignments) = render_resource_assignments {
|
||||||
{
|
|
||||||
// set binding uniforms to dynamic if render resource assignments use dynamic
|
// set binding uniforms to dynamic if render resource assignments use dynamic
|
||||||
// TODO: this breaks down if different assignments have different "dynamic" status or if the dynamic status changes.
|
// TODO: this breaks down if different assignments have different "dynamic" status or if the dynamic status changes.
|
||||||
// the fix would be to add "dynamic bindings" to the existing shader_def sets. this would ensure new pipelines are generated
|
// the fix would be to add "dynamic bindings" to the existing shader_def sets. this would ensure new pipelines are generated
|
||||||
// for all permutations of dynamic/non-dynamic
|
// for all permutations of dynamic/non-dynamic
|
||||||
for bind_group in layout.bind_groups.iter_mut() {
|
for bind_group in layout.bind_groups.iter_mut() {
|
||||||
for binding in bind_group.bindings.iter_mut() {
|
for binding in bind_group.bindings.iter_mut() {
|
||||||
if let Some(RenderResourceAssignment::Buffer { dynamic_index: Some(_), .. }) =
|
if let Some(RenderResourceAssignment::Buffer {
|
||||||
render_resource_assignments.get(&binding.name)
|
dynamic_index: Some(_),
|
||||||
|
..
|
||||||
|
}) = render_resource_assignments.get(&binding.name)
|
||||||
{
|
{
|
||||||
if let BindType::Uniform {
|
if let BindType::Uniform {
|
||||||
ref mut dynamic, ..
|
ref mut dynamic, ..
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
use super::{state_descriptors::PrimitiveTopology, PipelineDescriptor, VertexBufferDescriptors};
|
use super::{state_descriptors::PrimitiveTopology, PipelineDescriptor, VertexBufferDescriptors};
|
||||||
use crate::{
|
use crate::{
|
||||||
render_resource::{RenderResourceAssignments, RenderResourceAssignmentsId},
|
render_resource::{RenderResourceAssignments, RenderResourceAssignmentsId},
|
||||||
renderer::{RenderResourceContext, RenderResources},
|
|
||||||
shader::{Shader, ShaderSource},
|
shader::{Shader, ShaderSource},
|
||||||
Renderable,
|
Renderable,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,7 +3,7 @@ use crate::{
|
|||||||
render_graph::{CommandQueue, Node, ResourceSlots, SystemNode},
|
render_graph::{CommandQueue, Node, ResourceSlots, SystemNode},
|
||||||
render_resource::{
|
render_resource::{
|
||||||
BufferInfo, BufferUsage, RenderResource, RenderResourceAssignment,
|
BufferInfo, BufferUsage, RenderResource, RenderResourceAssignment,
|
||||||
RenderResourceAssignments, RenderResourceAssignmentsId, ResourceInfo,
|
RenderResourceAssignments, RenderResourceAssignmentsId,
|
||||||
},
|
},
|
||||||
renderer::{RenderContext, RenderResourceContext, RenderResources},
|
renderer::{RenderContext, RenderResourceContext, RenderResources},
|
||||||
shader::{AsUniforms, FieldBindType},
|
shader::{AsUniforms, FieldBindType},
|
||||||
|
|||||||
@ -14,6 +14,22 @@ pub struct SamplerDescriptor {
|
|||||||
pub compare_function: CompareFunction,
|
pub compare_function: CompareFunction,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for SamplerDescriptor {
|
||||||
|
fn default() -> Self {
|
||||||
|
SamplerDescriptor {
|
||||||
|
address_mode_u: AddressMode::ClampToEdge,
|
||||||
|
address_mode_v: AddressMode::ClampToEdge,
|
||||||
|
address_mode_w: AddressMode::ClampToEdge,
|
||||||
|
mag_filter: FilterMode::Nearest,
|
||||||
|
min_filter: FilterMode::Linear,
|
||||||
|
mipmap_filter: FilterMode::Nearest,
|
||||||
|
lod_min_clamp: -100.0,
|
||||||
|
lod_max_clamp: 100.0,
|
||||||
|
compare_function: CompareFunction::Always,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<&Texture> for SamplerDescriptor {
|
impl From<&Texture> for SamplerDescriptor {
|
||||||
fn from(_texture: &Texture) -> Self {
|
fn from(_texture: &Texture) -> Self {
|
||||||
SamplerDescriptor {
|
SamplerDescriptor {
|
||||||
|
|||||||
@ -46,6 +46,11 @@ impl<'a> RenderPass for WgpuRenderPass<'a> {
|
|||||||
.draw_indexed(indices, base_vertex, instances);
|
.draw_indexed(indices, base_vertex, instances);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>) {
|
||||||
|
self.render_pass
|
||||||
|
.draw(vertices, instances);
|
||||||
|
}
|
||||||
|
|
||||||
fn set_render_resources(
|
fn set_render_resources(
|
||||||
&mut self,
|
&mut self,
|
||||||
pipeline_descriptor: &PipelineDescriptor,
|
pipeline_descriptor: &PipelineDescriptor,
|
||||||
|
|||||||
@ -5,10 +5,10 @@
|
|||||||
uniform vec4 uTileSize[1];
|
uniform vec4 uTileSize[1];
|
||||||
uniform vec4 uFramebufferSize[1];
|
uniform vec4 uFramebufferSize[1];
|
||||||
layout(location = 5) in uint aTileIndex;
|
layout(location = 5) in uint aTileIndex;
|
||||||
layout(location = 1) in uint aFromPx;
|
layout(location = 3) in uint aFromPx;
|
||||||
layout(location = 3) in vec2 aFromSubpx;
|
layout(location = 1) in vec2 aFromSubpx;
|
||||||
layout(location = 2) in uint aToPx;
|
layout(location = 4) in uint aToPx;
|
||||||
layout(location = 4) in vec2 aToSubpx;
|
layout(location = 2) in vec2 aToSubpx;
|
||||||
layout(location = 0) in uvec2 aTessCoord;
|
layout(location = 0) in uvec2 aTessCoord;
|
||||||
out vec2 vFrom;
|
out vec2 vFrom;
|
||||||
out vec2 vTo;
|
out vec2 vTo;
|
||||||
|
|||||||
@ -5,10 +5,10 @@
|
|||||||
uniform vec4 uTileSize[1];
|
uniform vec4 uTileSize[1];
|
||||||
uniform vec4 uFramebufferSize[1];
|
uniform vec4 uFramebufferSize[1];
|
||||||
layout(location = 5) in uint aTileIndex;
|
layout(location = 5) in uint aTileIndex;
|
||||||
layout(location = 1) in uint aFromPx;
|
layout(location = 3) in uint aFromPx;
|
||||||
layout(location = 3) in vec2 aFromSubpx;
|
layout(location = 1) in vec2 aFromSubpx;
|
||||||
layout(location = 2) in uint aToPx;
|
layout(location = 4) in uint aToPx;
|
||||||
layout(location = 4) in vec2 aToSubpx;
|
layout(location = 2) in vec2 aToSubpx;
|
||||||
layout(location = 0) in uvec2 aTessCoord;
|
layout(location = 0) in uvec2 aTessCoord;
|
||||||
layout(location = 0) out vec2 vFrom;
|
layout(location = 0) out vec2 vFrom;
|
||||||
layout(location = 1) out vec2 vTo;
|
layout(location = 1) out vec2 vTo;
|
||||||
|
|||||||
@ -26,10 +26,10 @@ struct main0_out
|
|||||||
struct main0_in
|
struct main0_in
|
||||||
{
|
{
|
||||||
uint2 aTessCoord [[attribute(0)]];
|
uint2 aTessCoord [[attribute(0)]];
|
||||||
uint aFromPx [[attribute(1)]];
|
float2 aFromSubpx [[attribute(1)]];
|
||||||
uint aToPx [[attribute(2)]];
|
float2 aToSubpx [[attribute(2)]];
|
||||||
float2 aFromSubpx [[attribute(3)]];
|
uint aFromPx [[attribute(3)]];
|
||||||
float2 aToSubpx [[attribute(4)]];
|
uint aToPx [[attribute(4)]];
|
||||||
uint aTileIndex [[attribute(5)]];
|
uint aTileIndex [[attribute(5)]];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
crates/pathfinder/shaders/build/metal/fill.cs.spv
Normal file
BIN
crates/pathfinder/shaders/build/metal/fill.cs.spv
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -24,10 +24,10 @@ layout(std140, set=0, binding=1) uniform uTileSize {
|
|||||||
};
|
};
|
||||||
|
|
||||||
in uvec2 aTessCoord;
|
in uvec2 aTessCoord;
|
||||||
in uint aFromPx;
|
|
||||||
in uint aToPx;
|
|
||||||
in vec2 aFromSubpx;
|
in vec2 aFromSubpx;
|
||||||
in vec2 aToSubpx;
|
in vec2 aToSubpx;
|
||||||
|
in uint aFromPx;
|
||||||
|
in uint aToPx;
|
||||||
in uint aTileIndex;
|
in uint aTileIndex;
|
||||||
|
|
||||||
out vec2 vFrom;
|
out vec2 vFrom;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user