Pack vertices a little tighter
This commit is contained in:
parent
3b92ed0798
commit
4471a74144
|
@ -15,6 +15,7 @@ precision highp float;
|
||||||
uniform vec2 uFramebufferSize;
|
uniform vec2 uFramebufferSize;
|
||||||
uniform vec2 uTileSize;
|
uniform vec2 uTileSize;
|
||||||
uniform vec2 uStencilTextureSize;
|
uniform vec2 uStencilTextureSize;
|
||||||
|
uniform vec2 uViewBoxOrigin;
|
||||||
|
|
||||||
in vec2 aTessCoord;
|
in vec2 aTessCoord;
|
||||||
in vec2 aTileOrigin;
|
in vec2 aTileOrigin;
|
||||||
|
@ -33,7 +34,7 @@ vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth) {
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
uint tileIndex = uint(gl_InstanceID);
|
uint tileIndex = uint(gl_InstanceID);
|
||||||
vec2 position = aTileOrigin + uTileSize * aTessCoord;
|
vec2 position = (aTileOrigin + aTessCoord) * uTileSize + uViewBoxOrigin;
|
||||||
vec2 texCoord = computeTileOffset(tileIndex, uStencilTextureSize.x) + aTessCoord * uTileSize;
|
vec2 texCoord = computeTileOffset(tileIndex, uStencilTextureSize.x) + aTessCoord * uTileSize;
|
||||||
vTexCoord = texCoord / uStencilTextureSize;
|
vTexCoord = texCoord / uStencilTextureSize;
|
||||||
vBackdrop = aBackdrop;
|
vBackdrop = aBackdrop;
|
||||||
|
|
|
@ -54,9 +54,15 @@ export class Point2D {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Size2D {
|
export class Size2D {
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
|
|
||||||
|
constructor(width: number, height: number) {
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
Object.freeze(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Rect {
|
export class Rect {
|
||||||
|
|
|
@ -14,6 +14,7 @@ precision highp float;
|
||||||
|
|
||||||
uniform vec2 uFramebufferSize;
|
uniform vec2 uFramebufferSize;
|
||||||
uniform vec2 uTileSize;
|
uniform vec2 uTileSize;
|
||||||
|
uniform vec2 uViewBoxOrigin;
|
||||||
|
|
||||||
in vec2 aTessCoord;
|
in vec2 aTessCoord;
|
||||||
in vec2 aTileOrigin;
|
in vec2 aTileOrigin;
|
||||||
|
@ -22,7 +23,7 @@ in vec4 aColor;
|
||||||
out vec4 vColor;
|
out vec4 vColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec2 position = aTileOrigin + uTileSize * aTessCoord;
|
vec2 position = (aTileOrigin + aTessCoord) * uTileSize + uViewBoxOrigin;
|
||||||
vColor = aColor;
|
vColor = aColor;
|
||||||
gl_Position = vec4((position / uFramebufferSize * 2.0 - 1.0) * vec2(1.0, -1.0), 0.0, 1.0);
|
gl_Position = vec4((position / uFramebufferSize * 2.0 - 1.0) * vec2(1.0, -1.0), 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ import OPAQUE_FRAGMENT_SHADER_SOURCE from "./opaque.fs.glsl";
|
||||||
import STENCIL_VERTEX_SHADER_SOURCE from "./stencil.vs.glsl";
|
import STENCIL_VERTEX_SHADER_SOURCE from "./stencil.vs.glsl";
|
||||||
import STENCIL_FRAGMENT_SHADER_SOURCE from "./stencil.fs.glsl";
|
import STENCIL_FRAGMENT_SHADER_SOURCE from "./stencil.fs.glsl";
|
||||||
import AREA_LUT from "../resources/textures/area-lut.png";
|
import AREA_LUT from "../resources/textures/area-lut.png";
|
||||||
import {Matrix2D, Size2D} from "./geometry";
|
import {Matrix2D, Size2D, Rect, Point2D} from "./geometry";
|
||||||
import {SVGPath, TILE_SIZE} from "./tiling";
|
import {SVGPath, TILE_SIZE} from "./tiling";
|
||||||
import {staticCast, unwrapNull} from "./util";
|
import {staticCast, unwrapNull} from "./util";
|
||||||
|
|
||||||
|
@ -34,8 +34,8 @@ const QUAD_VERTEX_POSITIONS: Uint8Array = new Uint8Array([
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const FILL_INSTANCE_SIZE: number = 20;
|
const FILL_INSTANCE_SIZE: number = 20;
|
||||||
const SOLID_TILE_INSTANCE_SIZE: number = 12;
|
const SOLID_TILE_INSTANCE_SIZE: number = 8;
|
||||||
const MASK_TILE_INSTANCE_SIZE: number = 16;
|
const MASK_TILE_INSTANCE_SIZE: number = 12;
|
||||||
|
|
||||||
interface Color {
|
interface Color {
|
||||||
r: number;
|
r: number;
|
||||||
|
@ -58,10 +58,11 @@ class App {
|
||||||
private stencilFramebuffer: WebGLFramebuffer;
|
private stencilFramebuffer: WebGLFramebuffer;
|
||||||
private fillProgram: Program<'FramebufferSize' | 'TileSize' | 'AreaLUT',
|
private fillProgram: Program<'FramebufferSize' | 'TileSize' | 'AreaLUT',
|
||||||
'TessCoord' | 'From' | 'To' | 'TileIndex'>;
|
'TessCoord' | 'From' | 'To' | 'TileIndex'>;
|
||||||
private solidTileProgram: Program<'FramebufferSize' | 'TileSize',
|
private solidTileProgram: Program<'FramebufferSize' | 'TileSize' | 'ViewBoxOrigin',
|
||||||
'TessCoord' | 'TileOrigin' | 'Color'>;
|
'TessCoord' | 'TileOrigin' | 'Color'>;
|
||||||
private maskTileProgram:
|
private maskTileProgram:
|
||||||
Program<'FramebufferSize' | 'TileSize' | 'StencilTexture' | 'StencilTextureSize',
|
Program<'FramebufferSize' | 'TileSize' | 'StencilTexture' | 'StencilTextureSize' |
|
||||||
|
'ViewBoxOrigin',
|
||||||
'TessCoord' | 'TileOrigin' | 'Backdrop' | 'Color'>;
|
'TessCoord' | 'TileOrigin' | 'Backdrop' | 'Color'>;
|
||||||
private quadVertexBuffer: WebGLBuffer;
|
private quadVertexBuffer: WebGLBuffer;
|
||||||
private fillVertexBuffer: WebGLBuffer;
|
private fillVertexBuffer: WebGLBuffer;
|
||||||
|
@ -71,6 +72,8 @@ class App {
|
||||||
private maskTileVertexBuffer: WebGLBuffer;
|
private maskTileVertexBuffer: WebGLBuffer;
|
||||||
private maskVertexArray: WebGLVertexArrayObject;
|
private maskVertexArray: WebGLVertexArrayObject;
|
||||||
|
|
||||||
|
private viewBox: Rect;
|
||||||
|
|
||||||
private fillPrimitiveCount: number;
|
private fillPrimitiveCount: number;
|
||||||
private solidTileCount: number;
|
private solidTileCount: number;
|
||||||
private maskTileCount: number;
|
private maskTileCount: number;
|
||||||
|
@ -136,7 +139,8 @@ class App {
|
||||||
'FramebufferSize',
|
'FramebufferSize',
|
||||||
'TileSize',
|
'TileSize',
|
||||||
'StencilTexture',
|
'StencilTexture',
|
||||||
'StencilTextureSize'
|
'StencilTextureSize',
|
||||||
|
'ViewBoxOrigin',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'TessCoord',
|
'TessCoord',
|
||||||
|
@ -150,7 +154,7 @@ class App {
|
||||||
const solidTileProgram = new Program(gl,
|
const solidTileProgram = new Program(gl,
|
||||||
OPAQUE_VERTEX_SHADER_SOURCE,
|
OPAQUE_VERTEX_SHADER_SOURCE,
|
||||||
OPAQUE_FRAGMENT_SHADER_SOURCE,
|
OPAQUE_FRAGMENT_SHADER_SOURCE,
|
||||||
['FramebufferSize', 'TileSize'],
|
['FramebufferSize', 'TileSize', 'ViewBoxOrigin'],
|
||||||
['TessCoord', 'TileOrigin', 'Color']);
|
['TessCoord', 'TileOrigin', 'Color']);
|
||||||
this.solidTileProgram = solidTileProgram;
|
this.solidTileProgram = solidTileProgram;
|
||||||
|
|
||||||
|
@ -224,7 +228,7 @@ class App {
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.solidTileVertexBuffer);
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.solidTileVertexBuffer);
|
||||||
gl.vertexAttribPointer(solidTileProgram.attributes.TileOrigin,
|
gl.vertexAttribPointer(solidTileProgram.attributes.TileOrigin,
|
||||||
2,
|
2,
|
||||||
gl.FLOAT,
|
gl.SHORT,
|
||||||
false,
|
false,
|
||||||
SOLID_TILE_INSTANCE_SIZE,
|
SOLID_TILE_INSTANCE_SIZE,
|
||||||
0);
|
0);
|
||||||
|
@ -234,7 +238,7 @@ class App {
|
||||||
gl.UNSIGNED_BYTE,
|
gl.UNSIGNED_BYTE,
|
||||||
true,
|
true,
|
||||||
SOLID_TILE_INSTANCE_SIZE,
|
SOLID_TILE_INSTANCE_SIZE,
|
||||||
8);
|
4);
|
||||||
gl.vertexAttribDivisor(solidTileProgram.attributes.Color, 1);
|
gl.vertexAttribDivisor(solidTileProgram.attributes.Color, 1);
|
||||||
gl.enableVertexAttribArray(solidTileProgram.attributes.TessCoord);
|
gl.enableVertexAttribArray(solidTileProgram.attributes.TessCoord);
|
||||||
gl.enableVertexAttribArray(solidTileProgram.attributes.TileOrigin);
|
gl.enableVertexAttribArray(solidTileProgram.attributes.TileOrigin);
|
||||||
|
@ -254,7 +258,7 @@ class App {
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.maskTileVertexBuffer);
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.maskTileVertexBuffer);
|
||||||
gl.vertexAttribPointer(maskTileProgram.attributes.TileOrigin,
|
gl.vertexAttribPointer(maskTileProgram.attributes.TileOrigin,
|
||||||
2,
|
2,
|
||||||
gl.FLOAT,
|
gl.SHORT,
|
||||||
false,
|
false,
|
||||||
MASK_TILE_INSTANCE_SIZE,
|
MASK_TILE_INSTANCE_SIZE,
|
||||||
0);
|
0);
|
||||||
|
@ -264,20 +268,22 @@ class App {
|
||||||
gl.FLOAT,
|
gl.FLOAT,
|
||||||
false,
|
false,
|
||||||
MASK_TILE_INSTANCE_SIZE,
|
MASK_TILE_INSTANCE_SIZE,
|
||||||
8);
|
4);
|
||||||
gl.vertexAttribDivisor(maskTileProgram.attributes.Backdrop, 1);
|
gl.vertexAttribDivisor(maskTileProgram.attributes.Backdrop, 1);
|
||||||
gl.vertexAttribPointer(maskTileProgram.attributes.Color,
|
gl.vertexAttribPointer(maskTileProgram.attributes.Color,
|
||||||
4,
|
4,
|
||||||
gl.UNSIGNED_BYTE,
|
gl.UNSIGNED_BYTE,
|
||||||
true,
|
true,
|
||||||
MASK_TILE_INSTANCE_SIZE,
|
MASK_TILE_INSTANCE_SIZE,
|
||||||
12);
|
8);
|
||||||
gl.vertexAttribDivisor(maskTileProgram.attributes.Color, 1);
|
gl.vertexAttribDivisor(maskTileProgram.attributes.Color, 1);
|
||||||
gl.enableVertexAttribArray(maskTileProgram.attributes.TessCoord);
|
gl.enableVertexAttribArray(maskTileProgram.attributes.TessCoord);
|
||||||
gl.enableVertexAttribArray(maskTileProgram.attributes.TileOrigin);
|
gl.enableVertexAttribArray(maskTileProgram.attributes.TileOrigin);
|
||||||
gl.enableVertexAttribArray(maskTileProgram.attributes.Backdrop);
|
gl.enableVertexAttribArray(maskTileProgram.attributes.Backdrop);
|
||||||
gl.enableVertexAttribArray(maskTileProgram.attributes.Color);
|
gl.enableVertexAttribArray(maskTileProgram.attributes.Color);
|
||||||
|
|
||||||
|
this.viewBox = new Rect(new Point2D(0.0, 0.0), new Size2D(0.0, 0.0));
|
||||||
|
|
||||||
// Set up event handlers.
|
// Set up event handlers.
|
||||||
this.canvas.addEventListener('click', event => this.onClick(event), false);
|
this.canvas.addEventListener('click', event => this.onClick(event), false);
|
||||||
|
|
||||||
|
@ -289,6 +295,8 @@ class App {
|
||||||
redraw(): void {
|
redraw(): void {
|
||||||
const gl = this.gl, canvas = this.canvas;
|
const gl = this.gl, canvas = this.canvas;
|
||||||
|
|
||||||
|
console.log("viewBox", this.viewBox);
|
||||||
|
|
||||||
// Start timer.
|
// Start timer.
|
||||||
let timerQuery = null;
|
let timerQuery = null;
|
||||||
if (this.disjointTimerQueryExt != null) {
|
if (this.disjointTimerQueryExt != null) {
|
||||||
|
@ -333,6 +341,9 @@ class App {
|
||||||
framebufferSize.width,
|
framebufferSize.width,
|
||||||
framebufferSize.height);
|
framebufferSize.height);
|
||||||
gl.uniform2f(this.solidTileProgram.uniforms.TileSize, TILE_SIZE.width, TILE_SIZE.height);
|
gl.uniform2f(this.solidTileProgram.uniforms.TileSize, TILE_SIZE.width, TILE_SIZE.height);
|
||||||
|
gl.uniform2f(this.solidTileProgram.uniforms.ViewBoxOrigin,
|
||||||
|
this.viewBox.origin.x,
|
||||||
|
this.viewBox.origin.y);
|
||||||
gl.disable(gl.BLEND);
|
gl.disable(gl.BLEND);
|
||||||
gl.drawArraysInstanced(gl.TRIANGLE_FAN, 0, 4, this.solidTileCount);
|
gl.drawArraysInstanced(gl.TRIANGLE_FAN, 0, 4, this.solidTileCount);
|
||||||
|
|
||||||
|
@ -349,6 +360,9 @@ class App {
|
||||||
gl.uniform2f(this.maskTileProgram.uniforms.StencilTextureSize,
|
gl.uniform2f(this.maskTileProgram.uniforms.StencilTextureSize,
|
||||||
STENCIL_FRAMEBUFFER_SIZE.width,
|
STENCIL_FRAMEBUFFER_SIZE.width,
|
||||||
STENCIL_FRAMEBUFFER_SIZE.height);
|
STENCIL_FRAMEBUFFER_SIZE.height);
|
||||||
|
gl.uniform2f(this.maskTileProgram.uniforms.ViewBoxOrigin,
|
||||||
|
this.viewBox.origin.x,
|
||||||
|
this.viewBox.origin.y);
|
||||||
gl.blendEquation(gl.FUNC_ADD);
|
gl.blendEquation(gl.FUNC_ADD);
|
||||||
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
||||||
gl.enable(gl.BLEND);
|
gl.enable(gl.BLEND);
|
||||||
|
@ -402,11 +416,20 @@ class App {
|
||||||
const arrayBuffer = staticCast(reader.result, ArrayBuffer);
|
const arrayBuffer = staticCast(reader.result, ArrayBuffer);
|
||||||
const root = new RIFFChunk(new DataView(arrayBuffer));
|
const root = new RIFFChunk(new DataView(arrayBuffer));
|
||||||
for (const subchunk of root.subchunks()) {
|
for (const subchunk of root.subchunks()) {
|
||||||
|
const id = subchunk.stringID();
|
||||||
|
if (id === 'head') {
|
||||||
|
const headerData = subchunk.contents();
|
||||||
|
this.viewBox = new Rect(new Point2D(headerData.getFloat32(0, true),
|
||||||
|
headerData.getFloat32(4, true)),
|
||||||
|
new Size2D(headerData.getFloat32(8, true),
|
||||||
|
headerData.getFloat32(12, true)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let bindPoint, buffer;
|
let bindPoint, buffer;
|
||||||
let countFieldName: 'fillPrimitiveCount' | 'totalTileCount' | 'solidTileCount' |
|
let countFieldName: 'fillPrimitiveCount' | 'totalTileCount' | 'solidTileCount' |
|
||||||
'maskTileCount';
|
'maskTileCount';
|
||||||
let instanceSize;
|
let instanceSize;
|
||||||
const id = subchunk.stringID();
|
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case 'fill':
|
case 'fill':
|
||||||
bindPoint = gl.ARRAY_BUFFER;
|
bindPoint = gl.ARRAY_BUFFER;
|
||||||
|
|
|
@ -74,7 +74,7 @@ fn main() {
|
||||||
println!("Scene bounds: {:?}", scene.bounds);
|
println!("Scene bounds: {:?}", scene.bounds);
|
||||||
|
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
let mut built_scene = BuiltScene::new();
|
let mut built_scene = BuiltScene::new(&scene.view_box);
|
||||||
for _ in 0..runs {
|
for _ in 0..runs {
|
||||||
built_scene = scene.build();
|
built_scene = scene.build();
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ struct Scene {
|
||||||
objects: Vec<PathObject>,
|
objects: Vec<PathObject>,
|
||||||
styles: Vec<ComputedStyle>,
|
styles: Vec<ComputedStyle>,
|
||||||
bounds: Rect<f32>,
|
bounds: Rect<f32>,
|
||||||
view_box: Option<Rect<f32>>,
|
view_box: Rect<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -154,7 +154,7 @@ struct StyleId(u32);
|
||||||
|
|
||||||
impl Scene {
|
impl Scene {
|
||||||
fn new() -> Scene {
|
fn new() -> Scene {
|
||||||
Scene { objects: vec![], styles: vec![], bounds: Rect::zero(), view_box: None }
|
Scene { objects: vec![], styles: vec![], bounds: Rect::zero(), view_box: Rect::zero() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_path(path: &Path) -> Scene {
|
fn from_path(path: &Path) -> Scene {
|
||||||
|
@ -213,7 +213,7 @@ impl Scene {
|
||||||
elements.next().unwrap()),
|
elements.next().unwrap()),
|
||||||
Size2D::new(elements.next().unwrap(),
|
Size2D::new(elements.next().unwrap(),
|
||||||
elements.next().unwrap()));
|
elements.next().unwrap()));
|
||||||
scene.view_box = Some(global_transform.transform_rect(&view_box));
|
scene.view_box = global_transform.transform_rect(&view_box);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -311,7 +311,7 @@ impl Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build(&self) -> BuiltScene {
|
fn build(&self) -> BuiltScene {
|
||||||
let mut built_scene = BuiltScene::new();
|
let mut built_scene = BuiltScene::new(&self.view_box);
|
||||||
for object in &self.objects {
|
for object in &self.objects {
|
||||||
let mut tiler = Tiler::from_outline(&object.outline,
|
let mut tiler = Tiler::from_outline(&object.outline,
|
||||||
object.color,
|
object.color,
|
||||||
|
@ -935,7 +935,7 @@ struct Tiler<'o, 'p> {
|
||||||
fill_color: ColorU,
|
fill_color: ColorU,
|
||||||
built_scene: &'p mut BuiltScene,
|
built_scene: &'p mut BuiltScene,
|
||||||
|
|
||||||
view_box: Option<Rect<f32>>,
|
view_box: Rect<f32>,
|
||||||
|
|
||||||
point_queue: SortedVector<QueuedEndpoint>,
|
point_queue: SortedVector<QueuedEndpoint>,
|
||||||
active_edges: SortedVector<ActiveEdge>,
|
active_edges: SortedVector<ActiveEdge>,
|
||||||
|
@ -948,7 +948,7 @@ struct Tiler<'o, 'p> {
|
||||||
impl<'o, 'p> Tiler<'o, 'p> {
|
impl<'o, 'p> Tiler<'o, 'p> {
|
||||||
fn from_outline(outline: &'o Outline,
|
fn from_outline(outline: &'o Outline,
|
||||||
fill_color: ColorU,
|
fill_color: ColorU,
|
||||||
view_box: &Option<Rect<f32>>,
|
view_box: &Rect<f32>,
|
||||||
built_scene: &'p mut BuiltScene)
|
built_scene: &'p mut BuiltScene)
|
||||||
-> Tiler<'o, 'p> {
|
-> Tiler<'o, 'p> {
|
||||||
Tiler {
|
Tiler {
|
||||||
|
@ -974,13 +974,11 @@ impl<'o, 'p> Tiler<'o, 'p> {
|
||||||
|
|
||||||
// Clip to the view box.
|
// Clip to the view box.
|
||||||
let mut bounds = self.outline.bounds;
|
let mut bounds = self.outline.bounds;
|
||||||
if let Some(view_box) = self.view_box {
|
let max_x = f32::min(self.view_box.max_x(), bounds.max_x());
|
||||||
let max_x = f32::min(view_box.max_x(), bounds.max_x());
|
let max_y = f32::min(self.view_box.max_y(), bounds.max_y());
|
||||||
let max_y = f32::min(view_box.max_y(), bounds.max_y());
|
bounds.origin.x = f32::max(self.view_box.origin.x, bounds.origin.x);
|
||||||
bounds.origin.x = f32::max(view_box.origin.x, bounds.origin.x);
|
bounds.size.width = f32::max(0.0, max_x - bounds.origin.x);
|
||||||
bounds.size.width = f32::max(0.0, max_x - bounds.origin.x);
|
bounds.size.height = f32::max(0.0, max_y - bounds.origin.y);
|
||||||
bounds.size.height = f32::max(0.0, max_y - bounds.origin.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.active_edges.clear();
|
self.active_edges.clear();
|
||||||
|
|
||||||
|
@ -991,11 +989,8 @@ impl<'o, 'p> Tiler<'o, 'p> {
|
||||||
|
|
||||||
let tiles_across = ((strip_right_extent - strip_origin.x) / TILE_WIDTH) as usize;
|
let tiles_across = ((strip_right_extent - strip_origin.x) / TILE_WIDTH) as usize;
|
||||||
|
|
||||||
let view_box_origin_y = match self.view_box {
|
let mut tile_index_y = (f32::floor(self.view_box.origin.y / TILE_HEIGHT) * TILE_HEIGHT)
|
||||||
Some(view_box) => view_box.origin.y,
|
as i16;
|
||||||
None => 0.0,
|
|
||||||
};
|
|
||||||
let mut tile_index_y = (f32::floor(view_box_origin_y / TILE_HEIGHT) * TILE_HEIGHT) as i16;
|
|
||||||
|
|
||||||
self.strip_tiles.clear();
|
self.strip_tiles.clear();
|
||||||
self.strip_tiles.reserve(tiles_across);
|
self.strip_tiles.reserve(tiles_across);
|
||||||
|
@ -1124,6 +1119,7 @@ impl<'o, 'p> Tiler<'o, 'p> {
|
||||||
|
|
||||||
let contour = &outline.contours[point_index.contour_index];
|
let contour = &outline.contours[point_index.contour_index];
|
||||||
|
|
||||||
|
// TODO(pcwalton): Could use a bitset of processed edges…
|
||||||
let prev_endpoint_index = contour.prev_endpoint_index_of(point_index.point_index);
|
let prev_endpoint_index = contour.prev_endpoint_index_of(point_index.point_index);
|
||||||
let next_endpoint_index = contour.next_endpoint_index_of(point_index.point_index);
|
let next_endpoint_index = contour.next_endpoint_index_of(point_index.point_index);
|
||||||
if contour.point_is_logically_above(point_index.point_index, prev_endpoint_index) {
|
if contour.point_is_logically_above(point_index.point_index, prev_endpoint_index) {
|
||||||
|
@ -1166,7 +1162,6 @@ impl<'o, 'p> Tiler<'o, 'p> {
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn flush_tiles(&mut self, tile_index_y: i16) {
|
fn flush_tiles(&mut self, tile_index_y: i16) {
|
||||||
// Flush tiles.
|
// Flush tiles.
|
||||||
let first_tile_index = self.built_scene.mask_tiles.len() as u32;
|
|
||||||
for (tile_index_x, tile) in self.strip_tiles.iter().enumerate() {
|
for (tile_index_x, tile) in self.strip_tiles.iter().enumerate() {
|
||||||
if self.used_strip_tiles.contains(tile_index_x) {
|
if self.used_strip_tiles.contains(tile_index_x) {
|
||||||
self.built_scene.mask_tiles.push(*tile);
|
self.built_scene.mask_tiles.push(*tile);
|
||||||
|
@ -1286,6 +1281,7 @@ fn process_active_edge(active_edge: &mut Segment,
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct BuiltScene {
|
struct BuiltScene {
|
||||||
|
view_box: Rect<f32>,
|
||||||
fills: Vec<FillPrimitive>,
|
fills: Vec<FillPrimitive>,
|
||||||
solid_tiles: Vec<SolidTilePrimitive>,
|
solid_tiles: Vec<SolidTilePrimitive>,
|
||||||
mask_tiles: Vec<MaskTilePrimitive>,
|
mask_tiles: Vec<MaskTilePrimitive>,
|
||||||
|
@ -1322,23 +1318,32 @@ struct ColorU {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuiltScene {
|
impl BuiltScene {
|
||||||
fn new() -> BuiltScene {
|
fn new(view_box: &Rect<f32>) -> BuiltScene {
|
||||||
BuiltScene { fills: vec![], solid_tiles: vec![], mask_tiles: vec![] }
|
BuiltScene { view_box: *view_box, fills: vec![], solid_tiles: vec![], mask_tiles: vec![] }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write<W>(&self, writer: &mut W) -> io::Result<()> where W: Write {
|
fn write<W>(&self, writer: &mut W) -> io::Result<()> where W: Write {
|
||||||
writer.write_all(b"RIFF")?;
|
writer.write_all(b"RIFF")?;
|
||||||
|
|
||||||
|
let header_size = 4 * 4;
|
||||||
let fill_size = self.fills.len() * mem::size_of::<FillPrimitive>();
|
let fill_size = self.fills.len() * mem::size_of::<FillPrimitive>();
|
||||||
let solid_tiles_size = self.solid_tiles.len() * mem::size_of::<SolidTilePrimitive>();
|
let solid_tiles_size = self.solid_tiles.len() * mem::size_of::<SolidTilePrimitive>();
|
||||||
let mask_tiles_size = self.mask_tiles.len() * mem::size_of::<MaskTilePrimitive>();
|
let mask_tiles_size = self.mask_tiles.len() * mem::size_of::<MaskTilePrimitive>();
|
||||||
writer.write_u32::<LittleEndian>((4 +
|
writer.write_u32::<LittleEndian>((4 +
|
||||||
|
8 + header_size +
|
||||||
8 + fill_size +
|
8 + fill_size +
|
||||||
8 + solid_tiles_size +
|
8 + solid_tiles_size +
|
||||||
8 + mask_tiles_size) as u32)?;
|
8 + mask_tiles_size) as u32)?;
|
||||||
|
|
||||||
writer.write_all(b"PF3S")?;
|
writer.write_all(b"PF3S")?;
|
||||||
|
|
||||||
|
writer.write_all(b"head")?;
|
||||||
|
writer.write_u32::<LittleEndian>(header_size as u32)?;
|
||||||
|
writer.write_f32::<LittleEndian>(self.view_box.origin.x)?;
|
||||||
|
writer.write_f32::<LittleEndian>(self.view_box.origin.y)?;
|
||||||
|
writer.write_f32::<LittleEndian>(self.view_box.size.width)?;
|
||||||
|
writer.write_f32::<LittleEndian>(self.view_box.size.height)?;
|
||||||
|
|
||||||
writer.write_all(b"fill")?;
|
writer.write_all(b"fill")?;
|
||||||
writer.write_u32::<LittleEndian>(fill_size as u32)?;
|
writer.write_u32::<LittleEndian>(fill_size as u32)?;
|
||||||
for fill_primitive in &self.fills {
|
for fill_primitive in &self.fills {
|
||||||
|
|
Loading…
Reference in New Issue