[go: up one dir, main page]

gfx/
slice.rs

1// Copyright 2014 The Gfx-rs Developers.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Slices
16//!
17//! See `Slice`-structure documentation for more information on this module.
18
19use core::{handle, buffer};
20use core::{Primitive, Resources, VertexCount};
21use core::command::InstanceParams;
22use core::factory::Factory;
23use core::memory::Bind;
24use format::Format;
25use pso;
26
27/// A `Slice` dictates in which and in what order vertices get processed. It is required for
28/// processing a PSO.
29///
30/// # Overview
31/// A `Slice` in gfx has a different meaning from the term slice as employed more broadly in rust (`&[T]`).
32///
33/// A `Slice` object in essence dictates in what order the vertices in a `VertexBuffer` get
34/// processed. To do this, it contains an internal index-buffer. This `Buffer` is a list of
35/// indices into this `VertexBuffer` (vertex-index). A vertex-index of 0 represents the first
36/// vertex in the `VertexBuffer`, a vertex-index of 1 represents the second, 2 represents the
37/// third, and so on. The vertex-indices in the index-buffer are read in order; every vertex-index
38/// tells the pipeline which vertex to process next.
39///
40/// Because the same index can re-appear multiple times, duplicate-vertices can be avoided. For
41/// instance, if you want to draw a square, you need two triangles, and thus six vertices. Because
42/// the same index can reappear multiple times, this means we can instead use 4 vertices, and 6
43/// vertex-indices.
44///
45/// This index-buffer has a few variants. See the `IndexBuffer` documentation for a detailed
46/// description.
47///
48/// The `start` and `end` fields say where in the index-buffer to start and stop reading.
49/// Setting `start` to 0, and `end` to the length of the index-buffer, will cause the entire
50/// index-buffer to be processed. The `base_vertex` dictates the index of the first vertex
51/// in the `VertexBuffer`. This essentially moves the the start of the `VertexBuffer`, to the
52/// vertex with this index.
53///
54/// # Constuction & Handling
55/// The `Slice` structure can be constructed automatically when using a `Factory` to create a
56/// vertex buffer. If needed, it can also be created manually.
57///
58/// A `Slice` is required to process a PSO, as it contains the needed information on in what order
59/// to draw which vertices. As such, every `draw` call on an `Encoder` requires a `Slice`.
60#[derive(Clone, Debug, Eq, Hash, PartialEq)]
61pub struct Slice<R: Resources> {
62    /// The start index of the index-buffer. Processing will start at this location in the
63    /// index-buffer.
64    pub start: VertexCount,
65    /// The end index in the index-buffer. Processing will stop at this location (exclusive) in
66    /// the index buffer.
67    pub end: VertexCount,
68    /// This is the index of the first vertex in the `VertexBuffer`. This value will be added to
69    /// every index in the index-buffer, effectively moving the start of the `VertexBuffer` to this
70    /// base-vertex.
71    pub base_vertex: VertexCount,
72    /// Instancing configuration.
73    pub instances: Option<InstanceParams>,
74    /// Represents the type of index-buffer used.
75    pub buffer: IndexBuffer<R>,
76}
77
78impl<R: Resources> Slice<R> {
79    /// Creates a new `Slice` with a given vertex count.
80    pub fn from_vertex_count(count: VertexCount) -> Self {
81        Slice {
82            start: 0,
83            end: count,
84            base_vertex: 0,
85            instances: None,
86            buffer: IndexBuffer::Auto,
87        }
88    }
89    /// Creates a new `Slice` to match the supplied vertex buffer, from start to end, in order.
90    pub fn new_match_vertex_buffer<V>(vbuf: &handle::Buffer<R, V>) -> Self
91                                      where V: pso::buffer::Structure<Format> {
92        Slice {
93            start: 0,
94            end: vbuf.len() as u32,
95            base_vertex: 0,
96            instances: None,
97            buffer: IndexBuffer::Auto,
98        }
99    }
100
101    /// Calculates the number of primitives of the specified type in this `Slice`.
102    pub fn get_prim_count(&self, prim: Primitive) -> u32 {
103        use core::Primitive as p;
104        let nv = (self.end - self.start) as u32;
105        match prim {
106            p::PointList => nv,
107            p::LineList => nv / 2,
108            p::LineStrip => (nv-1),
109            p::TriangleList => nv / 3,
110            p::TriangleStrip => (nv-2) / 3,
111            p::LineListAdjacency => nv / 4,
112            p::LineStripAdjacency => (nv-3),
113            p::TriangleListAdjacency => nv / 6,
114            p::TriangleStripAdjacency => (nv-4) / 2,
115            p::PatchList(num) => nv / (num as u32),
116        }
117    }
118
119    /// Divides one slice into two at an index.
120    ///
121    /// The first will contain the range in the index-buffer [self.start, mid) (excluding the index mid itself) and the
122    /// second will contain the range [mid, self.end).
123    pub fn split_at(&self, mid: VertexCount) -> (Self, Self) {
124        let mut first = self.clone();
125        let mut second = self.clone();
126        first.end = mid;
127        second.start = mid;
128
129        (first, second)
130    }
131}
132
133/// Type of index-buffer used in a Slice.
134///
135/// The `Auto` variant represents a hypothetical index-buffer from 0 to infinity. In other words,
136/// all vertices get processed in order. Do note that the `Slice`'s `start` and `end` restrictions
137/// still apply for this variant. To render every vertex in the `VertexBuffer`, you would set
138/// `start` to 0, and `end` to the `VertexBuffer`'s length.
139///
140/// The `Index*` variants represent an actual `Buffer` with a list of vertex-indices. The numeric
141/// suffix specifies the amount of bits to use per index. Each of these also contains a
142/// base-vertex. This is the index of the first vertex in the `VertexBuffer`. This value will be
143/// added to every index in the index-buffer, effectively moving the start of the `VertexBuffer` to
144/// this base-vertex.
145///
146/// # Construction & Handling
147/// A `IndexBuffer` can be constructed using the `IntoIndexBuffer` trait, from either a slice or a
148/// `Buffer` of integers, using a factory.
149///
150/// An `IndexBuffer` is exclusively used to create `Slice`s.
151#[derive(Clone, Debug, Eq, Hash, PartialEq)]
152pub enum IndexBuffer<R: Resources> {
153    /// Represents a hypothetical index-buffer from 0 to infinity. In other words, all vertices
154    /// get processed in order.
155    Auto,
156    /// An index-buffer with unsigned 16 bit indices.
157    Index16(handle::Buffer<R, u16>),
158    /// An index-buffer with unsigned 32 bit indices.
159    Index32(handle::Buffer<R, u32>),
160}
161
162impl<R: Resources> Default for IndexBuffer<R> {
163    fn default() -> Self {
164        IndexBuffer::Auto
165    }
166}
167/// A helper trait to create `IndexBuffers` from different kinds of data.
168pub trait IntoIndexBuffer<R: Resources> {
169    /// Turns self into an `IndexBuffer`.
170    fn into_index_buffer<F: Factory<R> + ?Sized>(self, factory: &mut F) -> IndexBuffer<R>;
171}
172
173impl<R: Resources> IntoIndexBuffer<R> for IndexBuffer<R> {
174    fn into_index_buffer<F: Factory<R> + ?Sized>(self, _: &mut F) -> IndexBuffer<R> {
175        self
176    }
177}
178
179impl<R: Resources> IntoIndexBuffer<R> for () {
180    fn into_index_buffer<F: Factory<R> + ?Sized>(self, _: &mut F) -> IndexBuffer<R> {
181        IndexBuffer::Auto
182    }
183}
184
185macro_rules! impl_index_buffer {
186    ($prim_ty:ty, $buf_ty:ident) => (
187        impl<R: Resources> IntoIndexBuffer<R> for handle::Buffer<R, $prim_ty> {
188            fn into_index_buffer<F: Factory<R> + ?Sized>(self, _: &mut F) -> IndexBuffer<R> {
189                IndexBuffer::$buf_ty(self)
190            }
191        }
192
193        impl<'s, R: Resources> IntoIndexBuffer<R> for &'s [$prim_ty] {
194            fn into_index_buffer<F: Factory<R> + ?Sized>(self, factory: &mut F) -> IndexBuffer<R> {
195                factory.create_buffer_immutable(self, buffer::Role::Index, Bind::empty())
196                       .unwrap()
197                       .into_index_buffer(factory)
198            }
199        }
200    )
201}
202
203impl_index_buffer!(u16, Index16);
204impl_index_buffer!(u32, Index32);