Compress primitives.
This commit is contained in:
parent
68e0e791a4
commit
c0c0daa427
|
@ -22,7 +22,7 @@ uniform vec2 uViewBoxOrigin;
|
||||||
in vec2 aTessCoord;
|
in vec2 aTessCoord;
|
||||||
in vec2 aTileOrigin;
|
in vec2 aTileOrigin;
|
||||||
in int aBackdrop;
|
in int aBackdrop;
|
||||||
in int aObject;
|
in uint aObject;
|
||||||
|
|
||||||
out vec2 vTexCoord;
|
out vec2 vTexCoord;
|
||||||
out float vBackdrop;
|
out float vBackdrop;
|
||||||
|
|
|
@ -20,7 +20,7 @@ uniform vec2 uViewBoxOrigin;
|
||||||
|
|
||||||
in vec2 aTessCoord;
|
in vec2 aTessCoord;
|
||||||
in vec2 aTileOrigin;
|
in vec2 aTileOrigin;
|
||||||
in int aObject;
|
in uint aObject;
|
||||||
|
|
||||||
out vec4 vColor;
|
out vec4 vColor;
|
||||||
|
|
||||||
|
|
|
@ -33,9 +33,9 @@ const QUAD_VERTEX_POSITIONS: Uint8Array = new Uint8Array([
|
||||||
0, 1,
|
0, 1,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const FILL_INSTANCE_SIZE: number = 20;
|
const FILL_INSTANCE_SIZE: number = 8;
|
||||||
const SOLID_TILE_INSTANCE_SIZE: number = 8;
|
const SOLID_TILE_INSTANCE_SIZE: number = 6;
|
||||||
const MASK_TILE_INSTANCE_SIZE: number = 12;
|
const MASK_TILE_INSTANCE_SIZE: number = 8;
|
||||||
|
|
||||||
interface Color {
|
interface Color {
|
||||||
r: number;
|
r: number;
|
||||||
|
@ -58,7 +58,10 @@ class App {
|
||||||
private stencilTexture: WebGLTexture;
|
private stencilTexture: WebGLTexture;
|
||||||
private stencilFramebuffer: WebGLFramebuffer;
|
private stencilFramebuffer: WebGLFramebuffer;
|
||||||
private fillProgram: Program<'FramebufferSize' | 'TileSize' | 'AreaLUT',
|
private fillProgram: Program<'FramebufferSize' | 'TileSize' | 'AreaLUT',
|
||||||
'TessCoord' | 'From' | 'To' | 'TileIndex'>;
|
'TessCoord' |
|
||||||
|
'FromPx' | 'ToPx' |
|
||||||
|
'FromSubpx' | 'ToSubpx' |
|
||||||
|
'TileIndex'>;
|
||||||
private solidTileProgram: Program<'FramebufferSize' |
|
private solidTileProgram: Program<'FramebufferSize' |
|
||||||
'TileSize' |
|
'TileSize' |
|
||||||
'FillColorsTexture' | 'FillColorsTextureSize' |
|
'FillColorsTexture' | 'FillColorsTextureSize' |
|
||||||
|
@ -116,6 +119,19 @@ class App {
|
||||||
|
|
||||||
this.fillColorsTexture = unwrapNull(gl.createTexture());
|
this.fillColorsTexture = unwrapNull(gl.createTexture());
|
||||||
|
|
||||||
|
/*
|
||||||
|
const benchData = new Uint8Array(1600 * 1600 * 4);
|
||||||
|
for (let i = 0; i < benchData.length; i++)
|
||||||
|
benchData[i] = (Math.random() * 256) | 0;
|
||||||
|
const benchTexture = unwrapNull(gl.createTexture());
|
||||||
|
gl.bindTexture(gl.TEXTURE_2D, benchTexture);
|
||||||
|
const startTime = performance.now();
|
||||||
|
for (let i = 0; i < 100; i++)
|
||||||
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1600, 1600, 0, gl.RGBA, gl.UNSIGNED_BYTE, benchData);
|
||||||
|
const elapsedTime = (performance.now() - startTime) / 100;
|
||||||
|
console.log("texture upload: ", elapsedTime, "ms");
|
||||||
|
*/
|
||||||
|
|
||||||
this.stencilTexture = unwrapNull(gl.createTexture());
|
this.stencilTexture = unwrapNull(gl.createTexture());
|
||||||
gl.bindTexture(gl.TEXTURE_2D, this.stencilTexture);
|
gl.bindTexture(gl.TEXTURE_2D, this.stencilTexture);
|
||||||
gl.texImage2D(gl.TEXTURE_2D,
|
gl.texImage2D(gl.TEXTURE_2D,
|
||||||
|
@ -177,10 +193,15 @@ class App {
|
||||||
this.solidTileProgram = solidTileProgram;
|
this.solidTileProgram = solidTileProgram;
|
||||||
|
|
||||||
const fillProgram = new Program(gl,
|
const fillProgram = new Program(gl,
|
||||||
STENCIL_VERTEX_SHADER_SOURCE,
|
STENCIL_VERTEX_SHADER_SOURCE,
|
||||||
STENCIL_FRAGMENT_SHADER_SOURCE,
|
STENCIL_FRAGMENT_SHADER_SOURCE,
|
||||||
['FramebufferSize', 'TileSize', 'AreaLUT'],
|
['FramebufferSize', 'TileSize', 'AreaLUT'],
|
||||||
['TessCoord', 'From', 'To', 'TileIndex']);
|
[
|
||||||
|
'TessCoord',
|
||||||
|
'FromPx', 'ToPx',
|
||||||
|
'FromSubpx', 'ToSubpx',
|
||||||
|
'TileIndex'
|
||||||
|
]);
|
||||||
this.fillProgram = fillProgram;
|
this.fillProgram = fillProgram;
|
||||||
|
|
||||||
// Initialize quad VBO.
|
// Initialize quad VBO.
|
||||||
|
@ -203,29 +224,43 @@ class App {
|
||||||
0,
|
0,
|
||||||
0);
|
0);
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.fillVertexBuffer);
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.fillVertexBuffer);
|
||||||
gl.vertexAttribPointer(fillProgram.attributes.From,
|
gl.vertexAttribIPointer(fillProgram.attributes.FromPx,
|
||||||
|
1,
|
||||||
|
gl.UNSIGNED_BYTE,
|
||||||
|
FILL_INSTANCE_SIZE,
|
||||||
|
0);
|
||||||
|
gl.vertexAttribDivisor(fillProgram.attributes.FromPx, 1);
|
||||||
|
gl.vertexAttribIPointer(fillProgram.attributes.ToPx,
|
||||||
|
1,
|
||||||
|
gl.UNSIGNED_BYTE,
|
||||||
|
FILL_INSTANCE_SIZE,
|
||||||
|
1);
|
||||||
|
gl.vertexAttribDivisor(fillProgram.attributes.ToPx, 1);
|
||||||
|
gl.vertexAttribPointer(fillProgram.attributes.FromSubpx,
|
||||||
2,
|
2,
|
||||||
gl.FLOAT,
|
gl.UNSIGNED_BYTE,
|
||||||
false,
|
true,
|
||||||
FILL_INSTANCE_SIZE,
|
FILL_INSTANCE_SIZE,
|
||||||
0);
|
2);
|
||||||
gl.vertexAttribDivisor(fillProgram.attributes.From, 1);
|
gl.vertexAttribDivisor(fillProgram.attributes.FromSubpx, 1);
|
||||||
gl.vertexAttribPointer(fillProgram.attributes.To,
|
gl.vertexAttribPointer(fillProgram.attributes.ToSubpx,
|
||||||
2,
|
2,
|
||||||
gl.FLOAT,
|
gl.UNSIGNED_BYTE,
|
||||||
false,
|
true,
|
||||||
FILL_INSTANCE_SIZE,
|
FILL_INSTANCE_SIZE,
|
||||||
8);
|
4);
|
||||||
gl.vertexAttribDivisor(fillProgram.attributes.To, 1);
|
gl.vertexAttribDivisor(fillProgram.attributes.ToSubpx, 1);
|
||||||
gl.vertexAttribIPointer(fillProgram.attributes.TileIndex,
|
gl.vertexAttribIPointer(fillProgram.attributes.TileIndex,
|
||||||
1,
|
1,
|
||||||
gl.UNSIGNED_INT,
|
gl.UNSIGNED_SHORT,
|
||||||
FILL_INSTANCE_SIZE,
|
FILL_INSTANCE_SIZE,
|
||||||
16);
|
6);
|
||||||
gl.vertexAttribDivisor(fillProgram.attributes.TileIndex, 1);
|
gl.vertexAttribDivisor(fillProgram.attributes.TileIndex, 1);
|
||||||
gl.enableVertexAttribArray(fillProgram.attributes.TessCoord);
|
gl.enableVertexAttribArray(fillProgram.attributes.TessCoord);
|
||||||
gl.enableVertexAttribArray(fillProgram.attributes.From);
|
gl.enableVertexAttribArray(fillProgram.attributes.FromPx);
|
||||||
gl.enableVertexAttribArray(fillProgram.attributes.To);
|
gl.enableVertexAttribArray(fillProgram.attributes.ToPx);
|
||||||
|
gl.enableVertexAttribArray(fillProgram.attributes.FromSubpx);
|
||||||
|
gl.enableVertexAttribArray(fillProgram.attributes.ToSubpx);
|
||||||
gl.enableVertexAttribArray(fillProgram.attributes.TileIndex);
|
gl.enableVertexAttribArray(fillProgram.attributes.TileIndex);
|
||||||
|
|
||||||
// Initialize tile VBOs and IBOs.
|
// Initialize tile VBOs and IBOs.
|
||||||
|
@ -253,7 +288,7 @@ class App {
|
||||||
gl.vertexAttribDivisor(solidTileProgram.attributes.TileOrigin, 1);
|
gl.vertexAttribDivisor(solidTileProgram.attributes.TileOrigin, 1);
|
||||||
gl.vertexAttribIPointer(solidTileProgram.attributes.Object,
|
gl.vertexAttribIPointer(solidTileProgram.attributes.Object,
|
||||||
1,
|
1,
|
||||||
gl.INT,
|
gl.UNSIGNED_SHORT,
|
||||||
SOLID_TILE_INSTANCE_SIZE,
|
SOLID_TILE_INSTANCE_SIZE,
|
||||||
4);
|
4);
|
||||||
gl.vertexAttribDivisor(solidTileProgram.attributes.Object, 1);
|
gl.vertexAttribDivisor(solidTileProgram.attributes.Object, 1);
|
||||||
|
@ -282,15 +317,15 @@ class App {
|
||||||
gl.vertexAttribDivisor(maskTileProgram.attributes.TileOrigin, 1);
|
gl.vertexAttribDivisor(maskTileProgram.attributes.TileOrigin, 1);
|
||||||
gl.vertexAttribIPointer(maskTileProgram.attributes.Backdrop,
|
gl.vertexAttribIPointer(maskTileProgram.attributes.Backdrop,
|
||||||
1,
|
1,
|
||||||
gl.INT,
|
gl.SHORT,
|
||||||
MASK_TILE_INSTANCE_SIZE,
|
MASK_TILE_INSTANCE_SIZE,
|
||||||
4);
|
4);
|
||||||
gl.vertexAttribDivisor(maskTileProgram.attributes.Backdrop, 1);
|
gl.vertexAttribDivisor(maskTileProgram.attributes.Backdrop, 1);
|
||||||
gl.vertexAttribIPointer(maskTileProgram.attributes.Object,
|
gl.vertexAttribIPointer(maskTileProgram.attributes.Object,
|
||||||
1,
|
1,
|
||||||
gl.INT,
|
gl.UNSIGNED_SHORT,
|
||||||
MASK_TILE_INSTANCE_SIZE,
|
MASK_TILE_INSTANCE_SIZE,
|
||||||
8);
|
6);
|
||||||
gl.vertexAttribDivisor(maskTileProgram.attributes.Object, 1);
|
gl.vertexAttribDivisor(maskTileProgram.attributes.Object, 1);
|
||||||
gl.enableVertexAttribArray(maskTileProgram.attributes.TessCoord);
|
gl.enableVertexAttribArray(maskTileProgram.attributes.TessCoord);
|
||||||
gl.enableVertexAttribArray(maskTileProgram.attributes.TileOrigin);
|
gl.enableVertexAttribArray(maskTileProgram.attributes.TileOrigin);
|
||||||
|
@ -313,14 +348,17 @@ class App {
|
||||||
|
|
||||||
//console.log("viewBox", this.viewBox);
|
//console.log("viewBox", this.viewBox);
|
||||||
|
|
||||||
// Start timer.
|
// Initialize timers.
|
||||||
let timerQuery = null;
|
let fillTimerQuery = null, solidTimerQuery = null, maskTimerQuery = null;
|
||||||
if (this.disjointTimerQueryExt != null) {
|
if (this.disjointTimerQueryExt != null) {
|
||||||
timerQuery = unwrapNull(gl.createQuery());
|
fillTimerQuery = unwrapNull(gl.createQuery());
|
||||||
gl.beginQuery(this.disjointTimerQueryExt.TIME_ELAPSED_EXT, timerQuery);
|
solidTimerQuery = unwrapNull(gl.createQuery());
|
||||||
|
maskTimerQuery = unwrapNull(gl.createQuery());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill.
|
// Fill.
|
||||||
|
if (fillTimerQuery != null)
|
||||||
|
gl.beginQuery(this.disjointTimerQueryExt.TIME_ELAPSED_EXT, fillTimerQuery);
|
||||||
gl.bindFramebuffer(gl.FRAMEBUFFER, this.stencilFramebuffer);
|
gl.bindFramebuffer(gl.FRAMEBUFFER, this.stencilFramebuffer);
|
||||||
gl.viewport(0, 0, STENCIL_FRAMEBUFFER_SIZE.width, STENCIL_FRAMEBUFFER_SIZE.height);
|
gl.viewport(0, 0, STENCIL_FRAMEBUFFER_SIZE.width, STENCIL_FRAMEBUFFER_SIZE.height);
|
||||||
gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
||||||
|
@ -340,6 +378,8 @@ class App {
|
||||||
gl.enable(gl.BLEND);
|
gl.enable(gl.BLEND);
|
||||||
gl.drawArraysInstanced(gl.TRIANGLE_FAN, 0, 4, unwrapNull(this.fillPrimitiveCount));
|
gl.drawArraysInstanced(gl.TRIANGLE_FAN, 0, 4, unwrapNull(this.fillPrimitiveCount));
|
||||||
gl.disable(gl.BLEND);
|
gl.disable(gl.BLEND);
|
||||||
|
if (fillTimerQuery != null)
|
||||||
|
gl.endQuery(this.disjointTimerQueryExt.TIME_ELAPSED_EXT);
|
||||||
|
|
||||||
// Read back stencil and dump it.
|
// Read back stencil and dump it.
|
||||||
//this.dumpStencil();
|
//this.dumpStencil();
|
||||||
|
@ -351,6 +391,8 @@ class App {
|
||||||
gl.clearColor(0.85, 0.85, 0.85, 1.0);
|
gl.clearColor(0.85, 0.85, 0.85, 1.0);
|
||||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
if (solidTimerQuery != null)
|
||||||
|
gl.beginQuery(this.disjointTimerQueryExt.TIME_ELAPSED_EXT, solidTimerQuery);
|
||||||
gl.bindVertexArray(this.solidVertexArray);
|
gl.bindVertexArray(this.solidVertexArray);
|
||||||
gl.useProgram(this.solidTileProgram.program);
|
gl.useProgram(this.solidTileProgram.program);
|
||||||
gl.uniform2f(this.solidTileProgram.uniforms.FramebufferSize,
|
gl.uniform2f(this.solidTileProgram.uniforms.FramebufferSize,
|
||||||
|
@ -369,8 +411,12 @@ class App {
|
||||||
this.viewBox.origin.y);
|
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);
|
||||||
|
if (solidTimerQuery != null)
|
||||||
|
gl.endQuery(this.disjointTimerQueryExt.TIME_ELAPSED_EXT);
|
||||||
|
|
||||||
// Draw masked tiles.
|
// Draw masked tiles.
|
||||||
|
if (maskTimerQuery != null)
|
||||||
|
gl.beginQuery(this.disjointTimerQueryExt.TIME_ELAPSED_EXT, maskTimerQuery);
|
||||||
gl.bindVertexArray(this.maskVertexArray);
|
gl.bindVertexArray(this.maskVertexArray);
|
||||||
gl.useProgram(this.maskTileProgram.program);
|
gl.useProgram(this.maskTileProgram.program);
|
||||||
gl.uniform2f(this.maskTileProgram.uniforms.FramebufferSize,
|
gl.uniform2f(this.maskTileProgram.uniforms.FramebufferSize,
|
||||||
|
@ -398,11 +444,16 @@ class App {
|
||||||
gl.enable(gl.BLEND);
|
gl.enable(gl.BLEND);
|
||||||
gl.drawArraysInstanced(gl.TRIANGLE_FAN, 0, 4, this.maskTileCount);
|
gl.drawArraysInstanced(gl.TRIANGLE_FAN, 0, 4, this.maskTileCount);
|
||||||
gl.disable(gl.BLEND);
|
gl.disable(gl.BLEND);
|
||||||
|
if (maskTimerQuery != null)
|
||||||
|
gl.endQuery(this.disjointTimerQueryExt.TIME_ELAPSED_EXT);
|
||||||
|
|
||||||
// End timer.
|
// End timer.
|
||||||
if (timerQuery != null) {
|
if (fillTimerQuery != null && solidTimerQuery != null && maskTimerQuery != null) {
|
||||||
gl.endQuery(this.disjointTimerQueryExt.TIME_ELAPSED_EXT);
|
processQueries(gl, this.disjointTimerQueryExt, {
|
||||||
waitForQuery(gl, this.disjointTimerQueryExt, timerQuery);
|
fill: fillTimerQuery,
|
||||||
|
solid: solidTimerQuery,
|
||||||
|
mask: maskTimerQuery,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -611,16 +662,37 @@ class RIFFChunk {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function waitForQuery(gl: WebGL2RenderingContext, disjointTimerQueryExt: any, query: WebGLQuery):
|
interface Queries {
|
||||||
void {
|
fill: WebGLQuery;
|
||||||
const queryResultAvailable = disjointTimerQueryExt.QUERY_RESULT_AVAILABLE_EXT;
|
solid: WebGLQuery;
|
||||||
const queryResult = disjointTimerQueryExt.QUERY_RESULT_EXT;
|
mask: WebGLQuery;
|
||||||
if (!disjointTimerQueryExt.getQueryObjectEXT(query, queryResultAvailable)) {
|
};
|
||||||
setTimeout(() => waitForQuery(gl, disjointTimerQueryExt, query), 10);
|
|
||||||
return;
|
function getQueryResult(gl: WebGL2RenderingContext, disjointTimerQueryExt: any, query: WebGLQuery):
|
||||||
|
Promise<number> {
|
||||||
|
function go(resolve: (n: number) => void): void {
|
||||||
|
const queryResultAvailable = disjointTimerQueryExt.QUERY_RESULT_AVAILABLE_EXT;
|
||||||
|
const queryResult = disjointTimerQueryExt.QUERY_RESULT_EXT;
|
||||||
|
if (!disjointTimerQueryExt.getQueryObjectEXT(query, queryResultAvailable)) {
|
||||||
|
setTimeout(() => go(resolve), 10);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resolve(disjointTimerQueryExt.getQueryObjectEXT(query, queryResult) / 1000000.0);
|
||||||
}
|
}
|
||||||
const elapsed = disjointTimerQueryExt.getQueryObjectEXT(query, queryResult) / 1000000.0;
|
|
||||||
console.log(elapsed + "ms elapsed");
|
return new Promise((resolve, reject) => go(resolve));
|
||||||
|
}
|
||||||
|
|
||||||
|
function processQueries(gl: WebGL2RenderingContext, disjointTimerQueryExt: any, queries: Queries):
|
||||||
|
void {
|
||||||
|
Promise.all([
|
||||||
|
getQueryResult(gl, disjointTimerQueryExt, queries.fill),
|
||||||
|
getQueryResult(gl, disjointTimerQueryExt, queries.solid),
|
||||||
|
getQueryResult(gl, disjointTimerQueryExt, queries.mask),
|
||||||
|
]).then(results => {
|
||||||
|
const [fillResult, solidResult, maskResult] = results;
|
||||||
|
console.log(fillResult, "ms fill,", solidResult, "ms solid,", maskResult, "ms mask");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadAreaLUT(): Promise<HTMLImageElement> {
|
function loadAreaLUT(): Promise<HTMLImageElement> {
|
||||||
|
|
|
@ -15,14 +15,13 @@ precision highp float;
|
||||||
uniform sampler2D uAreaLUT;
|
uniform sampler2D uAreaLUT;
|
||||||
|
|
||||||
in vec2 vFrom;
|
in vec2 vFrom;
|
||||||
in vec2 vCtrl;
|
|
||||||
in vec2 vTo;
|
in vec2 vTo;
|
||||||
|
|
||||||
out vec4 oFragColor;
|
out vec4 oFragColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
// Unpack.
|
// Unpack.
|
||||||
vec2 from = vFrom, ctrl = vCtrl, to = vTo;
|
vec2 from = vFrom, to = vTo;
|
||||||
|
|
||||||
// Determine winding, and sort into a consistent order so we only need to find one root below.
|
// Determine winding, and sort into a consistent order so we only need to find one root below.
|
||||||
bool winding = from.x < to.x;
|
bool winding = from.x < to.x;
|
||||||
|
|
|
@ -16,12 +16,13 @@ uniform vec2 uFramebufferSize;
|
||||||
uniform vec2 uTileSize;
|
uniform vec2 uTileSize;
|
||||||
|
|
||||||
in vec2 aTessCoord;
|
in vec2 aTessCoord;
|
||||||
in vec2 aFrom;
|
in uint aFromPx;
|
||||||
in vec2 aTo;
|
in uint aToPx;
|
||||||
|
in vec2 aFromSubpx;
|
||||||
|
in vec2 aToSubpx;
|
||||||
in uint aTileIndex;
|
in uint aTileIndex;
|
||||||
|
|
||||||
out vec2 vFrom;
|
out vec2 vFrom;
|
||||||
out vec2 vCtrl;
|
|
||||||
out vec2 vTo;
|
out vec2 vTo;
|
||||||
|
|
||||||
vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth) {
|
vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth) {
|
||||||
|
@ -33,8 +34,8 @@ vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth) {
|
||||||
void main() {
|
void main() {
|
||||||
vec2 tileOrigin = computeTileOffset(aTileIndex, uFramebufferSize.x);
|
vec2 tileOrigin = computeTileOffset(aTileIndex, uFramebufferSize.x);
|
||||||
|
|
||||||
vec2 from = clamp(aFrom, vec2(0.0), uTileSize);
|
vec2 from = vec2(aFromPx & 15u, aFromPx >> 4u) + aFromSubpx;
|
||||||
vec2 to = clamp(aTo, vec2(0.0), uTileSize);
|
vec2 to = vec2(aToPx & 15u, aToPx >> 4u) + aToSubpx;
|
||||||
|
|
||||||
vec2 position;
|
vec2 position;
|
||||||
bool zeroArea = !(abs(from.x - to.x) > 0.1) || !(abs(uTileSize.y - min(from.y, to.y)) > 0.1);
|
bool zeroArea = !(abs(from.x - to.x) > 0.1) || !(abs(uTileSize.y - min(from.y, to.y)) > 0.1);
|
||||||
|
@ -50,8 +51,6 @@ void main() {
|
||||||
vFrom = from - position;
|
vFrom = from - position;
|
||||||
vTo = to - position;
|
vTo = to - position;
|
||||||
|
|
||||||
vCtrl = mix(vFrom, vTo, 0.5);
|
|
||||||
|
|
||||||
if (zeroArea)
|
if (zeroArea)
|
||||||
gl_Position = vec4(0.0);
|
gl_Position = vec4(0.0);
|
||||||
else
|
else
|
||||||
|
|
|
@ -40,7 +40,7 @@ use std::ops::Range;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use std::u32;
|
use std::u16;
|
||||||
use svgtypes::{Color as SvgColor, PathParser, PathSegment as SvgPathSegment, TransformListParser};
|
use svgtypes::{Color as SvgColor, PathParser, PathSegment as SvgPathSegment, TransformListParser};
|
||||||
use svgtypes::{TransformListToken};
|
use svgtypes::{TransformListToken};
|
||||||
|
|
||||||
|
@ -339,7 +339,7 @@ impl Scene {
|
||||||
&self.styles[style.0 as usize]
|
&self.styles[style.0 as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_shader(&self, object_index: u32) -> ObjectShader {
|
fn build_shader(&self, object_index: u16) -> ObjectShader {
|
||||||
ObjectShader {
|
ObjectShader {
|
||||||
fill_color: self.objects[object_index as usize].color,
|
fill_color: self.objects[object_index as usize].color,
|
||||||
}
|
}
|
||||||
|
@ -349,9 +349,9 @@ impl Scene {
|
||||||
fn build_objects_sequentially(&self) -> Vec<BuiltObject> {
|
fn build_objects_sequentially(&self) -> Vec<BuiltObject> {
|
||||||
self.objects.iter().enumerate().map(|(object_index, object)| {
|
self.objects.iter().enumerate().map(|(object_index, object)| {
|
||||||
let mut tiler = Tiler::new(&object.outline,
|
let mut tiler = Tiler::new(&object.outline,
|
||||||
object_index as u32,
|
object_index as u16,
|
||||||
&self.view_box,
|
&self.view_box,
|
||||||
&self.build_shader(object_index as u32));
|
&self.build_shader(object_index as u16));
|
||||||
tiler.generate_tiles();
|
tiler.generate_tiles();
|
||||||
tiler.built_object
|
tiler.built_object
|
||||||
}).collect()
|
}).collect()
|
||||||
|
@ -360,9 +360,9 @@ impl Scene {
|
||||||
fn build_objects(&self) -> Vec<BuiltObject> {
|
fn build_objects(&self) -> Vec<BuiltObject> {
|
||||||
self.objects.par_iter().enumerate().map(|(object_index, object)| {
|
self.objects.par_iter().enumerate().map(|(object_index, object)| {
|
||||||
let mut tiler = Tiler::new(&object.outline,
|
let mut tiler = Tiler::new(&object.outline,
|
||||||
object_index as u32,
|
object_index as u16,
|
||||||
&self.view_box,
|
&self.view_box,
|
||||||
&self.build_shader(object_index as u32));
|
&self.build_shader(object_index as u16));
|
||||||
tiler.generate_tiles();
|
tiler.generate_tiles();
|
||||||
tiler.built_object
|
tiler.built_object
|
||||||
}).collect()
|
}).collect()
|
||||||
|
@ -946,7 +946,7 @@ const TILE_HEIGHT: f32 = 16.0;
|
||||||
|
|
||||||
struct Tiler<'o> {
|
struct Tiler<'o> {
|
||||||
outline: &'o Outline,
|
outline: &'o Outline,
|
||||||
object_index: u32,
|
object_index: u16,
|
||||||
built_object: BuiltObject,
|
built_object: BuiltObject,
|
||||||
|
|
||||||
view_box: Rect<f32>,
|
view_box: Rect<f32>,
|
||||||
|
@ -958,7 +958,7 @@ struct Tiler<'o> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'o> Tiler<'o> {
|
impl<'o> Tiler<'o> {
|
||||||
fn new(outline: &'o Outline, object_index: u32, view_box: &Rect<f32>, shader: &ObjectShader)
|
fn new(outline: &'o Outline, object_index: u16, view_box: &Rect<f32>, shader: &ObjectShader)
|
||||||
-> Tiler<'o> {
|
-> Tiler<'o> {
|
||||||
let bounds = outline.bounds.intersection(&view_box).unwrap_or(Rect::zero());
|
let bounds = outline.bounds.intersection(&view_box).unwrap_or(Rect::zero());
|
||||||
let built_object = BuiltObject::new(&bounds, shader);
|
let built_object = BuiltObject::new(&bounds, shader);
|
||||||
|
@ -1255,16 +1255,16 @@ impl BuiltScene {
|
||||||
}
|
}
|
||||||
|
|
||||||
let scene_tile_index = scene.scene_tile_index(tile.tile_x, tile.tile_y);
|
let scene_tile_index = scene.scene_tile_index(tile.tile_x, tile.tile_y);
|
||||||
if z_buffer[scene_tile_index as usize] > object_index {
|
if z_buffer[scene_tile_index as usize] > object_index as u16 {
|
||||||
// Occluded.
|
// Occluded.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
z_buffer[scene_tile_index as usize] = object_index;
|
z_buffer[scene_tile_index as usize] = object_index as u16;
|
||||||
|
|
||||||
scene.solid_tiles.push(SolidTileScenePrimitive {
|
scene.solid_tiles.push(SolidTileScenePrimitive {
|
||||||
tile_x: tile.tile_x,
|
tile_x: tile.tile_x,
|
||||||
tile_y: tile.tile_y,
|
tile_y: tile.tile_y,
|
||||||
object_index: object_index as u32,
|
object_index: object_index as u16,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1278,23 +1278,23 @@ impl BuiltScene {
|
||||||
for (tile_index, tile) in object.tiles.iter().enumerate() {
|
for (tile_index, tile) in object.tiles.iter().enumerate() {
|
||||||
// Skip solid tiles, since we handled them above already.
|
// Skip solid tiles, since we handled them above already.
|
||||||
if object.solid_tiles[tile_index] {
|
if object.solid_tiles[tile_index] {
|
||||||
object_tile_index_to_scene_mask_tile_index.push(u32::MAX);
|
object_tile_index_to_scene_mask_tile_index.push(u16::MAX);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cull occluded tiles.
|
// Cull occluded tiles.
|
||||||
let scene_tile_index = scene.scene_tile_index(tile.tile_x, tile.tile_y);
|
let scene_tile_index = scene.scene_tile_index(tile.tile_x, tile.tile_y);
|
||||||
if z_buffer[scene_tile_index as usize] > object_index {
|
if z_buffer[scene_tile_index as usize] as usize > object_index {
|
||||||
object_tile_index_to_scene_mask_tile_index.push(u32::MAX);
|
object_tile_index_to_scene_mask_tile_index.push(u16::MAX);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visible mask tile.
|
// Visible mask tile.
|
||||||
let scene_mask_tile_index = scene.mask_tiles.len() as u32;
|
let scene_mask_tile_index = scene.mask_tiles.len() as u16;
|
||||||
object_tile_index_to_scene_mask_tile_index.push(scene_mask_tile_index);
|
object_tile_index_to_scene_mask_tile_index.push(scene_mask_tile_index);
|
||||||
scene.mask_tiles.push(MaskTileScenePrimitive {
|
scene.mask_tiles.push(MaskTileScenePrimitive {
|
||||||
tile: *tile,
|
tile: *tile,
|
||||||
object_index: object_index as u32,
|
object_index: object_index as u16,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1302,11 +1302,13 @@ impl BuiltScene {
|
||||||
for fill in &object.fills {
|
for fill in &object.fills {
|
||||||
let object_tile_index = object.tile_coords_to_index(fill.tile_x, fill.tile_y);
|
let object_tile_index = object.tile_coords_to_index(fill.tile_x, fill.tile_y);
|
||||||
match object_tile_index_to_scene_mask_tile_index[object_tile_index as usize] {
|
match object_tile_index_to_scene_mask_tile_index[object_tile_index as usize] {
|
||||||
u32::MAX => {}
|
u16::MAX => {}
|
||||||
scene_mask_tile_index => {
|
scene_mask_tile_index => {
|
||||||
scene.fills.push(FillScenePrimitive {
|
scene.fills.push(FillScenePrimitive {
|
||||||
from: fill.from,
|
from_px: fill.from_px,
|
||||||
to: fill.to,
|
to_px: fill.to_px,
|
||||||
|
from_subpx: fill.from_subpx,
|
||||||
|
to_subpx: fill.to_subpx,
|
||||||
mask_tile_index: scene_mask_tile_index,
|
mask_tile_index: scene_mask_tile_index,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1351,8 +1353,10 @@ struct BuiltScene {
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
struct FillObjectPrimitive {
|
struct FillObjectPrimitive {
|
||||||
from: Point2D<f32>,
|
from_px: Point2DU4,
|
||||||
to: Point2D<f32>,
|
to_px: Point2DU4,
|
||||||
|
from_subpx: Point2D<u8>,
|
||||||
|
to_subpx: Point2D<u8>,
|
||||||
tile_x: i16,
|
tile_x: i16,
|
||||||
tile_y: i16,
|
tile_y: i16,
|
||||||
}
|
}
|
||||||
|
@ -1361,27 +1365,29 @@ struct FillObjectPrimitive {
|
||||||
struct TileObjectPrimitive {
|
struct TileObjectPrimitive {
|
||||||
tile_x: i16,
|
tile_x: i16,
|
||||||
tile_y: i16,
|
tile_y: i16,
|
||||||
backdrop: i32,
|
backdrop: i16,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
struct FillScenePrimitive {
|
struct FillScenePrimitive {
|
||||||
from: Point2D<f32>,
|
from_px: Point2DU4,
|
||||||
to: Point2D<f32>,
|
to_px: Point2DU4,
|
||||||
mask_tile_index: u32,
|
from_subpx: Point2D<u8>,
|
||||||
|
to_subpx: Point2D<u8>,
|
||||||
|
mask_tile_index: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
struct SolidTileScenePrimitive {
|
struct SolidTileScenePrimitive {
|
||||||
tile_x: i16,
|
tile_x: i16,
|
||||||
tile_y: i16,
|
tile_y: i16,
|
||||||
object_index: u32,
|
object_index: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
struct MaskTileScenePrimitive {
|
struct MaskTileScenePrimitive {
|
||||||
tile: TileObjectPrimitive,
|
tile: TileObjectPrimitive,
|
||||||
object_index: u32,
|
object_index: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
|
@ -1431,6 +1437,11 @@ impl BuiltObject {
|
||||||
let tile_index = self.tile_coords_to_index(tile_x, tile_y);
|
let tile_index = self.tile_coords_to_index(tile_x, tile_y);
|
||||||
let (from, to) = (*from - tile_origin, *to - tile_origin);
|
let (from, to) = (*from - tile_origin, *to - tile_origin);
|
||||||
|
|
||||||
|
let from = Point2D::new(clamp(from.x, 0.0, MAX_U12), clamp(from.y, 0.0, MAX_U12));
|
||||||
|
let to = Point2D::new(clamp(to.x, 0.0, MAX_U12), clamp(to.y, 0.0, MAX_U12));
|
||||||
|
|
||||||
|
const MAX_U12: f32 = 16.0 - 1.0 / 256.0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
println!("from={:?} to={:?}", from, to);
|
println!("from={:?} to={:?}", from, to);
|
||||||
debug_assert!(from.x > -EPSILON);
|
debug_assert!(from.x > -EPSILON);
|
||||||
|
@ -1443,7 +1454,18 @@ impl BuiltObject {
|
||||||
debug_assert!(to.y < TILE_HEIGHT + EPSILON);
|
debug_assert!(to.y < TILE_HEIGHT + EPSILON);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
self.fills.push(FillObjectPrimitive { from, to, tile_x, tile_y });
|
let from_px = Point2DU4::new(from.x as u8, from.y as u8);
|
||||||
|
let to_px = Point2DU4::new(to.x as u8, to.y as u8);
|
||||||
|
let from_subpx = Point2D::new((from.x.fract() * 256.0) as u8,
|
||||||
|
(from.y.fract() * 256.0) as u8);
|
||||||
|
let to_subpx = Point2D::new((to.x.fract() * 256.0) as u8, (to.y.fract() * 256.0) as u8);
|
||||||
|
|
||||||
|
self.fills.push(FillObjectPrimitive {
|
||||||
|
from_px, to_px,
|
||||||
|
from_subpx, to_subpx,
|
||||||
|
tile_x, tile_y,
|
||||||
|
});
|
||||||
|
|
||||||
self.solid_tiles.set(tile_index as usize, false);
|
self.solid_tiles.set(tile_index as usize, false);
|
||||||
|
|
||||||
// FIXME(pcwalton): This is really sloppy!
|
// FIXME(pcwalton): This is really sloppy!
|
||||||
|
@ -1496,9 +1518,11 @@ impl BuiltScene {
|
||||||
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 {
|
||||||
write_point(writer, &fill_primitive.from)?;
|
writer.write_u8(fill_primitive.from_px.0)?;
|
||||||
write_point(writer, &fill_primitive.to)?;
|
writer.write_u8(fill_primitive.to_px.0)?;
|
||||||
writer.write_u32::<LittleEndian>(fill_primitive.mask_tile_index)?;
|
write_point2d_u8(writer, fill_primitive.from_subpx)?;
|
||||||
|
write_point2d_u8(writer, fill_primitive.to_subpx)?;
|
||||||
|
writer.write_u16::<LittleEndian>(fill_primitive.mask_tile_index)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.write_all(b"soli")?;
|
writer.write_all(b"soli")?;
|
||||||
|
@ -1506,7 +1530,7 @@ impl BuiltScene {
|
||||||
for &tile_primitive in &self.solid_tiles {
|
for &tile_primitive in &self.solid_tiles {
|
||||||
writer.write_i16::<LittleEndian>(tile_primitive.tile_x)?;
|
writer.write_i16::<LittleEndian>(tile_primitive.tile_x)?;
|
||||||
writer.write_i16::<LittleEndian>(tile_primitive.tile_y)?;
|
writer.write_i16::<LittleEndian>(tile_primitive.tile_y)?;
|
||||||
writer.write_u32::<LittleEndian>(tile_primitive.object_index)?;
|
writer.write_u16::<LittleEndian>(tile_primitive.object_index)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.write_all(b"mask")?;
|
writer.write_all(b"mask")?;
|
||||||
|
@ -1514,8 +1538,8 @@ impl BuiltScene {
|
||||||
for &tile_primitive in &self.mask_tiles {
|
for &tile_primitive in &self.mask_tiles {
|
||||||
writer.write_i16::<LittleEndian>(tile_primitive.tile.tile_x)?;
|
writer.write_i16::<LittleEndian>(tile_primitive.tile.tile_x)?;
|
||||||
writer.write_i16::<LittleEndian>(tile_primitive.tile.tile_y)?;
|
writer.write_i16::<LittleEndian>(tile_primitive.tile.tile_y)?;
|
||||||
writer.write_i32::<LittleEndian>(tile_primitive.tile.backdrop)?;
|
writer.write_i16::<LittleEndian>(tile_primitive.tile.backdrop)?;
|
||||||
writer.write_u32::<LittleEndian>(tile_primitive.object_index)?;
|
writer.write_u16::<LittleEndian>(tile_primitive.object_index)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.write_all(b"shad")?;
|
writer.write_all(b"shad")?;
|
||||||
|
@ -1527,16 +1551,17 @@ impl BuiltScene {
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
||||||
fn write_point<W>(writer: &mut W, point: &Point2D<f32>) -> io::Result<()> where W: Write {
|
fn write_point2d_u8<W>(writer: &mut W, point: Point2D<u8>)
|
||||||
writer.write_f32::<LittleEndian>(point.x)?;
|
-> io::Result<()> where W: Write {
|
||||||
writer.write_f32::<LittleEndian>(point.y)?;
|
writer.write_u8(point.x)?;
|
||||||
|
writer.write_u8(point.y)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SolidTileScenePrimitive {
|
impl SolidTileScenePrimitive {
|
||||||
fn new(tile_x: i16, tile_y: i16, object_index: u32) -> SolidTileScenePrimitive {
|
fn new(tile_x: i16, tile_y: i16, object_index: u16) -> SolidTileScenePrimitive {
|
||||||
SolidTileScenePrimitive { tile_x, tile_y, object_index }
|
SolidTileScenePrimitive { tile_x, tile_y, object_index }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1987,6 +2012,18 @@ impl PartialOrd<ActiveEdge> for ActiveEdge {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Geometry
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
struct Point2DU4(pub u8);
|
||||||
|
|
||||||
|
impl Point2DU4 {
|
||||||
|
fn new(x: u8, y: u8) -> Point2DU4 { Point2DU4(x | (y << 4)) }
|
||||||
|
|
||||||
|
fn x(self) -> u8 { self.0 & 0xf }
|
||||||
|
fn y(self) -> u8 { self.0 >> 4 }
|
||||||
|
}
|
||||||
|
|
||||||
// Path utilities
|
// Path utilities
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue