Factor out the GL rendering code into a separate crate
This commit is contained in:
parent
b6432fa47d
commit
dd480feb52
|
@ -162,16 +162,13 @@ dependencies = [
|
|||
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"jemallocator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pathfinder_geometry 0.3.0",
|
||||
"pathfinder_gl 0.1.0",
|
||||
"pathfinder_renderer 0.1.0",
|
||||
"pathfinder_svg 0.1.0",
|
||||
"rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sdl2 0.32.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"usvg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -531,6 +528,20 @@ dependencies = [
|
|||
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pathfinder_gl"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pathfinder_geometry 0.3.0",
|
||||
"pathfinder_renderer 0.1.0",
|
||||
"serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pathfinder_renderer"
|
||||
version = "0.1.0"
|
||||
|
|
|
@ -3,6 +3,7 @@ members = [
|
|||
"demo3",
|
||||
"geometry",
|
||||
"gfx-utils",
|
||||
"gl",
|
||||
"renderer",
|
||||
"svg",
|
||||
"utils/area-lut",
|
||||
|
|
|
@ -11,19 +11,14 @@ gl = "0.6"
|
|||
jemallocator = "0.1"
|
||||
rayon = "1.0"
|
||||
sdl2 = "0.32"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
serde_json = "1.0"
|
||||
usvg = "0.4"
|
||||
|
||||
[dependencies.image]
|
||||
version = "0.21"
|
||||
default-features = false
|
||||
features = ["png_codec"]
|
||||
|
||||
[dependencies.pathfinder_geometry]
|
||||
path = "../geometry"
|
||||
|
||||
[dependencies.pathfinder_gl]
|
||||
path = "../gl"
|
||||
|
||||
[dependencies.pathfinder_renderer]
|
||||
path = "../renderer"
|
||||
|
||||
|
|
|
@ -8,57 +8,32 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
use crate::debug_text::DebugRenderer;
|
||||
use crate::device::{Buffer, BufferTarget, BufferUploadMode, Framebuffer, Program, Texture};
|
||||
use crate::device::{TimerQuery, Uniform, VertexAttr};
|
||||
use clap::{App, Arg};
|
||||
use euclid::{Point2D, Rect, Size2D};
|
||||
use gl::types::{GLfloat, GLint, GLuint};
|
||||
use jemallocator;
|
||||
use pathfinder_geometry::point::Point4DF32;
|
||||
use pathfinder_geometry::transform3d::{Perspective, Transform3DF32};
|
||||
use pathfinder_gl::renderer::Renderer;
|
||||
use pathfinder_renderer::builder::SceneBuilder;
|
||||
use pathfinder_renderer::gpu_data::{Batch, BuiltScene, SolidTileScenePrimitive};
|
||||
use pathfinder_renderer::paint::ObjectShader;
|
||||
use pathfinder_renderer::gpu_data::BuiltScene;
|
||||
use pathfinder_renderer::scene::Scene;
|
||||
use pathfinder_renderer::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
||||
use pathfinder_renderer::z_buffer::ZBuffer;
|
||||
use pathfinder_svg::SceneExt;
|
||||
use rayon::ThreadPoolBuilder;
|
||||
use sdl2::event::Event;
|
||||
use sdl2::keyboard::Keycode;
|
||||
use sdl2::video::GLProfile;
|
||||
use std::collections::VecDeque;
|
||||
use std::f32::consts::FRAC_PI_4;
|
||||
use std::time::{Duration, Instant};
|
||||
use std::time::Instant;
|
||||
use std::path::PathBuf;
|
||||
use usvg::{Options as UsvgOptions, Tree};
|
||||
|
||||
mod debug_text;
|
||||
mod device;
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||
|
||||
static QUAD_VERTEX_POSITIONS: [u8; 8] = [0, 0, 1, 0, 1, 1, 0, 1];
|
||||
|
||||
// TODO(pcwalton): Replace with `mem::size_of` calls?
|
||||
const FILL_INSTANCE_SIZE: GLint = 8;
|
||||
const SOLID_TILE_INSTANCE_SIZE: GLint = 6;
|
||||
const MASK_TILE_INSTANCE_SIZE: GLint = 8;
|
||||
|
||||
const MASK_FRAMEBUFFER_WIDTH: u32 = TILE_WIDTH * 256;
|
||||
const MASK_FRAMEBUFFER_HEIGHT: u32 = TILE_HEIGHT * 256;
|
||||
|
||||
const MAIN_FRAMEBUFFER_WIDTH: u32 = 1067;
|
||||
const MAIN_FRAMEBUFFER_HEIGHT: u32 = 800;
|
||||
|
||||
const FILL_COLORS_TEXTURE_WIDTH: u32 = 256;
|
||||
const FILL_COLORS_TEXTURE_HEIGHT: u32 = 256;
|
||||
|
||||
const MOUSELOOK_ROTATION_SPEED: f32 = 0.01;
|
||||
const CAMERA_VELOCITY: f32 = 0.03;
|
||||
|
||||
|
@ -299,420 +274,3 @@ fn build_scene(scene: &Scene, options: &Options) -> BuiltScene {
|
|||
}
|
||||
built_scene
|
||||
}
|
||||
|
||||
struct Renderer {
|
||||
fill_program: FillProgram,
|
||||
solid_tile_program: SolidTileProgram,
|
||||
mask_tile_program: MaskTileProgram,
|
||||
area_lut_texture: Texture,
|
||||
#[allow(dead_code)]
|
||||
quad_vertex_positions_buffer: Buffer,
|
||||
fill_vertex_array: FillVertexArray,
|
||||
mask_tile_vertex_array: MaskTileVertexArray,
|
||||
solid_tile_vertex_array: SolidTileVertexArray,
|
||||
mask_framebuffer: Framebuffer,
|
||||
fill_colors_texture: Texture,
|
||||
|
||||
pending_timer_queries: VecDeque<TimerQuery>,
|
||||
free_timer_queries: Vec<TimerQuery>,
|
||||
|
||||
debug_renderer: DebugRenderer,
|
||||
|
||||
main_framebuffer_size: Size2D<u32>,
|
||||
}
|
||||
|
||||
impl Renderer {
|
||||
fn new(main_framebuffer_size: &Size2D<u32>) -> Renderer {
|
||||
let fill_program = FillProgram::new();
|
||||
let solid_tile_program = SolidTileProgram::new();
|
||||
let mask_tile_program = MaskTileProgram::new();
|
||||
|
||||
let area_lut_texture = Texture::from_png("area-lut");
|
||||
|
||||
let quad_vertex_positions_buffer = Buffer::new();
|
||||
quad_vertex_positions_buffer.upload(&QUAD_VERTEX_POSITIONS,
|
||||
BufferTarget::Vertex,
|
||||
BufferUploadMode::Static);
|
||||
|
||||
let fill_vertex_array = FillVertexArray::new(&fill_program, &quad_vertex_positions_buffer);
|
||||
let mask_tile_vertex_array = MaskTileVertexArray::new(&mask_tile_program,
|
||||
&quad_vertex_positions_buffer);
|
||||
let solid_tile_vertex_array = SolidTileVertexArray::new(&solid_tile_program,
|
||||
&quad_vertex_positions_buffer);
|
||||
|
||||
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));
|
||||
|
||||
let debug_renderer = DebugRenderer::new(main_framebuffer_size);
|
||||
|
||||
Renderer {
|
||||
fill_program,
|
||||
solid_tile_program,
|
||||
mask_tile_program,
|
||||
area_lut_texture,
|
||||
quad_vertex_positions_buffer,
|
||||
fill_vertex_array,
|
||||
mask_tile_vertex_array,
|
||||
solid_tile_vertex_array,
|
||||
mask_framebuffer,
|
||||
fill_colors_texture,
|
||||
|
||||
pending_timer_queries: VecDeque::new(),
|
||||
free_timer_queries: vec![],
|
||||
|
||||
debug_renderer,
|
||||
|
||||
main_framebuffer_size: *main_framebuffer_size,
|
||||
}
|
||||
}
|
||||
|
||||
fn render_scene(&mut self, built_scene: &BuiltScene) {
|
||||
let timer_query = self.free_timer_queries.pop().unwrap_or_else(|| TimerQuery::new());
|
||||
timer_query.begin();
|
||||
|
||||
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);
|
||||
self.draw_batch_mask_tiles(batch);
|
||||
}
|
||||
|
||||
timer_query.end();
|
||||
self.pending_timer_queries.push_back(timer_query);
|
||||
}
|
||||
|
||||
fn shift_timer_query(&mut self) -> Option<Duration> {
|
||||
let query = self.pending_timer_queries.front()?;
|
||||
if !query.is_available() {
|
||||
return None
|
||||
}
|
||||
let query = self.pending_timer_queries.pop_front().unwrap();
|
||||
let result = Duration::from_nanos(query.get());
|
||||
self.free_timer_queries.push(query);
|
||||
Some(result)
|
||||
}
|
||||
|
||||
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, BufferTarget::Vertex, BufferUploadMode::Dynamic);
|
||||
}
|
||||
|
||||
fn upload_batch(&mut self, batch: &Batch) {
|
||||
self.fill_vertex_array
|
||||
.vertex_buffer
|
||||
.upload(&batch.fills, BufferTarget::Vertex, BufferUploadMode::Dynamic);
|
||||
self.mask_tile_vertex_array
|
||||
.vertex_buffer
|
||||
.upload(&batch.mask_tiles, BufferTarget::Vertex, BufferUploadMode::Dynamic);
|
||||
}
|
||||
|
||||
fn draw_batch_fills(&mut self, batch: &Batch) {
|
||||
unsafe {
|
||||
gl::BindFramebuffer(gl::FRAMEBUFFER, self.mask_framebuffer.gl_framebuffer);
|
||||
gl::Viewport(0, 0, MASK_FRAMEBUFFER_WIDTH as GLint, MASK_FRAMEBUFFER_HEIGHT as GLint);
|
||||
// TODO(pcwalton): Only clear the appropriate portion?
|
||||
gl::ClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
gl::Clear(gl::COLOR_BUFFER_BIT);
|
||||
|
||||
gl::BindVertexArray(self.fill_vertex_array.gl_vertex_array);
|
||||
gl::UseProgram(self.fill_program.program.gl_program);
|
||||
gl::Uniform2f(self.fill_program.framebuffer_size_uniform.location,
|
||||
MASK_FRAMEBUFFER_WIDTH as GLfloat,
|
||||
MASK_FRAMEBUFFER_HEIGHT as GLfloat);
|
||||
gl::Uniform2f(self.fill_program.tile_size_uniform.location,
|
||||
TILE_WIDTH as GLfloat,
|
||||
TILE_HEIGHT as GLfloat);
|
||||
self.area_lut_texture.bind(0);
|
||||
gl::Uniform1i(self.fill_program.area_lut_uniform.location, 0);
|
||||
gl::BlendEquation(gl::FUNC_ADD);
|
||||
gl::BlendFunc(gl::ONE, gl::ONE);
|
||||
gl::Enable(gl::BLEND);
|
||||
gl::DrawArraysInstanced(gl::TRIANGLE_FAN, 0, 4, batch.fills.len() as GLint);
|
||||
gl::Disable(gl::BLEND);
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_batch_mask_tiles(&mut self, batch: &Batch) {
|
||||
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.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,
|
||||
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);
|
||||
self.mask_framebuffer.texture.bind(0);
|
||||
gl::Uniform1i(self.mask_tile_program.stencil_texture_uniform.location, 0);
|
||||
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);
|
||||
gl::BlendFuncSeparate(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA, gl::ONE, gl::ONE);
|
||||
gl::Enable(gl::BLEND);
|
||||
gl::DrawArraysInstanced(gl::TRIANGLE_FAN, 0, 4, batch.mask_tiles.len() as GLint);
|
||||
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 {
|
||||
gl_vertex_array: GLuint,
|
||||
vertex_buffer: Buffer,
|
||||
}
|
||||
|
||||
impl FillVertexArray {
|
||||
fn new(fill_program: &FillProgram, quad_vertex_positions_buffer: &Buffer) -> FillVertexArray {
|
||||
let vertex_buffer = Buffer::new();
|
||||
let mut gl_vertex_array = 0;
|
||||
unsafe {
|
||||
let tess_coord_attr = VertexAttr::new(&fill_program.program, "TessCoord");
|
||||
let from_px_attr = VertexAttr::new(&fill_program.program, "FromPx");
|
||||
let to_px_attr = VertexAttr::new(&fill_program.program, "ToPx");
|
||||
let from_subpx_attr = VertexAttr::new(&fill_program.program, "FromSubpx");
|
||||
let to_subpx_attr = VertexAttr::new(&fill_program.program, "ToSubpx");
|
||||
let tile_index_attr = VertexAttr::new(&fill_program.program, "TileIndex");
|
||||
|
||||
gl::GenVertexArrays(1, &mut gl_vertex_array);
|
||||
gl::BindVertexArray(gl_vertex_array);
|
||||
gl::UseProgram(fill_program.program.gl_program);
|
||||
gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer);
|
||||
tess_coord_attr.configure_float(2, gl::UNSIGNED_BYTE, false, 0, 0, 0);
|
||||
gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer.gl_buffer);
|
||||
from_px_attr.configure_int(1, gl::UNSIGNED_BYTE, FILL_INSTANCE_SIZE, 0, 1);
|
||||
to_px_attr.configure_int(1, gl::UNSIGNED_BYTE, FILL_INSTANCE_SIZE, 1, 1);
|
||||
from_subpx_attr.configure_float(2, gl::UNSIGNED_BYTE, true, FILL_INSTANCE_SIZE, 2, 1);
|
||||
to_subpx_attr.configure_float(2, gl::UNSIGNED_BYTE, true, FILL_INSTANCE_SIZE, 4, 1);
|
||||
tile_index_attr.configure_int(1, gl::UNSIGNED_SHORT, FILL_INSTANCE_SIZE, 6, 1);
|
||||
}
|
||||
|
||||
FillVertexArray { gl_vertex_array, vertex_buffer }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for FillVertexArray {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
gl::DeleteVertexArrays(1, &mut self.gl_vertex_array);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MaskTileVertexArray {
|
||||
gl_vertex_array: GLuint,
|
||||
vertex_buffer: Buffer,
|
||||
}
|
||||
|
||||
impl MaskTileVertexArray {
|
||||
fn new(mask_tile_program: &MaskTileProgram, quad_vertex_positions_buffer: &Buffer)
|
||||
-> MaskTileVertexArray {
|
||||
let vertex_buffer = Buffer::new();
|
||||
let mut gl_vertex_array = 0;
|
||||
unsafe {
|
||||
let tess_coord_attr = VertexAttr::new(&mask_tile_program.program, "TessCoord");
|
||||
let tile_origin_attr = VertexAttr::new(&mask_tile_program.program, "TileOrigin");
|
||||
let backdrop_attr = VertexAttr::new(&mask_tile_program.program, "Backdrop");
|
||||
let object_attr = VertexAttr::new(&mask_tile_program.program, "Object");
|
||||
|
||||
gl::GenVertexArrays(1, &mut gl_vertex_array);
|
||||
gl::BindVertexArray(gl_vertex_array);
|
||||
gl::UseProgram(mask_tile_program.program.gl_program);
|
||||
gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer);
|
||||
tess_coord_attr.configure_float(2, gl::UNSIGNED_BYTE, false, 0, 0, 0);
|
||||
gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer.gl_buffer);
|
||||
tile_origin_attr.configure_float(2, gl::SHORT, false, MASK_TILE_INSTANCE_SIZE, 0, 1);
|
||||
backdrop_attr.configure_int(1, gl::SHORT, MASK_TILE_INSTANCE_SIZE, 4, 1);
|
||||
object_attr.configure_int(2, gl::UNSIGNED_SHORT, MASK_TILE_INSTANCE_SIZE, 6, 1);
|
||||
}
|
||||
|
||||
MaskTileVertexArray { gl_vertex_array, vertex_buffer }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for MaskTileVertexArray {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
gl::DeleteVertexArrays(1, &mut self.gl_vertex_array);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SolidTileVertexArray {
|
||||
gl_vertex_array: GLuint,
|
||||
vertex_buffer: Buffer,
|
||||
}
|
||||
|
||||
impl SolidTileVertexArray {
|
||||
fn new(solid_tile_program: &SolidTileProgram, quad_vertex_positions_buffer: &Buffer)
|
||||
-> SolidTileVertexArray {
|
||||
let vertex_buffer = Buffer::new();
|
||||
let mut gl_vertex_array = 0;
|
||||
unsafe {
|
||||
let tess_coord_attr = VertexAttr::new(&solid_tile_program.program, "TessCoord");
|
||||
let tile_origin_attr = VertexAttr::new(&solid_tile_program.program, "TileOrigin");
|
||||
let object_attr = VertexAttr::new(&solid_tile_program.program, "Object");
|
||||
|
||||
gl::GenVertexArrays(1, &mut gl_vertex_array);
|
||||
gl::BindVertexArray(gl_vertex_array);
|
||||
gl::UseProgram(solid_tile_program.program.gl_program);
|
||||
gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer);
|
||||
tess_coord_attr.configure_float(2, gl::UNSIGNED_BYTE, false, 0, 0, 0);
|
||||
gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer.gl_buffer);
|
||||
tile_origin_attr.configure_float(2, gl::SHORT, false, SOLID_TILE_INSTANCE_SIZE, 0, 1);
|
||||
object_attr.configure_int(1, gl::UNSIGNED_SHORT, SOLID_TILE_INSTANCE_SIZE, 4, 1);
|
||||
}
|
||||
|
||||
SolidTileVertexArray { gl_vertex_array, vertex_buffer }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for SolidTileVertexArray {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
gl::DeleteVertexArrays(1, &mut self.gl_vertex_array);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct FillProgram {
|
||||
program: Program,
|
||||
framebuffer_size_uniform: Uniform,
|
||||
tile_size_uniform: Uniform,
|
||||
area_lut_uniform: Uniform,
|
||||
}
|
||||
|
||||
impl FillProgram {
|
||||
fn new() -> FillProgram {
|
||||
let program = Program::new("fill");
|
||||
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
||||
let tile_size_uniform = Uniform::new(&program, "TileSize");
|
||||
let area_lut_uniform = Uniform::new(&program, "AreaLUT");
|
||||
FillProgram { program, framebuffer_size_uniform, tile_size_uniform, area_lut_uniform }
|
||||
}
|
||||
}
|
||||
|
||||
struct SolidTileProgram {
|
||||
program: Program,
|
||||
framebuffer_size_uniform: Uniform,
|
||||
tile_size_uniform: Uniform,
|
||||
fill_colors_texture_uniform: Uniform,
|
||||
fill_colors_texture_size_uniform: Uniform,
|
||||
view_box_origin_uniform: Uniform,
|
||||
}
|
||||
|
||||
impl SolidTileProgram {
|
||||
fn new() -> SolidTileProgram {
|
||||
let program = Program::new("solid_tile");
|
||||
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
||||
let tile_size_uniform = Uniform::new(&program, "TileSize");
|
||||
let fill_colors_texture_uniform = Uniform::new(&program, "FillColorsTexture");
|
||||
let fill_colors_texture_size_uniform = Uniform::new(&program, "FillColorsTextureSize");
|
||||
let view_box_origin_uniform = Uniform::new(&program, "ViewBoxOrigin");
|
||||
SolidTileProgram {
|
||||
program,
|
||||
framebuffer_size_uniform,
|
||||
tile_size_uniform,
|
||||
fill_colors_texture_uniform,
|
||||
fill_colors_texture_size_uniform,
|
||||
view_box_origin_uniform,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MaskTileProgram {
|
||||
program: Program,
|
||||
framebuffer_size_uniform: Uniform,
|
||||
tile_size_uniform: Uniform,
|
||||
stencil_texture_uniform: Uniform,
|
||||
stencil_texture_size_uniform: Uniform,
|
||||
fill_colors_texture_uniform: Uniform,
|
||||
fill_colors_texture_size_uniform: Uniform,
|
||||
view_box_origin_uniform: Uniform,
|
||||
}
|
||||
|
||||
impl MaskTileProgram {
|
||||
fn new() -> MaskTileProgram {
|
||||
let program = Program::new("mask_tile");
|
||||
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
||||
let tile_size_uniform = Uniform::new(&program, "TileSize");
|
||||
let stencil_texture_uniform = Uniform::new(&program, "StencilTexture");
|
||||
let stencil_texture_size_uniform = Uniform::new(&program, "StencilTextureSize");
|
||||
let fill_colors_texture_uniform = Uniform::new(&program, "FillColorsTexture");
|
||||
let fill_colors_texture_size_uniform = Uniform::new(&program, "FillColorsTextureSize");
|
||||
let view_box_origin_uniform = Uniform::new(&program, "ViewBoxOrigin");
|
||||
MaskTileProgram {
|
||||
program,
|
||||
framebuffer_size_uniform,
|
||||
tile_size_uniform,
|
||||
stencil_texture_uniform,
|
||||
stencil_texture_size_uniform,
|
||||
fill_colors_texture_uniform,
|
||||
fill_colors_texture_size_uniform,
|
||||
view_box_origin_uniform,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
[package]
|
||||
name = "pathfinder_gl"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
|
||||
|
||||
[dependencies]
|
||||
euclid = "0.19"
|
||||
gl = "0.6"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
serde_json = "1.0"
|
||||
|
||||
[dependencies.image]
|
||||
version = "0.21"
|
||||
default-features = false
|
||||
features = ["png_codec"]
|
||||
|
||||
[dependencies.pathfinder_geometry]
|
||||
path = "../geometry"
|
||||
|
||||
[dependencies.pathfinder_renderer]
|
||||
path = "../renderer"
|
|
@ -1,4 +1,4 @@
|
|||
// pathfinder/demo3/src/debug_text.rs
|
||||
// pathfinder/gl/src/debug.rs
|
||||
//
|
||||
// Copyright © 2019 The Pathfinder Project Developers.
|
||||
//
|
||||
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Minimal text rendering.
|
||||
//! A debug overlay.
|
||||
//!
|
||||
//! We don't render the demo UI text using Pathfinder itself so that we can use the debug UI to
|
||||
//! debug Pathfinder if it's totally busted.
|
|
@ -0,0 +1,23 @@
|
|||
// pathfinder/gl/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.
|
||||
|
||||
//! An OpenGL backend for Pathfinder.
|
||||
//!
|
||||
//! It's not necessary to use this crate to render vector graphics with
|
||||
//! Pathfinder; you can use the `pathfinder_renderer` crate and do the GPU
|
||||
//! rendering yourself using the API or engine of your choice. This crate can
|
||||
//! be useful for simple use cases, however.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
pub mod debug;
|
||||
pub mod device;
|
||||
pub mod renderer;
|
|
@ -0,0 +1,450 @@
|
|||
// pathfinder/gl/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.
|
||||
|
||||
use crate::debug::DebugRenderer;
|
||||
use crate::device::{Buffer, BufferTarget, BufferUploadMode, Framebuffer, Program, Texture};
|
||||
use crate::device::{TimerQuery, Uniform, VertexAttr};
|
||||
use euclid::Size2D;
|
||||
use gl::types::{GLfloat, GLint, GLuint};
|
||||
use pathfinder_renderer::gpu_data::{Batch, BuiltScene, SolidTileScenePrimitive};
|
||||
use pathfinder_renderer::paint::ObjectShader;
|
||||
use pathfinder_renderer::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
||||
use std::collections::VecDeque;
|
||||
use std::time::Duration;
|
||||
|
||||
static QUAD_VERTEX_POSITIONS: [u8; 8] = [0, 0, 1, 0, 1, 1, 0, 1];
|
||||
|
||||
const MASK_FRAMEBUFFER_WIDTH: u32 = TILE_WIDTH * 256;
|
||||
const MASK_FRAMEBUFFER_HEIGHT: u32 = TILE_HEIGHT * 256;
|
||||
|
||||
// TODO(pcwalton): Replace with `mem::size_of` calls?
|
||||
const FILL_INSTANCE_SIZE: GLint = 8;
|
||||
const SOLID_TILE_INSTANCE_SIZE: GLint = 6;
|
||||
const MASK_TILE_INSTANCE_SIZE: GLint = 8;
|
||||
|
||||
const FILL_COLORS_TEXTURE_WIDTH: u32 = 256;
|
||||
const FILL_COLORS_TEXTURE_HEIGHT: u32 = 256;
|
||||
|
||||
pub struct Renderer {
|
||||
fill_program: FillProgram,
|
||||
solid_tile_program: SolidTileProgram,
|
||||
mask_tile_program: MaskTileProgram,
|
||||
area_lut_texture: Texture,
|
||||
#[allow(dead_code)]
|
||||
quad_vertex_positions_buffer: Buffer,
|
||||
fill_vertex_array: FillVertexArray,
|
||||
mask_tile_vertex_array: MaskTileVertexArray,
|
||||
solid_tile_vertex_array: SolidTileVertexArray,
|
||||
mask_framebuffer: Framebuffer,
|
||||
fill_colors_texture: Texture,
|
||||
|
||||
pending_timer_queries: VecDeque<TimerQuery>,
|
||||
free_timer_queries: Vec<TimerQuery>,
|
||||
|
||||
pub debug_renderer: DebugRenderer,
|
||||
|
||||
main_framebuffer_size: Size2D<u32>,
|
||||
}
|
||||
|
||||
impl Renderer {
|
||||
pub fn new(main_framebuffer_size: &Size2D<u32>) -> Renderer {
|
||||
let fill_program = FillProgram::new();
|
||||
let solid_tile_program = SolidTileProgram::new();
|
||||
let mask_tile_program = MaskTileProgram::new();
|
||||
|
||||
let area_lut_texture = Texture::from_png("area-lut");
|
||||
|
||||
let quad_vertex_positions_buffer = Buffer::new();
|
||||
quad_vertex_positions_buffer.upload(&QUAD_VERTEX_POSITIONS,
|
||||
BufferTarget::Vertex,
|
||||
BufferUploadMode::Static);
|
||||
|
||||
let fill_vertex_array = FillVertexArray::new(&fill_program, &quad_vertex_positions_buffer);
|
||||
let mask_tile_vertex_array = MaskTileVertexArray::new(&mask_tile_program,
|
||||
&quad_vertex_positions_buffer);
|
||||
let solid_tile_vertex_array = SolidTileVertexArray::new(&solid_tile_program,
|
||||
&quad_vertex_positions_buffer);
|
||||
|
||||
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));
|
||||
|
||||
let debug_renderer = DebugRenderer::new(main_framebuffer_size);
|
||||
|
||||
Renderer {
|
||||
fill_program,
|
||||
solid_tile_program,
|
||||
mask_tile_program,
|
||||
area_lut_texture,
|
||||
quad_vertex_positions_buffer,
|
||||
fill_vertex_array,
|
||||
mask_tile_vertex_array,
|
||||
solid_tile_vertex_array,
|
||||
mask_framebuffer,
|
||||
fill_colors_texture,
|
||||
|
||||
pending_timer_queries: VecDeque::new(),
|
||||
free_timer_queries: vec![],
|
||||
|
||||
debug_renderer,
|
||||
|
||||
main_framebuffer_size: *main_framebuffer_size,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_scene(&mut self, built_scene: &BuiltScene) {
|
||||
let timer_query = self.free_timer_queries.pop().unwrap_or_else(|| TimerQuery::new());
|
||||
timer_query.begin();
|
||||
|
||||
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);
|
||||
self.draw_batch_mask_tiles(batch);
|
||||
}
|
||||
|
||||
timer_query.end();
|
||||
self.pending_timer_queries.push_back(timer_query);
|
||||
}
|
||||
|
||||
pub fn shift_timer_query(&mut self) -> Option<Duration> {
|
||||
let query = self.pending_timer_queries.front()?;
|
||||
if !query.is_available() {
|
||||
return None
|
||||
}
|
||||
let query = self.pending_timer_queries.pop_front().unwrap();
|
||||
let result = Duration::from_nanos(query.get());
|
||||
self.free_timer_queries.push(query);
|
||||
Some(result)
|
||||
}
|
||||
|
||||
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, BufferTarget::Vertex, BufferUploadMode::Dynamic);
|
||||
}
|
||||
|
||||
fn upload_batch(&mut self, batch: &Batch) {
|
||||
self.fill_vertex_array
|
||||
.vertex_buffer
|
||||
.upload(&batch.fills, BufferTarget::Vertex, BufferUploadMode::Dynamic);
|
||||
self.mask_tile_vertex_array
|
||||
.vertex_buffer
|
||||
.upload(&batch.mask_tiles, BufferTarget::Vertex, BufferUploadMode::Dynamic);
|
||||
}
|
||||
|
||||
fn draw_batch_fills(&mut self, batch: &Batch) {
|
||||
unsafe {
|
||||
gl::BindFramebuffer(gl::FRAMEBUFFER, self.mask_framebuffer.gl_framebuffer);
|
||||
gl::Viewport(0, 0, MASK_FRAMEBUFFER_WIDTH as GLint, MASK_FRAMEBUFFER_HEIGHT as GLint);
|
||||
// TODO(pcwalton): Only clear the appropriate portion?
|
||||
gl::ClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
gl::Clear(gl::COLOR_BUFFER_BIT);
|
||||
|
||||
gl::BindVertexArray(self.fill_vertex_array.gl_vertex_array);
|
||||
gl::UseProgram(self.fill_program.program.gl_program);
|
||||
gl::Uniform2f(self.fill_program.framebuffer_size_uniform.location,
|
||||
MASK_FRAMEBUFFER_WIDTH as GLfloat,
|
||||
MASK_FRAMEBUFFER_HEIGHT as GLfloat);
|
||||
gl::Uniform2f(self.fill_program.tile_size_uniform.location,
|
||||
TILE_WIDTH as GLfloat,
|
||||
TILE_HEIGHT as GLfloat);
|
||||
self.area_lut_texture.bind(0);
|
||||
gl::Uniform1i(self.fill_program.area_lut_uniform.location, 0);
|
||||
gl::BlendEquation(gl::FUNC_ADD);
|
||||
gl::BlendFunc(gl::ONE, gl::ONE);
|
||||
gl::Enable(gl::BLEND);
|
||||
gl::DrawArraysInstanced(gl::TRIANGLE_FAN, 0, 4, batch.fills.len() as GLint);
|
||||
gl::Disable(gl::BLEND);
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_batch_mask_tiles(&mut self, batch: &Batch) {
|
||||
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.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,
|
||||
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);
|
||||
self.mask_framebuffer.texture.bind(0);
|
||||
gl::Uniform1i(self.mask_tile_program.stencil_texture_uniform.location, 0);
|
||||
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);
|
||||
gl::BlendFuncSeparate(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA, gl::ONE, gl::ONE);
|
||||
gl::Enable(gl::BLEND);
|
||||
gl::DrawArraysInstanced(gl::TRIANGLE_FAN, 0, 4, batch.mask_tiles.len() as GLint);
|
||||
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 {
|
||||
gl_vertex_array: GLuint,
|
||||
vertex_buffer: Buffer,
|
||||
}
|
||||
|
||||
impl FillVertexArray {
|
||||
fn new(fill_program: &FillProgram, quad_vertex_positions_buffer: &Buffer) -> FillVertexArray {
|
||||
let vertex_buffer = Buffer::new();
|
||||
let mut gl_vertex_array = 0;
|
||||
unsafe {
|
||||
let tess_coord_attr = VertexAttr::new(&fill_program.program, "TessCoord");
|
||||
let from_px_attr = VertexAttr::new(&fill_program.program, "FromPx");
|
||||
let to_px_attr = VertexAttr::new(&fill_program.program, "ToPx");
|
||||
let from_subpx_attr = VertexAttr::new(&fill_program.program, "FromSubpx");
|
||||
let to_subpx_attr = VertexAttr::new(&fill_program.program, "ToSubpx");
|
||||
let tile_index_attr = VertexAttr::new(&fill_program.program, "TileIndex");
|
||||
|
||||
gl::GenVertexArrays(1, &mut gl_vertex_array);
|
||||
gl::BindVertexArray(gl_vertex_array);
|
||||
gl::UseProgram(fill_program.program.gl_program);
|
||||
gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer);
|
||||
tess_coord_attr.configure_float(2, gl::UNSIGNED_BYTE, false, 0, 0, 0);
|
||||
gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer.gl_buffer);
|
||||
from_px_attr.configure_int(1, gl::UNSIGNED_BYTE, FILL_INSTANCE_SIZE, 0, 1);
|
||||
to_px_attr.configure_int(1, gl::UNSIGNED_BYTE, FILL_INSTANCE_SIZE, 1, 1);
|
||||
from_subpx_attr.configure_float(2, gl::UNSIGNED_BYTE, true, FILL_INSTANCE_SIZE, 2, 1);
|
||||
to_subpx_attr.configure_float(2, gl::UNSIGNED_BYTE, true, FILL_INSTANCE_SIZE, 4, 1);
|
||||
tile_index_attr.configure_int(1, gl::UNSIGNED_SHORT, FILL_INSTANCE_SIZE, 6, 1);
|
||||
}
|
||||
|
||||
FillVertexArray { gl_vertex_array, vertex_buffer }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for FillVertexArray {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
gl::DeleteVertexArrays(1, &mut self.gl_vertex_array);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MaskTileVertexArray {
|
||||
gl_vertex_array: GLuint,
|
||||
vertex_buffer: Buffer,
|
||||
}
|
||||
|
||||
impl MaskTileVertexArray {
|
||||
fn new(mask_tile_program: &MaskTileProgram, quad_vertex_positions_buffer: &Buffer)
|
||||
-> MaskTileVertexArray {
|
||||
let vertex_buffer = Buffer::new();
|
||||
let mut gl_vertex_array = 0;
|
||||
unsafe {
|
||||
let tess_coord_attr = VertexAttr::new(&mask_tile_program.program, "TessCoord");
|
||||
let tile_origin_attr = VertexAttr::new(&mask_tile_program.program, "TileOrigin");
|
||||
let backdrop_attr = VertexAttr::new(&mask_tile_program.program, "Backdrop");
|
||||
let object_attr = VertexAttr::new(&mask_tile_program.program, "Object");
|
||||
|
||||
gl::GenVertexArrays(1, &mut gl_vertex_array);
|
||||
gl::BindVertexArray(gl_vertex_array);
|
||||
gl::UseProgram(mask_tile_program.program.gl_program);
|
||||
gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer);
|
||||
tess_coord_attr.configure_float(2, gl::UNSIGNED_BYTE, false, 0, 0, 0);
|
||||
gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer.gl_buffer);
|
||||
tile_origin_attr.configure_float(2, gl::SHORT, false, MASK_TILE_INSTANCE_SIZE, 0, 1);
|
||||
backdrop_attr.configure_int(1, gl::SHORT, MASK_TILE_INSTANCE_SIZE, 4, 1);
|
||||
object_attr.configure_int(2, gl::UNSIGNED_SHORT, MASK_TILE_INSTANCE_SIZE, 6, 1);
|
||||
}
|
||||
|
||||
MaskTileVertexArray { gl_vertex_array, vertex_buffer }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for MaskTileVertexArray {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
gl::DeleteVertexArrays(1, &mut self.gl_vertex_array);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SolidTileVertexArray {
|
||||
gl_vertex_array: GLuint,
|
||||
vertex_buffer: Buffer,
|
||||
}
|
||||
|
||||
impl SolidTileVertexArray {
|
||||
fn new(solid_tile_program: &SolidTileProgram, quad_vertex_positions_buffer: &Buffer)
|
||||
-> SolidTileVertexArray {
|
||||
let vertex_buffer = Buffer::new();
|
||||
let mut gl_vertex_array = 0;
|
||||
unsafe {
|
||||
let tess_coord_attr = VertexAttr::new(&solid_tile_program.program, "TessCoord");
|
||||
let tile_origin_attr = VertexAttr::new(&solid_tile_program.program, "TileOrigin");
|
||||
let object_attr = VertexAttr::new(&solid_tile_program.program, "Object");
|
||||
|
||||
gl::GenVertexArrays(1, &mut gl_vertex_array);
|
||||
gl::BindVertexArray(gl_vertex_array);
|
||||
gl::UseProgram(solid_tile_program.program.gl_program);
|
||||
gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer);
|
||||
tess_coord_attr.configure_float(2, gl::UNSIGNED_BYTE, false, 0, 0, 0);
|
||||
gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer.gl_buffer);
|
||||
tile_origin_attr.configure_float(2, gl::SHORT, false, SOLID_TILE_INSTANCE_SIZE, 0, 1);
|
||||
object_attr.configure_int(1, gl::UNSIGNED_SHORT, SOLID_TILE_INSTANCE_SIZE, 4, 1);
|
||||
}
|
||||
|
||||
SolidTileVertexArray { gl_vertex_array, vertex_buffer }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for SolidTileVertexArray {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
gl::DeleteVertexArrays(1, &mut self.gl_vertex_array);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct FillProgram {
|
||||
program: Program,
|
||||
framebuffer_size_uniform: Uniform,
|
||||
tile_size_uniform: Uniform,
|
||||
area_lut_uniform: Uniform,
|
||||
}
|
||||
|
||||
impl FillProgram {
|
||||
fn new() -> FillProgram {
|
||||
let program = Program::new("fill");
|
||||
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
||||
let tile_size_uniform = Uniform::new(&program, "TileSize");
|
||||
let area_lut_uniform = Uniform::new(&program, "AreaLUT");
|
||||
FillProgram { program, framebuffer_size_uniform, tile_size_uniform, area_lut_uniform }
|
||||
}
|
||||
}
|
||||
|
||||
struct SolidTileProgram {
|
||||
program: Program,
|
||||
framebuffer_size_uniform: Uniform,
|
||||
tile_size_uniform: Uniform,
|
||||
fill_colors_texture_uniform: Uniform,
|
||||
fill_colors_texture_size_uniform: Uniform,
|
||||
view_box_origin_uniform: Uniform,
|
||||
}
|
||||
|
||||
impl SolidTileProgram {
|
||||
fn new() -> SolidTileProgram {
|
||||
let program = Program::new("solid_tile");
|
||||
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
||||
let tile_size_uniform = Uniform::new(&program, "TileSize");
|
||||
let fill_colors_texture_uniform = Uniform::new(&program, "FillColorsTexture");
|
||||
let fill_colors_texture_size_uniform = Uniform::new(&program, "FillColorsTextureSize");
|
||||
let view_box_origin_uniform = Uniform::new(&program, "ViewBoxOrigin");
|
||||
SolidTileProgram {
|
||||
program,
|
||||
framebuffer_size_uniform,
|
||||
tile_size_uniform,
|
||||
fill_colors_texture_uniform,
|
||||
fill_colors_texture_size_uniform,
|
||||
view_box_origin_uniform,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MaskTileProgram {
|
||||
program: Program,
|
||||
framebuffer_size_uniform: Uniform,
|
||||
tile_size_uniform: Uniform,
|
||||
stencil_texture_uniform: Uniform,
|
||||
stencil_texture_size_uniform: Uniform,
|
||||
fill_colors_texture_uniform: Uniform,
|
||||
fill_colors_texture_size_uniform: Uniform,
|
||||
view_box_origin_uniform: Uniform,
|
||||
}
|
||||
|
||||
impl MaskTileProgram {
|
||||
fn new() -> MaskTileProgram {
|
||||
let program = Program::new("mask_tile");
|
||||
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
||||
let tile_size_uniform = Uniform::new(&program, "TileSize");
|
||||
let stencil_texture_uniform = Uniform::new(&program, "StencilTexture");
|
||||
let stencil_texture_size_uniform = Uniform::new(&program, "StencilTextureSize");
|
||||
let fill_colors_texture_uniform = Uniform::new(&program, "FillColorsTexture");
|
||||
let fill_colors_texture_size_uniform = Uniform::new(&program, "FillColorsTextureSize");
|
||||
let view_box_origin_uniform = Uniform::new(&program, "ViewBoxOrigin");
|
||||
MaskTileProgram {
|
||||
program,
|
||||
framebuffer_size_uniform,
|
||||
tile_size_uniform,
|
||||
stencil_texture_uniform,
|
||||
stencil_texture_size_uniform,
|
||||
fill_colors_texture_uniform,
|
||||
fill_colors_texture_size_uniform,
|
||||
view_box_origin_uniform,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue