use "32 bit alignment" and "explicit shaders" pathfinder branches

This commit is contained in:
Carter Anderson 2020-05-10 12:53:26 -07:00
parent ff8c5292c2
commit a5f47fd7da
360 changed files with 5773 additions and 21894 deletions

View file

@ -12,8 +12,8 @@ bevy_asset = { path = "../bevy_asset" }
bevy_render = { path = "../bevy_render" }
legion = { path = "../bevy_legion" }
pathfinder_geometry = { path = "../pathfinder/geometry" }
pathfinder_gpu = { path = "../pathfinder/gpu" }
pathfinder_geometry = { path = "../pathfinder/geometry", features = ["shader_alignment_32_bits"] }
pathfinder_gpu = { path = "../pathfinder/gpu", features = ["shader_alignment_32_bits"] }
pathfinder_renderer = { path = "../pathfinder/renderer" }
pathfinder_simd = { path = "../pathfinder/simd" }
pathfinder_resources = { path = "../pathfinder/resources" }

View file

@ -1,4 +1,3 @@
use crate::shaders;
use bevy_asset::{AssetStorage, Handle};
use bevy_render::{
pipeline::{
@ -6,7 +5,7 @@ use bevy_render::{
VertexAttributeDescriptor, VertexBufferDescriptor, VertexFormat,
},
render_resource::{BufferInfo, BufferUsage, RenderResource},
renderer::{RenderContext, RenderResourceContext},
renderer::RenderContext,
shader::{Shader, ShaderSource, ShaderStage, ShaderStages},
texture::{
AddressMode, Extent3d, FilterMode, SamplerDescriptor, TextureDescriptor, TextureDimension,
@ -16,9 +15,9 @@ use bevy_render::{
use pathfinder_canvas::vec2i;
use pathfinder_geometry::{rect::RectI, vector::Vector2I};
use pathfinder_gpu::{
BufferData, BufferTarget, BufferUploadMode, Device, RenderState, RenderTarget, ShaderKind,
TextureData, TextureDataRef, TextureSamplingFlags, VertexAttrClass, VertexAttrDescriptor,
VertexAttrType,
BufferData, BufferTarget, BufferUploadMode, Device, ProgramKind, RenderState, RenderTarget,
ShaderKind, TextureData, TextureDataRef, TextureSamplingFlags, VertexAttrClass,
VertexAttrDescriptor, VertexAttrType, FeatureLevel,
};
use pathfinder_resources::ResourceLoader;
use std::{borrow::Cow, cell::RefCell, collections::HashMap, mem, rc::Rc, time::Duration};
@ -46,7 +45,7 @@ impl<'a> BevyPathfinderDevice<'a> {
pub struct BevyTimerQuery {}
pub struct BevyTextureDataReceiver {}
pub struct BevyUniform {
name: String,
pub name: String,
}
pub struct BevyVertexAttr {
@ -56,8 +55,8 @@ pub struct BevyVertexAttr {
#[derive(Debug)]
pub struct BevyVertexArray {
requested_descriptors: RefCell<HashMap<u32, VertexBufferDescriptor>>,
vertex_buffers: RefCell<Vec<RenderResource>>,
index_buffer: RefCell<Option<RenderResource>>,
vertex_buffers: RefCell<Vec<BevyBuffer>>,
index_buffer: RefCell<Option<BevyBuffer>>,
}
pub struct BevyTexture {
@ -66,15 +65,19 @@ pub struct BevyTexture {
sampler_resource: RefCell<Option<RenderResource>>,
}
#[derive(Debug, Clone)]
pub struct BevyBuffer {
handle: Rc<RefCell<Option<RenderResource>>>,
mode: BufferUploadMode,
}
impl<'a> Device for BevyPathfinderDevice<'a> {
type Buffer = BevyBuffer;
type Fence = ();
type Framebuffer = BevyTexture;
type Program = PipelineDescriptor;
type Shader = Handle<Shader>;
type StorageBuffer = ();
type Texture = BevyTexture;
type TextureDataReceiver = BevyTextureDataReceiver;
type TimerQuery = BevyTimerQuery;
@ -127,31 +130,38 @@ impl<'a> Device for BevyPathfinderDevice<'a> {
}
fn create_shader(
&self,
_resources: &dyn ResourceLoader,
resources: &dyn ResourceLoader,
name: &str,
kind: ShaderKind,
) -> Self::Shader {
let shader_bytes = match (name, kind) {
("blit", ShaderKind::Fragment) => shaders::BLIT_FS,
("blit", ShaderKind::Vertex) => shaders::BLIT_VS,
// ("debug_solid", ShaderKind::Fragment) => shaders::DEMO_GROUND_FS,
// ("demo_ground", ShaderKind::Vertex) => shaders::DEMO_GROUND_VS,
("fill", ShaderKind::Fragment) => shaders::FILL_FS,
("fill", ShaderKind::Vertex) => shaders::FILL_VS,
("reproject", ShaderKind::Fragment) => shaders::REPROJECT_FS,
("reproject", ShaderKind::Vertex) => shaders::REPROJECT_VS,
("stencil", ShaderKind::Fragment) => shaders::STENCIL_FS,
("stencil", ShaderKind::Vertex) => shaders::STENCIL_VS,
("tile_clip", ShaderKind::Fragment) => shaders::TILE_CLIP_FS,
("tile_clip", ShaderKind::Vertex) => shaders::TILE_CLIP_VS,
("tile_copy", ShaderKind::Fragment) => shaders::TILE_COPY_FS,
("tile_copy", ShaderKind::Vertex) => shaders::TILE_COPY_VS,
("tile", ShaderKind::Fragment) => shaders::TILE_FS,
("tile", ShaderKind::Vertex) => shaders::TILE_VS,
_ => panic!("encountered unexpected shader {} {:?}", name, kind),
// let shader_bytes = match (name, kind) {
// ("blit", ShaderKind::Fragment) => shaders::BLIT_FS,
// ("blit", ShaderKind::Vertex) => shaders::BLIT_VS,
// // ("debug_solid", ShaderKind::Fragment) => shaders::DEMO_GROUND_FS,
// // ("demo_ground", ShaderKind::Vertex) => shaders::DEMO_GROUND_VS,
// ("fill", ShaderKind::Fragment) => shaders::FILL_FS,
// ("fill", ShaderKind::Vertex) => shaders::FILL_VS,
// ("reproject", ShaderKind::Fragment) => shaders::REPROJECT_FS,
// ("reproject", ShaderKind::Vertex) => shaders::REPROJECT_VS,
// ("stencil", ShaderKind::Fragment) => shaders::STENCIL_FS,
// ("stencil", ShaderKind::Vertex) => shaders::STENCIL_VS,
// ("tile_clip", ShaderKind::Fragment) => shaders::TILE_CLIP_FS,
// ("tile_clip", ShaderKind::Vertex) => shaders::TILE_CLIP_VS,
// ("tile_copy", ShaderKind::Fragment) => shaders::TILE_COPY_FS,
// ("tile_copy", ShaderKind::Vertex) => shaders::TILE_COPY_VS,
// ("tile", ShaderKind::Fragment) => shaders::TILE_FS,
// ("tile", ShaderKind::Vertex) => shaders::TILE_VS,
// _ => panic!("encountered unexpected shader {} {:?}", name, kind),
// };
let suffix = match kind {
ShaderKind::Vertex => 'v',
ShaderKind::Fragment => 'f',
ShaderKind::Compute => 'c',
};
let path = format!("shaders/vulkan/{}.{}s.spv", name, suffix);
let bytes = resources.slurp(&path).unwrap();
self.create_shader_from_source(name, shader_bytes, kind)
self.create_shader_from_source(name, &bytes, kind)
}
fn create_shader_from_source(
&self,
@ -162,6 +172,7 @@ impl<'a> Device for BevyPathfinderDevice<'a> {
let stage = match kind {
ShaderKind::Fragment => ShaderStage::Fragment,
ShaderKind::Vertex => ShaderStage::Vertex,
ShaderKind::Compute => panic!("bevy does not currently support compute shaders"),
};
let shader = Shader::new(stage, ShaderSource::spirv_from_bytes(source));
let mut shaders = self.shaders.borrow_mut();
@ -183,17 +194,20 @@ impl<'a> Device for BevyPathfinderDevice<'a> {
fn create_program_from_shaders(
&self,
_resources: &dyn ResourceLoader,
name: &str,
vertex_shader: Self::Shader,
fragment_shader: Self::Shader,
_name: &str,
shaders: ProgramKind<Handle<Shader>>,
) -> Self::Program {
println!("{}", name);
let mut descriptor = PipelineDescriptor::new(ShaderStages {
vertex: vertex_shader,
fragment: Some(fragment_shader),
});
descriptor.reflect_layout(&self.shaders.borrow(), false, None, None);
descriptor
match shaders {
ProgramKind::Compute(_) => panic!("bevy does not currently support compute shaders"),
ProgramKind::Raster { vertex, fragment } => {
let mut descriptor = PipelineDescriptor::new(ShaderStages {
vertex,
fragment: Some(fragment),
});
descriptor.reflect_layout(&self.shaders.borrow(), false, None, None);
descriptor
}
}
}
fn get_vertex_attr(
&self,
@ -228,19 +242,20 @@ impl<'a> Device for BevyPathfinderDevice<'a> {
}
fn bind_buffer(
&self,
vertex_array: &Self::VertexArray,
buffer: &Self::Buffer,
vertex_array: &BevyVertexArray,
buffer: &BevyBuffer,
target: BufferTarget,
) {
match target {
BufferTarget::Vertex => vertex_array
.vertex_buffers
.borrow_mut()
.push(buffer.handle.borrow().unwrap().clone()),
.push(buffer.clone()),
BufferTarget::Index => {
*vertex_array.index_buffer.borrow_mut() =
Some(buffer.handle.borrow().unwrap().clone())
Some(buffer.clone())
}
_ => panic!("Buffers bound to vertex arrays must be vertex or index buffers!"),
}
}
fn configure_vertex_attr(
@ -282,6 +297,14 @@ impl<'a> Device for BevyPathfinderDevice<'a> {
// VertexFormat::Short3Normalized
// }
(VertexAttrClass::FloatNorm, VertexAttrType::I16, 4) => VertexFormat::Short4Norm,
(VertexAttrClass::Int, VertexAttrType::I32, 1) => VertexFormat::Int,
(VertexAttrClass::Int, VertexAttrType::I32, 2) => VertexFormat::Int2,
(VertexAttrClass::Int, VertexAttrType::I32, 3) => VertexFormat::Int3,
(VertexAttrClass::Int, VertexAttrType::I32, 4) => VertexFormat::Int4,
(VertexAttrClass::Int, VertexAttrType::U32, 1) => VertexFormat::Uint,
(VertexAttrClass::Int, VertexAttrType::U32, 2) => VertexFormat::Uint2,
(VertexAttrClass::Int, VertexAttrType::U32, 3) => VertexFormat::Uint3,
(VertexAttrClass::Int, VertexAttrType::U32, 4) => VertexFormat::Uint4,
(VertexAttrClass::Float, VertexAttrType::F32, 1) => VertexFormat::Float,
(VertexAttrClass::Float, VertexAttrType::F32, 2) => VertexFormat::Float2,
(VertexAttrClass::Float, VertexAttrType::F32, 3) => VertexFormat::Float3,
@ -340,20 +363,15 @@ impl<'a> Device for BevyPathfinderDevice<'a> {
texture
}
fn create_buffer(&self) -> Self::Buffer {
fn create_buffer(&self, mode: BufferUploadMode) -> Self::Buffer {
BevyBuffer {
handle: Rc::new(RefCell::new(None)),
mode,
}
}
fn allocate_buffer<T>(
&self,
buffer: &BevyBuffer,
data: BufferData<T>,
_target: BufferTarget,
mode: BufferUploadMode,
) {
let buffer_usage = match mode {
fn allocate_buffer<T>(&self, buffer: &BevyBuffer, data: BufferData<T>, _target: BufferTarget) {
let buffer_usage = match buffer.mode {
BufferUploadMode::Dynamic => BufferUsage::WRITE_ALL,
BufferUploadMode::Static => BufferUsage::COPY_DST,
};
@ -504,8 +522,8 @@ impl<'a> Device for BevyPathfinderDevice<'a> {
}
fn read_pixels(
&self,
target: &RenderTarget<Self>,
viewport: RectI,
_target: &RenderTarget<Self>,
_viewport: RectI,
) -> Self::TextureDataReceiver {
// TODO: this might actually be optional, which is great because otherwise this requires a command buffer sync
todo!()
@ -516,17 +534,17 @@ impl<'a> Device for BevyPathfinderDevice<'a> {
fn end_commands(&self) {
// 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>) {
todo!()
}
fn draw_elements(&self, index_count: u32, render_state: &RenderState<Self>) {
fn draw_elements(&self, _index_count: u32, _render_state: &RenderState<Self>) {
todo!()
}
fn draw_elements_instanced(
&self,
index_count: u32,
instance_count: u32,
render_state: &RenderState<Self>,
_index_count: u32,
_instance_count: u32,
_render_state: &RenderState<Self>,
) {
todo!()
}
@ -534,27 +552,82 @@ impl<'a> Device for BevyPathfinderDevice<'a> {
// TODO: maybe not needed
BevyTimerQuery {}
}
fn begin_timer_query(&self, query: &Self::TimerQuery) {}
fn end_timer_query(&self, query: &Self::TimerQuery) {}
fn try_recv_timer_query(&self, query: &Self::TimerQuery) -> Option<std::time::Duration> {
fn begin_timer_query(&self, _query: &Self::TimerQuery) {}
fn end_timer_query(&self, _query: &Self::TimerQuery) {}
fn try_recv_timer_query(&self, _query: &Self::TimerQuery) -> Option<std::time::Duration> {
None
}
fn recv_timer_query(&self, query: &Self::TimerQuery) -> std::time::Duration {
fn recv_timer_query(&self, _query: &Self::TimerQuery) -> std::time::Duration {
Duration::from_millis(0)
}
fn try_recv_texture_data(&self, receiver: &Self::TextureDataReceiver) -> Option<TextureData> {
fn try_recv_texture_data(&self, _receiver: &Self::TextureDataReceiver) -> Option<TextureData> {
None
}
fn recv_texture_data(&self, receiver: &Self::TextureDataReceiver) -> TextureData {
fn recv_texture_data(&self, _receiver: &Self::TextureDataReceiver) -> TextureData {
todo!()
}
fn feature_level(&self) -> pathfinder_gpu::FeatureLevel {
// TODO: change to 11 when compute is added
FeatureLevel::D3D10
}
fn set_compute_program_local_size(
&self,
_program: &mut Self::Program,
_local_size: pathfinder_gpu::ComputeDimensions,
) {
}
fn get_storage_buffer(
&self,
_program: &Self::Program,
_name: &str,
_binding: u32,
) -> Self::StorageBuffer {
panic!("Compute shader is unsupported in Bevy!");
}
fn upload_to_buffer<T>(
&self,
buffer: &BevyBuffer,
position: usize,
data: &[T],
_target: BufferTarget,
) {
let data_slice = &data[position..];
let temp_buffer = self
.render_context
.borrow()
.resources()
.create_buffer_with_data(
BufferInfo {
buffer_usage: BufferUsage::COPY_DST,
..Default::default()
},
slice_to_u8(data_slice),
);
let buffer_handle = buffer.handle.borrow().unwrap();
self.render_context.borrow_mut().copy_buffer_to_buffer(
temp_buffer,
0,
buffer_handle,
0,
data_slice.len() as u64,
)
}
fn dispatch_compute(
&self,
_dimensions: pathfinder_gpu::ComputeDimensions,
_state: &pathfinder_gpu::ComputeState<Self>,
) {
panic!("Compute shader is unsupported in Bevy!");
}
fn add_fence(&self) -> Self::Fence {}
fn wait_for_fence(&self, _fence: &Self::Fence) {}
}
fn get_texture_bytes<'a>(data_ref: &'a TextureDataRef) -> &'a [u8] {
match data_ref {
TextureDataRef::U8(data) => data,
TextureDataRef::F16(data) => {
panic!("we dont do half measures");
slice_to_u8(data)
}
TextureDataRef::F32(data) => data.as_bytes(),
}

View file

@ -1,10 +1,7 @@
mod device;
mod resource_loader;
mod pathfinder_node;
mod shaders;
use bevy_app::{AppBuilder, AppPlugin};
pub use device::*;
pub use resource_loader::*;
use bevy_render::render_graph::RenderGraph;
use pathfinder_node::PathfinderNode;

View file

@ -1,4 +1,4 @@
use crate::{BevyPathfinderDevice, BevyResourceLoader};
use crate::BevyPathfinderDevice;
use bevy_asset::AssetStorage;
use bevy_render::{
render_graph::{Node, ResourceSlots},
@ -15,6 +15,7 @@ use pathfinder_renderer::{
},
options::BuildOptions,
};
use pathfinder_resources::embedded::EmbeddedResourceLoader;
#[derive(Default)]
pub struct PathfinderNode;
@ -33,10 +34,11 @@ impl Node for PathfinderNode {
let window_size = Vector2I::new(640 as i32, 480 as i32);
let mut renderer = Renderer::new(
device,
&BevyResourceLoader::new(),
&EmbeddedResourceLoader::new(),
DestFramebuffer::full_window(window_size),
RendererOptions {
background_color: Some(ColorF::white()),
..Default::default()
},
);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 338 B

View file

@ -1,14 +0,0 @@
pub const BLIT_FS: &'static [u8] = include_bytes!("shaders/spirv/blit.fs.spv");
pub const BLIT_VS: &'static [u8] = include_bytes!("shaders/spirv/blit.vs.spv");
pub const FILL_FS: &'static [u8] = include_bytes!("shaders/spirv/fill.fs.spv");
pub const FILL_VS: &'static [u8] = include_bytes!("shaders/spirv/fill.vs.spv");
pub const REPROJECT_FS: &'static [u8] = include_bytes!("shaders/spirv/reproject.fs.spv");
pub const REPROJECT_VS: &'static [u8] = include_bytes!("shaders/spirv/reproject.vs.spv");
pub const STENCIL_FS: &'static [u8] = include_bytes!("shaders/spirv/stencil.fs.spv");
pub const STENCIL_VS: &'static [u8] = include_bytes!("shaders/spirv/stencil.vs.spv");
pub const TILE_CLIP_FS: &'static [u8] = include_bytes!("shaders/spirv/tile_clip.fs.spv");
pub const TILE_CLIP_VS: &'static [u8] = include_bytes!("shaders/spirv/tile_clip.vs.spv");
pub const TILE_COPY_FS: &'static [u8] = include_bytes!("shaders/spirv/tile_copy.fs.spv");
pub const TILE_COPY_VS: &'static [u8] = include_bytes!("shaders/spirv/tile_copy.vs.spv");
pub const TILE_FS: &'static [u8] = include_bytes!("shaders/spirv/tile.fs.spv");
pub const TILE_VS: &'static [u8] = include_bytes!("shaders/spirv/tile.vs.spv");

View file

@ -1,43 +0,0 @@
TARGET_DIR?=spirv
EMPTY=
SHADERS=\
blit.fs.glsl \
blit.vs.glsl \
fill.fs.glsl \
fill.vs.glsl \
reproject.fs.glsl \
reproject.vs.glsl \
stencil.fs.glsl \
stencil.vs.glsl \
tile.fs.glsl \
tile.vs.glsl \
tile_clip.fs.glsl \
tile_clip.vs.glsl \
tile_copy.fs.glsl \
tile_copy.vs.glsl \
$(EMPTY)
INCLUDES=\
$(EMPTY)
OUT=\
$(SHADERS:%.glsl=$(TARGET_DIR)/%.spv) \
$(EMPTY)
GLSLANGFLAGS=--auto-map-locations -I.
GLSLANGFLAGS_VULKAN=$(GLSLANGFLAGS) -V
all: $(OUT)
.PHONY: clean
clean:
rm -f $(OUT)
$(TARGET_DIR)/%.fs.spv: glsl/%.fs.glsl $(INCLUDES)
mkdir -p $(TARGET_DIR) && glslangValidator $(GLSLANGFLAGS_VULKAN) -S frag -o $@ $<
$(TARGET_DIR)/%.vs.spv: glsl/%.vs.glsl $(INCLUDES)
mkdir -p $(TARGET_DIR) && glslangValidator $(GLSLANGFLAGS_VULKAN) -S vert -o $@ $<

View file

@ -1,26 +0,0 @@
#version 450
// pathfinder/shaders/blit.fs.glsl
//
// Copyright © 2020 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
precision highp float;
precision highp sampler2D;
layout(set=0, binding=0) uniform texture2D uSrc;
layout(set=0, binding=1) uniform sampler uSrcSampler;
in vec2 vTexCoord;
out vec4 oFragColor;
void main() {
vec4 color = texture(sampler2D(uSrc, uSrcSampler), vTexCoord);
oFragColor = vec4(color.rgb * color.a, color.a);
}

View file

@ -1,27 +0,0 @@
#version 450
// pathfinder/shaders/blit.vs.glsl
//
// Copyright © 2020 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
precision highp float;
precision highp sampler2D;
in ivec2 aPosition;
out vec2 vTexCoord;
void main() {
vec2 texCoord = vec2(aPosition);
#ifdef PF_ORIGIN_UPPER_LEFT
texCoord.y = 1.0 - texCoord.y;
#endif
vTexCoord = texCoord;
gl_Position = vec4(mix(vec2(-1.0), vec2(1.0), vec2(aPosition)), 0.0, 1.0);
}

View file

@ -1,63 +0,0 @@
#version 450
// pathfinder/shaders/fill.vs.glsl
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
precision highp float;
precision highp sampler2D;
layout(set=0, binding=0) uniform uFramebufferSize {
vec2 framebufferSize;
};
layout(set=0, binding=1) uniform uTileSize {
vec2 tileSize;
};
in uvec2 aTessCoord;
in uint aFromPx;
in uint aToPx;
in vec2 aFromSubpx;
in vec2 aToSubpx;
in uint aTileIndex;
out vec2 vFrom;
out vec2 vTo;
vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth) {
uint tilesPerRow = uint(stencilTextureWidth / tileSize.x);
uvec2 tileOffset = uvec2(tileIndex % tilesPerRow, tileIndex / tilesPerRow);
return vec2(tileOffset) * tileSize;
}
void main() {
vec2 tileOrigin = computeTileOffset(aTileIndex, framebufferSize.x);
vec2 from = vec2(aFromPx & 15u, aFromPx >> 4u) + aFromSubpx;
vec2 to = vec2(aToPx & 15u, aToPx >> 4u) + aToSubpx;
vec2 position;
if (aTessCoord.x == 0u)
position.x = floor(min(from.x, to.x));
else
position.x = ceil(max(from.x, to.x));
if (aTessCoord.y == 0u)
position.y = floor(min(from.y, to.y));
else
position.y = tileSize.y;
vFrom = from - position;
vTo = to - position;
vec2 globalPosition = (tileOrigin + position) / framebufferSize * 2.0 - 1.0;
#ifdef PF_ORIGIN_UPPER_LEFT
globalPosition.y = -globalPosition.y;
#endif
gl_Position = vec4(globalPosition, 0.0, 1.0);
}

View file

@ -1,31 +0,0 @@
#version 450
// pathfinder/shaders/reproject.fs.glsl
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
precision highp float;
precision highp sampler2D;
layout(set=1, binding=0) uniform uOldTransform {
mat4 oldTransform;
};
layout(set=1, binding=1) uniform texture2D uTexture;
layout(set=1, binding=2) uniform sampler uTextureSampler;
in vec2 vTexCoord;
out vec4 oFragColor;
void main() {
vec4 normTexCoord = oldTransform * vec4(vTexCoord, 0.0, 1.0);
vec2 texCoord = ((normTexCoord.xy / normTexCoord.w) + 1.0) * 0.5;
oFragColor = texture(sampler2D(uTexture, uTextureSampler), texCoord);
}

View file

@ -1,33 +0,0 @@
#version 450
// pathfinder/shaders/reproject.vs.glsl
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
precision highp float;
precision highp sampler2D;
layout(set=0, binding=0) uniform uNewTransform {
mat4 newTransform;
};
in ivec2 aPosition;
out vec2 vTexCoord;
void main() {
vec2 position = vec2(aPosition);
vTexCoord = position;
#ifdef PF_ORIGIN_UPPER_LEFT
// FIXME(pcwalton): This is wrong.
position.y = 1.0 - position.y;
#endif
gl_Position = newTransform * vec4(position, 0.0, 1.0);
}

View file

@ -1,21 +0,0 @@
#version 450
// pathfinder/shaders/stencil.fs.glsl
//
// Copyright © 2018 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
precision highp float;
precision highp sampler2D;
out vec4 oFragColor;
void main() {
// This should be color masked out.
oFragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

View file

@ -1,615 +0,0 @@
#version 450
// pathfinder/shaders/tile.fs.glsl
//
// Copyright © 2020 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Mask UV 0 Mask UV 1
// + +
// | |
// +-----v-----+ +-----v-----+
// | | MIN | |
// | Mask 0 +-----> Mask 1 +------+
// | | | | |
// +-----------+ +-----------+ v +-------------+
// Apply | | GPU
// Mask +----> Composite +---->Blender
// ^ | |
// +-----------+ +-----------+ | +-------------+
// | | | | |
// | Color 0 +-----> Color 1 +------+
// | Filter | × | |
// | | | |
// +-----^-----+ +-----^-----+
// | |
// + +
// Color UV 0 Color UV 1
#extension GL_GOOGLE_include_directive : enable
precision highp float;
precision highp sampler2D;
#define EPSILON 0.00001
#define FRAC_6_PI 1.9098593171027443
#define FRAC_PI_3 1.0471975511965976
#define TILE_CTRL_MASK_MASK 0x3
#define TILE_CTRL_MASK_WINDING 0x1
#define TILE_CTRL_MASK_EVEN_ODD 0x2
#define TILE_CTRL_MASK_0_SHIFT 0
#define COMBINER_CTRL_COLOR_COMBINE_MASK 0x3
#define COMBINER_CTRL_COLOR_COMBINE_SRC_IN 0x1
#define COMBINER_CTRL_COLOR_COMBINE_DEST_IN 0x2
#define COMBINER_CTRL_FILTER_MASK 0x3
#define COMBINER_CTRL_FILTER_RADIAL_GRADIENT 0x1
#define COMBINER_CTRL_FILTER_TEXT 0x2
#define COMBINER_CTRL_FILTER_BLUR 0x3
#define COMBINER_CTRL_COMPOSITE_MASK 0xf
#define COMBINER_CTRL_COMPOSITE_NORMAL 0x0
#define COMBINER_CTRL_COMPOSITE_MULTIPLY 0x1
#define COMBINER_CTRL_COMPOSITE_SCREEN 0x2
#define COMBINER_CTRL_COMPOSITE_OVERLAY 0x3
#define COMBINER_CTRL_COMPOSITE_DARKEN 0x4
#define COMBINER_CTRL_COMPOSITE_LIGHTEN 0x5
#define COMBINER_CTRL_COMPOSITE_COLOR_DODGE 0x6
#define COMBINER_CTRL_COMPOSITE_COLOR_BURN 0x7
#define COMBINER_CTRL_COMPOSITE_HARD_LIGHT 0x8
#define COMBINER_CTRL_COMPOSITE_SOFT_LIGHT 0x9
#define COMBINER_CTRL_COMPOSITE_DIFFERENCE 0xa
#define COMBINER_CTRL_COMPOSITE_EXCLUSION 0xb
#define COMBINER_CTRL_COMPOSITE_HUE 0xc
#define COMBINER_CTRL_COMPOSITE_SATURATION 0xd
#define COMBINER_CTRL_COMPOSITE_COLOR 0xe
#define COMBINER_CTRL_COMPOSITE_LUMINOSITY 0xf
#define COMBINER_CTRL_COLOR_FILTER_SHIFT 4
#define COMBINER_CTRL_COLOR_COMBINE_SHIFT 6
#define COMBINER_CTRL_COMPOSITE_SHIFT 8
layout(set=1, binding=0) uniform sampler textureSampler;
layout(set=1, binding=1) uniform texture2D uColorTexture0;
layout(set=1, binding=2) uniform texture2D uMaskTexture0;
layout(set=1, binding=3) uniform texture2D uDestTexture;
layout(set=1, binding=4) uniform texture2D uGammaLUT;
layout(set=2, binding=0) uniform uFilterParams0 {
vec4 filterParams0;
};
layout(set=2, binding=1) uniform uFilterParams1 {
vec4 filterParams1;
};
layout(set=2, binding=2) uniform uFilterParams2 {
vec4 filterParams2;
};
layout(set=2, binding=3) uniform uFramebufferSize {
vec2 framebufferSize;
};
layout(set=2, binding=4) uniform uColorTexture0Size {
vec2 colorTexture0Size;
};
layout(set=2, binding=5) uniform uCtrl {
int ctrl;
};
in vec3 vMaskTexCoord0;
in vec2 vColorTexCoord0;
in vec4 vBaseColor;
in float vTileCtrl;
out vec4 oFragColor;
// Color sampling
vec4 sampleColor(texture2D colorTexture, vec2 colorTexCoord) {
return texture(sampler2D(colorTexture, textureSampler), colorTexCoord);
}
// Color combining
vec4 combineColor0(vec4 destColor, vec4 srcColor, int op) {
switch (op) {
case COMBINER_CTRL_COLOR_COMBINE_SRC_IN:
return vec4(srcColor.rgb, srcColor.a * destColor.a);
case COMBINER_CTRL_COLOR_COMBINE_DEST_IN:
return vec4(destColor.rgb, srcColor.a * destColor.a);
}
return destColor;
}
// Text filter
float filterTextSample1Tap(float offset, texture2D colorTexture, vec2 colorTexCoord) {
return texture(sampler2D(colorTexture, textureSampler), colorTexCoord + vec2(offset, 0.0)).r;
}
// Samples 9 taps around the current pixel.
void filterTextSample9Tap(out vec4 outAlphaLeft,
out float outAlphaCenter,
out vec4 outAlphaRight,
texture2D colorTexture,
vec2 colorTexCoord,
vec4 kernel,
float onePixel) {
bool wide = kernel.x > 0.0;
outAlphaLeft =
vec4(wide ? filterTextSample1Tap(-4.0 * onePixel, colorTexture, colorTexCoord) : 0.0,
filterTextSample1Tap(-3.0 * onePixel, colorTexture, colorTexCoord),
filterTextSample1Tap(-2.0 * onePixel, colorTexture, colorTexCoord),
filterTextSample1Tap(-1.0 * onePixel, colorTexture, colorTexCoord));
outAlphaCenter = filterTextSample1Tap(0.0, colorTexture, colorTexCoord);
outAlphaRight =
vec4(filterTextSample1Tap(1.0 * onePixel, colorTexture, colorTexCoord),
filterTextSample1Tap(2.0 * onePixel, colorTexture, colorTexCoord),
filterTextSample1Tap(3.0 * onePixel, colorTexture, colorTexCoord),
wide ? filterTextSample1Tap(4.0 * onePixel, colorTexture, colorTexCoord) : 0.0);
}
float filterTextConvolve7Tap(vec4 alpha0, vec3 alpha1, vec4 kernel) {
return dot(alpha0, kernel) + dot(alpha1, kernel.zyx);
}
float filterTextGammaCorrectChannel(float bgColor, float fgColor, texture2D gammaLUT) {
return texture(sampler2D(gammaLUT, textureSampler), vec2(fgColor, 1.0 - bgColor)).r;
}
// `fgColor` is in linear space.
vec3 filterTextGammaCorrect(vec3 bgColor, vec3 fgColor, texture2D gammaLUT) {
return vec3(filterTextGammaCorrectChannel(bgColor.r, fgColor.r, gammaLUT),
filterTextGammaCorrectChannel(bgColor.g, fgColor.g, gammaLUT),
filterTextGammaCorrectChannel(bgColor.b, fgColor.b, gammaLUT));
}
// | x y z w
// --------------+--------------------------------------------------------
// filterParams0 | kernel[0] kernel[1] kernel[2] kernel[3]
// filterParams1 | bgColor.r bgColor.g bgColor.b -
// filterParams2 | fgColor.r fgColor.g fgColor.b gammaCorrectionEnabled
vec4 filterText(vec2 colorTexCoord,
texture2D colorTexture,
texture2D gammaLUT,
vec2 colorTextureSize,
vec4 filterParams0,
vec4 filterParams1,
vec4 filterParams2) {
// Unpack.
vec4 kernel = filterParams0;
vec3 bgColor = filterParams1.rgb;
vec3 fgColor = filterParams2.rgb;
bool gammaCorrectionEnabled = filterParams2.a != 0.0;
// Apply defringing if necessary.
vec3 alpha;
if (kernel.w == 0.0) {
alpha = texture(sampler2D(colorTexture, textureSampler), colorTexCoord).rrr;
} else {
vec4 alphaLeft, alphaRight;
float alphaCenter;
filterTextSample9Tap(alphaLeft,
alphaCenter,
alphaRight,
colorTexture,
colorTexCoord,
kernel,
1.0 / colorTextureSize.x);
float r = filterTextConvolve7Tap(alphaLeft, vec3(alphaCenter, alphaRight.xy), kernel);
float g = filterTextConvolve7Tap(vec4(alphaLeft.yzw, alphaCenter), alphaRight.xyz, kernel);
float b = filterTextConvolve7Tap(vec4(alphaLeft.zw, alphaCenter, alphaRight.x),
alphaRight.yzw,
kernel);
alpha = vec3(r, g, b);
}
// Apply gamma correction if necessary.
if (gammaCorrectionEnabled)
alpha = filterTextGammaCorrect(bgColor, alpha, gammaLUT);
// Finish.
return vec4(mix(bgColor, fgColor, alpha), 1.0);
}
// Other filters
// This is based on Pixman (MIT license). Copy and pasting the excellent comment
// from there:
// Implementation of radial gradients following the PDF specification.
// See section 8.7.4.5.4 Type 3 (Radial) Shadings of the PDF Reference
// Manual (PDF 32000-1:2008 at the time of this writing).
//
// In the radial gradient problem we are given two circles (c₁,r₁) and
// (c₂,r₂) that define the gradient itself.
//
// Mathematically the gradient can be defined as the family of circles
//
// ((1-t)·c₁ + t·(c₂), (1-t)·r₁ + t·r₂)
//
// excluding those circles whose radius would be < 0. When a point
// belongs to more than one circle, the one with a bigger t is the only
// one that contributes to its color. When a point does not belong
// to any of the circles, it is transparent black, i.e. RGBA (0, 0, 0, 0).
// Further limitations on the range of values for t are imposed when
// the gradient is not repeated, namely t must belong to [0,1].
//
// The graphical result is the same as drawing the valid (radius > 0)
// circles with increasing t in [-∞, +∞] (or in [0,1] if the gradient
// is not repeated) using SOURCE operator composition.
//
// It looks like a cone pointing towards the viewer if the ending circle
// is smaller than the starting one, a cone pointing inside the page if
// the starting circle is the smaller one and like a cylinder if they
// have the same radius.
//
// What we actually do is, given the point whose color we are interested
// in, compute the t values for that point, solving for t in:
//
// length((1-t)·c₁ + t·(c₂) - p) = (1-t)·r₁ + t·r₂
//
// Let's rewrite it in a simpler way, by defining some auxiliary
// variables:
//
// cd = c₂ - c₁
// pd = p - c₁
// dr = r₂ - r₁
// length(t·cd - pd) = r₁ + t·dr
//
// which actually means
//
// hypot(t·cdx - pdx, t·cdy - pdy) = r₁ + t·dr
//
// or
//
// ⎷((t·cdx - pdx)² + (t·cdy - pdy)²) = r₁ + t·dr.
//
// If we impose (as stated earlier) that r₁ + t·dr ≥ 0, it becomes:
//
// (t·cdx - pdx)² + (t·cdy - pdy)² = (r₁ + t·dr)²
//
// where we can actually expand the squares and solve for t:
//
// t²cdx² - 2t·cdx·pdx + pdx² + t²cdy² - 2t·cdy·pdy + pdy² =
// = r₁² + 2·r₁·t·dr + t²·dr²
//
// (cdx² + cdy² - dr²)t² - 2(cdx·pdx + cdy·pdy + r₁·dr)t +
// (pdx² + pdy² - r₁²) = 0
//
// A = cdx² + cdy² - dr²
// B = pdx·cdx + pdy·cdy + r₁·dr
// C = pdx² + pdy² - r₁²
// At² - 2Bt + C = 0
//
// The solutions (unless the equation degenerates because of A = 0) are:
//
// t = (B ± ⎷(B² - A·C)) / A
//
// The solution we are going to prefer is the bigger one, unless the
// radius associated to it is negative (or it falls outside the valid t
// range).
//
// Additional observations (useful for optimizations):
// A does not depend on p
//
// A < 0 ⟺ one of the two circles completely contains the other one
// ⟺ for every p, the radii associated with the two t solutions have
// opposite sign
//
// | x y z w
// --------------+-----------------------------------------------------
// filterParams0 | lineFrom.x lineFrom.y lineVector.x lineVector.y
// filterParams1 | radii.x radii.y uvOrigin.x uvOrigin.y
// filterParams2 | - - - -
vec4 filterRadialGradient(vec2 colorTexCoord,
texture2D colorTexture,
vec2 colorTextureSize,
vec2 fragCoord,
vec2 framebufferSize,
vec4 filterParams0,
vec4 filterParams1) {
vec2 lineFrom = filterParams0.xy, lineVector = filterParams0.zw;
vec2 radii = filterParams1.xy, uvOrigin = filterParams1.zw;
vec2 dP = colorTexCoord - lineFrom, dC = lineVector;
float dR = radii.y - radii.x;
float a = dot(dC, dC) - dR * dR;
float b = dot(dP, dC) + radii.x * dR;
float c = dot(dP, dP) - radii.x * radii.x;
float discrim = b * b - a * c;
vec4 color = vec4(0.0);
if (abs(discrim) >= EPSILON) {
vec2 ts = vec2(sqrt(discrim) * vec2(1.0, -1.0) + vec2(b)) / vec2(a);
if (ts.x > ts.y)
ts = ts.yx;
float t = ts.x >= 0.0 ? ts.x : ts.y;
color = texture(sampler2D(colorTexture, textureSampler), uvOrigin + vec2(clamp(t, 0.0, 1.0), 0.0));
}
return color;
}
// | x y z w
// --------------+----------------------------------------------------
// filterParams0 | srcOffset.x srcOffset.y support -
// filterParams1 | gaussCoeff.x gaussCoeff.y gaussCoeff.z -
// filterParams2 | - - - -
vec4 filterBlur(vec2 colorTexCoord,
texture2D colorTexture,
vec2 colorTextureSize,
vec4 filterParams0,
vec4 filterParams1) {
// Unpack.
vec2 srcOffsetScale = filterParams0.xy / colorTextureSize;
int support = int(filterParams0.z);
vec3 gaussCoeff = filterParams1.xyz;
// Set up our incremental calculation.
float gaussSum = gaussCoeff.x;
vec4 color = texture(sampler2D(colorTexture, textureSampler), colorTexCoord) * gaussCoeff.x;
gaussCoeff.xy *= gaussCoeff.yz;
// This is a common trick that lets us use the texture filtering hardware to evaluate two
// texels at a time. The basic principle is that, if c0 and c1 are colors of adjacent texels
// and k0 and k1 are arbitrary factors, the formula `k0 * c0 + k1 * c1` is equivalent to
// `(k0 + k1) * lerp(c0, c1, k1 / (k0 + k1))`. Linear interpolation, as performed by the
// texturing hardware when sampling adjacent pixels in one direction, evaluates
// `lerp(c0, c1, t)` where t is the offset from the texel with color `c0`. To evaluate the
// formula `k0 * c0 + k1 * c1`, therefore, we can use the texture hardware to perform linear
// interpolation with `t = k1 / (k0 + k1)`.
for (int i = 1; i <= support; i += 2) {
float gaussPartialSum = gaussCoeff.x;
gaussCoeff.xy *= gaussCoeff.yz;
gaussPartialSum += gaussCoeff.x;
vec2 srcOffset = srcOffsetScale * (float(i) + gaussCoeff.x / gaussPartialSum);
color += (texture(sampler2D(colorTexture, textureSampler), colorTexCoord - srcOffset) +
texture(sampler2D(colorTexture, textureSampler), colorTexCoord + srcOffset)) * gaussPartialSum;
gaussSum += 2.0 * gaussPartialSum;
gaussCoeff.xy *= gaussCoeff.yz;
}
// Finish.
return color / gaussSum;
}
vec4 filterNone(vec2 colorTexCoord, texture2D colorTexture) {
return sampleColor(colorTexture, colorTexCoord);
}
vec4 filterColor(vec2 colorTexCoord,
texture2D colorTexture,
texture2D gammaLUT,
vec2 colorTextureSize,
vec2 fragCoord,
vec2 framebufferSize,
vec4 filterParams0,
vec4 filterParams1,
vec4 filterParams2,
int colorFilter) {
switch (colorFilter) {
case COMBINER_CTRL_FILTER_RADIAL_GRADIENT:
return filterRadialGradient(colorTexCoord,
colorTexture,
colorTextureSize,
fragCoord,
framebufferSize,
filterParams0,
filterParams1);
case COMBINER_CTRL_FILTER_BLUR:
return filterBlur(colorTexCoord,
colorTexture,
colorTextureSize,
filterParams0,
filterParams1);
case COMBINER_CTRL_FILTER_TEXT:
return filterText(colorTexCoord,
colorTexture,
gammaLUT,
colorTextureSize,
filterParams0,
filterParams1,
filterParams2);
}
return filterNone(colorTexCoord, colorTexture);
}
// Compositing
vec3 compositeSelect(bvec3 cond, vec3 ifTrue, vec3 ifFalse) {
return vec3(cond.x ? ifTrue.x : ifFalse.x,
cond.y ? ifTrue.y : ifFalse.y,
cond.z ? ifTrue.z : ifFalse.z);
}
float compositeDivide(float num, float denom) {
return denom != 0.0 ? num / denom : 0.0;
}
vec3 compositeColorDodge(vec3 destColor, vec3 srcColor) {
bvec3 destZero = equal(destColor, vec3(0.0)), srcOne = equal(srcColor, vec3(1.0));
return compositeSelect(destZero,
vec3(0.0),
compositeSelect(srcOne, vec3(1.0), destColor / (vec3(1.0) - srcColor)));
}
// https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_RGB_alternative
vec3 compositeHSLToRGB(vec3 hsl) {
float a = hsl.y * min(hsl.z, 1.0 - hsl.z);
vec3 ks = mod(vec3(0.0, 8.0, 4.0) + vec3(hsl.x * FRAC_6_PI), 12.0);
return hsl.zzz - clamp(min(ks - vec3(3.0), vec3(9.0) - ks), -1.0, 1.0) * a;
}
// https://en.wikipedia.org/wiki/HSL_and_HSV#From_RGB
vec3 compositeRGBToHSL(vec3 rgb) {
float v = max(max(rgb.r, rgb.g), rgb.b), xMin = min(min(rgb.r, rgb.g), rgb.b);
float c = v - xMin, l = mix(xMin, v, 0.5);
vec3 terms = rgb.r == v ? vec3(0.0, rgb.gb) :
rgb.g == v ? vec3(2.0, rgb.br) :
vec3(4.0, rgb.rg);
float h = FRAC_PI_3 * compositeDivide(terms.x * c + terms.y - terms.z, c);
float s = compositeDivide(c, v);
return vec3(h, s, l);
}
vec3 compositeScreen(vec3 destColor, vec3 srcColor) {
return destColor + srcColor - destColor * srcColor;
}
vec3 compositeHardLight(vec3 destColor, vec3 srcColor) {
return compositeSelect(lessThanEqual(srcColor, vec3(0.5)),
destColor * vec3(2.0) * srcColor,
compositeScreen(destColor, vec3(2.0) * srcColor - vec3(1.0)));
}
vec3 compositeSoftLight(vec3 destColor, vec3 srcColor) {
vec3 darkenedDestColor =
compositeSelect(lessThanEqual(destColor, vec3(0.25)),
((vec3(16.0) * destColor - 12.0) * destColor + 4.0) * destColor,
sqrt(destColor));
vec3 factor = compositeSelect(lessThanEqual(srcColor, vec3(0.5)),
destColor * (vec3(1.0) - destColor),
darkenedDestColor - destColor);
return destColor + (srcColor * 2.0 - 1.0) * factor;
}
vec3 compositeHSL(vec3 destColor, vec3 srcColor, int op) {
switch (op) {
case COMBINER_CTRL_COMPOSITE_HUE:
return vec3(srcColor.x, destColor.y, destColor.z);
case COMBINER_CTRL_COMPOSITE_SATURATION:
return vec3(destColor.x, srcColor.y, destColor.z);
case COMBINER_CTRL_COMPOSITE_COLOR:
return vec3(srcColor.x, srcColor.y, destColor.z);
default:
return vec3(destColor.x, destColor.y, srcColor.z);
}
}
vec3 compositeRGB(vec3 destColor, vec3 srcColor, int op) {
switch (op) {
case COMBINER_CTRL_COMPOSITE_MULTIPLY:
return destColor * srcColor;
case COMBINER_CTRL_COMPOSITE_SCREEN:
return compositeScreen(destColor, srcColor);
case COMBINER_CTRL_COMPOSITE_OVERLAY:
return compositeHardLight(srcColor, destColor);
case COMBINER_CTRL_COMPOSITE_DARKEN:
return min(destColor, srcColor);
case COMBINER_CTRL_COMPOSITE_LIGHTEN:
return max(destColor, srcColor);
case COMBINER_CTRL_COMPOSITE_COLOR_DODGE:
return compositeColorDodge(destColor, srcColor);
case COMBINER_CTRL_COMPOSITE_COLOR_BURN:
return vec3(1.0) - compositeColorDodge(vec3(1.0) - destColor, vec3(1.0) - srcColor);
case COMBINER_CTRL_COMPOSITE_HARD_LIGHT:
return compositeHardLight(destColor, srcColor);
case COMBINER_CTRL_COMPOSITE_SOFT_LIGHT:
return compositeSoftLight(destColor, srcColor);
case COMBINER_CTRL_COMPOSITE_DIFFERENCE:
return abs(destColor - srcColor);
case COMBINER_CTRL_COMPOSITE_EXCLUSION:
return destColor + srcColor - vec3(2.0) * destColor * srcColor;
case COMBINER_CTRL_COMPOSITE_HUE:
case COMBINER_CTRL_COMPOSITE_SATURATION:
case COMBINER_CTRL_COMPOSITE_COLOR:
case COMBINER_CTRL_COMPOSITE_LUMINOSITY:
return compositeHSLToRGB(compositeHSL(compositeRGBToHSL(destColor),
compositeRGBToHSL(srcColor),
op));
}
return srcColor;
}
vec4 composite(vec4 srcColor,
texture2D destTexture,
vec2 destTextureSize,
vec2 fragCoord,
int op) {
if (op == COMBINER_CTRL_COMPOSITE_NORMAL)
return srcColor;
// FIXME(pcwalton): What should the output alpha be here?
vec2 destTexCoord = fragCoord / destTextureSize;
vec4 destColor = texture(sampler2D(destTexture, textureSampler), destTexCoord);
vec3 blendedRGB = compositeRGB(destColor.rgb, srcColor.rgb, op);
return vec4(srcColor.a * (1.0 - destColor.a) * srcColor.rgb +
srcColor.a * destColor.a * blendedRGB +
(1.0 - srcColor.a) * destColor.rgb,
1.0);
}
// Masks
float sampleMask(float maskAlpha,
texture2D maskTexture,
vec3 maskTexCoord,
int maskCtrl) {
if (maskCtrl == 0)
return maskAlpha;
float coverage = texture(sampler2D(maskTexture, textureSampler), maskTexCoord.xy).r + maskTexCoord.z;
if ((maskCtrl & TILE_CTRL_MASK_WINDING) != 0)
coverage = abs(coverage);
else
coverage = 1.0 - abs(1.0 - mod(coverage, 2.0));
return min(maskAlpha, coverage);
}
// Main function
void calculateColor(int tileCtrl, int ctrl) {
// Sample mask.
int maskCtrl0 = (tileCtrl >> TILE_CTRL_MASK_0_SHIFT) & TILE_CTRL_MASK_MASK;
float maskAlpha = 1.0;
maskAlpha = sampleMask(maskAlpha, uMaskTexture0, vMaskTexCoord0, maskCtrl0);
// Sample color.
vec4 color = vBaseColor;
int color0Combine = (ctrl >> COMBINER_CTRL_COLOR_COMBINE_SHIFT) &
COMBINER_CTRL_COLOR_COMBINE_MASK;
if (color0Combine != 0) {
int color0Filter = (ctrl >> COMBINER_CTRL_COLOR_FILTER_SHIFT) & COMBINER_CTRL_FILTER_MASK;
vec4 color0 = filterColor(vColorTexCoord0,
uColorTexture0,
uGammaLUT,
colorTexture0Size,
gl_FragCoord.xy,
framebufferSize,
filterParams0,
filterParams1,
filterParams2,
color0Filter);
color = combineColor0(color, color0, color0Combine);
}
// Apply mask.
color.a *= maskAlpha;
// Apply composite.
int compositeOp = (ctrl >> COMBINER_CTRL_COMPOSITE_SHIFT) & COMBINER_CTRL_COMPOSITE_MASK;
color = composite(color, uDestTexture, framebufferSize, gl_FragCoord.xy, compositeOp);
// Premultiply alpha.
color.rgb *= color.a;
oFragColor = color;
}
// Entry point
//
// TODO(pcwalton): Generate this dynamically.
void main() {
calculateColor(int(vTileCtrl), ctrl);
}

View file

@ -1,61 +0,0 @@
#version 450
// pathfinder/shaders/tile.vs.glsl
//
// Copyright © 2020 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
precision highp float;
precision highp sampler2D;
layout(set=0, binding=0) uniform uTransform {
mat4 transform;
};
layout(set=0, binding=1) uniform uTileSize {
vec2 tileSize;
};
layout(set=0, binding=2) uniform texture2D uTextureMetadata;
layout(set=0, binding=3) uniform sampler uTextureMetadataSampler;
layout(set=0, binding=4) uniform uTextureMetadataSize {
ivec2 textureMetadataSize;
};
in ivec2 aTileOffset;
in ivec2 aTileOrigin;
in uvec2 aMaskTexCoord0;
in ivec2 aMaskBackdrop;
in int aColor;
in int aTileCtrl;
out vec3 vMaskTexCoord0;
out vec2 vColorTexCoord0;
out vec4 vBaseColor;
out float vTileCtrl;
void main() {
vec2 tileOrigin = vec2(aTileOrigin), tileOffset = vec2(aTileOffset);
vec2 position = (tileOrigin + tileOffset) * tileSize;
vec2 maskTexCoord0 = (vec2(aMaskTexCoord0) + tileOffset) / 256.0;
vec2 textureMetadataScale = vec2(1.0) / vec2(textureMetadataSize);
vec2 metadataEntryCoord = vec2(aColor % 128 * 4, aColor / 128);
vec2 colorTexMatrix0Coord = (metadataEntryCoord + vec2(0.5, 0.5)) * textureMetadataScale;
vec2 colorTexOffsetsCoord = (metadataEntryCoord + vec2(1.5, 0.5)) * textureMetadataScale;
vec2 baseColorCoord = (metadataEntryCoord + vec2(2.5, 0.5)) * textureMetadataScale;
vec4 colorTexMatrix0 = texture(sampler2D(uTextureMetadata, uTextureMetadataSampler), colorTexMatrix0Coord);
vec4 colorTexOffsets = texture(sampler2D(uTextureMetadata, uTextureMetadataSampler), colorTexOffsetsCoord);
vec4 baseColor = texture(sampler2D(uTextureMetadata, uTextureMetadataSampler), baseColorCoord);
vColorTexCoord0 = mat2(colorTexMatrix0) * position + colorTexOffsets.xy;
vMaskTexCoord0 = vec3(maskTexCoord0, float(aMaskBackdrop.x));
vBaseColor = baseColor;
vTileCtrl = float(aTileCtrl);
gl_Position = transform * vec4(position, 0.0, 1.0);
}

View file

@ -1,28 +0,0 @@
#version 450
// pathfinder/shaders/tile_clip.fs.glsl
//
// Copyright © 2020 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
precision highp float;
precision highp sampler2D;
layout(set=0, binding=0) uniform texture2D uSrc;
layout(set=0, binding=1) uniform sampler uSrcSampler;
in vec2 vTexCoord;
in float vBackdrop;
out vec4 oFragColor;
void main() {
vec4 alpha_texture_color = texture(sampler2D(uSrc, uSrcSampler), vTexCoord);
float alpha = clamp(abs(alpha_texture_color.r + vBackdrop), 0.0, 1.0);
oFragColor = vec4(alpha, 0.0, 0.0, 1.0);
}

View file

@ -1,30 +0,0 @@
#version 450
// pathfinder/shaders/tile_clip.vs.glsl
//
// Copyright © 2020 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
precision highp float;
precision highp sampler2D;
in ivec2 aTileOffset;
in ivec2 aDestTileOrigin;
in ivec2 aSrcTileOrigin;
in int aSrcBackdrop;
out vec2 vTexCoord;
out float vBackdrop;
void main() {
vec2 destPosition = vec2(aDestTileOrigin + aTileOffset) / vec2(256.0);
vec2 srcPosition = vec2(aSrcTileOrigin + aTileOffset) / vec2(256.0);
vTexCoord = srcPosition;
vBackdrop = float(aSrcBackdrop);
gl_Position = vec4(mix(vec2(-1.0), vec2(1.0), destPosition), 0.0, 1.0);
}

View file

@ -1,28 +0,0 @@
#version 450
// pathfinder/shaders/tile_copy.vs.glsl
//
// Copyright © 2020 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
precision highp float;
precision highp sampler2D;
layout(set=0, binding=0) uniform uTransform {
mat4 transform;
};
layout(set=0, binding=1) uniform uTileSize {
vec2 tileSize;
};
in ivec2 aTilePosition;
void main() {
vec2 position = vec2(aTilePosition) * tileSize;
gl_Position = transform * vec4(position, 0.0, 1.0);
}

View file

@ -14,7 +14,6 @@ members = [
"examples/canvas_moire",
"examples/canvas_nanovg",
"examples/canvas_text",
"examples/canvas_webgpu_minimal",
"examples/lottie_basic",
"examples/swf_basic",
"geometry",
@ -35,7 +34,6 @@ members = [
"utils/svg-to-skia",
"utils/convert",
"webgl",
"webgpu",
]
default-members = [

View file

@ -1,6 +1,109 @@
# Pathfinder Fork
# Pathfinder 3
Why fork pathfinder? WebGPU does not support some of the datatypes pathfinder uses in its shaders (ex: Short1, Char1). This means both the base shaders and the pathfinder_renderer code needed to change to accommodate that. Ideally these changes can either be merged directly into pathfinder, or be hidden behind a feature flag.
![Logo](https://github.com/servo/pathfinder/raw/master/resources/textures/pathfinder-logo.png)
Pathfinder 3 is a fast, practical, GPU-based rasterizer for fonts and vector graphics using OpenGL
3.0+, OpenGL ES 3.0+, WebGL 2, and Metal.
Forked from commit 84bf4341c253ae36756d27671a17cb44d59cd250
Please note that Pathfinder is under heavy development and is incomplete in various areas.
## Quick start
Pathfinder contains a library that implements a subset of the
[HTML canvas API](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API). You can quickly add
vector rendering to any Rust app with it. The library is available on `crates.io`. See
`examples/canvas_minimal` for a small example of usage.
### Demos
Demo app sources are available in [demo/](https://github.com/servo/pathfinder/tree/master/demo). A prebuilt package for Magic Leap can be found in [releases](https://github.com/servo/pathfinder/releases).
## Features
The project features:
* High quality antialiasing. Pathfinder can compute exact fractional trapezoidal area coverage on a
per-pixel basis for the highest-quality antialiasing possible (effectively 256xAA).
* Fast CPU setup, making full use of parallelism. Pathfinder 3 uses the Rayon library to quickly
perform a CPU tiling prepass to prepare vector scenes for the GPU. This prepass can be pipelined
with the GPU to hide its latency.
* Fast GPU rendering, even at small pixel sizes. Even on lower-end GPUs, Pathfinder typically
matches or exceeds the performance of the best CPU rasterizers. The difference is particularly
pronounced at large sizes, where Pathfinder regularly achieves multi-factor speedups.
* GPU compute-based rendering, where available. Pathfinder can optionally use compute shaders to
achieve better performance than what the built-in GPU rasterization hardware can provide. Compute
shader capability is not required, and all features are available without it.
* Advanced font rendering. Pathfinder can render fonts with slight hinting and can perform subpixel
antialiasing on LCD screens. It can do stem darkening/font dilation like macOS and FreeType in
order to make text easier to read at small sizes. The library also has support for gamma
correction.
* Support for SVG. Pathfinder 3 is designed to efficiently handle workloads that consist of many
overlapping vector paths, such as those commonly found in SVG and PDF files. It can perform
occlusion culling, which often results in dramatic performance wins over typical software
renderers that use the painter's algorithm. A simple loader that leverages the `resvg` library
to render a subset of SVG is included, so it's easy to get started.
* 3D capability. Pathfinder can render fonts and vector paths in 3D environments without any loss
in quality. This is intended to be useful for vector-graphics-based user interfaces in VR, for
example.
* Lightweight. Unlike large vector graphics packages that mix and match many different algorithms,
Pathfinder 3 uses a single, simple technique. It consists of a set of modular crates, so
applications can pick and choose only the components that are necessary to minimize dependencies.
* Portability to most GPUs manufactured in the last decade, including integrated and mobile GPUs.
Geometry, tessellation, and compute shader functionality is not required.
## Building
Pathfinder 3 is a set of modular packages, allowing you to choose which parts of the library you
need. An SVG rendering demo, written in Rust, is included, so you can try Pathfinder out right
away. It also provides an example of how to use the library. (Note that, like the rest of
Pathfinder, the demo is under heavy development and has known bugs.)
Running the demo is as simple as:
$ cd demo/native
$ cargo run --release
Running examples (e.g. `canvas_nanovg`) can be done with:
$ cd examples/canvas_nanovg
$ cargo run --release
Pathfinder libraries are available on `crates.io` with the `pathfinder_` prefix (e.g.
`pathfinder_canvas`), but you may wish to use the `master` branch for the latest features and bug
fixes.
## Community
There's a Matrix chat room available at
[`#pathfinder:mozilla.org`](https://matrix.to/#/!XiDASQfNTTMrJbXHTw:mozilla.org?via=mozilla.org).
If you're on the Mozilla Matrix server, you can search for Pathfinder to find it. For more
information on connecting to the Matrix network, see
[this `wiki.mozilla.org` page](https://wiki.mozilla.org/Matrix).
The entire Pathfinder community, including the chat room and GitHub project, is expected to abide
by the same Code of Conduct that the Rust project itself follows.
## Build status
[![Build Status](https://travis-ci.org/servo/pathfinder.svg?branch=master)](https://travis-ci.org/servo/pathfinder)
## Authors
The primary author is Patrick Walton (@pcwalton), with contributions from the Servo development
community.
The logo was designed by Jay Vining.
## License
Pathfinder is licensed under the same terms as Rust itself. See `LICENSE-APACHE` and `LICENSE-MIT`.
Material Design icons are copyright Google Inc. and licensed under the Apache 2.0 license.

View file

@ -1,52 +0,0 @@
[package]
name = "pathfinder_c"
version = "0.1.0"
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
edition = "2018"
build = "build.rs"
[lib]
crate-type = ["staticlib"]
[dependencies]
font-kit = "0.6"
foreign-types = "0.3"
gl = "0.14"
libc = "0.2"
[dependencies.pathfinder_canvas]
features = ["pf-text"]
path = "../canvas"
[dependencies.pathfinder_color]
path = "../color"
[dependencies.pathfinder_content]
path = "../content"
[dependencies.pathfinder_geometry]
path = "../geometry"
[dependencies.pathfinder_gl]
path = "../gl"
[dependencies.pathfinder_gpu]
path = "../gpu"
[dependencies.pathfinder_renderer]
path = "../renderer"
[dependencies.pathfinder_resources]
path = "../resources"
[dependencies.pathfinder_simd]
path = "../simd"
[target.'cfg(target_os = "macos")'.dependencies]
metal = "0.17"
[target.'cfg(target_os = "macos")'.dependencies.pathfinder_metal]
path = "../metal"
[build-dependencies]
cbindgen = "0.13"

View file

@ -1,20 +0,0 @@
// pathfinder/c/build.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use cbindgen;
use std::env;
use std::fs;
fn main() {
fs::create_dir_all("build/include/pathfinder").expect("Failed to create directories!");
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
cbindgen::generate(crate_dir).expect("cbindgen failed!")
.write_to_file("build/include/pathfinder/pathfinder.h");
}

View file

@ -1,454 +0,0 @@
/* Generated code. Do not edit; instead run `cargo build` in `pathfinder_c`. */
#ifndef PF_PATHFINDER_H
#define PF_PATHFINDER_H
#ifdef __APPLE__
#include <QuartzCore/QuartzCore.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Generated with cbindgen:0.13.2 */
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#define PF_ARC_DIRECTION_CCW 1
#define PF_ARC_DIRECTION_CW 0
#define PF_GL_VERSION_GL3 0
#define PF_GL_VERSION_GLES3 1
#define PF_LINE_CAP_BUTT 0
#define PF_LINE_CAP_ROUND 2
#define PF_LINE_CAP_SQUARE 1
#define PF_LINE_JOIN_BEVEL 1
#define PF_LINE_JOIN_MITER 0
#define PF_LINE_JOIN_ROUND 2
#define PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR 1
#define PF_TEXT_ALIGN_CENTER 1
#define PF_TEXT_ALIGN_LEFT 0
#define PF_TEXT_ALIGN_RIGHT 2
/**
* Options that influence scene building.
*/
typedef struct PFBuildOptionsPrivate PFBuildOptionsPrivate;
typedef struct PFCanvasFontContextPrivate PFCanvasFontContextPrivate;
typedef struct PFCanvasFontContextPrivate PFCanvasFontContextPrivate;
typedef struct PFCanvasRenderingContext2DPrivate PFCanvasRenderingContext2DPrivate;
typedef struct PFDestFramebufferGLDevicePrivate PFDestFramebufferGLDevicePrivate;
typedef struct PFDestFramebufferMetalDevicePrivate PFDestFramebufferMetalDevicePrivate;
typedef struct PFFillStylePrivate PFFillStylePrivate;
typedef struct PFGLDevicePrivate PFGLDevicePrivate;
/**
* Encapsulates the information needed to locate and open a font.
*
* This is either the path to the font or the raw in-memory font data.
*
* To open the font referenced by a handle, use a loader.
*/
typedef struct FKHandlePrivate FKHandlePrivate;
typedef struct PFMetalDevicePrivate PFMetalDevicePrivate;
typedef struct PFPath2DPrivate PFPath2DPrivate;
typedef struct PFRenderTransformPrivate PFRenderTransformPrivate;
typedef struct PFRendererGLDevicePrivate PFRendererGLDevicePrivate;
typedef struct PFRendererMetalDevicePrivate PFRendererMetalDevicePrivate;
typedef struct PFResourceLoaderWrapperPrivate PFResourceLoaderWrapperPrivate;
typedef struct PFScenePrivate PFScenePrivate;
typedef struct PFSceneProxyPrivate PFSceneProxyPrivate;
typedef PFBuildOptionsPrivate *PFBuildOptionsRef;
typedef struct {
float x;
float y;
} PFVector2F;
typedef PFRenderTransformPrivate *PFRenderTransformRef;
typedef PFCanvasRenderingContext2DPrivate *PFCanvasRef;
typedef PFCanvasFontContextPrivate *PFCanvasFontContextRef;
typedef PFScenePrivate *PFSceneRef;
typedef PFPath2DPrivate *PFPathRef;
typedef struct {
PFVector2F origin;
PFVector2F lower_right;
} PFRectF;
typedef FKHandlePrivate *FKHandleRef;
typedef struct {
float width;
} PFTextMetrics;
typedef PFFillStylePrivate *PFFillStyleRef;
typedef uint8_t PFLineCap;
typedef uint8_t PFLineJoin;
typedef uint8_t PFTextAlign;
/**
* Row-major order.
*/
typedef struct {
float m00;
float m01;
float m10;
float m11;
} PFMatrix2x2F;
/**
* Row-major order.
*/
typedef struct {
PFMatrix2x2F matrix;
PFVector2F vector;
} PFTransform2F;
typedef PFResourceLoaderWrapperPrivate *PFResourceLoaderRef;
typedef struct {
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
} PFColorU;
typedef PFDestFramebufferGLDevicePrivate *PFGLDestFramebufferRef;
typedef struct {
int32_t x;
int32_t y;
} PFVector2I;
typedef PFGLDevicePrivate *PFGLDeviceRef;
typedef uint8_t PFGLVersion;
typedef const void *(*PFGLFunctionLoader)(const char *name, void *userdata);
typedef PFRendererGLDevicePrivate *PFGLRendererRef;
typedef struct {
float r;
float g;
float b;
float a;
} PFColorF;
typedef uint8_t PFRendererOptionsFlags;
typedef struct {
PFColorF background_color;
PFRendererOptionsFlags flags;
} PFRendererOptions;
typedef PFDestFramebufferMetalDevicePrivate *PFMetalDestFramebufferRef;
typedef PFMetalDevicePrivate *PFMetalDeviceRef;
typedef PFRendererMetalDevicePrivate *PFMetalRendererRef;
typedef uint8_t PFArcDirection;
/**
* Row-major order.
*/
typedef struct {
float m00;
float m01;
float m02;
float m03;
float m10;
float m11;
float m12;
float m13;
float m20;
float m21;
float m22;
float m23;
float m30;
float m31;
float m32;
float m33;
} PFTransform4F;
typedef struct {
PFTransform4F transform;
PFVector2I window_size;
} PFPerspective;
typedef PFSceneProxyPrivate *PFSceneProxyRef;
PFBuildOptionsRef PFBuildOptionsCreate(void);
void PFBuildOptionsDestroy(PFBuildOptionsRef options);
void PFBuildOptionsSetDilation(PFBuildOptionsRef options, const PFVector2F *dilation);
void PFBuildOptionsSetSubpixelAAEnabled(PFBuildOptionsRef options, bool subpixel_aa_enabled);
/**
* Consumes the transform.
*/
void PFBuildOptionsSetTransform(PFBuildOptionsRef options, PFRenderTransformRef transform);
/**
* This function internally adds a reference to the font context. Therefore, if you created the
* font context, you must release it yourself to avoid a leak.
*/
PFCanvasRef PFCanvasCreate(PFCanvasFontContextRef font_context, const PFVector2F *size);
/**
* This function takes ownership of the supplied canvas and will automatically destroy it when
* the scene is destroyed.
*/
PFSceneRef PFCanvasCreateScene(PFCanvasRef canvas);
void PFCanvasDestroy(PFCanvasRef canvas);
/**
* This function automatically destroys the path. If you wish to use the path again, clone it
* first.
*/
void PFCanvasFillPath(PFCanvasRef canvas, PFPathRef path);
void PFCanvasFillRect(PFCanvasRef canvas, const PFRectF *rect);
void PFCanvasFillText(PFCanvasRef canvas,
const char *string,
uintptr_t string_len,
const PFVector2F *position);
PFCanvasFontContextRef PFCanvasFontContextAddRef(PFCanvasFontContextRef font_context);
PFCanvasFontContextRef PFCanvasFontContextCreateWithFonts(const FKHandleRef *fonts,
uintptr_t font_count);
PFCanvasFontContextRef PFCanvasFontContextCreateWithSystemSource(void);
void PFCanvasFontContextRelease(PFCanvasFontContextRef font_context);
void PFCanvasMeasureText(PFCanvasRef canvas,
const char *string,
uintptr_t string_len,
PFTextMetrics *out_text_metrics);
void PFCanvasResetTransform(PFCanvasRef canvas);
void PFCanvasRestore(PFCanvasRef canvas);
void PFCanvasSave(PFCanvasRef canvas);
void PFCanvasSetFillStyle(PFCanvasRef canvas, PFFillStyleRef fill_style);
void PFCanvasSetFontByPostScriptName(PFCanvasRef canvas,
const char *postscript_name,
uintptr_t postscript_name_len);
void PFCanvasSetFontSize(PFCanvasRef canvas, float new_font_size);
void PFCanvasSetLineCap(PFCanvasRef canvas, PFLineCap new_line_cap);
void PFCanvasSetLineDash(PFCanvasRef canvas,
const float *new_line_dashes,
uintptr_t new_line_dash_count);
void PFCanvasSetLineDashOffset(PFCanvasRef canvas, float new_offset);
void PFCanvasSetLineJoin(PFCanvasRef canvas, PFLineJoin new_line_join);
void PFCanvasSetLineWidth(PFCanvasRef canvas, float new_line_width);
void PFCanvasSetMiterLimit(PFCanvasRef canvas, float new_miter_limit);
void PFCanvasSetStrokeStyle(PFCanvasRef canvas, PFFillStyleRef stroke_style);
void PFCanvasSetTextAlign(PFCanvasRef canvas, PFTextAlign new_text_align);
void PFCanvasSetTransform(PFCanvasRef canvas, const PFTransform2F *transform);
/**
* This function automatically destroys the path. If you wish to use the path again, clone it
* first.
*/
void PFCanvasStrokePath(PFCanvasRef canvas, PFPathRef path);
void PFCanvasStrokeRect(PFCanvasRef canvas, const PFRectF *rect);
void PFCanvasStrokeText(PFCanvasRef canvas,
const char *string,
uintptr_t string_len,
const PFVector2F *position);
PFResourceLoaderRef PFFilesystemResourceLoaderLocate(void);
PFFillStyleRef PFFillStyleCreateColor(const PFColorU *color);
void PFFillStyleDestroy(PFFillStyleRef fill_style);
PFGLDestFramebufferRef PFGLDestFramebufferCreateFullWindow(const PFVector2I *window_size);
void PFGLDestFramebufferDestroy(PFGLDestFramebufferRef dest_framebuffer);
PFGLDeviceRef PFGLDeviceCreate(PFGLVersion version, uint32_t default_framebuffer);
void PFGLDeviceDestroy(PFGLDeviceRef device);
void PFGLLoadWith(PFGLFunctionLoader loader, void *userdata);
/**
* This function takes ownership of and automatically takes responsibility for destroying `device`
* and `dest_framebuffer`. However, it does not take ownership of `resources`; therefore, if you
* created the resource loader, you must destroy it yourself to avoid a memory leak.
*/
PFGLRendererRef PFGLRendererCreate(PFGLDeviceRef device,
PFResourceLoaderRef resources,
PFGLDestFramebufferRef dest_framebuffer,
const PFRendererOptions *options);
void PFGLRendererDestroy(PFGLRendererRef renderer);
PFGLDeviceRef PFGLRendererGetDevice(PFGLRendererRef renderer);
PFMetalDestFramebufferRef PFMetalDestFramebufferCreateFullWindow(const PFVector2I *window_size);
void PFMetalDestFramebufferDestroy(PFMetalDestFramebufferRef dest_framebuffer);
PFMetalDeviceRef PFMetalDeviceCreate(CAMetalLayer *layer);
void PFMetalDeviceDestroy(PFMetalDeviceRef device);
void PFMetalDevicePresentDrawable(PFMetalDeviceRef device);
/**
* This function takes ownership of and automatically takes responsibility for destroying `device`
* and `dest_framebuffer`. However, it does not take ownership of `resources`; therefore, if you
* created the resource loader, you must destroy it yourself to avoid a memory leak.
*/
PFMetalRendererRef PFMetalRendererCreate(PFMetalDeviceRef device,
PFResourceLoaderRef resources,
PFMetalDestFramebufferRef dest_framebuffer,
const PFRendererOptions *options);
void PFMetalRendererDestroy(PFMetalRendererRef renderer);
/**
* Returns a reference to the Metal device in the renderer.
*
* This reference remains valid as long as the device is alive.
*/
PFMetalDeviceRef PFMetalRendererGetDevice(PFMetalRendererRef renderer);
void PFPathArc(PFPathRef path,
const PFVector2F *center,
float radius,
float start_angle,
float end_angle,
PFArcDirection direction);
void PFPathArcTo(PFPathRef path, const PFVector2F *ctrl, const PFVector2F *to, float radius);
void PFPathBezierCurveTo(PFPathRef path,
const PFVector2F *ctrl0,
const PFVector2F *ctrl1,
const PFVector2F *to);
PFPathRef PFPathClone(PFPathRef path);
void PFPathClosePath(PFPathRef path);
PFPathRef PFPathCreate(void);
void PFPathDestroy(PFPathRef path);
void PFPathEllipse(PFPathRef path,
const PFVector2F *center,
const PFVector2F *axes,
float rotation,
float start_angle,
float end_angle);
void PFPathLineTo(PFPathRef path, const PFVector2F *to);
void PFPathMoveTo(PFPathRef path, const PFVector2F *to);
void PFPathQuadraticCurveTo(PFPathRef path, const PFVector2F *ctrl, const PFVector2F *to);
void PFPathRect(PFPathRef path, const PFRectF *rect);
PFRenderTransformRef PFRenderTransformCreate2D(const PFTransform2F *transform);
PFRenderTransformRef PFRenderTransformCreatePerspective(const PFPerspective *perspective);
void PFRenderTransformDestroy(PFRenderTransformRef transform);
void PFResourceLoaderDestroy(PFResourceLoaderRef loader);
void PFSceneDestroy(PFSceneRef scene);
/**
* This function does not take ownership of `renderer` or `build_options`. Therefore, if you
* created the renderer and/or options, you must destroy them yourself to avoid a leak.
*/
void PFSceneProxyBuildAndRenderGL(PFSceneProxyRef scene_proxy,
PFGLRendererRef renderer,
PFBuildOptionsRef build_options);
/**
* This function does not take ownership of `renderer` or `build_options`. Therefore, if you
* created the renderer and/or options, you must destroy them yourself to avoid a leak.
*/
void PFSceneProxyBuildAndRenderMetal(PFSceneProxyRef scene_proxy,
PFMetalRendererRef renderer,
PFBuildOptionsRef build_options);
PFSceneProxyRef PFSceneProxyCreateFromSceneAndRayonExecutor(PFSceneRef scene);
void PFSceneProxyDestroy(PFSceneProxyRef scene_proxy);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,54 +0,0 @@
language = "C"
header = """\
/* Generated code. Do not edit; instead run `cargo build` in `pathfinder_c`. */
#ifndef PF_PATHFINDER_H
#define PF_PATHFINDER_H
#ifdef __APPLE__
#include <QuartzCore/QuartzCore.h>
#endif
#ifdef __cplusplus
extern \"C\" {
#endif
"""
trailer = """\
#ifdef __cplusplus
}
#endif
#endif
"""
include_version = true
[parse]
parse_deps = true
include = [
"font-kit",
"pathfinder_canvas",
"pathfinder_content",
"pathfinder_geometry",
"pathfinder_gl",
"pathfinder_gpu",
"pathfinder_metal",
"pathfinder_renderer",
]
[export.rename]
"BuildOptions" = "PFBuildOptionsPrivate"
"CanvasFontContext" = "PFCanvasFontContextPrivate"
"CanvasRenderingContext2D" = "PFCanvasRenderingContext2DPrivate"
"DestFramebuffer_GLDevice" = "PFDestFramebufferGLDevicePrivate"
"DestFramebuffer_MetalDevice" = "PFDestFramebufferMetalDevicePrivate"
"FillStyle" = "PFFillStylePrivate"
"GLDevice" = "PFGLDevicePrivate"
"Handle" = "FKHandlePrivate"
"MetalDevice" = "PFMetalDevicePrivate"
"Path2D" = "PFPath2DPrivate"
"RenderTransform" = "PFRenderTransformPrivate"
"Renderer_GLDevice" = "PFRendererGLDevicePrivate"
"Renderer_MetalDevice" = "PFRendererMetalDevicePrivate"
"ResourceLoaderWrapper" = "PFResourceLoaderWrapperPrivate"
"Scene" = "PFScenePrivate"
"SceneProxy" = "PFSceneProxyPrivate"

View file

@ -1,811 +0,0 @@
// pathfinder/c/src/lib.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! C bindings to Pathfinder.
use font_kit::handle::Handle;
use foreign_types::ForeignTypeRef;
use gl;
use pathfinder_canvas::{Canvas, CanvasFontContext, CanvasRenderingContext2D, FillStyle, LineJoin};
use pathfinder_canvas::{Path2D, TextAlign, TextMetrics};
use pathfinder_color::{ColorF, ColorU};
use pathfinder_content::fill::FillRule;
use pathfinder_content::outline::ArcDirection;
use pathfinder_content::stroke::LineCap;
use pathfinder_geometry::rect::{RectF, RectI};
use pathfinder_geometry::transform2d::{Matrix2x2F, Transform2F};
use pathfinder_geometry::transform3d::{Perspective, Transform4F};
use pathfinder_geometry::vector::{Vector2F, Vector2I};
use pathfinder_gl::{GLDevice, GLVersion};
use pathfinder_resources::ResourceLoader;
use pathfinder_resources::fs::FilesystemResourceLoader;
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
use pathfinder_renderer::gpu::renderer::Renderer;
use pathfinder_renderer::options::{BuildOptions, RenderTransform};
use pathfinder_renderer::scene::Scene;
use pathfinder_simd::default::F32x4;
use std::ffi::CString;
use std::os::raw::{c_char, c_void};
use std::slice;
use std::str;
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
use metal::{CAMetalLayer, CoreAnimationLayerRef};
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
use pathfinder_metal::MetalDevice;
// Constants
// `canvas`
pub const PF_LINE_CAP_BUTT: u8 = 0;
pub const PF_LINE_CAP_SQUARE: u8 = 1;
pub const PF_LINE_CAP_ROUND: u8 = 2;
pub const PF_LINE_JOIN_MITER: u8 = 0;
pub const PF_LINE_JOIN_BEVEL: u8 = 1;
pub const PF_LINE_JOIN_ROUND: u8 = 2;
pub const PF_TEXT_ALIGN_LEFT: u8 = 0;
pub const PF_TEXT_ALIGN_CENTER: u8 = 1;
pub const PF_TEXT_ALIGN_RIGHT: u8 = 2;
// `content`
pub const PF_ARC_DIRECTION_CW: u8 = 0;
pub const PF_ARC_DIRECTION_CCW: u8 = 1;
// `gl`
pub const PF_GL_VERSION_GL3: u8 = 0;
pub const PF_GL_VERSION_GLES3: u8 = 1;
// `renderer`
pub const PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR: u8 = 0x1;
// Types
// External: `font-kit`
pub type FKHandleRef = *mut Handle;
// `canvas`
pub type PFCanvasRef = *mut CanvasRenderingContext2D;
pub type PFPathRef = *mut Path2D;
pub type PFCanvasFontContextRef = *mut CanvasFontContext;
pub type PFFillStyleRef = *mut FillStyle;
pub type PFLineCap = u8;
pub type PFLineJoin = u8;
pub type PFArcDirection = u8;
pub type PFTextAlign = u8;
#[repr(C)]
pub struct PFTextMetrics {
pub width: f32,
}
// `content`
#[repr(C)]
pub struct PFColorF {
pub r: f32,
pub g: f32,
pub b: f32,
pub a: f32,
}
#[repr(C)]
pub struct PFColorU {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8,
}
// `geometry`
#[repr(C)]
pub struct PFVector2F {
pub x: f32,
pub y: f32,
}
#[repr(C)]
pub struct PFVector2I {
pub x: i32,
pub y: i32,
}
#[repr(C)]
pub struct PFRectF {
pub origin: PFVector2F,
pub lower_right: PFVector2F,
}
#[repr(C)]
pub struct PFRectI {
pub origin: PFVector2I,
pub lower_right: PFVector2I,
}
/// Row-major order.
#[repr(C)]
pub struct PFMatrix2x2F {
pub m00: f32, pub m01: f32,
pub m10: f32, pub m11: f32,
}
/// Row-major order.
#[repr(C)]
pub struct PFTransform2F {
pub matrix: PFMatrix2x2F,
pub vector: PFVector2F,
}
/// Row-major order.
#[repr(C)]
pub struct PFTransform4F {
pub m00: f32, pub m01: f32, pub m02: f32, pub m03: f32,
pub m10: f32, pub m11: f32, pub m12: f32, pub m13: f32,
pub m20: f32, pub m21: f32, pub m22: f32, pub m23: f32,
pub m30: f32, pub m31: f32, pub m32: f32, pub m33: f32,
}
#[repr(C)]
pub struct PFPerspective {
pub transform: PFTransform4F,
pub window_size: PFVector2I,
}
// `gl`
pub type PFGLDeviceRef = *mut GLDevice;
pub type PFGLVersion = u8;
pub type PFGLFunctionLoader = extern "C" fn(name: *const c_char, userdata: *mut c_void)
-> *const c_void;
// `gpu`
pub type PFGLDestFramebufferRef = *mut DestFramebuffer<GLDevice>;
pub type PFGLRendererRef = *mut Renderer<GLDevice>;
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
pub type PFMetalDestFramebufferRef = *mut DestFramebuffer<MetalDevice>;
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
pub type PFMetalRendererRef = *mut Renderer<MetalDevice>;
// FIXME(pcwalton): Double-boxing is unfortunate. Remove this when `std::raw::TraitObject` is
// stable?
pub type PFResourceLoaderRef = *mut ResourceLoaderWrapper;
pub struct ResourceLoaderWrapper(Box<dyn ResourceLoader>);
// `metal`
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
pub type PFMetalDeviceRef = *mut MetalDevice;
// `renderer`
pub type PFSceneRef = *mut Scene;
pub type PFSceneProxyRef = *mut SceneProxy;
#[repr(C)]
pub struct PFRendererOptions {
pub background_color: PFColorF,
pub flags: PFRendererOptionsFlags,
}
pub type PFRendererOptionsFlags = u8;
pub type PFBuildOptionsRef = *mut BuildOptions;
pub type PFRenderTransformRef = *mut RenderTransform;
// `canvas`
/// This function internally adds a reference to the font context. Therefore, if you created the
/// font context, you must release it yourself to avoid a leak.
#[no_mangle]
pub unsafe extern "C" fn PFCanvasCreate(font_context: PFCanvasFontContextRef,
size: *const PFVector2F)
-> PFCanvasRef {
Box::into_raw(Box::new(Canvas::new((*size).to_rust()).get_context_2d((*font_context).clone())))
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasDestroy(canvas: PFCanvasRef) {
drop(Box::from_raw(canvas))
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasFontContextCreateWithSystemSource() -> PFCanvasFontContextRef {
Box::into_raw(Box::new(CanvasFontContext::from_system_source()))
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasFontContextCreateWithFonts(fonts: *const FKHandleRef,
font_count: usize)
-> PFCanvasFontContextRef {
let fonts = slice::from_raw_parts(fonts, font_count);
Box::into_raw(Box::new(CanvasFontContext::from_fonts(fonts.into_iter().map(|font| {
(**font).clone()
}))))
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasFontContextAddRef(font_context: PFCanvasFontContextRef)
-> PFCanvasFontContextRef {
Box::into_raw(Box::new((*font_context).clone()))
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasFontContextRelease(font_context: PFCanvasFontContextRef) {
drop(Box::from_raw(font_context))
}
/// This function takes ownership of the supplied canvas and will automatically destroy it when
/// the scene is destroyed.
#[no_mangle]
pub unsafe extern "C" fn PFCanvasCreateScene(canvas: PFCanvasRef) -> PFSceneRef {
Box::into_raw(Box::new(Box::from_raw(canvas).into_canvas().into_scene()))
}
// Drawing rectangles
#[no_mangle]
pub unsafe extern "C" fn PFCanvasFillRect(canvas: PFCanvasRef, rect: *const PFRectF) {
(*canvas).fill_rect((*rect).to_rust())
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasStrokeRect(canvas: PFCanvasRef, rect: *const PFRectF) {
(*canvas).stroke_rect((*rect).to_rust())
}
// Drawing text
#[no_mangle]
pub unsafe extern "C" fn PFCanvasFillText(canvas: PFCanvasRef,
string: *const c_char,
string_len: usize,
position: *const PFVector2F) {
(*canvas).fill_text(to_rust_string(&string, string_len), (*position).to_rust())
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasStrokeText(canvas: PFCanvasRef,
string: *const c_char,
string_len: usize,
position: *const PFVector2F) {
(*canvas).stroke_text(to_rust_string(&string, string_len), (*position).to_rust())
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasMeasureText(canvas: PFCanvasRef,
string: *const c_char,
string_len: usize,
out_text_metrics: *mut PFTextMetrics) {
debug_assert!(!out_text_metrics.is_null());
*out_text_metrics = (*canvas).measure_text(to_rust_string(&string, string_len)).to_c()
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSetLineWidth(canvas: PFCanvasRef, new_line_width: f32) {
(*canvas).set_line_width(new_line_width)
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSetLineCap(canvas: PFCanvasRef, new_line_cap: PFLineCap) {
(*canvas).set_line_cap(match new_line_cap {
PF_LINE_CAP_SQUARE => LineCap::Square,
PF_LINE_CAP_ROUND => LineCap::Round,
_ => LineCap::Butt,
});
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSetLineJoin(canvas: PFCanvasRef, new_line_join: PFLineJoin) {
(*canvas).set_line_join(match new_line_join {
PF_LINE_JOIN_BEVEL => LineJoin::Bevel,
PF_LINE_JOIN_ROUND => LineJoin::Round,
_ => LineJoin::Miter,
});
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSetMiterLimit(canvas: PFCanvasRef, new_miter_limit: f32) {
(*canvas).set_miter_limit(new_miter_limit);
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSetLineDash(canvas: PFCanvasRef,
new_line_dashes: *const f32,
new_line_dash_count: usize) {
(*canvas).set_line_dash(slice::from_raw_parts(new_line_dashes, new_line_dash_count).to_vec())
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSetTransform(canvas: PFCanvasRef,
transform: *const PFTransform2F) {
(*canvas).set_transform(&(*transform).to_rust());
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasResetTransform(canvas: PFCanvasRef) {
(*canvas).reset_transform();
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSave(canvas: PFCanvasRef) {
(*canvas).save();
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasRestore(canvas: PFCanvasRef) {
(*canvas).restore();
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSetLineDashOffset(canvas: PFCanvasRef, new_offset: f32) {
(*canvas).set_line_dash_offset(new_offset)
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSetFontByPostScriptName(canvas: PFCanvasRef,
postscript_name: *const c_char,
postscript_name_len: usize) {
(*canvas).set_font(to_rust_string(&postscript_name, postscript_name_len))
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSetFontSize(canvas: PFCanvasRef, new_font_size: f32) {
(*canvas).set_font_size(new_font_size)
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSetTextAlign(canvas: PFCanvasRef, new_text_align: PFTextAlign) {
(*canvas).set_text_align(match new_text_align {
PF_TEXT_ALIGN_CENTER => TextAlign::Center,
PF_TEXT_ALIGN_RIGHT => TextAlign::Right,
_ => TextAlign::Left,
});
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSetFillStyle(canvas: PFCanvasRef, fill_style: PFFillStyleRef) {
// FIXME(pcwalton): Avoid the copy?
(*canvas).set_fill_style((*fill_style).clone())
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSetStrokeStyle(canvas: PFCanvasRef,
stroke_style: PFFillStyleRef) {
// FIXME(pcwalton): Avoid the copy?
(*canvas).set_stroke_style((*stroke_style).clone())
}
/// This function automatically destroys the path. If you wish to use the path again, clone it
/// first.
#[no_mangle]
pub unsafe extern "C" fn PFCanvasFillPath(canvas: PFCanvasRef, path: PFPathRef) {
// TODO(pcwalton): Expose fill rules to the C API.
(*canvas).fill_path(*Box::from_raw(path), FillRule::Winding)
}
/// This function automatically destroys the path. If you wish to use the path again, clone it
/// first.
#[no_mangle]
pub unsafe extern "C" fn PFCanvasStrokePath(canvas: PFCanvasRef, path: PFPathRef) {
(*canvas).stroke_path(*Box::from_raw(path))
}
#[no_mangle]
pub unsafe extern "C" fn PFPathCreate() -> PFPathRef {
Box::into_raw(Box::new(Path2D::new()))
}
#[no_mangle]
pub unsafe extern "C" fn PFPathDestroy(path: PFPathRef) {
drop(Box::from_raw(path))
}
#[no_mangle]
pub unsafe extern "C" fn PFPathClone(path: PFPathRef) -> PFPathRef {
Box::into_raw(Box::new((*path).clone()))
}
#[no_mangle]
pub unsafe extern "C" fn PFPathMoveTo(path: PFPathRef, to: *const PFVector2F) {
(*path).move_to((*to).to_rust())
}
#[no_mangle]
pub unsafe extern "C" fn PFPathLineTo(path: PFPathRef, to: *const PFVector2F) {
(*path).line_to((*to).to_rust())
}
#[no_mangle]
pub unsafe extern "C" fn PFPathQuadraticCurveTo(path: PFPathRef,
ctrl: *const PFVector2F,
to: *const PFVector2F) {
(*path).quadratic_curve_to((*ctrl).to_rust(), (*to).to_rust())
}
#[no_mangle]
pub unsafe extern "C" fn PFPathBezierCurveTo(path: PFPathRef,
ctrl0: *const PFVector2F,
ctrl1: *const PFVector2F,
to: *const PFVector2F) {
(*path).bezier_curve_to((*ctrl0).to_rust(), (*ctrl1).to_rust(), (*to).to_rust())
}
#[no_mangle]
pub unsafe extern "C" fn PFPathArc(path: PFPathRef,
center: *const PFVector2F,
radius: f32,
start_angle: f32,
end_angle: f32,
direction: PFArcDirection) {
let direction = if direction == 0 { ArcDirection::CW } else { ArcDirection::CCW };
(*path).arc((*center).to_rust(), radius, start_angle, end_angle, direction)
}
#[no_mangle]
pub unsafe extern "C" fn PFPathArcTo(path: PFPathRef,
ctrl: *const PFVector2F,
to: *const PFVector2F,
radius: f32) {
(*path).arc_to((*ctrl).to_rust(), (*to).to_rust(), radius)
}
#[no_mangle]
pub unsafe extern "C" fn PFPathRect(path: PFPathRef, rect: *const PFRectF) {
(*path).rect((*rect).to_rust())
}
#[no_mangle]
pub unsafe extern "C" fn PFPathEllipse(path: PFPathRef,
center: *const PFVector2F,
axes: *const PFVector2F,
rotation: f32,
start_angle: f32,
end_angle: f32) {
(*path).ellipse((*center).to_rust(), (*axes).to_rust(), rotation, start_angle, end_angle)
}
#[no_mangle]
pub unsafe extern "C" fn PFPathClosePath(path: PFPathRef) {
(*path).close_path()
}
#[no_mangle]
pub unsafe extern "C" fn PFFillStyleCreateColor(color: *const PFColorU) -> PFFillStyleRef {
Box::into_raw(Box::new(FillStyle::Color((*color).to_rust())))
}
#[no_mangle]
pub unsafe extern "C" fn PFFillStyleDestroy(fill_style: PFFillStyleRef) {
drop(Box::from_raw(fill_style))
}
// `gl`
#[no_mangle]
pub unsafe extern "C" fn PFFilesystemResourceLoaderLocate() -> PFResourceLoaderRef {
let loader = Box::new(FilesystemResourceLoader::locate());
Box::into_raw(Box::new(ResourceLoaderWrapper(loader as Box<dyn ResourceLoader>)))
}
#[no_mangle]
pub unsafe extern "C" fn PFGLLoadWith(loader: PFGLFunctionLoader, userdata: *mut c_void) {
gl::load_with(|name| {
let name = CString::new(name).unwrap();
loader(name.as_ptr(), userdata)
});
}
#[no_mangle]
pub unsafe extern "C" fn PFGLDeviceCreate(version: PFGLVersion, default_framebuffer: u32)
-> PFGLDeviceRef {
let version = match version { PF_GL_VERSION_GLES3 => GLVersion::GLES3, _ => GLVersion::GL3 };
Box::into_raw(Box::new(GLDevice::new(version, default_framebuffer)))
}
#[no_mangle]
pub unsafe extern "C" fn PFGLDeviceDestroy(device: PFGLDeviceRef) {
drop(Box::from_raw(device))
}
#[no_mangle]
pub unsafe extern "C" fn PFResourceLoaderDestroy(loader: PFResourceLoaderRef) {
drop(Box::from_raw(loader))
}
// `gpu`
#[no_mangle]
pub unsafe extern "C" fn PFGLDestFramebufferCreateFullWindow(window_size: *const PFVector2I)
-> PFGLDestFramebufferRef {
Box::into_raw(Box::new(DestFramebuffer::full_window((*window_size).to_rust())))
}
#[no_mangle]
pub unsafe extern "C" fn PFGLDestFramebufferDestroy(dest_framebuffer: PFGLDestFramebufferRef) {
drop(Box::from_raw(dest_framebuffer))
}
/// This function takes ownership of and automatically takes responsibility for destroying `device`
/// and `dest_framebuffer`. However, it does not take ownership of `resources`; therefore, if you
/// created the resource loader, you must destroy it yourself to avoid a memory leak.
#[no_mangle]
pub unsafe extern "C" fn PFGLRendererCreate(device: PFGLDeviceRef,
resources: PFResourceLoaderRef,
dest_framebuffer: PFGLDestFramebufferRef,
options: *const PFRendererOptions)
-> PFGLRendererRef {
Box::into_raw(Box::new(Renderer::new(*Box::from_raw(device),
&*((*resources).0),
*Box::from_raw(dest_framebuffer),
(*options).to_rust())))
}
#[no_mangle]
pub unsafe extern "C" fn PFGLRendererDestroy(renderer: PFGLRendererRef) {
drop(Box::from_raw(renderer))
}
#[no_mangle]
pub unsafe extern "C" fn PFGLRendererGetDevice(renderer: PFGLRendererRef) -> PFGLDeviceRef {
&mut (*renderer).device
}
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
#[no_mangle]
pub unsafe extern "C" fn PFMetalDestFramebufferCreateFullWindow(window_size: *const PFVector2I)
-> PFMetalDestFramebufferRef {
Box::into_raw(Box::new(DestFramebuffer::full_window((*window_size).to_rust())))
}
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
#[no_mangle]
pub unsafe extern "C" fn PFMetalDestFramebufferDestroy(dest_framebuffer:
PFMetalDestFramebufferRef) {
drop(Box::from_raw(dest_framebuffer))
}
/// This function takes ownership of and automatically takes responsibility for destroying `device`
/// and `dest_framebuffer`. However, it does not take ownership of `resources`; therefore, if you
/// created the resource loader, you must destroy it yourself to avoid a memory leak.
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
#[no_mangle]
pub unsafe extern "C" fn PFMetalRendererCreate(device: PFMetalDeviceRef,
resources: PFResourceLoaderRef,
dest_framebuffer: PFMetalDestFramebufferRef,
options: *const PFRendererOptions)
-> PFMetalRendererRef {
Box::into_raw(Box::new(Renderer::new(*Box::from_raw(device),
&*((*resources).0),
*Box::from_raw(dest_framebuffer),
(*options).to_rust())))
}
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
#[no_mangle]
pub unsafe extern "C" fn PFMetalRendererDestroy(renderer: PFMetalRendererRef) {
drop(Box::from_raw(renderer))
}
/// Returns a reference to the Metal device in the renderer.
///
/// This reference remains valid as long as the device is alive.
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
#[no_mangle]
pub unsafe extern "C" fn PFMetalRendererGetDevice(renderer: PFMetalRendererRef)
-> PFMetalDeviceRef {
&mut (*renderer).device
}
/// This function does not take ownership of `renderer` or `build_options`. Therefore, if you
/// created the renderer and/or options, you must destroy them yourself to avoid a leak.
#[no_mangle]
pub unsafe extern "C" fn PFSceneProxyBuildAndRenderGL(scene_proxy: PFSceneProxyRef,
renderer: PFGLRendererRef,
build_options: PFBuildOptionsRef) {
(*scene_proxy).build_and_render(&mut *renderer, (*build_options).clone())
}
/// This function does not take ownership of `renderer` or `build_options`. Therefore, if you
/// created the renderer and/or options, you must destroy them yourself to avoid a leak.
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
#[no_mangle]
pub unsafe extern "C" fn PFSceneProxyBuildAndRenderMetal(scene_proxy: PFSceneProxyRef,
renderer: PFMetalRendererRef,
build_options: PFBuildOptionsRef) {
(*scene_proxy).build_and_render(&mut *renderer, (*build_options).clone())
}
// `metal`
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
#[no_mangle]
pub unsafe extern "C" fn PFMetalDeviceCreate(layer: *mut CAMetalLayer)
-> PFMetalDeviceRef {
Box::into_raw(Box::new(MetalDevice::new(CoreAnimationLayerRef::from_ptr(layer))))
}
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
#[no_mangle]
pub unsafe extern "C" fn PFMetalDeviceDestroy(device: PFMetalDeviceRef) {
drop(Box::from_raw(device))
}
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
#[no_mangle]
pub unsafe extern "C" fn PFMetalDevicePresentDrawable(device: PFMetalDeviceRef) {
(*device).present_drawable()
}
// `renderer`
#[no_mangle]
pub unsafe extern "C" fn PFRenderTransformCreate2D(transform: *const PFTransform2F)
-> PFRenderTransformRef {
Box::into_raw(Box::new(RenderTransform::Transform2D((*transform).to_rust())))
}
#[no_mangle]
pub unsafe extern "C" fn PFRenderTransformCreatePerspective(perspective: *const PFPerspective)
-> PFRenderTransformRef {
Box::into_raw(Box::new(RenderTransform::Perspective((*perspective).to_rust())))
}
#[no_mangle]
pub unsafe extern "C" fn PFRenderTransformDestroy(transform: PFRenderTransformRef) {
drop(Box::from_raw(transform))
}
#[no_mangle]
pub unsafe extern "C" fn PFBuildOptionsCreate() -> PFBuildOptionsRef {
Box::into_raw(Box::new(BuildOptions::default()))
}
#[no_mangle]
pub unsafe extern "C" fn PFBuildOptionsDestroy(options: PFBuildOptionsRef) {
drop(Box::from_raw(options))
}
/// Consumes the transform.
#[no_mangle]
pub unsafe extern "C" fn PFBuildOptionsSetTransform(options: PFBuildOptionsRef,
transform: PFRenderTransformRef) {
(*options).transform = *Box::from_raw(transform)
}
#[no_mangle]
pub unsafe extern "C" fn PFBuildOptionsSetDilation(options: PFBuildOptionsRef,
dilation: *const PFVector2F) {
(*options).dilation = (*dilation).to_rust()
}
#[no_mangle]
pub unsafe extern "C" fn PFBuildOptionsSetSubpixelAAEnabled(options: PFBuildOptionsRef,
subpixel_aa_enabled: bool) {
(*options).subpixel_aa_enabled = subpixel_aa_enabled
}
#[no_mangle]
pub unsafe extern "C" fn PFSceneDestroy(scene: PFSceneRef) {
drop(Box::from_raw(scene))
}
#[no_mangle]
pub unsafe extern "C" fn PFSceneProxyCreateFromSceneAndRayonExecutor(scene: PFSceneRef)
-> PFSceneProxyRef {
Box::into_raw(Box::new(SceneProxy::from_scene(*Box::from_raw(scene), RayonExecutor)))
}
#[no_mangle]
pub unsafe extern "C" fn PFSceneProxyDestroy(scene_proxy: PFSceneProxyRef) {
drop(Box::from_raw(scene_proxy))
}
// Helpers for `canvas`
unsafe fn to_rust_string(ptr: &*const c_char, mut len: usize) -> &str {
if len == 0 {
len = libc::strlen(*ptr);
}
str::from_utf8(slice::from_raw_parts(*ptr as *const u8, len)).unwrap()
}
trait TextMetricsExt {
fn to_c(&self) -> PFTextMetrics;
}
impl TextMetricsExt for TextMetrics {
fn to_c(&self) -> PFTextMetrics {
PFTextMetrics { width: self.width }
}
}
// Helpers for `content`
impl PFColorF {
#[inline]
pub fn to_rust(&self) -> ColorF {
ColorF(F32x4::new(self.r, self.g, self.b, self.a))
}
}
impl PFColorU {
#[inline]
pub fn to_rust(&self) -> ColorU {
ColorU { r: self.r, g: self.g, b: self.b, a: self.a }
}
}
// Helpers for `geometry`
impl PFRectF {
#[inline]
pub fn to_rust(&self) -> RectF {
RectF::from_points(self.origin.to_rust(), self.lower_right.to_rust())
}
}
impl PFRectI {
#[inline]
pub fn to_rust(&self) -> RectI {
RectI::from_points(self.origin.to_rust(), self.lower_right.to_rust())
}
}
impl PFVector2F {
#[inline]
pub fn to_rust(&self) -> Vector2F {
Vector2F::new(self.x, self.y)
}
}
impl PFVector2I {
#[inline]
pub fn to_rust(&self) -> Vector2I {
Vector2I::new(self.x, self.y)
}
}
impl PFMatrix2x2F {
#[inline]
pub fn to_rust(&self) -> Matrix2x2F {
Matrix2x2F::row_major(self.m00, self.m01, self.m10, self.m11)
}
}
impl PFTransform2F {
#[inline]
pub fn to_rust(&self) -> Transform2F {
Transform2F { matrix: self.matrix.to_rust(), vector: self.vector.to_rust() }
}
}
impl PFTransform4F {
#[inline]
pub fn to_rust(&self) -> Transform4F {
Transform4F::row_major(self.m00, self.m01, self.m02, self.m03,
self.m10, self.m11, self.m12, self.m13,
self.m20, self.m21, self.m22, self.m23,
self.m30, self.m31, self.m32, self.m33)
}
}
impl PFPerspective {
#[inline]
pub fn to_rust(&self) -> Perspective {
Perspective {
transform: self.transform.to_rust(),
window_size: self.window_size.to_rust(),
}
}
}
// Helpers for `renderer`
impl PFRendererOptions {
pub fn to_rust(&self) -> RendererOptions {
let has_background_color = self.flags & PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR;
RendererOptions {
background_color: if has_background_color != 0 {
Some(self.background_color.to_rust())
} else {
None
},
}
}
}

View file

@ -1,10 +0,0 @@
*.iml
.gradle
/local.properties
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
.DS_Store
/build
/captures
.externalNativeBuild

View file

@ -1 +0,0 @@
/build

View file

@ -1,34 +0,0 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
defaultConfig {
applicationId "graphics.pathfinder.pathfinderdemo"
minSdkVersion 24
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
ndk {
abiFilters "arm64-v8a"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
compile 'com.google.vr:sdk-base:1.160.0'
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:support-v4:27.1.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

View file

@ -1,21 +0,0 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View file

@ -1,67 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="graphics.pathfinder.pathfinderdemo">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-feature
android:name="android.software.vr.mode"
android:required="false" />
<uses-feature
android:name="android.hardware.vr.high_performance"
android:required="false" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".PathfinderDemoActivity"
android:configChanges="density|navigation|orientation|keyboardHidden|screenSize|uiMode"
android:label="@string/app_name"
android:resizeableActivity="false"
android:theme="@style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<!--
This marks the Activity as a Daydream Activity and allows it
to be launched from the Daydream Home.
-->
<category android:name="com.google.intent.category.DAYDREAM" />
<!--
This marks the Activity as a Cardboard Activity and allows it
to be launched from the Cardboard app.
-->
<category android:name="com.google.intent.category.CARDBOARD" />
<!--
This allows this Activity to be launched from the traditional
Android 2D launcher as well. Remove it if you do not want
this Activity to be launched directly from the 2D launcher.
-->
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".PathfinderDemoVRListenerService"
android:label="@string/service_name"
android:permission="android.permission.BIND_VR_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.vr.VrListenerService" />
</intent-filter>
</service>
<activity
android:name=".PathfinderDemoFileBrowserActivity"
android:label="@string/title_activity_pathfinder_demo_file_browser"></activity>
</application>
</manifest>

View file

@ -1 +0,0 @@
../../../../../../resources

View file

@ -1,178 +0,0 @@
package graphics.pathfinder.pathfinderdemo;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
/**
* An example full-screen activity that shows and hides the system UI (i.e.
* status bar and navigation/system bar) with user interaction.
*/
public class PathfinderDemoActivity extends Activity {
private PathfinderDemoRenderer mRenderer;
/**
* Some older devices needs a small delay between UI widget updates
* and a change of the status and navigation bar.
*/
private PathfinderDemoSurfaceView mContentView;
private GestureDetector mGestureDetector;
private ScaleGestureDetector mScaleGestureDetector;
ComponentName mVRListenerComponentName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
String[] perms = new String[1];
perms[0] = Manifest.permission.READ_EXTERNAL_STORAGE;
ActivityCompat.requestPermissions(this, perms,
1);
} else {
init();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (permissions[0] == Manifest.permission.READ_EXTERNAL_STORAGE)
init();
}
@RequiresApi(api = Build.VERSION_CODES.N)
void setVRMode(boolean enabled) {
mContentView.setStereoModeEnabled(enabled);
mContentView.setDistortionCorrectionEnabled(false);
}
@RequiresApi(api = Build.VERSION_CODES.N)
@SuppressLint("ClickableViewAccessibility")
private void init() {
mVRListenerComponentName = new ComponentName("graphics.pathfinder.pathfinderdemo",
"graphics.pathfinder.pathfinderdemo.PathfinderDemoVRListenerService");
setContentView(R.layout.activity_pathfinder);
mContentView = findViewById(R.id.fullscreen_content);
setVRMode(false);
mContentView.setEGLContextClientVersion(3);
mRenderer = new PathfinderDemoRenderer(this);
mContentView.setRenderer(mRenderer);
GestureDetector.SimpleOnGestureListener gestureListener =
new GestureDetector.SimpleOnGestureListener() {
public boolean onScroll(final MotionEvent from,
final MotionEvent to,
final float deltaX,
final float deltaY) {
final int x = Math.round(to.getX());
final int y = Math.round(to.getY());
PathfinderDemoRenderer.pushMouseDraggedEvent(x, y);
return true;
}
public boolean onDown(final MotionEvent event) {
final int x = Math.round(event.getX());
final int y = Math.round(event.getY());
PathfinderDemoRenderer.pushMouseDownEvent(x, y);
return true;
}
};
mGestureDetector = new GestureDetector(getApplicationContext(), gestureListener);
ScaleGestureDetector.SimpleOnScaleGestureListener scaleGestureListener =
new ScaleGestureDetector.SimpleOnScaleGestureListener() {
public boolean onScale(final ScaleGestureDetector detector) {
int focusX = Math.round(detector.getFocusX());
int focusY = Math.round(detector.getFocusY());
float factor = (detector.getScaleFactor() - 1.0f) * 0.5f;
PathfinderDemoRenderer.pushZoomEvent(factor, focusX, focusY);
return true;
}
};
mScaleGestureDetector = new ScaleGestureDetector(getApplicationContext(),
scaleGestureListener);
mContentView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(final View view, final MotionEvent event) {
boolean result = mScaleGestureDetector.onTouchEvent(event);
if (!mScaleGestureDetector.isInProgress())
result = mGestureDetector.onTouchEvent(event) || result;
return result;
}
});
final SensorManager sensorManager = (SensorManager)
getSystemService(Context.SENSOR_SERVICE);
final Sensor rotationSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
sensorManager.registerListener(new SensorEventListener() {
private boolean mInitialized;
private float mPitch;
private float mYaw;
@Override
public void onSensorChanged(SensorEvent event) {
// https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles#Quaternion_to_Euler_Angles_Conversion
final float[] q = event.values;
final float pitch = (float)Math.asin(2.0 * (q[0] * q[2] - q[3] * q[1]));
final float yaw = (float)Math.atan2(2.0 * (q[0] * q[3] + q[1] * q[2]),
1.0 - 2.0 * (q[2] * q[2] + q[3] * q[3]));
final float deltaPitch = pitch - mPitch;
final float deltaYaw = yaw - mYaw;
mPitch = pitch;
mYaw = yaw;
if (!mInitialized) {
mInitialized = true;
return;
}
PathfinderDemoRenderer.pushLookEvent(-deltaPitch, deltaYaw);
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}, rotationSensor, 5000);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
}
public void presentOpenSVGDialog() {
final Intent intent = new Intent(this, PathfinderDemoFileBrowserActivity.class);
startActivity(intent);
}
}

View file

@ -1,47 +0,0 @@
package graphics.pathfinder.pathfinderdemo;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import java.io.IOException;
public class PathfinderDemoFileBrowserActivity extends Activity {
private ListView mBrowserView;
private static String SVG_RESOURCE_PATH = "svg/";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pathfinder_demo_file_browser);
mBrowserView = findViewById(R.id.fileBrowserBrowser);
try {
final AssetManager assetManager = getAssets();
final String[] svgFilenames = assetManager.list("resources/" + SVG_RESOURCE_PATH);
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(
this,
R.layout.layout_pathfinder_demo_file_browser_list_item,
svgFilenames);
mBrowserView.setAdapter(adapter);
} catch (IOException exception) {
throw new RuntimeException(exception);
}
mBrowserView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
TextView textView = (TextView)view;
PathfinderDemoRenderer.pushOpenSVGEvent(SVG_RESOURCE_PATH + textView.getText());
finish();
}
});
}
}

View file

@ -1,96 +0,0 @@
package graphics.pathfinder.pathfinderdemo;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.util.Log;
import com.google.vr.sdk.base.Eye;
import com.google.vr.sdk.base.GvrView;
import com.google.vr.sdk.base.HeadTransform;
import com.google.vr.sdk.base.Viewport;
import javax.microedition.khronos.egl.EGLConfig;
public class PathfinderDemoRenderer extends Object implements GvrView.Renderer {
private final PathfinderDemoActivity mActivity;
private boolean mInitialized;
private boolean mInVRMode;
private static native void init(PathfinderDemoActivity activity,
PathfinderDemoResourceLoader resourceLoader,
int width,
int height);
private static native int prepareFrame();
private static native void drawScene();
private static native void finishDrawingFrame();
public static native void pushWindowResizedEvent(int width, int height);
public static native void pushMouseDownEvent(int x, int y);
public static native void pushMouseDraggedEvent(int x, int y);
public static native void pushZoomEvent(float scale, int centerX, int centerY);
public static native void pushLookEvent(float pitch, float yaw);
public static native void pushOpenSVGEvent(String path);
static {
System.loadLibrary("pathfinder_android_demo");
}
PathfinderDemoRenderer(PathfinderDemoActivity activity) {
super();
mActivity = activity;
mInitialized = false;
}
@Override
public void onDrawFrame(HeadTransform headTransform, Eye leftEye, Eye rightEye) {
final boolean inVR = prepareFrame() > 1;
if (inVR != mInVRMode) {
mInVRMode = inVR;
try {
mActivity.setVrModeEnabled(mInVRMode, mActivity.mVRListenerComponentName);
mActivity.setVRMode(inVR);
} catch (PackageManager.NameNotFoundException exception) {
throw new RuntimeException(exception);
}
}
drawScene();
finishDrawingFrame();
}
@Override
public void onFinishFrame(Viewport viewport) {
}
@Override
public void onSurfaceChanged(int width, int height) {
if (!mInitialized) {
init(mActivity,
new PathfinderDemoResourceLoader(mActivity.getAssets()),
width,
height);
mInitialized = true;
} else {
pushWindowResizedEvent(width, height);
}
}
@Override
public void onSurfaceCreated(EGLConfig config) {
}
@Override
public void onRendererShutdown() {
}
}

View file

@ -1,40 +0,0 @@
package graphics.pathfinder.pathfinderdemo;
import android.content.res.AssetManager;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
public class PathfinderDemoResourceLoader {
private AssetManager m_assetManager;
PathfinderDemoResourceLoader(AssetManager assetManager) {
m_assetManager = assetManager;
}
ByteBuffer slurp(String path) {
try {
InputStream inputStream = m_assetManager.open("resources/" + path);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
while (true) {
int nRead = inputStream.read(buffer, 0, buffer.length);
if (nRead == -1)
break;
outputStream.write(buffer, 0, nRead);
}
byte[] outputBytes = outputStream.toByteArray();
ByteBuffer resultBuffer = ByteBuffer.allocateDirect(outputStream.size());
resultBuffer.put(outputBytes);
return resultBuffer;
} catch (IOException exception) {
Log.e("Pathfinder", "Resource not found: " + path);
return null;
}
}
}

View file

@ -1,15 +0,0 @@
package graphics.pathfinder.pathfinderdemo;
import android.content.Context;
import android.util.AttributeSet;
import com.google.vr.sdk.base.GvrView;
public class PathfinderDemoSurfaceView extends GvrView {
public PathfinderDemoSurfaceView(Context context) {
super(context);
}
public PathfinderDemoSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
}
}

View file

@ -1,10 +0,0 @@
package graphics.pathfinder.pathfinderdemo;
import android.os.Build;
import android.service.vr.VrListenerService;
import android.support.annotation.RequiresApi;
@RequiresApi(api = Build.VERSION_CODES.N)
public class PathfinderDemoVRListenerService extends VrListenerService {
}

View file

@ -1 +0,0 @@
../../../../../../../target/aarch64-linux-android/release/libpathfinder_android_demo.so

View file

@ -1,34 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeColor="#00000000"
android:strokeWidth="1">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeColor="#00000000"
android:strokeWidth="1" />
</vector>

View file

@ -1,170 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillColor="#26A69A"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
</vector>

View file

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#0099cc"
tools:context=".PathfinderDemoActivity">
<!-- The primary full-screen view. This can be replaced with whatever view
is needed to present your content, e.g. VideoView, SurfaceView,
TextureView, etc. -->
<graphics.pathfinder.pathfinderdemo.PathfinderDemoSurfaceView
android:id="@+id/fullscreen_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:keepScreenOn="true" />
<!-- This FrameLayout insets its children based on system windows using
android:fitsSystemWindows. -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<LinearLayout
android:id="@+id/fullscreen_content_controls"
style="?metaButtonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:background="@color/black_overlay"
android:orientation="horizontal"
tools:ignore="UselessParent">
</LinearLayout>
</FrameLayout>
</FrameLayout>

View file

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".PathfinderDemoFileBrowserActivity">
<ListView
android:id="@+id/fileBrowserBrowser"
style="@android:style/Widget.Material.ListView"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</LinearLayout>

View file

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:lineSpacingExtra="14sp"
android:textAppearance="@android:style/TextAppearance"
android:textSize="18sp">
</TextView>

View file

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View file

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View file

@ -1,12 +0,0 @@
<resources>
<!-- Declare custom theme attributes that allow changing which styles are
used for button bars depending on the API level.
?android:attr/buttonBarStyle is new as of API 11 so this is
necessary to support previous API levels. -->
<declare-styleable name="ButtonBarContainerTheme">
<attr name="metaButtonBarStyle" format="reference" />
<attr name="metaButtonBarButtonStyle" format="reference" />
</declare-styleable>
</resources>

View file

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="black_overlay">#66000000</color>
</resources>

View file

@ -1,9 +0,0 @@
<resources>
<string name="app_name">Pathfinder Demo</string>
<string name="dummy_button">Dummy Button</string>
<string name="dummy_content">DUMMY\nCONTENT</string>
<string name="service_name">PathfinderVRListenerService</string>
<string name="title_activity_pathfinder_demo_file_browser">PathfinderDemoFileBrowserActivity
</string>
</resources>

View file

@ -1,23 +0,0 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="FullscreenTheme" parent="AppTheme">
<item name="android:actionBarStyle">@style/FullscreenActionBarStyle</item>
<item name="android:windowActionBarOverlay">true</item>
<item name="android:windowBackground">@null</item>
<item name="metaButtonBarStyle">?android:attr/buttonBarStyle</item>
<item name="metaButtonBarButtonStyle">?android:attr/buttonBarButtonStyle</item>
</style>
<style name="FullscreenActionBarStyle" parent="Widget.AppCompat.ActionBar">
<item name="android:background">@color/black_overlay</item>
</style>
</resources>

View file

@ -1,27 +0,0 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

View file

@ -1,14 +0,0 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
android.useDeprecatedNdk=true

View file

@ -1,6 +0,0 @@
#Fri Mar 08 12:48:37 PST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip

View file

@ -1,172 +0,0 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

View file

@ -1,84 +0,0 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View file

@ -1,26 +0,0 @@
[package]
name = "pathfinder_android_demo"
version = "0.1.0"
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
edition = "2018"
[lib]
crate_type = ["cdylib"]
[dependencies]
egl = "0.2"
gl = "0.14"
jni = "0.15"
lazy_static = "1.3"
[dependencies.pathfinder_demo]
path = "../../common"
[dependencies.pathfinder_geometry]
path = "../../../geometry"
[dependencies.pathfinder_gl]
path = "../../../gl"
[dependencies.pathfinder_gpu]
path = "../../../gpu"

View file

@ -1,294 +0,0 @@
// pathfinder/demo/android/rust/src/main.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate lazy_static;
use jni::objects::{GlobalRef, JByteBuffer, JClass, JObject, JString, JValue};
use jni::{JNIEnv, JavaVM};
use pathfinder_demo::window::{Event, SVGPath, View, Window, WindowSize};
use pathfinder_demo::DemoApp;
use pathfinder_demo::Options;
use pathfinder_geometry::vector::{Vector2I, vec2i};
use pathfinder_geometry::rect::RectI;
use pathfinder_gl::GLVersion;
use pathfinder_resources::ResourceLoader;
use std::cell::RefCell;
use std::io::Error as IOError;
use std::mem;
use std::os::raw::c_void;
use std::path::PathBuf;
use std::sync::Mutex;
lazy_static! {
static ref EVENT_QUEUE: Mutex<Vec<Event>> = Mutex::new(vec![]);
}
thread_local! {
static DEMO_APP: RefCell<Option<DemoApp<WindowImpl>>> = RefCell::new(None);
static JAVA_ACTIVITY: RefCell<Option<JavaActivity>> = RefCell::new(None);
static JAVA_RESOURCE_LOADER: RefCell<Option<JavaResourceLoader>> = RefCell::new(None);
}
static RESOURCE_LOADER: AndroidResourceLoader = AndroidResourceLoader;
#[no_mangle]
pub unsafe extern "system" fn Java_graphics_pathfinder_pathfinderdemo_PathfinderDemoRenderer_init(
env: JNIEnv,
class: JClass,
activity: JObject,
loader: JObject,
width: i32,
height: i32,
) {
let logical_size = vec2i(width, height);
let window_size = WindowSize {
logical_size,
backing_scale_factor: 1.0,
};
let window = WindowImpl { size: logical_size };
let options = Options::default();
JAVA_ACTIVITY.with(|java_activity| {
*java_activity.borrow_mut() = Some(JavaActivity::new(env.clone(), activity));
});
JAVA_RESOURCE_LOADER.with(|java_resource_loader| {
*java_resource_loader.borrow_mut() = Some(JavaResourceLoader::new(env, loader));
});
DEMO_APP.with(|demo_app| {
gl::load_with(|name| egl::get_proc_address(name) as *const c_void);
*demo_app.borrow_mut() = Some(DemoApp::new(window, window_size, options));
});
}
#[no_mangle]
pub unsafe extern "system" fn Java_graphics_pathfinder_pathfinderdemo_PathfinderDemoRenderer_prepareFrame(
env: JNIEnv,
class: JClass,
) -> i32 {
DEMO_APP.with(|demo_app| {
let mut event_queue = EVENT_QUEUE.lock().unwrap();
match *demo_app.borrow_mut() {
Some(ref mut demo_app) => {
demo_app.prepare_frame(mem::replace(&mut *event_queue, vec![])) as i32
}
None => 0,
}
})
}
#[no_mangle]
pub unsafe extern "system" fn Java_graphics_pathfinder_pathfinderdemo_PathfinderDemoRenderer_drawScene(
env: JNIEnv,
class: JClass,
) {
DEMO_APP.with(|demo_app| {
if let Some(ref mut demo_app) = *demo_app.borrow_mut() {
demo_app.draw_scene()
}
})
}
#[no_mangle]
pub unsafe extern "system" fn Java_graphics_pathfinder_pathfinderdemo_PathfinderDemoRenderer_finishDrawingFrame(
env: JNIEnv,
class: JClass,
) {
DEMO_APP.with(|demo_app| {
if let Some(ref mut demo_app) = *demo_app.borrow_mut() {
demo_app.finish_drawing_frame()
}
})
}
#[no_mangle]
pub unsafe extern "system" fn Java_graphics_pathfinder_pathfinderdemo_PathfinderDemoRenderer_pushWindowResizedEvent(
env: JNIEnv,
class: JClass,
width: i32,
height: i32,
) {
EVENT_QUEUE
.lock()
.unwrap()
.push(Event::WindowResized(WindowSize {
logical_size: vec2i(width, height),
backing_scale_factor: 1.0,
}))
}
#[no_mangle]
pub unsafe extern "system" fn Java_graphics_pathfinder_pathfinderdemo_PathfinderDemoRenderer_pushMouseDownEvent(
_: JNIEnv,
_: JClass,
x: i32,
y: i32,
) {
EVENT_QUEUE.lock().unwrap().push(Event::MouseDown(vec2i(x, y)))
}
#[no_mangle]
pub unsafe extern "system" fn Java_graphics_pathfinder_pathfinderdemo_PathfinderDemoRenderer_pushMouseDraggedEvent(
_: JNIEnv,
_: JClass,
x: i32,
y: i32,
) {
EVENT_QUEUE.lock().unwrap().push(Event::MouseDragged(vec2i(x, y)))
}
#[no_mangle]
pub unsafe extern "system" fn Java_graphics_pathfinder_pathfinderdemo_PathfinderDemoRenderer_pushZoomEvent(
_: JNIEnv,
_: JClass,
factor: f32,
center_x: i32,
center_y: i32,
) {
EVENT_QUEUE.lock().unwrap().push(Event::Zoom(factor, vec2i(center_x, center_y)))
}
#[no_mangle]
pub unsafe extern "system" fn Java_graphics_pathfinder_pathfinderdemo_PathfinderDemoRenderer_pushLookEvent(
_: JNIEnv,
_: JClass,
pitch: f32,
yaw: f32,
) {
EVENT_QUEUE.lock().unwrap().push(Event::Look { pitch, yaw })
}
#[no_mangle]
pub unsafe extern "system" fn Java_graphics_pathfinder_pathfinderdemo_PathfinderDemoRenderer_pushOpenSVGEvent(
env: JNIEnv,
_: JClass,
string: JObject,
) {
let string: String = env.get_string(JString::from(string)).unwrap().into();
EVENT_QUEUE
.lock()
.unwrap()
.push(Event::OpenSVG(SVGPath::Resource(string)))
}
struct WindowImpl {
size: Vector2I,
}
impl Window for WindowImpl {
fn gl_version(&self) -> GLVersion {
GLVersion::GLES3
}
fn viewport(&self, view: View) -> RectI {
let mut width = self.size.x();
let mut offset_x = 0;
let height = self.size.y();
if let View::Stereo(index) = view {
width = width / 2;
offset_x = (index as i32) * width;
}
let size = vec2i(width, height);
let offset = vec2i(offset_x, 0);
RectI::new(offset, size)
}
fn make_current(&mut self, _view: View) {}
fn present(&mut self) {}
fn resource_loader(&self) -> &dyn ResourceLoader {
&RESOURCE_LOADER
}
fn create_user_event_id(&self) -> u32 {
0
}
fn push_user_event(message_type: u32, message_data: u32) {}
fn present_open_svg_dialog(&mut self) {
JAVA_ACTIVITY.with(|java_activity| {
let mut java_activity = java_activity.borrow_mut();
let java_activity = java_activity.as_mut().unwrap();
let env = java_activity.vm.get_env().unwrap();
env.call_method(
java_activity.activity.as_obj(),
"presentOpenSVGDialog",
"()V",
&[],
)
.unwrap();
});
}
fn run_save_dialog(&self, extension: &str) -> Result<PathBuf, ()> {
// TODO(pcwalton)
Err(())
}
}
struct AndroidResourceLoader;
impl ResourceLoader for AndroidResourceLoader {
fn slurp(&self, path: &str) -> Result<Vec<u8>, IOError> {
JAVA_RESOURCE_LOADER.with(|java_resource_loader| {
let java_resource_loader = java_resource_loader.borrow();
let java_resource_loader = java_resource_loader.as_ref().unwrap();
let loader = java_resource_loader.loader.as_obj();
let env = java_resource_loader.vm.get_env().unwrap();
match env
.call_method(
loader,
"slurp",
"(Ljava/lang/String;)Ljava/nio/ByteBuffer;",
&[JValue::Object(*env.new_string(path).unwrap())],
)
.unwrap()
{
JValue::Object(object) => {
let byte_buffer = JByteBuffer::from(object);
Ok(Vec::from(
env.get_direct_buffer_address(byte_buffer).unwrap(),
))
}
_ => panic!("Unexpected return value!"),
}
})
}
}
struct JavaActivity {
activity: GlobalRef,
vm: JavaVM,
}
impl JavaActivity {
fn new(env: JNIEnv, activity: JObject) -> JavaActivity {
JavaActivity {
activity: env.new_global_ref(activity).unwrap(),
vm: env.get_java_vm().unwrap(),
}
}
}
struct JavaResourceLoader {
loader: GlobalRef,
vm: JavaVM,
}
impl JavaResourceLoader {
fn new(env: JNIEnv, loader: JObject) -> JavaResourceLoader {
JavaResourceLoader {
loader: env.new_global_ref(loader).unwrap(),
vm: env.get_java_vm().unwrap(),
}
}
}

View file

@ -1 +0,0 @@
include ':app'

View file

@ -1,61 +0,0 @@
[package]
name = "pathfinder_demo"
version = "0.1.0"
edition = "2018"
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
[features]
pf-gl = []
[dependencies]
clap = "2.32"
gl = "0.14"
rayon = "1.0"
usvg = "0.9"
[dependencies.image]
version = "0.23"
default-features = false
features = ["png"]
[dependencies.log]
version = "0.4"
[dependencies.pathfinder_color]
path = "../../color"
[dependencies.pathfinder_content]
path = "../../content"
[dependencies.pathfinder_export]
path = "../../export"
[dependencies.pathfinder_geometry]
path = "../../geometry"
[dependencies.pathfinder_gl]
path = "../../gl"
[dependencies.pathfinder_gpu]
path = "../../gpu"
[dependencies.pathfinder_renderer]
path = "../../renderer"
[dependencies.pathfinder_resources]
path = "../../resources"
[dependencies.pathfinder_simd]
path = "../../simd"
[dependencies.pathfinder_svg]
path = "../../svg"
[dependencies.pathfinder_ui]
path = "../../ui"
[target.'cfg(target_os = "macos")'.dependencies]
metal = "0.17"
[target.'cfg(target_os = "macos")'.dependencies.pathfinder_metal]
path = "../../metal"

View file

@ -1,188 +0,0 @@
// pathfinder/demo/common/src/camera.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Camera management code for the demo.
// TODO(#140, pcwalton): Move some of this out of the demo and into the library
// proper.
use crate::window::{OcularTransform, View};
use pathfinder_geometry::vector::{Vector2I, Vector4F};
use pathfinder_geometry::rect::RectF;
use pathfinder_geometry::transform2d::Transform2F;
use pathfinder_geometry::transform3d::{Perspective, Transform4F};
use std::f32::consts::FRAC_PI_4;
const NEAR_CLIP_PLANE: f32 = 0.01;
const FAR_CLIP_PLANE: f32 = 10.0;
// Half of the eye separation distance.
const DEFAULT_EYE_OFFSET: f32 = 0.025;
pub enum Camera {
TwoD(Transform2F),
ThreeD {
// The ocular transform used for rendering of the scene to the scene framebuffer. If we are
// performing stereoscopic rendering, this is then reprojected according to the eye
// transforms below.
scene_transform: OcularTransform,
// For each eye, the perspective from camera coordinates to display coordinates,
// and the view transform from world coordinates to camera coordinates.
eye_transforms: Vec<OcularTransform>,
// The modelview transform from world coordinates to SVG coordinates
modelview_transform: CameraTransform3D,
// The camera's velocity (in world coordinates)
velocity: Vector4F,
},
}
impl Camera {
pub fn new(mode: Mode, view_box: RectF, viewport_size: Vector2I) -> Camera {
if mode == Mode::TwoD {
Camera::new_2d(view_box, viewport_size)
} else {
Camera::new_3d(mode, view_box, viewport_size)
}
}
fn new_2d(view_box: RectF, viewport_size: Vector2I) -> Camera {
let scale = i32::min(viewport_size.x(), viewport_size.y()) as f32 *
scale_factor_for_view_box(view_box);
let origin = viewport_size.to_f32() * 0.5 - view_box.size() * (scale * 0.5);
Camera::TwoD(Transform2F::from_scale(scale).translate(origin))
}
fn new_3d(mode: Mode, view_box: RectF, viewport_size: Vector2I) -> Camera {
let viewport_count = mode.viewport_count();
let fov_y = FRAC_PI_4;
let aspect = viewport_size.x() as f32 / viewport_size.y() as f32;
let projection =
Transform4F::from_perspective(fov_y, aspect, NEAR_CLIP_PLANE, FAR_CLIP_PLANE);
let perspective = Perspective::new(&projection, viewport_size);
// Create a scene transform by moving the camera back from the center of the eyes so that
// its field of view encompasses the field of view of both eyes.
let z_offset = Vector4F::new(0.0, 0.0, -DEFAULT_EYE_OFFSET * projection.c0.x(), 1.0);
let scene_transform = OcularTransform {
perspective,
modelview_to_eye: Transform4F::from_translation(z_offset),
};
// For now, initialize the eye transforms as copies of the scene transform.
let eye_offset = DEFAULT_EYE_OFFSET;
let eye_transforms = (0..viewport_count)
.map(|viewport_index| {
let this_eye_offset = if viewport_index == 0 {
eye_offset
} else {
-eye_offset
};
let this_eye_offset = Vector4F::new(this_eye_offset, 0.0, 0.0, 1.0);
OcularTransform {
perspective,
modelview_to_eye: Transform4F::from_translation(this_eye_offset),
}
})
.collect();
Camera::ThreeD {
scene_transform,
eye_transforms,
modelview_transform: CameraTransform3D::new(view_box),
velocity: Vector4F::default(),
}
}
pub fn is_3d(&self) -> bool {
match *self {
Camera::ThreeD { .. } => true,
Camera::TwoD { .. } => false,
}
}
pub fn mode(&self) -> Mode {
match *self {
Camera::ThreeD {
ref eye_transforms, ..
} if eye_transforms.len() >= 2 => Mode::VR,
Camera::ThreeD { .. } => Mode::ThreeD,
Camera::TwoD { .. } => Mode::TwoD,
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct CameraTransform3D {
position: Vector4F,
pub yaw: f32,
pub pitch: f32,
scale: f32,
}
impl CameraTransform3D {
fn new(view_box: RectF) -> CameraTransform3D {
let scale = scale_factor_for_view_box(view_box);
CameraTransform3D {
position: Vector4F::new(
0.5 * view_box.max_x(),
-0.5 * view_box.max_y(),
1.5 / scale,
1.0,
),
yaw: 0.0,
pitch: 0.0,
scale,
}
}
pub fn offset(&mut self, vector: Vector4F) -> bool {
let update = !vector.is_zero();
if update {
let rotation = Transform4F::from_rotation(-self.yaw, -self.pitch, 0.0);
self.position = self.position + rotation * vector;
}
update
}
pub fn to_transform(&self) -> Transform4F {
let flip = Vector4F::new(1.0, -1.0, 1.0, 1.0);
Transform4F::from_scale(flip).translate(-self.position)
.uniform_scale(2.0 * self.scale)
.rotate(self.yaw, self.pitch, 0.0)
}
}
#[derive(Clone, Copy, PartialEq)]
pub enum Mode {
TwoD = 0,
ThreeD = 1,
VR = 2,
}
impl Mode {
pub fn viewport_count(self) -> usize {
match self {
Mode::TwoD | Mode::ThreeD => 1,
Mode::VR => 2,
}
}
pub fn view(self, viewport: u32) -> View {
match self {
Mode::TwoD | Mode::ThreeD => View::Mono,
Mode::VR => View::Stereo(viewport),
}
}
}
pub fn scale_factor_for_view_box(view_box: RectF) -> f32 {
1.0 / f32::min(view_box.size().x(), view_box.size().y())
}

View file

@ -1,45 +0,0 @@
// pathfinder/demo/common/src/concurrent.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Concurrency implementation for the demo.
use pathfinder_renderer::concurrent::executor::{Executor, SequentialExecutor};
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
use rayon::ThreadPoolBuilder;
pub struct DemoExecutor {
sequential_mode: bool,
}
impl DemoExecutor {
pub fn new(thread_count: Option<usize>) -> DemoExecutor {
let sequential_mode = thread_count == Some(1);
if !sequential_mode {
let mut thread_pool_builder = ThreadPoolBuilder::new();
if let Some(thread_count) = thread_count {
thread_pool_builder = thread_pool_builder.num_threads(thread_count);
}
thread_pool_builder.build_global().unwrap();
}
DemoExecutor { sequential_mode }
}
}
impl Executor for DemoExecutor {
fn build_vector<T, F>(&self, length: usize, builder: F) -> Vec<T>
where T: Send, F: Fn(usize) -> T + Send + Sync {
if self.sequential_mode {
SequentialExecutor.build_vector(length, builder)
} else {
RayonExecutor.build_vector(length, builder)
}
}
}

View file

@ -1,82 +0,0 @@
// pathfinder/demo/common/src/device.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! GPU rendering code specifically for the demo.
use pathfinder_gpu::{BufferTarget, Device, VertexAttrClass, VertexAttrDescriptor, VertexAttrType};
use pathfinder_resources::ResourceLoader;
pub struct GroundProgram<D>
where
D: Device,
{
pub program: D::Program,
pub transform_uniform: D::Uniform,
pub gridline_count_uniform: D::Uniform,
pub ground_color_uniform: D::Uniform,
pub gridline_color_uniform: D::Uniform,
}
impl<D> GroundProgram<D>
where
D: Device,
{
pub fn new(device: &D, resources: &dyn ResourceLoader) -> GroundProgram<D> {
let program = device.create_program(resources, "demo_ground");
let transform_uniform = device.get_uniform(&program, "Transform");
let gridline_count_uniform = device.get_uniform(&program, "GridlineCount");
let ground_color_uniform = device.get_uniform(&program, "GroundColor");
let gridline_color_uniform = device.get_uniform(&program, "GridlineColor");
GroundProgram {
program,
transform_uniform,
gridline_count_uniform,
ground_color_uniform,
gridline_color_uniform,
}
}
}
pub struct GroundVertexArray<D>
where
D: Device,
{
pub vertex_array: D::VertexArray,
}
impl<D> GroundVertexArray<D>
where
D: Device,
{
pub fn new(
device: &D,
ground_program: &GroundProgram<D>,
quad_vertex_positions_buffer: &D::Buffer,
quad_vertex_indices_buffer: &D::Buffer,
) -> GroundVertexArray<D> {
let vertex_array = device.create_vertex_array();
let position_attr = device.get_vertex_attr(&ground_program.program, "Position").unwrap();
device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex);
device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor {
size: 2,
class: VertexAttrClass::Int,
attr_type: VertexAttrType::I16,
stride: 4,
offset: 0,
divisor: 0,
buffer_index: 0,
});
device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index);
GroundVertexArray { vertex_array }
}
}

View file

@ -1,889 +0,0 @@
// pathfinder/demo/common/src/lib.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A demo app for Pathfinder.
#[macro_use]
extern crate log;
// Mode is used in Options, so has to be public
pub use crate::camera::Mode;
use crate::camera::Camera;
use crate::concurrent::DemoExecutor;
use crate::device::{GroundProgram, GroundVertexArray};
use crate::ui::{DemoUIModel, DemoUIPresenter, ScreenshotInfo, ScreenshotType, UIAction};
use crate::window::{Event, Keycode, SVGPath, Window, WindowSize};
use clap::{App, Arg};
use pathfinder_content::effects::DEFRINGING_KERNEL_CORE_GRAPHICS;
use pathfinder_content::effects::PatternFilter;
use pathfinder_content::effects::STEM_DARKENING_FACTORS;
use pathfinder_content::outline::Outline;
use pathfinder_content::pattern::Pattern;
use pathfinder_content::render_target::RenderTargetId;
use pathfinder_export::{Export, FileFormat};
use pathfinder_geometry::rect::{RectF, RectI};
use pathfinder_geometry::transform2d::Transform2F;
use pathfinder_geometry::transform3d::Transform4F;
use pathfinder_geometry::vector::{Vector2F, Vector2I, Vector4F, vec2f, vec2i};
use pathfinder_gpu::Device;
use pathfinder_renderer::concurrent::scene_proxy::{RenderCommandStream, SceneProxy};
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
use pathfinder_renderer::gpu::renderer::{RenderStats, RenderTime, Renderer};
use pathfinder_renderer::options::{BuildOptions, RenderTransform};
use pathfinder_renderer::paint::Paint;
use pathfinder_renderer::scene::{DrawPath, RenderTarget, Scene};
use pathfinder_resources::ResourceLoader;
use pathfinder_svg::BuiltSVG;
use pathfinder_ui::{MousePosition, UIEvent};
use std::fs::File;
use std::io::{BufWriter, Read};
use std::path::PathBuf;
use std::thread;
use std::time::Duration;
use usvg::{Options as UsvgOptions, Tree};
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
use pathfinder_gl::GLDevice as DeviceImpl;
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
use pathfinder_metal::MetalDevice as DeviceImpl;
static DEFAULT_SVG_VIRTUAL_PATH: &'static str = "svg/Ghostscript_Tiger.svg";
const MOUSELOOK_ROTATION_SPEED: f32 = 0.007;
const CAMERA_VELOCITY: f32 = 0.02;
// How much the scene is scaled when a scale gesture is performed.
const CAMERA_SCALE_SPEED_2D: f32 = 6.0;
// How much the scene is scaled when a zoom button is clicked.
const CAMERA_ZOOM_AMOUNT_2D: f32 = 0.1;
// Half of the eye separation distance.
const DEFAULT_EYE_OFFSET: f32 = 0.025;
const APPROX_FONT_SIZE: f32 = 16.0;
const MESSAGE_TIMEOUT_SECS: u64 = 5;
pub mod window;
mod camera;
mod concurrent;
mod device;
mod renderer;
mod ui;
pub struct DemoApp<W> where W: Window {
pub window: W,
pub should_exit: bool,
pub options: Options,
window_size: WindowSize,
svg_tree: Tree,
scene_metadata: SceneMetadata,
render_transform: Option<RenderTransform>,
render_command_stream: Option<RenderCommandStream>,
camera: Camera,
frame_counter: u32,
pending_screenshot_info: Option<ScreenshotInfo>,
mouselook_enabled: bool,
pub dirty: bool,
expire_message_event_id: u32,
message_epoch: u32,
last_mouse_position: Vector2I,
current_frame: Option<Frame>,
ui_model: DemoUIModel,
ui_presenter: DemoUIPresenter<DeviceImpl>,
scene_proxy: SceneProxy,
renderer: Renderer<DeviceImpl>,
scene_framebuffer: Option<<DeviceImpl as Device>::Framebuffer>,
ground_program: GroundProgram<DeviceImpl>,
ground_vertex_array: GroundVertexArray<DeviceImpl>,
}
impl<W> DemoApp<W> where W: Window {
pub fn new(window: W, window_size: WindowSize, mut options: Options) -> DemoApp<W> {
let expire_message_event_id = window.create_user_event_id();
let device;
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
{
device = DeviceImpl::new(window.metal_layer());
}
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
{
device = DeviceImpl::new(window.gl_version(), window.gl_default_framebuffer());
}
let resources = window.resource_loader();
// Read command line options.
options.command_line_overrides();
// Set up the executor.
let executor = DemoExecutor::new(options.jobs);
let mut ui_model = DemoUIModel::new(&options);
let render_options = RendererOptions { background_color: None };
let filter = build_filter(&ui_model);
let viewport = window.viewport(options.mode.view(0));
let (mut built_svg, svg_tree) = load_scene(resources,
&options.input_path,
viewport.size(),
filter);
let message = get_svg_building_message(&built_svg);
let dest_framebuffer = DestFramebuffer::Default {
viewport,
window_size: window_size.device_size(),
};
let renderer = Renderer::new(device, resources, dest_framebuffer, render_options);
let scene_metadata = SceneMetadata::new_clipping_view_box(&mut built_svg.scene,
viewport.size());
let camera = Camera::new(options.mode, scene_metadata.view_box, viewport.size());
let scene_proxy = SceneProxy::from_scene(built_svg.scene, executor);
let ground_program = GroundProgram::new(&renderer.device, resources);
let ground_vertex_array = GroundVertexArray::new(&renderer.device,
&ground_program,
&renderer.quad_vertex_positions_buffer(),
&renderer.quad_vertex_indices_buffer());
let mut message_epoch = 0;
emit_message::<W>(
&mut ui_model,
&mut message_epoch,
expire_message_event_id,
message,
);
let ui_presenter = DemoUIPresenter::new(&renderer.device, resources);
DemoApp {
window,
should_exit: false,
options,
window_size,
svg_tree,
scene_metadata,
render_transform: None,
render_command_stream: None,
camera,
frame_counter: 0,
pending_screenshot_info: None,
mouselook_enabled: false,
dirty: true,
expire_message_event_id,
message_epoch,
last_mouse_position: Vector2I::default(),
current_frame: None,
ui_presenter,
ui_model,
scene_proxy,
renderer,
scene_framebuffer: None,
ground_program,
ground_vertex_array,
}
}
pub fn prepare_frame(&mut self, events: Vec<Event>) -> u32 {
// Clear dirty flag.
self.dirty = false;
// Handle events.
let ui_events = self.handle_events(events);
// Update the scene.
self.build_scene();
// Save the frame.
//
// FIXME(pcwalton): This is super ugly.
let transform = self.render_transform.clone().unwrap();
self.current_frame = Some(Frame::new(transform, ui_events));
// Prepare to render the frame.
self.prepare_frame_rendering()
}
fn build_scene(&mut self) {
self.render_transform = match self.camera {
Camera::ThreeD {
ref scene_transform,
ref mut modelview_transform,
ref mut velocity,
..
} => {
if modelview_transform.offset(*velocity) {
self.dirty = true;
}
let perspective = scene_transform.perspective *
scene_transform.modelview_to_eye *
modelview_transform.to_transform();
Some(RenderTransform::Perspective(perspective))
}
Camera::TwoD(transform) => Some(RenderTransform::Transform2D(transform)),
};
let build_options = BuildOptions {
transform: self.render_transform.clone().unwrap(),
dilation: if self.ui_model.stem_darkening_effect_enabled {
let font_size = APPROX_FONT_SIZE * self.window_size.backing_scale_factor;
vec2f(STEM_DARKENING_FACTORS[0], STEM_DARKENING_FACTORS[1]) * font_size
} else {
Vector2F::zero()
},
subpixel_aa_enabled: self.ui_model.subpixel_aa_effect_enabled,
};
self.render_command_stream = Some(self.scene_proxy.build_with_stream(build_options));
}
fn handle_events(&mut self, events: Vec<Event>) -> Vec<UIEvent> {
let mut ui_events = vec![];
self.dirty = false;
for event in events {
match event {
Event::Quit { .. } | Event::KeyDown(Keycode::Escape) => {
self.should_exit = true;
self.dirty = true;
}
Event::WindowResized(new_size) => {
self.window_size = new_size;
let viewport = self.window.viewport(self.ui_model.mode.view(0));
self.scene_proxy.set_view_box(RectF::new(Vector2F::zero(),
viewport.size().to_f32()));
self.renderer.set_main_framebuffer_size(self.window_size.device_size());
self.dirty = true;
}
Event::MouseDown(new_position) => {
let mouse_position = self.process_mouse_position(new_position);
ui_events.push(UIEvent::MouseDown(mouse_position));
}
Event::MouseMoved(new_position) if self.mouselook_enabled => {
let mouse_position = self.process_mouse_position(new_position);
if let Camera::ThreeD { ref mut modelview_transform, .. } = self.camera {
let rotation = mouse_position.relative.to_f32() * MOUSELOOK_ROTATION_SPEED;
modelview_transform.yaw += rotation.x();
modelview_transform.pitch += rotation.y();
self.dirty = true;
}
}
Event::MouseDragged(new_position) => {
let mouse_position = self.process_mouse_position(new_position);
ui_events.push(UIEvent::MouseDragged(mouse_position));
self.dirty = true;
}
Event::Zoom(d_dist, position) => {
if let Camera::TwoD(ref mut transform) = self.camera {
let backing_scale_factor = self.window_size.backing_scale_factor;
let position = position.to_f32() * backing_scale_factor;
let scale_delta = 1.0 + d_dist * CAMERA_SCALE_SPEED_2D;
*transform = transform.translate(-position)
.scale(scale_delta)
.translate(position);
}
}
Event::Look { pitch, yaw } => {
if let Camera::ThreeD { ref mut modelview_transform, .. } = self.camera {
modelview_transform.pitch += pitch;
modelview_transform.yaw += yaw;
}
}
Event::SetEyeTransforms(new_eye_transforms) => {
if let Camera::ThreeD {
ref mut scene_transform,
ref mut eye_transforms,
..
} = self.camera
{
*eye_transforms = new_eye_transforms;
// Calculate the new scene transform by lerp'ing the eye transforms.
*scene_transform = eye_transforms[0];
for (index, eye_transform) in eye_transforms.iter().enumerate().skip(1) {
let weight = 1.0 / (index + 1) as f32;
scene_transform.perspective.transform =
scene_transform.perspective
.transform
.lerp(weight, &eye_transform.perspective.transform);
scene_transform.modelview_to_eye =
scene_transform.modelview_to_eye
.lerp(weight, &eye_transform.modelview_to_eye);
}
// TODO: calculate the eye offset from the eye transforms?
let z_offset = -DEFAULT_EYE_OFFSET *
scene_transform.perspective.transform.c0.x();
let z_offset = Vector4F::new(0.0, 0.0, z_offset, 1.0);
scene_transform.modelview_to_eye =
Transform4F::from_translation(z_offset) *
scene_transform.modelview_to_eye;
}
}
Event::KeyDown(Keycode::Alphanumeric(b'w')) => {
if let Camera::ThreeD {
ref mut velocity, ..
} = self.camera
{
let scale_factor =
camera::scale_factor_for_view_box(self.scene_metadata.view_box);
velocity.set_z(-CAMERA_VELOCITY / scale_factor);
self.dirty = true;
}
}
Event::KeyDown(Keycode::Alphanumeric(b's')) => {
if let Camera::ThreeD {
ref mut velocity, ..
} = self.camera
{
let scale_factor =
camera::scale_factor_for_view_box(self.scene_metadata.view_box);
velocity.set_z(CAMERA_VELOCITY / scale_factor);
self.dirty = true;
}
}
Event::KeyDown(Keycode::Alphanumeric(b'a')) => {
if let Camera::ThreeD {
ref mut velocity, ..
} = self.camera
{
let scale_factor =
camera::scale_factor_for_view_box(self.scene_metadata.view_box);
velocity.set_x(-CAMERA_VELOCITY / scale_factor);
self.dirty = true;
}
}
Event::KeyDown(Keycode::Alphanumeric(b'd')) => {
if let Camera::ThreeD {
ref mut velocity, ..
} = self.camera
{
let scale_factor =
camera::scale_factor_for_view_box(self.scene_metadata.view_box);
velocity.set_x(CAMERA_VELOCITY / scale_factor);
self.dirty = true;
}
}
Event::KeyUp(Keycode::Alphanumeric(b'w'))
| Event::KeyUp(Keycode::Alphanumeric(b's')) => {
if let Camera::ThreeD {
ref mut velocity, ..
} = self.camera
{
velocity.set_z(0.0);
self.dirty = true;
}
}
Event::KeyUp(Keycode::Alphanumeric(b'a'))
| Event::KeyUp(Keycode::Alphanumeric(b'd')) => {
if let Camera::ThreeD {
ref mut velocity, ..
} = self.camera
{
velocity.set_x(0.0);
self.dirty = true;
}
}
Event::KeyDown(Keycode::Tab) => {
self.options.ui = match self.options.ui {
UIVisibility::None => UIVisibility::Stats,
UIVisibility::Stats => UIVisibility::All,
UIVisibility::All => UIVisibility::None,
}
}
Event::OpenSVG(ref svg_path) => {
let viewport = self.window.viewport(self.ui_model.mode.view(0));
let filter = build_filter(&self.ui_model);
let (mut built_svg, svg_tree) = load_scene(self.window.resource_loader(),
svg_path,
viewport.size(),
filter);
self.ui_model.message = get_svg_building_message(&built_svg);
let viewport_size = self.window.viewport(self.ui_model.mode.view(0)).size();
self.scene_metadata =
SceneMetadata::new_clipping_view_box(&mut built_svg.scene, viewport_size);
self.camera = Camera::new(self.ui_model.mode,
self.scene_metadata.view_box,
viewport_size);
self.scene_proxy.replace_scene(built_svg.scene);
self.svg_tree = svg_tree;
self.dirty = true;
}
Event::User {
message_type: event_id,
message_data: expected_epoch,
} if event_id == self.expire_message_event_id
&& expected_epoch as u32 == self.message_epoch =>
{
self.ui_model.message = String::new();
self.dirty = true;
}
_ => continue,
}
}
ui_events
}
fn process_mouse_position(&mut self, new_position: Vector2I) -> MousePosition {
let absolute = new_position * self.window_size.backing_scale_factor as i32;
let relative = absolute - self.last_mouse_position;
self.last_mouse_position = absolute;
MousePosition { absolute, relative }
}
pub fn finish_drawing_frame(&mut self) {
self.maybe_take_screenshot();
self.update_stats();
self.draw_debug_ui();
let frame = self.current_frame.take().unwrap();
for ui_event in &frame.ui_events {
self.dirty = true;
self.renderer.debug_ui_presenter.ui_presenter.event_queue.push(*ui_event);
}
self.renderer.debug_ui_presenter.ui_presenter.mouse_position =
self.last_mouse_position.to_f32() * self.window_size.backing_scale_factor;
let mut ui_action = UIAction::None;
if self.options.ui == UIVisibility::All {
self.ui_presenter.update(
&self.renderer.device,
&mut self.window,
&mut self.renderer.debug_ui_presenter,
&mut ui_action,
&mut self.ui_model,
);
}
self.handle_ui_events(frame, &mut ui_action);
self.renderer.device.end_commands();
self.window.present(&mut self.renderer.device);
self.frame_counter += 1;
}
fn update_stats(&mut self) {
let frame = self.current_frame.as_mut().unwrap();
if let Some(rendering_time) = self.renderer.shift_rendering_time() {
frame.scene_rendering_times.push(rendering_time);
}
if frame.scene_stats.is_empty() && frame.scene_rendering_times.is_empty() {
return
}
let zero = RenderStats::default();
let aggregate_stats = frame.scene_stats.iter().fold(zero, |sum, item| sum + *item);
if !frame.scene_rendering_times.is_empty() {
let total_rendering_time = frame.scene_rendering_times
.iter()
.fold(RenderTime::default(), |sum, item| sum + *item);
self.renderer.debug_ui_presenter.add_sample(aggregate_stats, total_rendering_time);
}
}
fn maybe_take_screenshot(&mut self) {
match self.pending_screenshot_info.take() {
None => {}
Some(ScreenshotInfo { kind: ScreenshotType::PNG, path }) => {
self.take_raster_screenshot(path)
}
Some(ScreenshotInfo { kind: ScreenshotType::SVG, path }) => {
// FIXME(pcwalton): This won't work on Android.
let mut writer = BufWriter::new(File::create(path).unwrap());
self.scene_proxy.copy_scene().export(&mut writer, FileFormat::SVG).unwrap();
}
}
}
fn handle_ui_events(&mut self, mut frame: Frame, ui_action: &mut UIAction) {
frame.ui_events = self.renderer.debug_ui_presenter.ui_presenter.event_queue.drain();
self.handle_ui_action(ui_action);
// Switch camera mode (2D/3D) if requested.
//
// FIXME(pcwalton): This should really be an MVC setup.
if self.camera.mode() != self.ui_model.mode {
let viewport_size = self.window.viewport(self.ui_model.mode.view(0)).size();
self.camera = Camera::new(self.ui_model.mode,
self.scene_metadata.view_box,
viewport_size);
}
for ui_event in frame.ui_events {
match ui_event {
UIEvent::MouseDown(_) if self.camera.is_3d() => {
// If nothing handled the mouse-down event, toggle mouselook.
self.mouselook_enabled = !self.mouselook_enabled;
}
UIEvent::MouseDragged(position) => {
if let Camera::TwoD(ref mut transform) = self.camera {
*transform = transform.translate(position.relative.to_f32());
}
}
_ => {}
}
}
}
fn handle_ui_action(&mut self, ui_action: &mut UIAction) {
match ui_action {
UIAction::None => {}
UIAction::ModelChanged => self.dirty = true,
UIAction::EffectsChanged => {
let viewport_size = self.window.viewport(self.ui_model.mode.view(0)).size();
let filter = build_filter(&self.ui_model);
let mut built_svg = build_svg_tree(&self.svg_tree, viewport_size, filter);
self.scene_metadata =
SceneMetadata::new_clipping_view_box(&mut built_svg.scene, viewport_size);
self.scene_proxy.replace_scene(built_svg.scene);
self.dirty = true;
}
UIAction::TakeScreenshot(ref info) => {
self.pending_screenshot_info = Some((*info).clone());
self.dirty = true;
}
UIAction::ZoomIn => {
if let Camera::TwoD(ref mut transform) = self.camera {
let scale = 1.0 + CAMERA_ZOOM_AMOUNT_2D;
let center = center_of_window(&self.window_size);
*transform = transform.translate(-center).scale(scale).translate(center);
self.dirty = true;
}
}
UIAction::ZoomOut => {
if let Camera::TwoD(ref mut transform) = self.camera {
let scale = 1.0 - CAMERA_ZOOM_AMOUNT_2D;
let center = center_of_window(&self.window_size);
*transform = transform.translate(-center).scale(scale).translate(center);
self.dirty = true;
}
}
UIAction::ZoomActualSize => {
if let Camera::TwoD(ref mut transform) = self.camera {
*transform = Transform2F::default();
self.dirty = true;
}
}
UIAction::Rotate(theta) => {
if let Camera::TwoD(ref mut transform) = self.camera {
let old_rotation = transform.rotation();
let center = center_of_window(&self.window_size);
*transform = transform.translate(-center)
.rotate(*theta - old_rotation)
.translate(center);
}
}
}
}
}
#[derive(Clone)]
pub struct Options {
pub jobs: Option<usize>,
pub mode: Mode,
pub input_path: SVGPath,
pub ui: UIVisibility,
pub background_color: BackgroundColor,
hidden_field_for_future_proofing: (),
}
impl Default for Options {
fn default() -> Self {
Options {
jobs: None,
mode: Mode::TwoD,
input_path: SVGPath::Default,
ui: UIVisibility::All,
background_color: BackgroundColor::Light,
hidden_field_for_future_proofing: (),
}
}
}
impl Options {
fn command_line_overrides(&mut self) {
let matches = App::new("tile-svg")
.arg(
Arg::with_name("jobs")
.short("j")
.long("jobs")
.value_name("THREADS")
.takes_value(true)
.help("Number of threads to use"),
)
.arg(
Arg::with_name("3d")
.short("3")
.long("3d")
.help("Run in 3D")
.conflicts_with("vr"),
)
.arg(
Arg::with_name("vr")
.short("V")
.long("vr")
.help("Run in VR")
.conflicts_with("3d"),
)
.arg(
Arg::with_name("ui")
.short("u")
.long("ui")
.takes_value(true)
.possible_values(&["none", "stats", "all"])
.help("How much UI to show"),
)
.arg(
Arg::with_name("background")
.short("b")
.long("background")
.takes_value(true)
.possible_values(&["light", "dark", "transparent"])
.help("The background color to use"),
)
.arg(
Arg::with_name("INPUT")
.help("Path to the SVG file to render")
.index(1),
)
.get_matches();
if let Some(jobs) = matches.value_of("jobs") {
self.jobs = jobs.parse().ok();
}
if matches.is_present("3d") {
self.mode = Mode::ThreeD;
} else if matches.is_present("vr") {
self.mode = Mode::VR;
}
if let Some(ui) = matches.value_of("ui") {
self.ui = match ui {
"none" => UIVisibility::None,
"stats" => UIVisibility::Stats,
_ => UIVisibility::All,
};
}
if let Some(background_color) = matches.value_of("background") {
self.background_color = match background_color {
"light" => BackgroundColor::Light,
"dark" => BackgroundColor::Dark,
_ => BackgroundColor::Transparent,
};
}
if let Some(path) = matches.value_of("INPUT") {
self.input_path = SVGPath::Path(PathBuf::from(path));
};
}
}
#[derive(Clone, Copy, PartialEq)]
pub enum UIVisibility {
None,
Stats,
All,
}
fn load_scene(resource_loader: &dyn ResourceLoader,
input_path: &SVGPath,
viewport_size: Vector2I,
filter: Option<PatternFilter>)
-> (BuiltSVG, Tree) {
let mut data;
match *input_path {
SVGPath::Default => data = resource_loader.slurp(DEFAULT_SVG_VIRTUAL_PATH).unwrap(),
SVGPath::Resource(ref name) => data = resource_loader.slurp(name).unwrap(),
SVGPath::Path(ref path) => {
data = vec![];
File::open(path).unwrap().read_to_end(&mut data).unwrap();
}
};
let tree = Tree::from_data(&data, &UsvgOptions::default()).expect("Failed to parse the SVG!");
let built_svg = build_svg_tree(&tree, viewport_size, filter);
(built_svg, tree)
}
// FIXME(pcwalton): Rework how transforms work in the demo. The transform affects the final
// composite steps, breaking this approach.
fn build_svg_tree(tree: &Tree, viewport_size: Vector2I, filter: Option<PatternFilter>)
-> BuiltSVG {
let mut scene = Scene::new();
let filter_info = filter.map(|filter| {
let scale = match filter {
PatternFilter::Text { defringing_kernel: Some(_), .. } => vec2i(3, 1),
_ => vec2i(1, 1),
};
let name = "Text".to_owned();
let render_target_size = viewport_size * scale;
let render_target = RenderTarget::new(render_target_size, name);
let render_target_id = scene.push_render_target(render_target);
FilterInfo { filter, render_target_id, render_target_size }
});
let mut built_svg = BuiltSVG::from_tree_and_scene(&tree, scene);
if let Some(FilterInfo { filter, render_target_id, render_target_size }) = filter_info {
let mut pattern = Pattern::from_render_target(render_target_id, render_target_size);
pattern.set_filter(Some(filter));
let paint_id = built_svg.scene.push_paint(&Paint::from_pattern(pattern));
let outline = Outline::from_rect(RectI::new(vec2i(0, 0), viewport_size).to_f32());
let path = DrawPath::new(outline, paint_id);
built_svg.scene.pop_render_target();
built_svg.scene.push_path(path);
}
return built_svg;
struct FilterInfo {
filter: PatternFilter,
render_target_id: RenderTargetId,
render_target_size: Vector2I,
}
}
fn center_of_window(window_size: &WindowSize) -> Vector2F {
window_size.device_size().to_f32() * 0.5
}
fn get_svg_building_message(built_svg: &BuiltSVG) -> String {
if built_svg.result_flags.is_empty() {
return String::new();
}
format!(
"Warning: These features in the SVG are unsupported: {}.",
built_svg.result_flags
)
}
fn emit_message<W>(
ui_model: &mut DemoUIModel,
message_epoch: &mut u32,
expire_message_event_id: u32,
message: String,
) where
W: Window,
{
if message.is_empty() {
return;
}
ui_model.message = message;
let expected_epoch = *message_epoch + 1;
*message_epoch = expected_epoch;
thread::spawn(move || {
thread::sleep(Duration::from_secs(MESSAGE_TIMEOUT_SECS));
W::push_user_event(expire_message_event_id, expected_epoch);
});
}
struct Frame {
transform: RenderTransform,
ui_events: Vec<UIEvent>,
scene_rendering_times: Vec<RenderTime>,
scene_stats: Vec<RenderStats>,
}
impl Frame {
fn new(transform: RenderTransform, ui_events: Vec<UIEvent>) -> Frame {
Frame {
transform,
ui_events,
scene_rendering_times: vec![],
scene_stats: vec![],
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum BackgroundColor {
Light = 0,
Dark = 1,
Transparent = 2,
}
impl BackgroundColor {
fn as_str(&self) -> &'static str {
match *self {
BackgroundColor::Light => "Light",
BackgroundColor::Dark => "Dark",
BackgroundColor::Transparent => "Transparent",
}
}
}
struct SceneMetadata {
view_box: RectF,
}
impl SceneMetadata {
// FIXME(pcwalton): The fact that this mutates the scene is really ugly!
// Can we simplify this?
fn new_clipping_view_box(scene: &mut Scene, viewport_size: Vector2I) -> SceneMetadata {
let view_box = scene.view_box();
scene.set_view_box(RectF::new(Vector2F::zero(), viewport_size.to_f32()));
SceneMetadata { view_box }
}
}
fn build_filter(ui_model: &DemoUIModel) -> Option<PatternFilter> {
if !ui_model.gamma_correction_effect_enabled && !ui_model.subpixel_aa_effect_enabled {
return None;
}
Some(PatternFilter::Text {
fg_color: ui_model.foreground_color().to_f32(),
bg_color: ui_model.background_color().to_f32(),
gamma_correction: ui_model.gamma_correction_effect_enabled,
defringing_kernel: if ui_model.subpixel_aa_effect_enabled {
// TODO(pcwalton): Select FreeType defringing kernel as necessary.
Some(DEFRINGING_KERNEL_CORE_GRAPHICS)
} else {
None
}
})
}

View file

@ -1,305 +0,0 @@
// pathfinder/demo/common/src/renderer.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Rendering functionality for the demo.
use crate::camera::{Camera, Mode};
use crate::window::{View, Window};
use crate::{BackgroundColor, DemoApp, UIVisibility};
use image::ColorType;
use pathfinder_color::{ColorF, ColorU};
use pathfinder_gpu::{ClearOps, DepthFunc, DepthState, Device, Primitive, RenderOptions};
use pathfinder_gpu::{RenderState, RenderTarget, TextureData, TextureFormat, UniformData};
use pathfinder_geometry::rect::RectI;
use pathfinder_geometry::transform3d::Transform4F;
use pathfinder_geometry::vector::{Vector2I, Vector4F};
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
use pathfinder_renderer::options::RenderTransform;
use std::path::PathBuf;
const GROUND_SOLID_COLOR: ColorU = ColorU {
r: 80,
g: 80,
b: 80,
a: 255,
};
const GROUND_LINE_COLOR: ColorU = ColorU {
r: 127,
g: 127,
b: 127,
a: 255,
};
const GRIDLINE_COUNT: i32 = 10;
impl<W> DemoApp<W> where W: Window {
pub fn prepare_frame_rendering(&mut self) -> u32 {
// Make the context current.
let view = self.ui_model.mode.view(0);
self.window.make_current(view);
// Set up framebuffers.
let window_size = self.window_size.device_size();
let mode = self.camera.mode();
let scene_count = match mode {
Mode::VR => {
let viewport = self.window.viewport(View::Stereo(0));
if self.scene_framebuffer.is_none()
|| self.renderer.device.texture_size(
&self
.renderer
.device
.framebuffer_texture(self.scene_framebuffer.as_ref().unwrap()),
) != viewport.size()
{
let scene_texture = self
.renderer
.device
.create_texture(TextureFormat::RGBA8, viewport.size());
self.scene_framebuffer =
Some(self.renderer.device.create_framebuffer(scene_texture));
}
self.renderer
.replace_dest_framebuffer(DestFramebuffer::Other(
self.scene_framebuffer.take().unwrap(),
));
2
}
_ => {
self.renderer
.replace_dest_framebuffer(DestFramebuffer::Default {
viewport: self.window.viewport(View::Mono),
window_size,
});
1
}
};
// Clear to the appropriate color.
let clear_color = match mode {
Mode::TwoD => Some(self.ui_model.background_color().to_f32()),
Mode::ThreeD => None,
Mode::VR => Some(ColorF::transparent_black()),
};
self.renderer.set_options(RendererOptions { background_color: clear_color });
scene_count
}
pub fn draw_scene(&mut self) {
self.renderer.device.begin_commands();
let view = self.ui_model.mode.view(0);
self.window.make_current(view);
if self.camera.mode() != Mode::VR {
self.draw_environment(0);
}
self.renderer.device.end_commands();
self.render_vector_scene();
// Reattach default framebuffer.
if self.camera.mode() == Mode::VR {
if let DestFramebuffer::Other(scene_framebuffer) =
self.renderer
.replace_dest_framebuffer(DestFramebuffer::Default {
viewport: self.window.viewport(View::Mono),
window_size: self.window_size.device_size(),
})
{
self.scene_framebuffer = Some(scene_framebuffer);
}
}
}
pub fn begin_compositing(&mut self) {
self.renderer.device.begin_commands();
}
pub fn composite_scene(&mut self, render_scene_index: u32) {
let (eye_transforms, scene_transform, modelview_transform) = match self.camera {
Camera::ThreeD {
ref eye_transforms,
ref scene_transform,
ref modelview_transform,
..
} if eye_transforms.len() > 1 => (eye_transforms, scene_transform, modelview_transform),
_ => return,
};
debug!(
"scene_transform.perspective={:?}",
scene_transform.perspective
);
debug!(
"scene_transform.modelview_to_eye={:?}",
scene_transform.modelview_to_eye
);
debug!("modelview transform={:?}", modelview_transform);
let viewport = self.window.viewport(View::Stereo(render_scene_index));
self.window.make_current(View::Stereo(render_scene_index));
self.renderer.replace_dest_framebuffer(DestFramebuffer::Default {
viewport,
window_size: self.window_size.device_size(),
});
self.draw_environment(render_scene_index);
let scene_framebuffer = self.scene_framebuffer.as_ref().unwrap();
let scene_texture = self.renderer.device.framebuffer_texture(scene_framebuffer);
let mut quad_scale = self.scene_metadata.view_box.size().to_4d();
quad_scale.set_z(1.0);
let quad_scale_transform = Transform4F::from_scale(quad_scale);
let scene_transform_matrix = scene_transform.perspective *
scene_transform.modelview_to_eye *
modelview_transform.to_transform() *
quad_scale_transform;
let eye_transform = &eye_transforms[render_scene_index as usize];
let eye_transform_matrix = eye_transform.perspective *
eye_transform.modelview_to_eye *
modelview_transform.to_transform() *
quad_scale_transform;
debug!(
"eye transform({}).modelview_to_eye={:?}",
render_scene_index, eye_transform.modelview_to_eye
);
debug!(
"eye transform_matrix({})={:?}",
render_scene_index, eye_transform_matrix
);
debug!("---");
self.renderer.reproject_texture(
scene_texture,
&scene_transform_matrix.transform,
&eye_transform_matrix.transform,
);
}
// Draws the ground, if applicable.
fn draw_environment(&self, render_scene_index: u32) {
let frame = &self.current_frame.as_ref().unwrap();
let perspective = match frame.transform {
RenderTransform::Transform2D(..) => return,
RenderTransform::Perspective(perspective) => perspective,
};
if self.ui_model.background_color == BackgroundColor::Transparent {
return;
}
let ground_scale = self.scene_metadata.view_box.max_x() * 2.0;
let mut offset = self.scene_metadata.view_box.lower_right().to_4d();
offset.set_z(ground_scale);
offset = offset * Vector4F::new(-0.5, 1.0, -0.5, 1.0);
let base_transform = perspective.transform * Transform4F::from_translation(offset);
// Fill ground.
let transform = base_transform *
Transform4F::from_scale(Vector4F::new(ground_scale, 1.0, ground_scale, 1.0));
// Don't clear the first scene after drawing it.
let clear_color = if render_scene_index == 0 {
Some(self.ui_model.background_color().to_f32())
} else {
None
};
self.renderer.device.draw_elements(6, &RenderState {
target: &self.renderer.draw_render_target(),
program: &self.ground_program.program,
vertex_array: &self.ground_vertex_array.vertex_array,
primitive: Primitive::Triangles,
textures: &[],
uniforms: &[
(&self.ground_program.transform_uniform,
UniformData::from_transform_3d(&transform)),
(&self.ground_program.ground_color_uniform,
UniformData::Vec4(GROUND_SOLID_COLOR.to_f32().0)),
(&self.ground_program.gridline_color_uniform,
UniformData::Vec4(GROUND_LINE_COLOR.to_f32().0)),
(&self.ground_program.gridline_count_uniform, UniformData::Int(GRIDLINE_COUNT)),
],
viewport: self.renderer.draw_viewport(),
options: RenderOptions {
depth: Some(DepthState { func: DepthFunc::Less, write: true }),
clear_ops: ClearOps { color: clear_color, depth: Some(1.0), stencil: Some(0) },
..RenderOptions::default()
},
});
}
fn render_vector_scene(&mut self) {
if self.ui_model.mode == Mode::TwoD {
self.renderer.disable_depth();
} else {
self.renderer.enable_depth();
}
self.renderer.begin_scene();
// Issue render commands!
for command in self.render_command_stream.as_mut().unwrap() {
self.renderer.render_command(&command);
}
self.current_frame
.as_mut()
.unwrap()
.scene_stats
.push(self.renderer.stats);
self.renderer.end_scene();
}
pub fn take_raster_screenshot(&mut self, path: PathBuf) {
let drawable_size = self.window_size.device_size();
let viewport = RectI::new(Vector2I::default(), drawable_size);
let texture_data_receiver =
self.renderer.device.read_pixels(&RenderTarget::Default, viewport);
let pixels = match self.renderer.device.recv_texture_data(&texture_data_receiver) {
TextureData::U8(pixels) => pixels,
_ => panic!("Unexpected pixel format for default framebuffer!"),
};
image::save_buffer(
path,
&pixels,
drawable_size.x() as u32,
drawable_size.y() as u32,
ColorType::Rgba8,
)
.unwrap();
}
pub fn draw_debug_ui(&mut self) {
if self.options.ui == UIVisibility::None {
return;
}
let viewport = self.window.viewport(View::Mono);
self.window.make_current(View::Mono);
self.renderer.replace_dest_framebuffer(DestFramebuffer::Default {
viewport,
window_size: self.window_size.device_size(),
});
self.renderer.draw_debug_ui();
}
}

View file

@ -1,656 +0,0 @@
// pathfinder/demo/src/ui.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::camera::Mode;
use crate::window::Window;
use crate::{BackgroundColor, Options};
use pathfinder_color::ColorU;
use pathfinder_geometry::rect::RectI;
use pathfinder_geometry::vector::{Vector2I, vec2i};
use pathfinder_gpu::Device;
use pathfinder_renderer::gpu::debug::DebugUIPresenter;
use pathfinder_resources::ResourceLoader;
use pathfinder_ui::{BUTTON_HEIGHT, BUTTON_TEXT_OFFSET, BUTTON_WIDTH, FONT_ASCENT, PADDING};
use pathfinder_ui::{TEXT_COLOR, TOOLTIP_HEIGHT, WINDOW_COLOR};
use std::f32::consts::PI;
use std::path::PathBuf;
const SLIDER_WIDTH: i32 = 360;
const SLIDER_HEIGHT: i32 = 48;
const SLIDER_TRACK_HEIGHT: i32 = 24;
const SLIDER_KNOB_WIDTH: i32 = 12;
const SLIDER_KNOB_HEIGHT: i32 = 48;
const EFFECTS_PANEL_WIDTH: i32 = 550;
const EFFECTS_PANEL_HEIGHT: i32 = BUTTON_HEIGHT * 3 + PADDING * 4;
const BACKGROUND_PANEL_WIDTH: i32 = 250;
const BACKGROUND_PANEL_HEIGHT: i32 = BUTTON_HEIGHT * 3;
const SCREENSHOT_PANEL_WIDTH: i32 = 275;
const SCREENSHOT_PANEL_HEIGHT: i32 = BUTTON_HEIGHT * 2;
const ROTATE_PANEL_WIDTH: i32 = SLIDER_WIDTH + PADDING * 2;
const ROTATE_PANEL_HEIGHT: i32 = PADDING * 2 + SLIDER_HEIGHT;
const LIGHT_BG_COLOR: ColorU = ColorU { r: 248, g: 248, b: 248, a: 255, };
const DARK_BG_COLOR: ColorU = ColorU { r: 32, g: 32, b: 32, a: 255, };
const TRANSPARENT_BG_COLOR: ColorU = ColorU { r: 0, g: 0, b: 0, a: 0, };
static EFFECTS_PNG_NAME: &'static str = "demo-effects";
static OPEN_PNG_NAME: &'static str = "demo-open";
static ROTATE_PNG_NAME: &'static str = "demo-rotate";
static ZOOM_IN_PNG_NAME: &'static str = "demo-zoom-in";
static ZOOM_ACTUAL_SIZE_PNG_NAME: &'static str = "demo-zoom-actual-size";
static ZOOM_OUT_PNG_NAME: &'static str = "demo-zoom-out";
static BACKGROUND_PNG_NAME: &'static str = "demo-background";
static SCREENSHOT_PNG_NAME: &'static str = "demo-screenshot";
pub struct DemoUIModel {
pub mode: Mode,
pub background_color: BackgroundColor,
pub gamma_correction_effect_enabled: bool,
pub stem_darkening_effect_enabled: bool,
pub subpixel_aa_effect_enabled: bool,
pub rotation: i32,
pub message: String,
}
impl DemoUIModel {
pub fn new(options: &Options) -> DemoUIModel {
DemoUIModel {
mode: options.mode,
background_color: options.background_color,
gamma_correction_effect_enabled: false,
stem_darkening_effect_enabled: false,
subpixel_aa_effect_enabled: false,
rotation: SLIDER_WIDTH / 2,
message: String::new(),
}
}
fn rotation(&self) -> f32 {
(self.rotation as f32 / SLIDER_WIDTH as f32 * 2.0 - 1.0) * PI
}
// Only relevant if in monochrome mode.
pub fn foreground_color(&self) -> ColorU {
match self.background_color {
BackgroundColor::Light | BackgroundColor::Transparent => ColorU::black(),
BackgroundColor::Dark => ColorU::white(),
}
}
pub fn background_color(&self) -> ColorU {
match self.background_color {
BackgroundColor::Light => LIGHT_BG_COLOR,
BackgroundColor::Dark => DARK_BG_COLOR,
BackgroundColor::Transparent => TRANSPARENT_BG_COLOR,
}
}
}
pub struct DemoUIPresenter<D>
where
D: Device,
{
effects_texture: D::Texture,
open_texture: D::Texture,
rotate_texture: D::Texture,
zoom_in_texture: D::Texture,
zoom_actual_size_texture: D::Texture,
zoom_out_texture: D::Texture,
background_texture: D::Texture,
screenshot_texture: D::Texture,
effects_panel_visible: bool,
background_panel_visible: bool,
screenshot_panel_visible: bool,
rotate_panel_visible: bool,
}
impl<D> DemoUIPresenter<D>
where
D: Device,
{
pub fn new(device: &D, resources: &dyn ResourceLoader) -> DemoUIPresenter<D> {
let effects_texture = device.create_texture_from_png(resources, EFFECTS_PNG_NAME);
let open_texture = device.create_texture_from_png(resources, OPEN_PNG_NAME);
let rotate_texture = device.create_texture_from_png(resources, ROTATE_PNG_NAME);
let zoom_in_texture = device.create_texture_from_png(resources, ZOOM_IN_PNG_NAME);
let zoom_actual_size_texture = device.create_texture_from_png(resources,
ZOOM_ACTUAL_SIZE_PNG_NAME);
let zoom_out_texture = device.create_texture_from_png(resources, ZOOM_OUT_PNG_NAME);
let background_texture = device.create_texture_from_png(resources, BACKGROUND_PNG_NAME);
let screenshot_texture = device.create_texture_from_png(resources, SCREENSHOT_PNG_NAME);
DemoUIPresenter {
effects_texture,
open_texture,
rotate_texture,
zoom_in_texture,
zoom_actual_size_texture,
zoom_out_texture,
background_texture,
screenshot_texture,
effects_panel_visible: false,
background_panel_visible: false,
screenshot_panel_visible: false,
rotate_panel_visible: false,
}
}
pub fn update<W>(
&mut self,
device: &D,
window: &mut W,
debug_ui_presenter: &mut DebugUIPresenter<D>,
action: &mut UIAction,
model: &mut DemoUIModel
) where
W: Window,
{
// Draw message text.
self.draw_message_text(device, debug_ui_presenter, model);
// Draw button strip.
let bottom = debug_ui_presenter.ui_presenter.framebuffer_size().y() - PADDING;
let mut position = vec2i(PADDING, bottom - BUTTON_HEIGHT);
let button_size = vec2i(BUTTON_WIDTH, BUTTON_HEIGHT);
// Draw effects button.
if debug_ui_presenter.ui_presenter.draw_button(device, position, &self.effects_texture) {
self.effects_panel_visible = !self.effects_panel_visible;
}
if !self.effects_panel_visible {
debug_ui_presenter.ui_presenter.draw_tooltip(
device,
"Effects",
RectI::new(position, button_size),
);
}
position += vec2i(button_size.x() + PADDING, 0);
// Draw open button.
if debug_ui_presenter.ui_presenter.draw_button(device, position, &self.open_texture) {
// FIXME(pcwalton): This is not sufficient for Android, where we will need to take in
// the contents of the file.
window.present_open_svg_dialog();
}
debug_ui_presenter.ui_presenter.draw_tooltip(device,
"Open SVG",
RectI::new(position, button_size));
position += vec2i(BUTTON_WIDTH + PADDING, 0);
// Draw screenshot button.
if debug_ui_presenter.ui_presenter.draw_button(device,
position,
&self.screenshot_texture) {
self.screenshot_panel_visible = !self.screenshot_panel_visible;
}
if !self.screenshot_panel_visible {
debug_ui_presenter.ui_presenter.draw_tooltip(
device,
"Take Screenshot",
RectI::new(position, button_size),
);
}
// Draw screenshot panel, if necessary.
self.draw_screenshot_panel(device, window, debug_ui_presenter, position.x(), action);
position += vec2i(button_size.x() + PADDING, 0);
// Draw mode switch.
let new_mode = debug_ui_presenter.ui_presenter.draw_text_switch(
device,
position,
&["2D", "3D", "VR"],
model.mode as u8);
if new_mode != model.mode as u8 {
model.mode = match new_mode {
0 => Mode::TwoD,
1 => Mode::ThreeD,
_ => Mode::VR,
};
*action = UIAction::ModelChanged;
}
let mode_switch_width = debug_ui_presenter.ui_presenter.measure_segmented_control(3);
let mode_switch_size = vec2i(mode_switch_width, BUTTON_HEIGHT);
debug_ui_presenter.ui_presenter.draw_tooltip(
device,
"2D/3D/VR Mode",
RectI::new(position, mode_switch_size),
);
position += vec2i(mode_switch_width + PADDING, 0);
// Draw background switch.
if debug_ui_presenter.ui_presenter.draw_button(device,
position,
&self.background_texture) {
self.background_panel_visible = !self.background_panel_visible;
}
if !self.background_panel_visible {
debug_ui_presenter.ui_presenter.draw_tooltip(
device,
"Background Color",
RectI::new(position, button_size),
);
}
// Draw background panel, if necessary.
self.draw_background_panel(device, debug_ui_presenter, position.x(), action, model);
position += vec2i(button_size.x() + PADDING, 0);
// Draw effects panel, if necessary.
self.draw_effects_panel(device, debug_ui_presenter, model, action);
// Draw rotate and zoom buttons, if applicable.
if model.mode != Mode::TwoD {
return;
}
if debug_ui_presenter.ui_presenter.draw_button(device, position, &self.rotate_texture) {
self.rotate_panel_visible = !self.rotate_panel_visible;
}
if !self.rotate_panel_visible {
debug_ui_presenter.ui_presenter.draw_tooltip(device,
"Rotate",
RectI::new(position, button_size));
}
self.draw_rotate_panel(device, debug_ui_presenter, position.x(), action, model);
position += vec2i(BUTTON_WIDTH + PADDING, 0);
// Draw zoom control.
self.draw_zoom_control(device, debug_ui_presenter, position, action);
}
fn draw_zoom_control(
&mut self,
device: &D,
debug_ui_presenter: &mut DebugUIPresenter<D>,
position: Vector2I,
action: &mut UIAction,
) {
let zoom_segmented_control_width =
debug_ui_presenter.ui_presenter.measure_segmented_control(3);
let zoom_segmented_control_rect =
RectI::new(position, vec2i(zoom_segmented_control_width, BUTTON_HEIGHT));
debug_ui_presenter.ui_presenter.draw_tooltip(device, "Zoom", zoom_segmented_control_rect);
let zoom_textures = &[
&self.zoom_in_texture,
&self.zoom_actual_size_texture,
&self.zoom_out_texture
];
match debug_ui_presenter.ui_presenter.draw_image_segmented_control(device,
position,
zoom_textures,
None) {
Some(0) => *action = UIAction::ZoomIn,
Some(1) => *action = UIAction::ZoomActualSize,
Some(2) => *action = UIAction::ZoomOut,
_ => {}
}
}
fn draw_message_text(&mut self,
device: &D,
debug_ui_presenter: &mut DebugUIPresenter<D>,
model: &mut DemoUIModel) {
if model.message.is_empty() {
return;
}
let message_size = debug_ui_presenter.ui_presenter.measure_text(&model.message);
let window_origin = vec2i(PADDING, PADDING);
let window_size = vec2i(PADDING * 2 + message_size, TOOLTIP_HEIGHT);
debug_ui_presenter.ui_presenter.draw_solid_rounded_rect(
device,
RectI::new(window_origin, window_size),
WINDOW_COLOR,
);
debug_ui_presenter.ui_presenter.draw_text(
device,
&model.message,
window_origin + vec2i(PADDING, PADDING + FONT_ASCENT),
false,
);
}
fn draw_effects_panel(&mut self,
device: &D,
debug_ui_presenter: &mut DebugUIPresenter<D>,
model: &mut DemoUIModel,
action: &mut UIAction) {
if !self.effects_panel_visible {
return;
}
let bottom = debug_ui_presenter.ui_presenter.framebuffer_size().y() - PADDING;
let effects_panel_y = bottom - (BUTTON_HEIGHT + PADDING + EFFECTS_PANEL_HEIGHT);
debug_ui_presenter.ui_presenter.draw_solid_rounded_rect(
device,
RectI::new(vec2i(PADDING, effects_panel_y),
vec2i(EFFECTS_PANEL_WIDTH, EFFECTS_PANEL_HEIGHT)),
WINDOW_COLOR,
);
self.draw_effects_switch(
device,
action,
debug_ui_presenter,
"Gamma Correction",
0,
effects_panel_y,
&mut model.gamma_correction_effect_enabled);
self.draw_effects_switch(
device,
action,
debug_ui_presenter,
"Stem Darkening",
1,
effects_panel_y,
&mut model.stem_darkening_effect_enabled);
self.draw_effects_switch(
device,
action,
debug_ui_presenter,
"Subpixel AA",
2,
effects_panel_y,
&mut model.subpixel_aa_effect_enabled);
}
fn draw_screenshot_panel<W>(
&mut self,
device: &D,
window: &mut W,
debug_ui_presenter: &mut DebugUIPresenter<D>,
panel_x: i32,
action: &mut UIAction,
) where W: Window {
if !self.screenshot_panel_visible {
return;
}
let bottom = debug_ui_presenter.ui_presenter.framebuffer_size().y() - PADDING;
let panel_y = bottom - (BUTTON_HEIGHT + PADDING + SCREENSHOT_PANEL_HEIGHT);
let panel_position = vec2i(panel_x, panel_y);
debug_ui_presenter.ui_presenter.draw_solid_rounded_rect(
device,
RectI::new(panel_position, vec2i(SCREENSHOT_PANEL_WIDTH, SCREENSHOT_PANEL_HEIGHT)),
WINDOW_COLOR,
);
self.draw_screenshot_menu_item(
device,
window,
debug_ui_presenter,
ScreenshotType::PNG,
panel_position,
action,
);
self.draw_screenshot_menu_item(
device,
window,
debug_ui_presenter,
ScreenshotType::SVG,
panel_position,
action,
);
}
fn draw_background_panel(
&mut self,
device: &D,
debug_ui_presenter: &mut DebugUIPresenter<D>,
panel_x: i32,
action: &mut UIAction,
model: &mut DemoUIModel,
) {
if !self.background_panel_visible {
return;
}
let bottom = debug_ui_presenter.ui_presenter.framebuffer_size().y() - PADDING;
let panel_y = bottom - (BUTTON_HEIGHT + PADDING + BACKGROUND_PANEL_HEIGHT);
let panel_position = vec2i(panel_x, panel_y);
debug_ui_presenter.ui_presenter.draw_solid_rounded_rect(
device,
RectI::new(panel_position, vec2i(BACKGROUND_PANEL_WIDTH, BACKGROUND_PANEL_HEIGHT)),
WINDOW_COLOR,
);
self.draw_background_menu_item(
device,
debug_ui_presenter,
BackgroundColor::Light,
panel_position,
action,
model,
);
self.draw_background_menu_item(
device,
debug_ui_presenter,
BackgroundColor::Dark,
panel_position,
action,
model,
);
self.draw_background_menu_item(
device,
debug_ui_presenter,
BackgroundColor::Transparent,
panel_position,
action,
model,
);
}
fn draw_rotate_panel(
&mut self,
device: &D,
debug_ui_presenter: &mut DebugUIPresenter<D>,
rotate_panel_x: i32,
action: &mut UIAction,
model: &mut DemoUIModel
) {
if !self.rotate_panel_visible {
return;
}
let bottom = debug_ui_presenter.ui_presenter.framebuffer_size().y() - PADDING;
let rotate_panel_y = bottom - (BUTTON_HEIGHT + PADDING + ROTATE_PANEL_HEIGHT);
let rotate_panel_origin = vec2i(rotate_panel_x, rotate_panel_y);
let rotate_panel_size = vec2i(ROTATE_PANEL_WIDTH, ROTATE_PANEL_HEIGHT);
debug_ui_presenter.ui_presenter.draw_solid_rounded_rect(
device,
RectI::new(rotate_panel_origin, rotate_panel_size),
WINDOW_COLOR,
);
let (widget_x, widget_y) = (rotate_panel_x + PADDING, rotate_panel_y + PADDING);
let widget_rect = RectI::new(vec2i(widget_x, widget_y),
vec2i(SLIDER_WIDTH, SLIDER_KNOB_HEIGHT));
if let Some(position) = debug_ui_presenter
.ui_presenter
.event_queue
.handle_mouse_down_or_dragged_in_rect(widget_rect)
{
model.rotation = position.x();
*action = UIAction::Rotate(model.rotation());
}
let slider_track_y =
rotate_panel_y + PADDING + SLIDER_KNOB_HEIGHT / 2 - SLIDER_TRACK_HEIGHT / 2;
let slider_track_rect = RectI::new(vec2i(widget_x, slider_track_y),
vec2i(SLIDER_WIDTH, SLIDER_TRACK_HEIGHT));
debug_ui_presenter.ui_presenter.draw_rect_outline(device, slider_track_rect, TEXT_COLOR);
let slider_knob_x = widget_x + model.rotation - SLIDER_KNOB_WIDTH / 2;
let slider_knob_rect = RectI::new(vec2i(slider_knob_x, widget_y),
vec2i(SLIDER_KNOB_WIDTH, SLIDER_KNOB_HEIGHT));
debug_ui_presenter.ui_presenter.draw_solid_rect(device, slider_knob_rect, TEXT_COLOR);
}
fn draw_screenshot_menu_item<W>(
&mut self,
device: &D,
window: &mut W,
debug_ui_presenter: &mut DebugUIPresenter<D>,
screenshot_type: ScreenshotType,
panel_position: Vector2I,
action: &mut UIAction,
) where W: Window {
let index = screenshot_type as i32;
let text = format!("Save as {}...", screenshot_type.as_str());
let widget_size = vec2i(BACKGROUND_PANEL_WIDTH, BUTTON_HEIGHT);
let widget_origin = panel_position + vec2i(0, widget_size.y() * index);
let widget_rect = RectI::new(widget_origin, widget_size);
if self.draw_menu_item(device,
debug_ui_presenter,
&text,
widget_rect,
false) {
// FIXME(pcwalton): This is not sufficient for Android, where we will need to take in
// the contents of the file.
if let Ok(path) = window.run_save_dialog(screenshot_type.extension()) {
self.screenshot_panel_visible = false;
*action = UIAction::TakeScreenshot(ScreenshotInfo { kind: screenshot_type, path });
}
}
}
fn draw_background_menu_item(
&mut self,
device: &D,
debug_ui_presenter: &mut DebugUIPresenter<D>,
color: BackgroundColor,
panel_position: Vector2I,
action: &mut UIAction,
model: &mut DemoUIModel,
) {
let (text, index) = (color.as_str(), color as i32);
let widget_size = vec2i(BACKGROUND_PANEL_WIDTH, BUTTON_HEIGHT);
let widget_origin = panel_position + vec2i(0, widget_size.y() * index);
let widget_rect = RectI::new(widget_origin, widget_size);
let selected = color == model.background_color;
if self.draw_menu_item(device,
debug_ui_presenter,
text,
widget_rect,
selected) {
model.background_color = color;
*action = UIAction::ModelChanged;
}
}
fn draw_menu_item(&self,
device: &D,
debug_ui_presenter: &mut DebugUIPresenter<D>,
text: &str,
widget_rect: RectI,
selected: bool)
-> bool {
if selected {
debug_ui_presenter.ui_presenter.draw_solid_rounded_rect(device,
widget_rect,
TEXT_COLOR);
}
let (text_x, text_y) = (PADDING * 2, BUTTON_TEXT_OFFSET);
let text_position = widget_rect.origin() + vec2i(text_x, text_y);
debug_ui_presenter.ui_presenter.draw_text(device, text, text_position, selected);
debug_ui_presenter.ui_presenter
.event_queue
.handle_mouse_down_in_rect(widget_rect)
.is_some()
}
fn draw_effects_switch(
&self,
device: &D,
action: &mut UIAction,
debug_ui_presenter: &mut DebugUIPresenter<D>,
text: &str,
index: i32,
window_y: i32,
value: &mut bool) {
let text_x = PADDING * 2;
let text_y = window_y + PADDING + BUTTON_TEXT_OFFSET + (BUTTON_HEIGHT + PADDING) * index;
debug_ui_presenter.ui_presenter.draw_text(device, text, vec2i(text_x, text_y), false);
let switch_width = debug_ui_presenter.ui_presenter.measure_segmented_control(2);
let switch_x = PADDING + EFFECTS_PANEL_WIDTH - (switch_width + PADDING);
let switch_y = window_y + PADDING + (BUTTON_HEIGHT + PADDING) * index;
let switch_position = vec2i(switch_x, switch_y);
let new_value =
debug_ui_presenter
.ui_presenter
.draw_text_switch(device, switch_position, &["Off", "On"], *value as u8) != 0;
if new_value != *value {
*action = UIAction::EffectsChanged;
*value = new_value;
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum UIAction {
None,
ModelChanged,
EffectsChanged,
TakeScreenshot(ScreenshotInfo),
ZoomIn,
ZoomActualSize,
ZoomOut,
Rotate(f32),
}
#[derive(Clone, Debug, PartialEq)]
pub struct ScreenshotInfo {
pub kind: ScreenshotType,
pub path: PathBuf,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ScreenshotType {
PNG = 0,
SVG = 1,
}
impl ScreenshotType {
fn extension(&self) -> &'static str {
match *self {
ScreenshotType::PNG => "png",
ScreenshotType::SVG => "svg",
}
}
fn as_str(&self) -> &'static str {
match *self {
ScreenshotType::PNG => "PNG",
ScreenshotType::SVG => "SVG",
}
}
}

View file

@ -1,117 +0,0 @@
// pathfinder/demo/common/src/window.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A minimal cross-platform windowing layer.
use pathfinder_geometry::rect::RectI;
use pathfinder_geometry::transform3d::{Perspective, Transform4F};
use pathfinder_geometry::vector::Vector2I;
use pathfinder_resources::ResourceLoader;
use rayon::ThreadPoolBuilder;
use std::path::PathBuf;
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
use metal::CoreAnimationLayerRef;
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
use pathfinder_metal::MetalDevice;
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
use gl::types::GLuint;
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
use pathfinder_gl::{GLDevice, GLVersion};
pub trait Window {
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
fn gl_version(&self) -> GLVersion;
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
fn gl_default_framebuffer(&self) -> GLuint { 0 }
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
fn present(&mut self, device: &mut GLDevice);
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
fn metal_layer(&self) -> &CoreAnimationLayerRef;
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
fn present(&mut self, device: &mut MetalDevice);
fn make_current(&mut self, view: View);
fn viewport(&self, view: View) -> RectI;
fn resource_loader(&self) -> &dyn ResourceLoader;
fn create_user_event_id(&self) -> u32;
fn push_user_event(message_type: u32, message_data: u32);
fn present_open_svg_dialog(&mut self);
fn run_save_dialog(&self, extension: &str) -> Result<PathBuf, ()>;
fn adjust_thread_pool_settings(&self, builder: ThreadPoolBuilder) -> ThreadPoolBuilder {
builder
}
}
pub enum Event {
Quit,
WindowResized(WindowSize),
KeyDown(Keycode),
KeyUp(Keycode),
MouseDown(Vector2I),
MouseMoved(Vector2I),
MouseDragged(Vector2I),
Zoom(f32, Vector2I),
Look {
pitch: f32,
yaw: f32,
},
SetEyeTransforms(Vec<OcularTransform>),
OpenSVG(SVGPath),
User {
message_type: u32,
message_data: u32,
},
}
#[derive(Clone, Copy)]
pub enum Keycode {
Alphanumeric(u8),
Escape,
Tab,
}
#[derive(Clone, Copy, Debug)]
pub struct WindowSize {
pub logical_size: Vector2I,
pub backing_scale_factor: f32,
}
impl WindowSize {
#[inline]
pub fn device_size(&self) -> Vector2I {
(self.logical_size.to_f32() * self.backing_scale_factor).to_i32()
}
}
#[derive(Clone, Copy, Debug)]
pub enum View {
Mono,
Stereo(u32),
}
#[derive(Clone, Copy, Debug)]
pub struct OcularTransform {
// The perspective which converts from camera coordinates to display coordinates
pub perspective: Perspective,
// The view transform which converts from world coordinates to camera coordinates
pub modelview_to_eye: Transform4F,
}
#[derive(Clone)]
pub enum SVGPath {
Default,
Resource(String),
Path(PathBuf),
}

View file

@ -1,4 +0,0 @@
[target.aarch64-linux-android]
linker = "./fake-ld.sh"
ar = "aarch64-linux-android-ar"
rustflags = "-Clinker-flavor=ld"

View file

@ -1 +0,0 @@
.out/

View file

@ -1,51 +0,0 @@
[package]
name = "pathfinder_magicleap_demo"
version = "0.1.0"
edition = "2018"
authors = ["Alan Jeffrey <ajeffrey@mozilla.com>"]
[dependencies]
gl = "0.14"
rayon = "1.0"
usvg = "0.9"
egl = "0.2"
log = "0.4"
smallvec = "1.2"
glutin = { version = "0.23", optional = true }
crossbeam-channel = "0.4"
[lib]
crate-type = ["cdylib"]
[features]
mocked = ["glutin"]
[dependencies.pathfinder_color]
path = "../../color"
[dependencies.pathfinder_content]
path = "../../content"
[dependencies.pathfinder_demo]
path = "../common"
[dependencies.pathfinder_geometry]
path = "../../geometry"
[dependencies.pathfinder_gl]
path = "../../gl"
[dependencies.pathfinder_gpu]
path = "../../gpu"
[dependencies.pathfinder_renderer]
path = "../../renderer"
[dependencies.pathfinder_simd]
path = "../../simd"
[dependencies.pathfinder_svg]
path = "../../svg"
[dependencies.pathfinder_ui]
path = "../../ui"

View file

@ -1,15 +0,0 @@
.PHONY: debug release install
debug:
cargo build --target aarch64-linux-android
$(MAGICLEAP_SDK)/mabu -t debug_device PathfinderDemo.package -s $(MLCERT)
release:
cargo build --release --target aarch64-linux-android
$(MAGICLEAP_SDK)/mabu -t release_device PathfinderDemo.package -s $(MLCERT)
install: .out/PathfinderDemo/PathfinderDemo.mpk
$(MAGICLEAP_SDK)/tools/mldb/mldb install -u .out/PathfinderDemo/PathfinderDemo.mpk
run:
${MAGICLEAP_SDK}/tools/mldb/mldb launch -w com.mozilla.pathfinder.demo

View file

@ -1,19 +0,0 @@
KIND = program
SRCS = src/main.cpp
LIBPATHS.debug = \
../../target/aarch64-linux-android/debug
LIBPATHS.release = \
../../target/aarch64-linux-android/release
USES = ml_sdk OpenGL stdc++
STLIBS = \
pathfinder_immersive_demo
SHLIBS = \
ml_privileges
DATAS = \
../../resources/** : resources/

View file

@ -1,8 +0,0 @@
USES = "lre/scenes"
REFS = PathfinderImmersiveDemo PathfinderLandscapeDemo
OPTIONS=package/debuggable/on
DATAS = \
../../target/aarch64-linux-android/release/*.so : bin/

View file

@ -1,17 +0,0 @@
KIND = program
SRCS = src/main.cpp
LIBPATHS.debug = \
../../target/aarch64-linux-android/debug
LIBPATHS.release = \
../../target/aarch64-linux-android/release
USES = ml_sdk OpenGL stdc++
SHLIBS = \
pathfinder_magicleap_demo \
ml_privileges
DATAS = \
../../resources/** : resources/

View file

@ -1,19 +0,0 @@
KIND = program
SRCS = src/landscape.cpp
LIBPATHS.debug = \
../../target/aarch64-linux-android/debug
LIBPATHS.release = \
../../target/aarch64-linux-android/release
INCS = \
src/ \
lre/code/inc/gen/
USES = \
lumin_runtime \
lre/code/srcs
SHLIBS = \
pathfinder_magicleap_demo

View file

@ -1,25 +0,0 @@
# Magic Leap demo
First, install v0.20.0 or later of the Magic Leap SDK. By default this is installed in `MagicLeap/mlsdk/<version>`, for example:
```
export MAGICLEAP_SDK=~/MagicLeap/mlsdk/v0.20.0
```
You will also need a signing certificate.
```
export MLCERT=~/MagicLeap/cert/mycert.cert
```
Now build the pathfinder demo library and `.mpk` archive:
```
cd demo/pathfinder
make release
```
The `.mpk` can be installed:
```
make install
```
and run:
```
make run
```

View file

@ -1,18 +0,0 @@
#!/usr/bin/env bash
# This shell script strips out the -landroid that is passed by default by rustc to
# the linker on aarch64-linux-android, and adds some entries to the ld search path.
set -o errexit
set -o nounset
set -o pipefail
TARGET=${TARGET:-"aarch64-linux-android"}
LD=${LD:-"${MAGICLEAP_SDK}/tools/toolchains/bin/${TARGET}-ld"}
LDFLAGS=${LDFLAGS:-"--sysroot=${MAGICLEAP_SDK}/lumin -L${MAGICLEAP_SDK}/lumin/usr/lib -L${MAGICLEAP_SDK}/tools/toolchains/lib/gcc/${TARGET}/4.9.x ${MAGICLEAP_SDK}/lumin/usr/lib/crtbegin_so.o"}
# Remove the -landroid flag, grr
ARGS=("$@")
ARGS=${ARGS[@]/-landroid}
${LD} ${LDFLAGS} ${ARGS}

View file

@ -1,12 +0,0 @@
.DS_Store
*.log
*.json.dirty
*.json.lock
*.pyc
*.sln
*.vcxproj*
pipeline/cache/intermediate/
.out/
.vscode/
.vs/

View file

@ -1,13 +0,0 @@
KIND = program
INCS = \
code/inc/ \
code/inc/gen/
SRCS = \
code/src/main.cpp \
code/src/PathfinderDemo.cpp
USES = \
lumin_runtime \
code/srcs

View file

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="ASCII"?>
<mlproject:mlproject xmlns:mlproject="http://www.magicleap.com/uidesigner/mlproject" generated="true" srcGenVersion="1">
<designFile path="scenes/PathfinderDemo.design"/>
<pipelineDirectory path="pipeline"/>
<preferences key="srcgen.directories.incgen" value="inc/gen"/>
<preferences key="srcgen.directories.src" value="src"/>
<preferences key="srcgen.directories.srcgen" value="src/gen"/>
<preferences key="srcgen.directories.basedir" value="code"/>
<preferences key="srcgen.directories.inc" value="inc"/>
</mlproject:mlproject>

View file

@ -1,3 +0,0 @@
USES = "scenes" "pipeline/cache/AssetManifest"
REFS = PathfinderDemo

View file

@ -1,99 +0,0 @@
// %BANNER_BEGIN%
// ---------------------------------------------------------------------
// %COPYRIGHT_BEGIN%
//
// Copyright (c) 2018 Magic Leap, Inc. All Rights Reserved.
// Use of this file is governed by the Creator Agreement, located
// here: https://id.magicleap.com/creator-terms
//
// %COPYRIGHT_END%
// ---------------------------------------------------------------------
// %BANNER_END%
// %SRC_VERSION%: 1
#include <lumin/LandscapeApp.h>
#include <lumin/Prism.h>
#include <lumin/event/ServerEvent.h>
#include <SceneDescriptor.h>
#include <PrismSceneManager.h>
/**
* PathfinderDemo Landscape Application
*/
class PathfinderDemo : public lumin::LandscapeApp {
public:
/**
* Constructs the Landscape Application.
*/
PathfinderDemo();
/**
* Destroys the Landscape Application.
*/
virtual ~PathfinderDemo();
/**
* Disallows the copy constructor.
*/
PathfinderDemo(const PathfinderDemo&) = delete;
/**
* Disallows the move constructor.
*/
PathfinderDemo(PathfinderDemo&&) = delete;
/**
* Disallows the copy assignment operator.
*/
PathfinderDemo& operator=(const PathfinderDemo&) = delete;
/**
* Disallows the move assignment operator.
*/
PathfinderDemo& operator=(PathfinderDemo&&) = delete;
protected:
/**
* Initializes the Landscape Application.
* @return - 0 on success, error code on failure.
*/
int init() override;
/**
* Deinitializes the Landscape Application.
* @return - 0 on success, error code on failure.
*/
int deInit() override;
/**
* Returns the initial size of the Prism
* Used in createPrism().
*/
const glm::vec3 getInitialPrismSize() const;
/**
* Creates the prism, updates the private variable prism_ with the created prism.
*/
void createInitialPrism();
/**
* Initializes and creates the scene of all scenes marked as initially instanced
*/
void spawnInitialScenes();
/**
* Run application login
*/
virtual bool updateLoop(float fDelta) override;
/**
* Handle events from the server
*/
virtual bool eventListener(lumin::ServerEvent* event) override;
private:
lumin::Prism* prism_ = nullptr; // represents the bounded space where the App renders.
PrismSceneManager* prismSceneManager_ = nullptr;
};

View file

@ -1,45 +0,0 @@
// -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING --
//
// THE CONTENTS OF THIS FILE IS GENERATED BY CODE AND
// ANY MODIFICATIONS WILL BE OVERWRITTEN
//
// -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING --
// %BANNER_BEGIN%
// ---------------------------------------------------------------------
// %COPYRIGHT_BEGIN%
//
// Copyright (c) 2018 Magic Leap, Inc. All Rights Reserved.
// Use of this file is governed by the Creator Agreement, located
// here: https://id.magicleap.com/creator-terms
//
// %COPYRIGHT_END%
// ---------------------------------------------------------------------
// %BANNER_END%
// %SRC_VERSION%: 1
#pragma once
#include <SpawnedSceneBase.h>
#include <SpawnedSceneHandlers.h>
namespace scenes {
namespace PathfinderDemo {
namespace externalNodes {
}
struct SpawnedScene : public SpawnedSceneBase {
SpawnedScene(const SceneDescriptor& sceneDescriptor, lumin::Node* root);
~SpawnedScene();
};
SpawnedSceneBase* createSpawnedScene(const SceneDescriptor& sceneDescriptor, lumin::Node* root);
SpawnedSceneHandlers* createSpawnedSceneHandlers(SpawnedSceneBase& spawnedScene);
extern const SceneDescriptor descriptor;
}
}

View file

@ -1,74 +0,0 @@
// -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING --
//
// THE CONTENTS OF THIS FILE IS GENERATED BY CODE AND
// ANY MODIFICATIONS WILL BE OVERWRITTEN
//
// -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING --
// %BANNER_BEGIN%
// ---------------------------------------------------------------------
// %COPYRIGHT_BEGIN%
//
// Copyright (c) 2018 Magic Leap, Inc. All Rights Reserved.
// Use of this file is governed by the Creator Agreement, located
// here: https://id.magicleap.com/creator-terms
//
// %COPYRIGHT_END%
// ---------------------------------------------------------------------
// %BANNER_END%
// %SRC_VERSION%: 1
#pragma once
#include <lumin/Prism.h>
#include <lumin/node/Node.h>
#include <SceneDescriptor.h>
#include <SpawnedSceneBase.h>
#include <SpawnedSceneUserData.h>
#include <scenes.h>
class PrismSceneManager {
public:
typedef std::function<SpawnedSceneUserData*(SpawnedSceneBase&)> (*CreateSpawnedSceneUserData);
static void setUserDataCreator(const SceneDescriptor & sceneDescriptor, CreateSpawnedSceneUserData createSpawnedSceneUserData);
public:
PrismSceneManager(lumin::Prism* prism);
enum class SceneState {
Unloaded,
ResourceModelLoaded,
ResourceAndObjectModelLoaded,
};
void setSceneState(const SceneDescriptor & sceneDescriptor, SceneState sceneState);
SceneState getSceneState(const SceneDescriptor & sceneDescriptor, SceneState sceneState) const;
SpawnedSceneBase* spawnScene(const SceneDescriptor & sceneDescriptor);
lumin::Node* spawn(const SceneDescriptor & sceneDescriptor);
private:
typedef SpawnedSceneBase* (*CreateSpawnedScene)(const SceneDescriptor& sceneDescriptor, lumin::Node* root);
static const CreateSpawnedScene createSpawnedScene[scenes::numberOfExternalScenes];
typedef SpawnedSceneHandlers* (*CreateSpawnedSceneHandlers)(SpawnedSceneBase& spawnedScene);
static const CreateSpawnedSceneHandlers createSpawnedSceneHandlers[scenes::numberOfExternalScenes];
static CreateSpawnedSceneUserData createSpawnedSceneUserData[scenes::numberOfExternalScenes];
private:
lumin::Node* createNodeTree(const SceneDescriptor & sceneDescriptor);
private:
lumin::Prism* prism_;
SceneState sceneStates_[scenes::numberOfExternalScenes];
std::string objectModelNames_[scenes::numberOfExternalScenes];
};

View file

@ -1,58 +0,0 @@
// -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING --
//
// THE CONTENTS OF THIS FILE IS GENERATED BY CODE AND
// ANY MODIFICATIONS WILL BE OVERWRITTEN
//
// -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING --
// %BANNER_BEGIN%
// ---------------------------------------------------------------------
// %COPYRIGHT_BEGIN%
//
// Copyright (c) 2018 Magic Leap, Inc. All Rights Reserved.
// Use of this file is governed by the Creator Agreement, located
// here: https://id.magicleap.com/creator-terms
//
// %COPYRIGHT_END%
// ---------------------------------------------------------------------
// %BANNER_END%
// %SRC_VERSION%: 1
#pragma once
#include <string>
#include <map>
// data class
class SceneDescriptor {
public:
typedef std::map<std::string /* externalNodeName */, const std::string& /* externalNodeId */> ExternalNodeReferences;
SceneDescriptor(int index, const char* externalName, const char* id, const char* sceneGraphFilePath, const char* resourceModelFilePath, const ExternalNodeReferences& externalNodeReferences, bool initiallySpawned);
const std::string& getExternalName() const;
const std::string& getId() const;
const std::string& getSceneGraphPath() const;
const std::string& getResourceModelPath() const;
const ExternalNodeReferences & getExternalNodeReferences() const;
bool getInitiallySpawned() const;
private:
friend class PrismSceneManager;
int getIndex() const;
private:
int index_;
std::string externalName_;
std::string id_;
std::string sceneGraphPath_;
std::string resourceModelPath_;
const ExternalNodeReferences& externalNodeReferences_;
bool initiallySpawned_;
};
bool operator<(const SceneDescriptor& a, const SceneDescriptor& b);

View file

@ -1,43 +0,0 @@
// -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING --
//
// THE CONTENTS OF THIS FILE IS GENERATED BY CODE AND
// ANY MODIFICATIONS WILL BE OVERWRITTEN
//
// -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING --
// %BANNER_BEGIN%
// ---------------------------------------------------------------------
// %COPYRIGHT_BEGIN%
//
// Copyright (c) 2018 Magic Leap, Inc. All Rights Reserved.
// Use of this file is governed by the Creator Agreement, located
// here: https://id.magicleap.com/creator-terms
//
// %COPYRIGHT_END%
// ---------------------------------------------------------------------
// %BANNER_END%
// %SRC_VERSION%: 1
#pragma once
#include <lumin/node/Node.h>
class SceneDescriptor;
class SpawnedSceneHandlers;
struct SpawnedSceneUserData;
struct SpawnedSceneBase {
SpawnedSceneBase(const SceneDescriptor &sd, lumin::Node* rt);
virtual ~SpawnedSceneBase();
SpawnedSceneBase() = delete;
SpawnedSceneBase(const SpawnedSceneBase&) = delete;
SpawnedSceneBase(const SpawnedSceneBase&&) = delete;
const SceneDescriptor& sceneDescriptor;
lumin::Node* root = nullptr;
SpawnedSceneHandlers* handlers = nullptr;
SpawnedSceneUserData* userData = nullptr;
};

Some files were not shown because too many files have changed in this diff Show more