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);