WIP: get demo compiling again
This commit is contained in:
parent
28d948a36e
commit
6e0e621d19
|
@ -15,12 +15,14 @@ precision highp float;
|
|||
uniform vec2 uFramebufferSize;
|
||||
uniform vec2 uTileSize;
|
||||
uniform vec2 uStencilTextureSize;
|
||||
uniform sampler2D uFillColorsTexture;
|
||||
uniform vec2 uFillColorsTextureSize;
|
||||
uniform vec2 uViewBoxOrigin;
|
||||
|
||||
in vec2 aTessCoord;
|
||||
in vec2 aTileOrigin;
|
||||
in float aBackdrop;
|
||||
in vec4 aColor;
|
||||
in int aObject;
|
||||
|
||||
out vec2 vTexCoord;
|
||||
out float vBackdrop;
|
||||
|
@ -38,6 +40,6 @@ void main() {
|
|||
vec2 texCoord = computeTileOffset(tileIndex, uStencilTextureSize.x) + aTessCoord * uTileSize;
|
||||
vTexCoord = texCoord / uStencilTextureSize;
|
||||
vBackdrop = aBackdrop;
|
||||
vColor = aColor;
|
||||
vColor = texture(uFillColorsTexture, vec2(float(aObject) / uFillColorsTextureSize.x, 0.0));
|
||||
gl_Position = vec4((position / uFramebufferSize * 2.0 - 1.0) * vec2(1.0, -1.0), 0.0, 1.0);
|
||||
}
|
||||
|
|
|
@ -14,17 +14,18 @@ precision highp float;
|
|||
|
||||
uniform vec2 uFramebufferSize;
|
||||
uniform vec2 uTileSize;
|
||||
uniform sampler2D uFillColorsTexture;
|
||||
uniform vec2 uFillColorsTextureSize;
|
||||
uniform vec2 uViewBoxOrigin;
|
||||
|
||||
in vec2 aTessCoord;
|
||||
in vec2 aTileOrigin;
|
||||
in vec4 aColor;
|
||||
in int aObject;
|
||||
|
||||
out vec4 vColor;
|
||||
|
||||
void main() {
|
||||
vec2 position = (aTileOrigin + aTessCoord) * uTileSize + uViewBoxOrigin;
|
||||
vColor = aColor;
|
||||
vColor = texture(uFillColorsTexture, vec2(float(aObject) / uFillColorsTextureSize.x, 0.0));
|
||||
gl_Position = vec4((position / uFramebufferSize * 2.0 - 1.0) * vec2(1.0, -1.0), 0.0, 1.0);
|
||||
}
|
||||
|
||||
|
|
|
@ -54,16 +54,23 @@ class App {
|
|||
private gl: WebGL2RenderingContext;
|
||||
private disjointTimerQueryExt: any;
|
||||
private areaLUTTexture: WebGLTexture;
|
||||
private fillColorsTexture: WebGLTexture;
|
||||
private stencilTexture: WebGLTexture;
|
||||
private stencilFramebuffer: WebGLFramebuffer;
|
||||
private fillProgram: Program<'FramebufferSize' | 'TileSize' | 'AreaLUT',
|
||||
'TessCoord' | 'From' | 'To' | 'TileIndex'>;
|
||||
private solidTileProgram: Program<'FramebufferSize' | 'TileSize' | 'ViewBoxOrigin',
|
||||
'TessCoord' | 'TileOrigin' | 'Color'>;
|
||||
private maskTileProgram:
|
||||
Program<'FramebufferSize' | 'TileSize' | 'StencilTexture' | 'StencilTextureSize' |
|
||||
private solidTileProgram: Program<'FramebufferSize' |
|
||||
'TileSize' |
|
||||
'FillColorsTexture' | 'FillColorsTextureSize' |
|
||||
'ViewBoxOrigin',
|
||||
'TessCoord' | 'TileOrigin' | 'Backdrop' | 'Color'>;
|
||||
'TessCoord' | 'TileOrigin' | 'Object'>;
|
||||
private maskTileProgram:
|
||||
Program<'FramebufferSize' |
|
||||
'TileSize' |
|
||||
'StencilTexture' | 'StencilTextureSize' |
|
||||
'FillColorsTexture' | 'FillColorsTextureSize' |
|
||||
'ViewBoxOrigin',
|
||||
'TessCoord' | 'TileOrigin' | 'Backdrop' | 'Object'>;
|
||||
private quadVertexBuffer: WebGLBuffer;
|
||||
private fillVertexBuffer: WebGLBuffer;
|
||||
private fillVertexArray: WebGLVertexArrayObject;
|
||||
|
@ -77,6 +84,7 @@ class App {
|
|||
private fillPrimitiveCount: number;
|
||||
private solidTileCount: number;
|
||||
private maskTileCount: number;
|
||||
private objectCount: number;
|
||||
|
||||
constructor(areaLUT: HTMLImageElement) {
|
||||
const canvas = staticCast(document.getElementById('canvas'), HTMLCanvasElement);
|
||||
|
@ -106,6 +114,8 @@ class App {
|
|||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
|
||||
this.fillColorsTexture = unwrapNull(gl.createTexture());
|
||||
|
||||
this.stencilTexture = unwrapNull(gl.createTexture());
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.stencilTexture);
|
||||
gl.texImage2D(gl.TEXTURE_2D,
|
||||
|
@ -140,6 +150,8 @@ class App {
|
|||
'TileSize',
|
||||
'StencilTexture',
|
||||
'StencilTextureSize',
|
||||
'FillColorsTexture',
|
||||
'FillColorsTextureSize',
|
||||
'ViewBoxOrigin',
|
||||
],
|
||||
[
|
||||
|
@ -147,15 +159,21 @@ class App {
|
|||
'TileOrigin',
|
||||
'TileIndex',
|
||||
'Backdrop',
|
||||
'Color',
|
||||
'Object',
|
||||
]);
|
||||
this.maskTileProgram = maskTileProgram;
|
||||
|
||||
const solidTileProgram = new Program(gl,
|
||||
OPAQUE_VERTEX_SHADER_SOURCE,
|
||||
OPAQUE_FRAGMENT_SHADER_SOURCE,
|
||||
['FramebufferSize', 'TileSize', 'ViewBoxOrigin'],
|
||||
['TessCoord', 'TileOrigin', 'Color']);
|
||||
[
|
||||
'FramebufferSize',
|
||||
'TileSize',
|
||||
'FillColorsTexture',
|
||||
'FillColorsTextureSize',
|
||||
'ViewBoxOrigin',
|
||||
],
|
||||
['TessCoord', 'TileOrigin', 'Object']);
|
||||
this.solidTileProgram = solidTileProgram;
|
||||
|
||||
const fillProgram = new Program(gl,
|
||||
|
@ -233,16 +251,15 @@ class App {
|
|||
SOLID_TILE_INSTANCE_SIZE,
|
||||
0);
|
||||
gl.vertexAttribDivisor(solidTileProgram.attributes.TileOrigin, 1);
|
||||
gl.vertexAttribPointer(solidTileProgram.attributes.Color,
|
||||
4,
|
||||
gl.UNSIGNED_BYTE,
|
||||
true,
|
||||
gl.vertexAttribIPointer(solidTileProgram.attributes.Object,
|
||||
1,
|
||||
gl.INT,
|
||||
SOLID_TILE_INSTANCE_SIZE,
|
||||
4);
|
||||
gl.vertexAttribDivisor(solidTileProgram.attributes.Color, 1);
|
||||
gl.vertexAttribDivisor(solidTileProgram.attributes.Object, 1);
|
||||
gl.enableVertexAttribArray(solidTileProgram.attributes.TessCoord);
|
||||
gl.enableVertexAttribArray(solidTileProgram.attributes.TileOrigin);
|
||||
gl.enableVertexAttribArray(solidTileProgram.attributes.Color);
|
||||
gl.enableVertexAttribArray(solidTileProgram.attributes.Object);
|
||||
|
||||
// Initialize mask tile VAO.
|
||||
this.maskVertexArray = unwrapNull(gl.createVertexArray());
|
||||
|
@ -270,17 +287,16 @@ class App {
|
|||
MASK_TILE_INSTANCE_SIZE,
|
||||
4);
|
||||
gl.vertexAttribDivisor(maskTileProgram.attributes.Backdrop, 1);
|
||||
gl.vertexAttribPointer(maskTileProgram.attributes.Color,
|
||||
4,
|
||||
gl.UNSIGNED_BYTE,
|
||||
true,
|
||||
gl.vertexAttribIPointer(maskTileProgram.attributes.Object,
|
||||
1,
|
||||
gl.INT,
|
||||
MASK_TILE_INSTANCE_SIZE,
|
||||
8);
|
||||
gl.vertexAttribDivisor(maskTileProgram.attributes.Color, 1);
|
||||
gl.vertexAttribDivisor(maskTileProgram.attributes.Object, 1);
|
||||
gl.enableVertexAttribArray(maskTileProgram.attributes.TessCoord);
|
||||
gl.enableVertexAttribArray(maskTileProgram.attributes.TileOrigin);
|
||||
gl.enableVertexAttribArray(maskTileProgram.attributes.Backdrop);
|
||||
gl.enableVertexAttribArray(maskTileProgram.attributes.Color);
|
||||
gl.enableVertexAttribArray(maskTileProgram.attributes.Object);
|
||||
|
||||
this.viewBox = new Rect(new Point2D(0.0, 0.0), new Size2D(0.0, 0.0));
|
||||
|
||||
|
@ -290,6 +306,7 @@ class App {
|
|||
this.fillPrimitiveCount = 0;
|
||||
this.solidTileCount = 0;
|
||||
this.maskTileCount = 0;
|
||||
this.objectCount = 0;
|
||||
}
|
||||
|
||||
redraw(): void {
|
||||
|
@ -341,6 +358,13 @@ class App {
|
|||
framebufferSize.width,
|
||||
framebufferSize.height);
|
||||
gl.uniform2f(this.solidTileProgram.uniforms.TileSize, TILE_SIZE.width, TILE_SIZE.height);
|
||||
gl.activeTexture(gl.TEXTURE0);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.fillColorsTexture);
|
||||
gl.uniform1i(this.solidTileProgram.uniforms.FillColorsTexture, 0);
|
||||
// FIXME(pcwalton): Maybe this should be an ivec2 or uvec2?
|
||||
gl.uniform2f(this.solidTileProgram.uniforms.FillColorsTextureSize,
|
||||
this.objectCount,
|
||||
1.0);
|
||||
gl.uniform2f(this.solidTileProgram.uniforms.ViewBoxOrigin,
|
||||
this.viewBox.origin.x,
|
||||
this.viewBox.origin.y);
|
||||
|
@ -360,6 +384,13 @@ class App {
|
|||
gl.uniform2f(this.maskTileProgram.uniforms.StencilTextureSize,
|
||||
STENCIL_FRAMEBUFFER_SIZE.width,
|
||||
STENCIL_FRAMEBUFFER_SIZE.height);
|
||||
gl.activeTexture(gl.TEXTURE1);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.fillColorsTexture);
|
||||
gl.uniform1i(this.maskTileProgram.uniforms.FillColorsTexture, 1);
|
||||
// FIXME(pcwalton): Maybe this should be an ivec2 or uvec2?
|
||||
gl.uniform2f(this.maskTileProgram.uniforms.FillColorsTextureSize,
|
||||
this.objectCount,
|
||||
1.0);
|
||||
gl.uniform2f(this.maskTileProgram.uniforms.ViewBoxOrigin,
|
||||
this.viewBox.origin.x,
|
||||
this.viewBox.origin.y);
|
||||
|
@ -416,6 +447,8 @@ class App {
|
|||
const arrayBuffer = staticCast(reader.result, ArrayBuffer);
|
||||
const root = new RIFFChunk(new DataView(arrayBuffer));
|
||||
for (const subchunk of root.subchunks()) {
|
||||
const self = this;
|
||||
|
||||
const id = subchunk.stringID();
|
||||
if (id === 'head') {
|
||||
const headerData = subchunk.contents();
|
||||
|
@ -426,36 +459,54 @@ class App {
|
|||
continue;
|
||||
}
|
||||
|
||||
let bindPoint, buffer;
|
||||
let countFieldName: 'fillPrimitiveCount' | 'totalTileCount' | 'solidTileCount' |
|
||||
'maskTileCount';
|
||||
let instanceSize;
|
||||
switch (id) {
|
||||
case 'fill':
|
||||
bindPoint = gl.ARRAY_BUFFER;
|
||||
buffer = this.fillVertexBuffer;
|
||||
countFieldName = 'fillPrimitiveCount';
|
||||
instanceSize = FILL_INSTANCE_SIZE;
|
||||
uploadArrayBuffer(this.fillVertexBuffer,
|
||||
'fillPrimitiveCount',
|
||||
FILL_INSTANCE_SIZE);
|
||||
break;
|
||||
case 'soli':
|
||||
bindPoint = gl.ARRAY_BUFFER;
|
||||
buffer = this.solidTileVertexBuffer;
|
||||
countFieldName = 'solidTileCount';
|
||||
instanceSize = SOLID_TILE_INSTANCE_SIZE;
|
||||
uploadArrayBuffer(this.solidTileVertexBuffer,
|
||||
'solidTileCount',
|
||||
SOLID_TILE_INSTANCE_SIZE);
|
||||
break;
|
||||
case 'mask':
|
||||
bindPoint = gl.ARRAY_BUFFER;
|
||||
buffer = this.maskTileVertexBuffer;
|
||||
countFieldName = 'maskTileCount';
|
||||
instanceSize = MASK_TILE_INSTANCE_SIZE;
|
||||
uploadArrayBuffer(this.maskTileVertexBuffer,
|
||||
'maskTileCount',
|
||||
MASK_TILE_INSTANCE_SIZE);
|
||||
break;
|
||||
case 'shad':
|
||||
this.objectCount = subchunk.length() / 4;
|
||||
gl.activeTexture(gl.TEXTURE0);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.fillColorsTexture);
|
||||
gl.texImage2D(gl.TEXTURE_2D,
|
||||
0,
|
||||
gl.RGBA,
|
||||
this.objectCount,
|
||||
1,
|
||||
0,
|
||||
gl.RGBA,
|
||||
gl.UNSIGNED_BYTE,
|
||||
subchunk.contents());
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unexpected subchunk ID: " + id);
|
||||
}
|
||||
|
||||
gl.bindBuffer(bindPoint, buffer);
|
||||
gl.bufferData(bindPoint, subchunk.contents(), gl.DYNAMIC_DRAW);
|
||||
this[countFieldName] = subchunk.length() / instanceSize;
|
||||
type CountFieldName = 'fillPrimitiveCount' | 'solidTileCount' | 'maskTileCount';
|
||||
|
||||
function uploadArrayBuffer(buffer: WebGLBuffer,
|
||||
countFieldName: CountFieldName,
|
||||
instanceSize: number):
|
||||
void {
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, subchunk.contents(), gl.DYNAMIC_DRAW);
|
||||
self[countFieldName] = subchunk.length() / instanceSize;
|
||||
}
|
||||
}
|
||||
|
||||
this.redraw();
|
||||
|
|
|
@ -28,6 +28,7 @@ use lyon_path::iterator::PathIter;
|
|||
use pathfinder_path_utils::stroke::{StrokeStyle, StrokeToFillIter};
|
||||
use quick_xml::Reader;
|
||||
use quick_xml::events::{BytesStart, Event};
|
||||
use rayon::ThreadPoolBuilder;
|
||||
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
|
@ -58,9 +59,11 @@ fn main() {
|
|||
.value_name("COUNT")
|
||||
.takes_value(true)
|
||||
.help("Run a benchmark with COUNT runs"))
|
||||
.arg(Arg::with_name("sequential").short("s")
|
||||
.long("sequential")
|
||||
.help("Use only one thread"))
|
||||
.arg(Arg::with_name("jobs").short("j")
|
||||
.long("jobs")
|
||||
.value_name("THREADS")
|
||||
.takes_value(true)
|
||||
.help("Number of threads to use"))
|
||||
.arg(Arg::with_name("INPUT").help("Path to the SVG file to render")
|
||||
.required(true)
|
||||
.index(1))
|
||||
|
@ -72,20 +75,26 @@ fn main() {
|
|||
Some(runs) => runs.parse().unwrap(),
|
||||
None => 1,
|
||||
};
|
||||
let sequential = matches.is_present("sequential");
|
||||
let jobs: Option<usize> = matches.value_of("jobs").map(|string| string.parse().unwrap());
|
||||
let input_path = PathBuf::from(matches.value_of("INPUT").unwrap());
|
||||
let output_path = matches.value_of("OUTPUT").map(PathBuf::from);
|
||||
|
||||
// Set up Rayon.
|
||||
let mut thread_pool_builder = ThreadPoolBuilder::new();
|
||||
if let Some(jobs) = jobs {
|
||||
thread_pool_builder = thread_pool_builder.num_threads(jobs);
|
||||
}
|
||||
thread_pool_builder.build_global().unwrap();
|
||||
|
||||
let scene = Scene::from_path(&input_path);
|
||||
println!("Scene bounds: {:?}", scene.bounds);
|
||||
|
||||
let start_time = Instant::now();
|
||||
let mut built_scene = BuiltScene::new(&scene.view_box, scene.objects.len() as u32);
|
||||
for _ in 0..runs {
|
||||
let built_objects = if sequential {
|
||||
scene.build_objects_sequentially()
|
||||
} else {
|
||||
scene.build_objects_in_parallel()
|
||||
let built_objects = match jobs {
|
||||
Some(1) => scene.build_objects_sequentially(),
|
||||
_ => scene.build_objects(),
|
||||
};
|
||||
built_scene = BuiltScene::from_objects(&scene.view_box, &built_objects);
|
||||
}
|
||||
|
@ -321,17 +330,30 @@ impl Scene {
|
|||
&self.styles[style.0 as usize]
|
||||
}
|
||||
|
||||
fn build_shader(&self, object_index: u32) -> ObjectShader {
|
||||
ObjectShader {
|
||||
fill_color: self.objects[object_index as usize].color,
|
||||
}
|
||||
}
|
||||
|
||||
// This function exists to make profiling easier.
|
||||
fn build_objects_sequentially(&self) -> Vec<BuiltObject> {
|
||||
self.objects.iter().enumerate().map(|(object_index, object)| {
|
||||
let mut tiler = Tiler::new(&object.outline, object_index as u32, &self.view_box);
|
||||
let mut tiler = Tiler::new(&object.outline,
|
||||
object_index as u32,
|
||||
&self.view_box,
|
||||
&self.build_shader(object_index as u32));
|
||||
tiler.generate_tiles();
|
||||
tiler.built_object
|
||||
}).collect()
|
||||
}
|
||||
|
||||
fn build_objects_in_parallel(&self) -> Vec<BuiltObject> {
|
||||
fn build_objects(&self) -> Vec<BuiltObject> {
|
||||
self.objects.par_iter().enumerate().map(|(object_index, object)| {
|
||||
let mut tiler = Tiler::new(&object.outline, object_index as u32, &self.view_box);
|
||||
let mut tiler = Tiler::new(&object.outline,
|
||||
object_index as u32,
|
||||
&self.view_box,
|
||||
&self.build_shader(object_index as u32));
|
||||
tiler.generate_tiles();
|
||||
tiler.built_object
|
||||
}).collect()
|
||||
|
@ -955,9 +977,10 @@ struct Tiler<'o> {
|
|||
}
|
||||
|
||||
impl<'o> Tiler<'o> {
|
||||
fn new(outline: &'o Outline, object_index: u32, view_box: &Rect<f32>) -> Tiler<'o> {
|
||||
fn new(outline: &'o Outline, object_index: u32, view_box: &Rect<f32>, shader: &ObjectShader)
|
||||
-> Tiler<'o> {
|
||||
let bounds = outline.bounds.intersection(&view_box).unwrap_or(Rect::zero());
|
||||
let built_object = BuiltObject::new(&bounds);
|
||||
let built_object = BuiltObject::new(&bounds, shader);
|
||||
|
||||
Tiler {
|
||||
outline,
|
||||
|
@ -1023,7 +1046,7 @@ impl<'o> Tiler<'o> {
|
|||
};
|
||||
|
||||
// Move over to the correct tile, filling in as we go.
|
||||
let mut segment_tile_x = f32::floor(segment_x / TILE_WIDTH) as i16;
|
||||
let segment_tile_x = f32::floor(segment_x / TILE_WIDTH) as i16;
|
||||
while current_tile_x < segment_tile_x {
|
||||
//println!("... filling!");
|
||||
self.built_object.get_tile_mut(current_tile_x, tile_y).backdrop = current_winding;
|
||||
|
@ -1153,10 +1176,10 @@ impl BuiltScene {
|
|||
fn new(view_box: &Rect<f32>, object_count: u32) -> BuiltScene {
|
||||
BuiltScene {
|
||||
view_box: *view_box,
|
||||
object_count,
|
||||
fills: vec![],
|
||||
solid_tiles: vec![],
|
||||
mask_tiles: vec![],
|
||||
shaders: vec![ObjectShader::default(); object_count as usize],
|
||||
|
||||
tile_rect: round_rect_out_to_tile_bounds(view_box),
|
||||
}
|
||||
|
@ -1237,6 +1260,7 @@ struct BuiltObject {
|
|||
tiles: Vec<TileObjectPrimitive>,
|
||||
fills: Vec<FillObjectPrimitive>,
|
||||
mask_tiles: FixedBitSet,
|
||||
shader: ObjectShader,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -1245,7 +1269,7 @@ struct BuiltScene {
|
|||
fills: Vec<FillScenePrimitive>,
|
||||
solid_tiles: Vec<SolidTileScenePrimitive>,
|
||||
mask_tiles: Vec<MaskTileScenePrimitive>,
|
||||
object_count: u32,
|
||||
shaders: Vec<ObjectShader>,
|
||||
|
||||
tile_rect: Rect<i16>,
|
||||
}
|
||||
|
@ -1285,7 +1309,12 @@ struct MaskTileScenePrimitive {
|
|||
object_index: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
struct ObjectShader {
|
||||
fill_color: ColorU,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
struct ColorU {
|
||||
r: u8,
|
||||
g: u8,
|
||||
|
@ -1296,7 +1325,7 @@ struct ColorU {
|
|||
// Utilities for built objects
|
||||
|
||||
impl BuiltObject {
|
||||
fn new(bounds: &Rect<f32>) -> BuiltObject {
|
||||
fn new(bounds: &Rect<f32>, shader: &ObjectShader) -> BuiltObject {
|
||||
// Compute the tile rect.
|
||||
let tile_rect = round_rect_out_to_tile_bounds(&bounds);
|
||||
|
||||
|
@ -1315,6 +1344,7 @@ impl BuiltObject {
|
|||
tiles,
|
||||
fills: vec![],
|
||||
mask_tiles: FixedBitSet::with_capacity(tile_count),
|
||||
shader: *shader,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1350,11 +1380,13 @@ impl BuiltScene {
|
|||
let fill_size = self.fills.len() * mem::size_of::<FillScenePrimitive>();
|
||||
let solid_tiles_size = self.solid_tiles.len() * mem::size_of::<SolidTileScenePrimitive>();
|
||||
let mask_tiles_size = self.mask_tiles.len() * mem::size_of::<MaskTileScenePrimitive>();
|
||||
let shaders_size = self.shaders.len() * mem::size_of::<ObjectShader>();
|
||||
writer.write_u32::<LittleEndian>((4 +
|
||||
8 + header_size +
|
||||
8 + fill_size +
|
||||
8 + solid_tiles_size +
|
||||
8 + mask_tiles_size) as u32)?;
|
||||
8 + mask_tiles_size +
|
||||
8 + shaders_size) as u32)?;
|
||||
|
||||
writer.write_all(b"PF3S")?;
|
||||
|
||||
|
@ -1390,6 +1422,13 @@ impl BuiltScene {
|
|||
writer.write_u32::<LittleEndian>(tile_primitive.object_index)?;
|
||||
}
|
||||
|
||||
writer.write_all(b"shad")?;
|
||||
writer.write_u32::<LittleEndian>(shaders_size as u32)?;
|
||||
for &shader in &self.shaders {
|
||||
let fill_color = shader.fill_color;
|
||||
writer.write_all(&[fill_color.r, fill_color.g, fill_color.b, fill_color.a])?;
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
|
||||
fn write_point<W>(writer: &mut W, point: &Point2D<f32>) -> io::Result<()> where W: Write {
|
||||
|
|
Loading…
Reference in New Issue