diff --git a/demo2/pathfinder.ts b/demo2/pathfinder.ts index b4f6a4e5..e141c517 100644 --- a/demo2/pathfinder.ts +++ b/demo2/pathfinder.ts @@ -338,8 +338,8 @@ class App { gl.bindTexture(gl.TEXTURE_2D, this.stencilTexture); gl.uniform1i(this.maskTileProgram.uniforms.StencilTexture, 0); gl.uniform2f(this.maskTileProgram.uniforms.StencilTextureSize, - STENCIL_FRAMEBUFFER_SIZE.width, - STENCIL_FRAMEBUFFER_SIZE.height); + STENCIL_FRAMEBUFFER_SIZE.width, + STENCIL_FRAMEBUFFER_SIZE.height); gl.activeTexture(gl.TEXTURE1); gl.bindTexture(gl.TEXTURE_2D, this.fillColorsTexture); gl.uniform1i(this.maskTileProgram.uniforms.FillColorsTexture, 1); diff --git a/demo3/shaders/fill.fs.glsl b/demo3/shaders/fill.fs.glsl index 51ca70f1..0cb0ab7f 100644 --- a/demo3/shaders/fill.fs.glsl +++ b/demo3/shaders/fill.fs.glsl @@ -24,8 +24,7 @@ void main() { vec2 from = vFrom, to = vTo; // Determine winding, and sort into a consistent order so we only need to find one root below. - bool winding = from.x < to.x; - vec2 left = winding ? from : to, right = winding ? to : from; + vec2 left = from.x < to.x ? from : to, right = from.x < to.x ? to : from; // Shoot a vertical ray toward the curve. vec2 window = clamp(vec2(from.x, to.x), -0.5, 0.5); diff --git a/demo3/shaders/fill.vs.glsl b/demo3/shaders/fill.vs.glsl index b81bd8ad..b841116d 100644 --- a/demo3/shaders/fill.vs.glsl +++ b/demo3/shaders/fill.vs.glsl @@ -1,8 +1,8 @@ #version 330 -// pathfinder/demo2/stencil.vs.glsl +// pathfinder/demo3/fill.vs.glsl // -// Copyright © 2018 The Pathfinder Project Developers. +// Copyright © 2019 The Pathfinder Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license @@ -38,7 +38,6 @@ void main() { vec2 to = vec2(aToPx & 15u, aToPx >> 4u) + aToSubpx; vec2 position; - bool zeroArea = !(abs(from.x - to.x) > 0.1) || !(abs(uTileSize.y - min(from.y, to.y)) > 0.1); if (aTessCoord.x < 0.5) position.x = floor(min(from.x, to.x)); else @@ -51,7 +50,7 @@ void main() { vFrom = from - position; vTo = to - position; - if (zeroArea) + if (!(abs(from.x - to.x) > 0.1) || !(abs(uTileSize.y - min(from.y, to.y)) > 0.1)) gl_Position = vec4(0.0); else gl_Position = vec4((tileOrigin + position) / uFramebufferSize * 2.0 - 1.0, 0.0, 1.0); diff --git a/demo3/shaders/mask_tile.fs.glsl b/demo3/shaders/mask_tile.fs.glsl index a7ef2d81..2596e026 100644 --- a/demo3/shaders/mask_tile.fs.glsl +++ b/demo3/shaders/mask_tile.fs.glsl @@ -22,7 +22,5 @@ out vec4 oFragColor; void main() { float coverage = abs(texture(uStencilTexture, vTexCoord).r + vBackdrop); - vec4 color = vec4(1.0, 0.0, 0.0, 1.0); - //oFragColor = vec4(vColor.rgb, vColor.a * coverage); - oFragColor = vec4(color.rgb, color.a * coverage); + oFragColor = vec4(vColor.rgb, vColor.a * coverage); } diff --git a/demo3/shaders/mask_tile.vs.glsl b/demo3/shaders/mask_tile.vs.glsl index 1c7293b5..6f51b2a7 100644 --- a/demo3/shaders/mask_tile.vs.glsl +++ b/demo3/shaders/mask_tile.vs.glsl @@ -34,12 +34,18 @@ vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth) { return vec2(tileOffset) * uTileSize; } +vec2 computeFillColorTexCoord(uint object, vec2 textureSize) { + uint width = uint(textureSize.x); + return (vec2(float(object % width), float(object / width)) + vec2(0.5)) / textureSize; +} + void main() { uint tileIndex = uint(gl_InstanceID); vec2 position = (aTileOrigin + aTessCoord) * uTileSize + uViewBoxOrigin; vec2 texCoord = computeTileOffset(tileIndex, uStencilTextureSize.x) + aTessCoord * uTileSize; + vec2 colorTexCoord = computeFillColorTexCoord(aObject, uFillColorsTextureSize); vTexCoord = texCoord / uStencilTextureSize; vBackdrop = float(aBackdrop); - vColor = texture(uFillColorsTexture, vec2(float(aObject) / uFillColorsTextureSize.x, 0.0)); + vColor = texture(uFillColorsTexture, colorTexCoord); gl_Position = vec4((position / uFramebufferSize * 2.0 - 1.0) * vec2(1.0, -1.0), 0.0, 1.0); } diff --git a/demo3/shaders/solid_tile.vs.glsl b/demo3/shaders/solid_tile.vs.glsl index 38743f85..b25cdfc0 100644 --- a/demo3/shaders/solid_tile.vs.glsl +++ b/demo3/shaders/solid_tile.vs.glsl @@ -24,8 +24,14 @@ in uint aObject; out vec4 vColor; +vec2 computeFillColorTexCoord(uint object, vec2 textureSize) { + uint width = uint(textureSize.x); + return (vec2(float(object % width), float(object / width)) + vec2(0.5)) / textureSize; +} + void main() { vec2 position = (aTileOrigin + aTessCoord) * uTileSize + uViewBoxOrigin; - vColor = texture(uFillColorsTexture, vec2(float(aObject) / uFillColorsTextureSize.x, 0.0)); + vec2 colorTexCoord = computeFillColorTexCoord(aObject, uFillColorsTextureSize); + vColor = texture(uFillColorsTexture, colorTexCoord); gl_Position = vec4((position / uFramebufferSize * 2.0 - 1.0) * vec2(1.0, -1.0), 0.0, 1.0); } diff --git a/demo3/src/main.rs b/demo3/src/main.rs index 0d62c8d0..1000a463 100644 --- a/demo3/src/main.rs +++ b/demo3/src/main.rs @@ -10,10 +10,11 @@ use clap::{App, Arg}; use euclid::Size2D; -use gl::types::{GLchar, GLenum, GLfloat, GLint, GLsizei, GLsizeiptr, GLuint, GLvoid}; +use gl::types::{GLchar, GLfloat, GLint, GLsizei, GLsizeiptr, GLuint, GLvoid}; use jemallocator; use pathfinder_renderer::builder::SceneBuilder; -use pathfinder_renderer::gpu_data::{Batch, BuiltScene, FillBatchPrimitive}; +use pathfinder_renderer::gpu_data::{Batch, BuiltScene, SolidTileScenePrimitive}; +use pathfinder_renderer::paint::ObjectShader; use pathfinder_renderer::scene::Scene; use pathfinder_renderer::tiles::{TILE_HEIGHT, TILE_WIDTH}; use pathfinder_renderer::z_buffer::ZBuffer; @@ -44,10 +45,12 @@ const MASK_TILE_INSTANCE_SIZE: GLint = 8; const MASK_FRAMEBUFFER_WIDTH: u32 = TILE_WIDTH * 256; const MASK_FRAMEBUFFER_HEIGHT: u32 = TILE_HEIGHT * 256; -// FIXME(pcwalton): Make this dynamic! const MAIN_FRAMEBUFFER_WIDTH: u32 = 800; const MAIN_FRAMEBUFFER_HEIGHT: u32 = 800; +const FILL_COLORS_TEXTURE_WIDTH: u32 = 256; +const FILL_COLORS_TEXTURE_HEIGHT: u32 = 256; + fn main() { let scene = load_scene(); @@ -61,6 +64,7 @@ fn main() { let window = sdl_video.window("Pathfinder Demo", MAIN_FRAMEBUFFER_WIDTH, MAIN_FRAMEBUFFER_HEIGHT) .opengl() + .allow_highdpi() .build() .unwrap(); @@ -69,9 +73,11 @@ fn main() { let mut sdl_event_pump = sdl_context.event_pump().unwrap(); let mut exit = false; - while !exit { - let mut renderer = Renderer::new(); + let (drawable_width, drawable_height) = window.drawable_size(); + let mut renderer = Renderer::new(&Size2D::new(drawable_width, drawable_height)); + + while !exit { unsafe { gl::ClearColor(1.0, 1.0, 1.0, 1.0); gl::Clear(gl::COLOR_BUFFER_BIT); @@ -190,10 +196,13 @@ struct Renderer { mask_tile_vertex_array: MaskTileVertexArray, solid_tile_vertex_array: SolidTileVertexArray, mask_framebuffer: Framebuffer, + fill_colors_texture: Texture, + + main_framebuffer_size: Size2D, } impl Renderer { - fn new() -> Renderer { + fn new(main_framebuffer_size: &Size2D) -> Renderer { let fill_program = FillProgram::new(); let solid_tile_program = SolidTileProgram::new(); let mask_tile_program = MaskTileProgram::new(); @@ -212,6 +221,9 @@ impl Renderer { let mask_framebuffer = Framebuffer::new(&Size2D::new(MASK_FRAMEBUFFER_WIDTH, MASK_FRAMEBUFFER_HEIGHT)); + let fill_colors_texture = Texture::new_rgba(&Size2D::new(FILL_COLORS_TEXTURE_WIDTH, + FILL_COLORS_TEXTURE_HEIGHT)); + Renderer { fill_program, solid_tile_program, @@ -222,10 +234,18 @@ impl Renderer { mask_tile_vertex_array, solid_tile_vertex_array, mask_framebuffer, + fill_colors_texture, + + main_framebuffer_size: *main_framebuffer_size, } } fn render_scene(&mut self, built_scene: &BuiltScene) { + self.upload_shaders(&built_scene.shaders); + + self.upload_solid_tiles(&built_scene.solid_tiles); + self.draw_solid_tiles(&built_scene.solid_tiles); + for batch in &built_scene.batches { self.upload_batch(batch); self.draw_batch_fills(batch); @@ -233,6 +253,22 @@ impl Renderer { } } + fn upload_shaders(&mut self, shaders: &[ObjectShader]) { + let size = Size2D::new(FILL_COLORS_TEXTURE_WIDTH, FILL_COLORS_TEXTURE_HEIGHT); + let mut fill_colors = vec![0; size.width as usize * size.height as usize * 4]; + for (shader_index, shader) in shaders.iter().enumerate() { + fill_colors[shader_index * 4 + 0] = shader.fill_color.r; + fill_colors[shader_index * 4 + 1] = shader.fill_color.g; + fill_colors[shader_index * 4 + 2] = shader.fill_color.b; + fill_colors[shader_index * 4 + 3] = shader.fill_color.a; + } + self.fill_colors_texture.upload_rgba(&size, &fill_colors); + } + + fn upload_solid_tiles(&mut self, solid_tiles: &[SolidTileScenePrimitive]) { + self.solid_tile_vertex_array.vertex_buffer.upload(solid_tiles, BufferUploadMode::Dynamic); + } + fn upload_batch(&mut self, batch: &Batch) { self.fill_vertex_array.vertex_buffer.upload(&batch.fills, BufferUploadMode::Dynamic); self.mask_tile_vertex_array.vertex_buffer.upload(&batch.mask_tiles, @@ -268,13 +304,16 @@ impl Renderer { fn draw_batch_mask_tiles(&mut self, batch: &Batch) { unsafe { gl::BindFramebuffer(gl::FRAMEBUFFER, 0); - gl::Viewport(0, 0, MAIN_FRAMEBUFFER_WIDTH as GLint, MAIN_FRAMEBUFFER_HEIGHT as GLint); + gl::Viewport(0, + 0, + self.main_framebuffer_size.width as GLint, + self.main_framebuffer_size.height as GLint); gl::BindVertexArray(self.mask_tile_vertex_array.gl_vertex_array); gl::UseProgram(self.mask_tile_program.program.gl_program); gl::Uniform2f(self.mask_tile_program.framebuffer_size_uniform.location, - MAIN_FRAMEBUFFER_WIDTH as GLfloat, - MAIN_FRAMEBUFFER_HEIGHT as GLfloat); + self.main_framebuffer_size.width as GLfloat, + self.main_framebuffer_size.height as GLfloat); gl::Uniform2f(self.mask_tile_program.tile_size_uniform.location, TILE_WIDTH as GLfloat, TILE_HEIGHT as GLfloat); @@ -283,6 +322,11 @@ impl Renderer { gl::Uniform2f(self.mask_tile_program.stencil_texture_size_uniform.location, MASK_FRAMEBUFFER_WIDTH as GLfloat, MASK_FRAMEBUFFER_HEIGHT as GLfloat); + self.fill_colors_texture.bind(1); + gl::Uniform1i(self.mask_tile_program.fill_colors_texture_uniform.location, 1); + gl::Uniform2f(self.mask_tile_program.fill_colors_texture_size_uniform.location, + FILL_COLORS_TEXTURE_WIDTH as GLfloat, + FILL_COLORS_TEXTURE_HEIGHT as GLfloat); // FIXME(pcwalton): Fill this in properly! gl::Uniform2f(self.mask_tile_program.view_box_origin_uniform.location, 0.0, 0.0); gl::BlendEquation(gl::FUNC_ADD); @@ -292,6 +336,34 @@ impl Renderer { gl::Disable(gl::BLEND); } } + + fn draw_solid_tiles(&mut self, solid_tiles: &[SolidTileScenePrimitive]) { + unsafe { + gl::BindFramebuffer(gl::FRAMEBUFFER, 0); + gl::Viewport(0, + 0, + self.main_framebuffer_size.width as GLint, + self.main_framebuffer_size.height as GLint); + + gl::BindVertexArray(self.solid_tile_vertex_array.gl_vertex_array); + gl::UseProgram(self.solid_tile_program.program.gl_program); + gl::Uniform2f(self.solid_tile_program.framebuffer_size_uniform.location, + self.main_framebuffer_size.width as GLfloat, + self.main_framebuffer_size.height as GLfloat); + gl::Uniform2f(self.solid_tile_program.tile_size_uniform.location, + TILE_WIDTH as GLfloat, + TILE_HEIGHT as GLfloat); + self.fill_colors_texture.bind(0); + gl::Uniform1i(self.solid_tile_program.fill_colors_texture_uniform.location, 0); + gl::Uniform2f(self.solid_tile_program.fill_colors_texture_size_uniform.location, + FILL_COLORS_TEXTURE_WIDTH as GLfloat, + FILL_COLORS_TEXTURE_HEIGHT as GLfloat); + // FIXME(pcwalton): Fill this in properly! + gl::Uniform2f(self.solid_tile_program.view_box_origin_uniform.location, 0.0, 0.0); + gl::Disable(gl::BLEND); + gl::DrawArraysInstanced(gl::TRIANGLE_FAN, 0, 4, solid_tiles.len() as GLint); + } + } } struct FillVertexArray { @@ -587,6 +659,7 @@ impl MaskTileProgram { } } +#[derive(Debug)] struct Uniform { location: GLint, } @@ -727,6 +800,26 @@ impl Texture { texture } + fn new_rgba(size: &Size2D) -> Texture { + let mut texture = Texture { gl_texture: 0 }; + unsafe { + gl::GenTextures(1, &mut texture.gl_texture); + texture.bind(0); + gl::TexImage2D(gl::TEXTURE_2D, + 0, + gl::RGBA as GLint, + size.width as GLsizei, + size.height as GLsizei, + 0, + gl::RGBA, + gl::UNSIGNED_BYTE, + ptr::null()); + } + + texture.set_parameters(); + texture + } + fn from_png(name: &str) -> Texture { let path = format!("textures/{}.png", name); let image = image::open(&path).unwrap().to_luma(); @@ -757,6 +850,24 @@ impl Texture { } } + fn upload_rgba(&self, size: &Size2D, data: &[u8]) { + assert!(data.len() >= size.width as usize * size.height as usize * 4); + unsafe { + self.bind(0); + gl::TexImage2D(gl::TEXTURE_2D, + 0, + gl::RGBA as GLint, + size.width as GLsizei, + size.height as GLsizei, + 0, + gl::RGBA, + gl::UNSIGNED_BYTE, + data.as_ptr() as *const GLvoid); + } + + self.set_parameters(); + } + fn set_parameters(&self) { self.bind(0); unsafe { diff --git a/geometry/src/line_segment.rs b/geometry/src/line_segment.rs index 2d424240..ae32d569 100644 --- a/geometry/src/line_segment.rs +++ b/geometry/src/line_segment.rs @@ -161,9 +161,9 @@ impl Sub for LineSegmentF32 { } #[derive(Clone, Copy, Debug)] -#[repr(C)] +#[repr(transparent)] pub struct LineSegmentU4(pub u16); #[derive(Clone, Copy, Debug)] -#[repr(C)] +#[repr(transparent)] pub struct LineSegmentU8(pub u32); diff --git a/renderer/src/gpu_data.rs b/renderer/src/gpu_data.rs index 82aeb538..42d93351 100644 --- a/renderer/src/gpu_data.rs +++ b/renderer/src/gpu_data.rs @@ -60,7 +60,7 @@ pub struct TileObjectPrimitive { } #[derive(Clone, Copy, Debug)] -#[repr(C)] +#[repr(packed)] pub struct FillBatchPrimitive { pub px: LineSegmentU4, pub subpx: LineSegmentU8,