Don't distinguish between render targets and other images in the texture atlas
allocator
This commit is contained in:
parent
a8f7438cd9
commit
9935c9fdff
|
@ -10,8 +10,7 @@
|
||||||
|
|
||||||
//! A simple quadtree-based texture allocator.
|
//! A simple quadtree-based texture allocator.
|
||||||
|
|
||||||
use crate::gpu_data::TexturePageId;
|
use crate::gpu_data::{TextureLocation, TexturePageId};
|
||||||
use pathfinder_content::render_target::RenderTargetId;
|
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
use pathfinder_geometry::vector::{Vector2F, Vector2I};
|
use pathfinder_geometry::vector::{Vector2F, Vector2I};
|
||||||
|
|
||||||
|
@ -28,8 +27,6 @@ pub enum TexturePageAllocator {
|
||||||
Atlas(TextureAtlasAllocator),
|
Atlas(TextureAtlasAllocator),
|
||||||
// A single image.
|
// A single image.
|
||||||
Image { size: Vector2I },
|
Image { size: Vector2I },
|
||||||
// A render target.
|
|
||||||
RenderTarget { size: Vector2I, id: RenderTargetId },
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -38,12 +35,6 @@ pub struct TextureAtlasAllocator {
|
||||||
size: u32,
|
size: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
|
||||||
pub struct TextureLocation {
|
|
||||||
pub page: TexturePageId,
|
|
||||||
pub rect: RectI,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum TreeNode {
|
enum TreeNode {
|
||||||
EmptyLeaf,
|
EmptyLeaf,
|
||||||
|
@ -75,8 +66,7 @@ impl TextureAllocator {
|
||||||
// Try to add to each atlas.
|
// Try to add to each atlas.
|
||||||
for (page_index, page) in self.pages.iter_mut().enumerate() {
|
for (page_index, page) in self.pages.iter_mut().enumerate() {
|
||||||
match *page {
|
match *page {
|
||||||
TexturePageAllocator::Image { .. } |
|
TexturePageAllocator::Image { .. } => {}
|
||||||
TexturePageAllocator::RenderTarget { .. } => {}
|
|
||||||
TexturePageAllocator::Atlas(ref mut allocator) => {
|
TexturePageAllocator::Atlas(ref mut allocator) => {
|
||||||
if let Some(rect) = allocator.allocate(requested_size) {
|
if let Some(rect) = allocator.allocate(requested_size) {
|
||||||
return TextureLocation { page: TexturePageId(page_index as u32), rect };
|
return TextureLocation { page: TexturePageId(page_index as u32), rect };
|
||||||
|
@ -93,26 +83,17 @@ impl TextureAllocator {
|
||||||
TextureLocation { page, rect }
|
TextureLocation { page, rect }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allocate_image(&mut self, requested_size: Vector2I) -> TextureLocation {
|
pub fn allocate_image(&mut self, requested_size: Vector2I) -> TextureLocation {
|
||||||
let page = TexturePageId(self.pages.len() as u32);
|
let page = TexturePageId(self.pages.len() as u32);
|
||||||
let rect = RectI::new(Vector2I::default(), requested_size);
|
let rect = RectI::new(Vector2I::default(), requested_size);
|
||||||
self.pages.push(TexturePageAllocator::Image { size: rect.size() });
|
self.pages.push(TexturePageAllocator::Image { size: rect.size() });
|
||||||
TextureLocation { page, rect }
|
TextureLocation { page, rect }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn allocate_render_target(&mut self, requested_size: Vector2I, id: RenderTargetId)
|
|
||||||
-> TextureLocation {
|
|
||||||
let page = TexturePageId(self.pages.len() as u32);
|
|
||||||
let rect = RectI::new(Vector2I::default(), requested_size);
|
|
||||||
self.pages.push(TexturePageAllocator::RenderTarget { size: rect.size(), id });
|
|
||||||
TextureLocation { page, rect }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn page_size(&self, page_index: TexturePageId) -> Vector2I {
|
pub fn page_size(&self, page_index: TexturePageId) -> Vector2I {
|
||||||
match self.pages[page_index.0 as usize] {
|
match self.pages[page_index.0 as usize] {
|
||||||
TexturePageAllocator::Atlas(ref atlas) => Vector2I::splat(atlas.size as i32),
|
TexturePageAllocator::Atlas(ref atlas) => Vector2I::splat(atlas.size as i32),
|
||||||
TexturePageAllocator::Image { size, .. } |
|
TexturePageAllocator::Image { size, .. } => size,
|
||||||
TexturePageAllocator::RenderTarget { size, .. } => size,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,14 +105,6 @@ impl TextureAllocator {
|
||||||
pub fn page_count(&self) -> u32 {
|
pub fn page_count(&self) -> u32 {
|
||||||
self.pages.len() as u32
|
self.pages.len() as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn page_render_target_id(&self, page_index: TexturePageId) -> Option<RenderTargetId> {
|
|
||||||
match self.pages[page_index.0 as usize] {
|
|
||||||
TexturePageAllocator::RenderTarget { id, .. } => Some(id),
|
|
||||||
TexturePageAllocator::Atlas(_) | TexturePageAllocator::Image { .. } => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextureAtlasAllocator {
|
impl TextureAtlasAllocator {
|
||||||
|
|
|
@ -20,7 +20,7 @@ use crate::gpu::shaders::{SolidTileVertexArray, StencilProgram, StencilVertexArr
|
||||||
use crate::gpu::shaders::{TileFilterBasicProgram, TileFilterBlurProgram, TileFilterProgram};
|
use crate::gpu::shaders::{TileFilterBasicProgram, TileFilterBlurProgram, TileFilterProgram};
|
||||||
use crate::gpu::shaders::{TileFilterTextProgram, TileFilterVertexArray};
|
use crate::gpu::shaders::{TileFilterTextProgram, TileFilterVertexArray};
|
||||||
use crate::gpu_data::{AlphaTile, FillBatchPrimitive, MaskTile, RenderCommand, RenderTargetTile};
|
use crate::gpu_data::{AlphaTile, FillBatchPrimitive, MaskTile, RenderCommand, RenderTargetTile};
|
||||||
use crate::gpu_data::{SolidTileVertex, TexturePageDescriptor, TexturePageId};
|
use crate::gpu_data::{SolidTileVertex, TextureLocation, TexturePageDescriptor, TexturePageId};
|
||||||
use crate::options::BoundingQuad;
|
use crate::options::BoundingQuad;
|
||||||
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
||||||
use pathfinder_color::{self as color, ColorF, ColorU};
|
use pathfinder_color::{self as color, ColorF, ColorU};
|
||||||
|
@ -430,11 +430,11 @@ where
|
||||||
RenderCommand::AllocateTexturePages(ref texture_page_descriptors) => {
|
RenderCommand::AllocateTexturePages(ref texture_page_descriptors) => {
|
||||||
self.allocate_texture_pages(texture_page_descriptors)
|
self.allocate_texture_pages(texture_page_descriptors)
|
||||||
}
|
}
|
||||||
RenderCommand::UploadTexelData { page, ref texels, rect } => {
|
RenderCommand::UploadTexelData { ref texels, location } => {
|
||||||
self.upload_texel_data(page, texels, rect)
|
self.upload_texel_data(texels, location)
|
||||||
}
|
}
|
||||||
RenderCommand::DeclareRenderTarget { render_target_id, texture_page_id } => {
|
RenderCommand::DeclareRenderTarget { id, location } => {
|
||||||
self.declare_render_target(render_target_id, texture_page_id)
|
self.declare_render_target(id, location)
|
||||||
}
|
}
|
||||||
RenderCommand::AddFills(ref fills) => self.add_fills(fills),
|
RenderCommand::AddFills(ref fills) => self.add_fills(fills),
|
||||||
RenderCommand::FlushFills => {
|
RenderCommand::FlushFills => {
|
||||||
|
@ -599,23 +599,25 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upload_texel_data(&mut self, page_id: TexturePageId, texels: &[ColorU], rect: RectI) {
|
fn upload_texel_data(&mut self, texels: &[ColorU], location: TextureLocation) {
|
||||||
let texture_page = &mut self.texture_pages[page_id.0 as usize];
|
let texture_page = &mut self.texture_pages[location.page.0 as usize];
|
||||||
let texture = self.device.framebuffer_texture(&texture_page.framebuffer);
|
let texture = self.device.framebuffer_texture(&texture_page.framebuffer);
|
||||||
let texels = color::color_slice_to_u8_slice(texels);
|
let texels = color::color_slice_to_u8_slice(texels);
|
||||||
self.device.upload_to_texture(texture, rect, TextureDataRef::U8(texels));
|
self.device.upload_to_texture(texture, location.rect, TextureDataRef::U8(texels));
|
||||||
texture_page.must_preserve_contents = true;
|
texture_page.must_preserve_contents = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declare_render_target(&mut self,
|
fn declare_render_target(&mut self,
|
||||||
render_target_id: RenderTargetId,
|
render_target_id: RenderTargetId,
|
||||||
texture_page_id: TexturePageId) {
|
location: TextureLocation) {
|
||||||
while self.render_targets.len() < render_target_id.0 as usize + 1 {
|
while self.render_targets.len() < render_target_id.0 as usize + 1 {
|
||||||
self.render_targets.push(RenderTargetInfo { texture_page: TexturePageId(!0) });
|
self.render_targets.push(RenderTargetInfo {
|
||||||
|
location: TextureLocation { page: TexturePageId(!0), rect: RectI::default() },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
let mut render_target = &mut self.render_targets[render_target_id.0 as usize];
|
let mut render_target = &mut self.render_targets[render_target_id.0 as usize];
|
||||||
debug_assert_eq!(render_target.texture_page, TexturePageId(!0));
|
debug_assert_eq!(render_target.location.page, TexturePageId(!0));
|
||||||
render_target.texture_page = texture_page_id;
|
render_target.location = location;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upload_mask_tiles(&mut self, mask_tiles: &[MaskTile], fill_rule: FillRule) {
|
fn upload_mask_tiles(&mut self, mask_tiles: &[MaskTile], fill_rule: FillRule) {
|
||||||
|
@ -1153,7 +1155,7 @@ where
|
||||||
pub fn draw_render_target(&self) -> RenderTarget<D> {
|
pub fn draw_render_target(&self) -> RenderTarget<D> {
|
||||||
match self.render_target_stack.last() {
|
match self.render_target_stack.last() {
|
||||||
Some(&render_target_id) => {
|
Some(&render_target_id) => {
|
||||||
let texture_page_id = self.render_target_texture_page_id(render_target_id);
|
let texture_page_id = self.render_target_location(render_target_id).page;
|
||||||
let framebuffer = self.texture_page_framebuffer(texture_page_id);
|
let framebuffer = self.texture_page_framebuffer(texture_page_id);
|
||||||
RenderTarget::Framebuffer(framebuffer)
|
RenderTarget::Framebuffer(framebuffer)
|
||||||
}
|
}
|
||||||
|
@ -1264,7 +1266,7 @@ where
|
||||||
render_target_id: RenderTargetId,
|
render_target_id: RenderTargetId,
|
||||||
direction: BlurDirection,
|
direction: BlurDirection,
|
||||||
sigma: f32) {
|
sigma: f32) {
|
||||||
let src_texture_page = self.render_target_texture_page_id(render_target_id);
|
let src_texture_page = self.render_target_location(render_target_id).page;
|
||||||
let src_texture = self.texture_page(src_texture_page);
|
let src_texture = self.texture_page(src_texture_page);
|
||||||
let src_texture_size = self.device.texture_size(src_texture);
|
let src_texture_size = self.device.texture_size(src_texture);
|
||||||
|
|
||||||
|
@ -1310,8 +1312,10 @@ where
|
||||||
blend_state: Option<BlendState>) {
|
blend_state: Option<BlendState>) {
|
||||||
let clear_color = self.clear_color_for_draw_operation();
|
let clear_color = self.clear_color_for_draw_operation();
|
||||||
let main_viewport = self.main_viewport();
|
let main_viewport = self.main_viewport();
|
||||||
let src_texture_page = self.render_target_texture_page_id(render_target_id);
|
|
||||||
let src_texture = self.texture_page(src_texture_page);
|
// TODO(pcwalton): Other viewports.
|
||||||
|
let src_texture_location = self.render_target_location(render_target_id);
|
||||||
|
let src_texture = self.texture_page(src_texture_location.page);
|
||||||
let src_texture_size = self.device.texture_size(src_texture);
|
let src_texture_size = self.device.texture_size(src_texture);
|
||||||
|
|
||||||
uniforms.extend_from_slice(&[
|
uniforms.extend_from_slice(&[
|
||||||
|
@ -1379,7 +1383,7 @@ where
|
||||||
fn clear_color_for_draw_operation(&self) -> Option<ColorF> {
|
fn clear_color_for_draw_operation(&self) -> Option<ColorF> {
|
||||||
let must_preserve_contents = match self.render_target_stack.last() {
|
let must_preserve_contents = match self.render_target_stack.last() {
|
||||||
Some(&render_target_id) => {
|
Some(&render_target_id) => {
|
||||||
let texture_page = self.render_target_texture_page_id(render_target_id);
|
let texture_page = self.render_target_location(render_target_id).page;
|
||||||
self.texture_pages[texture_page.0 as usize].must_preserve_contents
|
self.texture_pages[texture_page.0 as usize].must_preserve_contents
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
@ -1400,7 +1404,7 @@ where
|
||||||
fn preserve_draw_framebuffer(&mut self) {
|
fn preserve_draw_framebuffer(&mut self) {
|
||||||
match self.render_target_stack.last() {
|
match self.render_target_stack.last() {
|
||||||
Some(&render_target_id) => {
|
Some(&render_target_id) => {
|
||||||
let texture_page = self.render_target_texture_page_id(render_target_id);
|
let texture_page = self.render_target_location(render_target_id).page;
|
||||||
self.texture_pages[texture_page.0 as usize].must_preserve_contents = true;
|
self.texture_pages[texture_page.0 as usize].must_preserve_contents = true;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
@ -1412,11 +1416,7 @@ where
|
||||||
|
|
||||||
pub fn draw_viewport(&self) -> RectI {
|
pub fn draw_viewport(&self) -> RectI {
|
||||||
match self.render_target_stack.last() {
|
match self.render_target_stack.last() {
|
||||||
Some(&render_target_id) => {
|
Some(&render_target_id) => self.render_target_location(render_target_id).rect,
|
||||||
let texture_page = self.render_target_texture_page_id(render_target_id);
|
|
||||||
let texture = self.texture_page(texture_page);
|
|
||||||
RectI::new(Vector2I::default(), self.device.texture_size(texture))
|
|
||||||
}
|
|
||||||
None => self.main_viewport(),
|
None => self.main_viewport(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1438,8 +1438,8 @@ where
|
||||||
Vector2I::new(MASK_FRAMEBUFFER_WIDTH, MASK_FRAMEBUFFER_HEIGHT))
|
Vector2I::new(MASK_FRAMEBUFFER_WIDTH, MASK_FRAMEBUFFER_HEIGHT))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_target_texture_page_id(&self, render_target_id: RenderTargetId) -> TexturePageId {
|
fn render_target_location(&self, render_target_id: RenderTargetId) -> TextureLocation {
|
||||||
self.render_targets[render_target_id.0 as usize].texture_page
|
self.render_targets[render_target_id.0 as usize].location
|
||||||
}
|
}
|
||||||
|
|
||||||
fn texture_page_framebuffer(&self, id: TexturePageId) -> &D::Framebuffer {
|
fn texture_page_framebuffer(&self, id: TexturePageId) -> &D::Framebuffer {
|
||||||
|
@ -1584,7 +1584,7 @@ struct TexturePage<D> where D: Device {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RenderTargetInfo {
|
struct RenderTargetInfo {
|
||||||
texture_page: TexturePageId,
|
location: TextureLocation,
|
||||||
}
|
}
|
||||||
|
|
||||||
trait ToBlendState {
|
trait ToBlendState {
|
||||||
|
|
|
@ -42,12 +42,12 @@ pub enum RenderCommand {
|
||||||
AllocateTexturePages(Vec<TexturePageDescriptor>),
|
AllocateTexturePages(Vec<TexturePageDescriptor>),
|
||||||
|
|
||||||
// Uploads data to a texture page.
|
// Uploads data to a texture page.
|
||||||
UploadTexelData { page: TexturePageId, texels: Vec<ColorU>, rect: RectI },
|
UploadTexelData { texels: Vec<ColorU>, location: TextureLocation },
|
||||||
|
|
||||||
// Associates a render target with a texture page.
|
// Associates a render target with a texture page.
|
||||||
//
|
//
|
||||||
// TODO(pcwalton): Add a rect to this so we can render to subrects of a page.
|
// TODO(pcwalton): Add a rect to this so we can render to subrects of a page.
|
||||||
DeclareRenderTarget { render_target_id: RenderTargetId, texture_page_id: TexturePageId },
|
DeclareRenderTarget { id: RenderTargetId, location: TextureLocation },
|
||||||
|
|
||||||
// Adds fills to the queue.
|
// Adds fills to the queue.
|
||||||
AddFills(Vec<FillBatchPrimitive>),
|
AddFills(Vec<FillBatchPrimitive>),
|
||||||
|
@ -90,6 +90,12 @@ pub struct TexturePageDescriptor {
|
||||||
pub size: Vector2I,
|
pub size: Vector2I,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
|
pub struct TextureLocation {
|
||||||
|
pub page: TexturePageId,
|
||||||
|
pub rect: RectI,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct AlphaTileBatch {
|
pub struct AlphaTileBatch {
|
||||||
pub tiles: Vec<AlphaTile>,
|
pub tiles: Vec<AlphaTile>,
|
||||||
|
@ -214,14 +220,11 @@ impl Debug for RenderCommand {
|
||||||
RenderCommand::AllocateTexturePages(ref pages) => {
|
RenderCommand::AllocateTexturePages(ref pages) => {
|
||||||
write!(formatter, "AllocateTexturePages(x{})", pages.len())
|
write!(formatter, "AllocateTexturePages(x{})", pages.len())
|
||||||
}
|
}
|
||||||
RenderCommand::UploadTexelData { page, rect, .. } => {
|
RenderCommand::UploadTexelData { ref texels, location } => {
|
||||||
write!(formatter, "UploadTexelData({:?}, {:?})", page, rect)
|
write!(formatter, "UploadTexelData({:?}, {:?})", texels, location)
|
||||||
}
|
}
|
||||||
RenderCommand::DeclareRenderTarget { render_target_id, texture_page_id } => {
|
RenderCommand::DeclareRenderTarget { id, location } => {
|
||||||
write!(formatter,
|
write!(formatter, "DeclareRenderTarget({:?}, {:?})", id, location)
|
||||||
"DeclareRenderTarget({:?}, {:?})",
|
|
||||||
render_target_id,
|
|
||||||
texture_page_id)
|
|
||||||
}
|
}
|
||||||
RenderCommand::AddFills(ref fills) => write!(formatter, "AddFills(x{})", fills.len()),
|
RenderCommand::AddFills(ref fills) => write!(formatter, "AddFills(x{})", fills.len()),
|
||||||
RenderCommand::FlushFills => write!(formatter, "FlushFills"),
|
RenderCommand::FlushFills => write!(formatter, "FlushFills"),
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use crate::allocator::{AllocationMode, TextureAllocator, TextureLocation};
|
use crate::allocator::{AllocationMode, TextureAllocator};
|
||||||
use crate::gpu_data::{RenderCommand, TexturePageDescriptor, TexturePageId};
|
use crate::gpu_data::{RenderCommand, TextureLocation, TexturePageDescriptor, TexturePageId};
|
||||||
use crate::scene::RenderTarget;
|
use crate::scene::RenderTarget;
|
||||||
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
@ -24,7 +24,6 @@ use pathfinder_geometry::vector::{Vector2F, Vector2I};
|
||||||
use pathfinder_gpu::TextureSamplingFlags;
|
use pathfinder_gpu::TextureSamplingFlags;
|
||||||
use pathfinder_simd::default::{F32x2, F32x4};
|
use pathfinder_simd::default::{F32x2, F32x4};
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
use std::mem;
|
|
||||||
|
|
||||||
// The size of a gradient tile.
|
// The size of a gradient tile.
|
||||||
//
|
//
|
||||||
|
@ -199,10 +198,8 @@ impl Palette {
|
||||||
|
|
||||||
// Assign render target locations.
|
// Assign render target locations.
|
||||||
let mut render_target_locations = vec![];
|
let mut render_target_locations = vec![];
|
||||||
for (render_target_index, render_target) in self.render_targets.iter().enumerate() {
|
for render_target in &self.render_targets {
|
||||||
let render_target_id = RenderTargetId(render_target_index as u32);
|
render_target_locations.push(allocator.allocate_image(render_target.size()));
|
||||||
render_target_locations.push(allocator.allocate_render_target(render_target.size(),
|
|
||||||
render_target_id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign paint locations.
|
// Assign paint locations.
|
||||||
|
@ -313,18 +310,9 @@ impl Palette {
|
||||||
// Allocate the texels.
|
// Allocate the texels.
|
||||||
//
|
//
|
||||||
// TODO(pcwalton): This is slow. Do more on GPU.
|
// TODO(pcwalton): This is slow. Do more on GPU.
|
||||||
let mut page_texels = vec![];
|
let mut page_texels: Vec<_> = metadata.iter().map(|metadata| {
|
||||||
for page_index in 0..allocator.page_count() {
|
Texels::new(allocator.page_size(metadata.texture_page))
|
||||||
let page_id = TexturePageId(page_index);
|
}).collect();
|
||||||
let page_size = allocator.page_size(page_id);
|
|
||||||
match allocator.page_render_target_id(page_id) {
|
|
||||||
Some(_) => page_texels.push(vec![]),
|
|
||||||
None => {
|
|
||||||
let page_area = page_size.x() as usize * page_size.y() as usize;
|
|
||||||
page_texels.push(vec![ColorU::default(); page_area]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw to texels.
|
// Draw to texels.
|
||||||
//
|
//
|
||||||
|
@ -332,26 +320,22 @@ impl Palette {
|
||||||
for (paint, metadata) in self.paints.iter().zip(metadata.iter()) {
|
for (paint, metadata) in self.paints.iter().zip(metadata.iter()) {
|
||||||
let texture_page = metadata.texture_page;
|
let texture_page = metadata.texture_page;
|
||||||
let texels = &mut page_texels[texture_page.0 as usize];
|
let texels = &mut page_texels[texture_page.0 as usize];
|
||||||
let page_size = allocator.page_size(texture_page);
|
|
||||||
let page_scale = allocator.page_scale(texture_page);
|
|
||||||
|
|
||||||
match paint {
|
match paint {
|
||||||
Paint::Color(color) => {
|
Paint::Color(color) => {
|
||||||
put_pixel(metadata.texture_rect.origin(), *color, texels, page_size);
|
texels.put_texel(metadata.texture_rect.origin(), *color);
|
||||||
}
|
}
|
||||||
Paint::Gradient(ref gradient) => {
|
Paint::Gradient(ref gradient) => {
|
||||||
self.render_gradient(gradient,
|
self.render_gradient(gradient,
|
||||||
metadata.texture_rect,
|
metadata.texture_rect,
|
||||||
&metadata.texture_transform,
|
&metadata.texture_transform,
|
||||||
texels,
|
texels);
|
||||||
page_size,
|
|
||||||
page_scale);
|
|
||||||
}
|
}
|
||||||
Paint::Pattern(ref pattern) => {
|
Paint::Pattern(ref pattern) => {
|
||||||
match pattern.source {
|
match pattern.source {
|
||||||
PatternSource::RenderTarget(_) => {}
|
PatternSource::RenderTarget(_) => {}
|
||||||
PatternSource::Image(ref image) => {
|
PatternSource::Image(ref image) => {
|
||||||
self.render_image(image, metadata.texture_rect, texels, page_size);
|
self.render_image(image, metadata.texture_rect, texels);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -362,25 +346,21 @@ impl Palette {
|
||||||
let mut render_commands = vec![
|
let mut render_commands = vec![
|
||||||
RenderCommand::AllocateTexturePages(texture_page_descriptors)
|
RenderCommand::AllocateTexturePages(texture_page_descriptors)
|
||||||
];
|
];
|
||||||
for page_index in 0..allocator.page_count() {
|
for (index, location) in render_target_locations.into_iter().enumerate() {
|
||||||
let page_id = TexturePageId(page_index);
|
let id = RenderTargetId(index as u32);
|
||||||
|
render_commands.push(RenderCommand::DeclareRenderTarget { id, location });
|
||||||
|
}
|
||||||
|
for (page_index, texels) in page_texels.into_iter().enumerate() {
|
||||||
|
if let Some(texel_data) = texels.data {
|
||||||
|
let page_id = TexturePageId(page_index as u32);
|
||||||
let page_size = allocator.page_size(page_id);
|
let page_size = allocator.page_size(page_id);
|
||||||
match allocator.page_render_target_id(page_id) {
|
let rect = RectI::new(Vector2I::default(), page_size);
|
||||||
Some(render_target_id) => {
|
|
||||||
render_commands.push(RenderCommand::DeclareRenderTarget {
|
|
||||||
render_target_id,
|
|
||||||
texture_page_id: page_id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
render_commands.push(RenderCommand::UploadTexelData {
|
render_commands.push(RenderCommand::UploadTexelData {
|
||||||
page: page_id,
|
texels: texel_data,
|
||||||
texels: mem::replace(&mut page_texels[page_index as usize], vec![]),
|
location: TextureLocation { page: page_id, rect },
|
||||||
rect: RectI::new(Vector2I::default(), page_size),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
PaintInfo { render_commands, metadata }
|
PaintInfo { render_commands, metadata }
|
||||||
}
|
}
|
||||||
|
@ -390,9 +370,7 @@ impl Palette {
|
||||||
gradient: &Gradient,
|
gradient: &Gradient,
|
||||||
tex_rect: RectI,
|
tex_rect: RectI,
|
||||||
tex_transform: &Transform2F,
|
tex_transform: &Transform2F,
|
||||||
texels: &mut [ColorU],
|
texels: &mut Texels) {
|
||||||
tex_size: Vector2I,
|
|
||||||
tex_scale: Vector2F) {
|
|
||||||
match *gradient.geometry() {
|
match *gradient.geometry() {
|
||||||
GradientGeometry::Linear(gradient_line) => {
|
GradientGeometry::Linear(gradient_line) => {
|
||||||
// FIXME(pcwalton): Paint transparent if gradient line has zero size, per spec.
|
// FIXME(pcwalton): Paint transparent if gradient line has zero size, per spec.
|
||||||
|
@ -404,12 +382,13 @@ impl Palette {
|
||||||
for y in 0..(GRADIENT_TILE_LENGTH as i32) {
|
for y in 0..(GRADIENT_TILE_LENGTH as i32) {
|
||||||
for x in 0..(GRADIENT_TILE_LENGTH as i32) {
|
for x in 0..(GRADIENT_TILE_LENGTH as i32) {
|
||||||
let point = tex_rect.origin() + Vector2I::new(x, y);
|
let point = tex_rect.origin() + Vector2I::new(x, y);
|
||||||
let vector = point.to_f32().scale_xy(tex_scale) - gradient_line.from();
|
let vector = point.to_f32().scale_xy(texels.scale()) -
|
||||||
|
gradient_line.from();
|
||||||
|
|
||||||
let mut t = gradient_line.vector().projection_coefficient(vector);
|
let mut t = gradient_line.vector().projection_coefficient(vector);
|
||||||
t = util::clamp(t, 0.0, 1.0);
|
t = util::clamp(t, 0.0, 1.0);
|
||||||
|
|
||||||
put_pixel(point, gradient.sample(t), texels, tex_size);
|
texels.put_texel(point, gradient.sample(t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -530,27 +509,20 @@ impl Palette {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
put_pixel(point, color, texels, tex_size);
|
texels.put_texel(point, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_image(&self,
|
fn render_image(&self, image: &Image, tex_rect: RectI, texels: &mut Texels) {
|
||||||
image: &Image,
|
|
||||||
tex_rect: RectI,
|
|
||||||
texels: &mut [ColorU],
|
|
||||||
tex_size: Vector2I) {
|
|
||||||
let image_size = image.size();
|
let image_size = image.size();
|
||||||
for y in 0..image_size.y() {
|
for y in 0..image_size.y() {
|
||||||
let dest_origin = tex_rect.origin() + Vector2I::new(0, y);
|
let dest_origin = tex_rect.origin() + Vector2I::new(0, y);
|
||||||
let dest_start_index = paint_texel_index(dest_origin, tex_size);
|
|
||||||
let src_start_index = y as usize * image_size.x() as usize;
|
let src_start_index = y as usize * image_size.x() as usize;
|
||||||
let dest_end_index = dest_start_index + image_size.x() as usize;
|
|
||||||
let src_end_index = src_start_index + image_size.x() as usize;
|
let src_end_index = src_start_index + image_size.x() as usize;
|
||||||
texels[dest_start_index..dest_end_index].copy_from_slice(
|
texels.blit_scanline(dest_origin, &image.pixels()[src_start_index..src_end_index]);
|
||||||
&image.pixels()[src_start_index..src_end_index]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -565,12 +537,41 @@ impl PaintMetadata {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint_texel_index(position: Vector2I, tex_size: Vector2I) -> usize {
|
struct Texels {
|
||||||
position.y() as usize * tex_size.x() as usize + position.x() as usize
|
data: Option<Vec<ColorU>>,
|
||||||
|
size: Vector2I,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn put_pixel(position: Vector2I, color: ColorU, texels: &mut [ColorU], tex_size: Vector2I) {
|
impl Texels {
|
||||||
texels[paint_texel_index(position, tex_size)] = color
|
fn new(size: Vector2I) -> Texels {
|
||||||
|
Texels { data: None, size }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn texel_index(&self, position: Vector2I) -> usize {
|
||||||
|
position.y() as usize * self.size.x() as usize + position.x() as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
fn allocate_texels_if_necessary(&mut self) {
|
||||||
|
if self.data.is_none() {
|
||||||
|
let area = self.size.x() as usize * self.size.y() as usize;
|
||||||
|
self.data = Some(vec![ColorU::transparent_black(); area]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn blit_scanline(&mut self, dest_origin: Vector2I, src: &[ColorU]) {
|
||||||
|
self.allocate_texels_if_necessary();
|
||||||
|
let start_index = self.texel_index(dest_origin);
|
||||||
|
let end_index = start_index + src.len();
|
||||||
|
self.data.as_mut().unwrap()[start_index..end_index].copy_from_slice(src)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn put_texel(&mut self, position: Vector2I, color: ColorU) {
|
||||||
|
self.blit_scanline(position, &[color])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scale(&self) -> Vector2F {
|
||||||
|
Vector2F::splat(1.0) / self.size.to_f32()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rect_to_uv(rect: RectI, texture_scale: Vector2F) -> RectF {
|
fn rect_to_uv(rect: RectI, texture_scale: Vector2F) -> RectF {
|
||||||
|
|
Loading…
Reference in New Issue