1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
/*!
In order to draw, you need to provide a way for the video card to know how to link primitives
together.
There are eleven types of primitives, each one with a corresponding struct:
- `PointsList`
- `LinesList`
- `LinesListAdjacency`
- `LineStrip`
- `LineStripAdjacency`
- `TrianglesList`
- `TrianglesListAdjacency`
- `TriangleStrip`
- `TriangleStripAdjacency`
- `TriangleFan`
- `Patches`
There are two ways to specify the indices that must be used:
- Passing a reference to an `IndexBuffer`, which contains a list of indices.
- `NoIndices`, in which case the vertices will be used in the order in which they are in the
vertex buffer.
## Multidraw indirect
In addition to indices, you can also use **multidraw indirect** rendering.
The idea is to put a list of things to render in a buffer, and pass that buffer to OpenGL.
*/
use gl;
use ToGlEnum;
use CapabilitiesSource;
use version::Api;
use version::Version;
use std::mem;
use buffer::BufferAnySlice;
pub use self::buffer::{IndexBuffer, IndexBufferSlice, IndexBufferAny};
pub use self::buffer::CreationError as BufferCreationError;
pub use self::multidraw::{DrawCommandsNoIndicesBuffer, DrawCommandNoIndices};
pub use self::multidraw::{DrawCommandsIndicesBuffer, DrawCommandIndices};
mod buffer;
mod multidraw;
/// Describes a source of indices used for drawing.
#[derive(Clone)]
pub enum IndicesSource<'a> {
/// A buffer uploaded in video memory.
IndexBuffer {
/// The buffer.
buffer: BufferAnySlice<'a>,
/// Type of indices in the buffer.
data_type: IndexType,
/// Type of primitives contained in the vertex source.
primitives: PrimitiveType,
},
/// Use a multidraw indirect buffer without indices.
MultidrawArray {
/// The buffer.
buffer: BufferAnySlice<'a>,
/// Type of primitives contained in the vertex source.
primitives: PrimitiveType,
},
/// Use a multidraw indirect buffer with indices.
MultidrawElement {
/// The buffer of the commands.
commands: BufferAnySlice<'a>,
/// The buffer of the indices.
indices: BufferAnySlice<'a>,
/// Type of indices in the buffer.
data_type: IndexType,
/// Type of primitives contained in the vertex source.
primitives: PrimitiveType,
},
/// Don't use indices. Assemble primitives by using the order in which the vertices are in
/// the vertices source.
NoIndices {
/// Type of primitives contained in the vertex source.
primitives: PrimitiveType,
},
}
impl<'a> IndicesSource<'a> {
/// Returns the type of the primitives.
#[inline]
pub fn get_primitives_type(&self) -> PrimitiveType {
match self {
&IndicesSource::IndexBuffer { primitives, .. } => primitives,
&IndicesSource::MultidrawArray { primitives, .. } => primitives,
&IndicesSource::MultidrawElement { primitives, .. } => primitives,
&IndicesSource::NoIndices { primitives } => primitives,
}
}
}
/// List of available primitives.
///
/// See [this page for a visual representation of each primitive
/// type](https://msdn.microsoft.com/en-us/library/windows/desktop/bb205124%28v=vs.85%29.aspx).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PrimitiveType {
/// Each vertex is an individual point.
Points,
/// Vertices are grouped by chunks of two vertices. Each chunk represents a line.
LinesList,
/// Vertices are grouped by chunks of four vertices. The second and third vertices of each
/// chunk represents the line.
///
/// Adjacency information doesn't do anything per-se, but is passed to the geometry shader if
/// there is any.
/// The first vertex represents the vertex adjacent to the second vertex. The fourth vertex
/// represents the vertex adjacent to the third vertex.
LinesListAdjacency,
/// Each vertex (except the last one) forms a line with the next vertex.
///
/// For example vertices 0 and 1 form a line, vertices 1 and 2 form a line, vertices 2 and 3
/// form a line, etc.
LineStrip,
/// Similar to `LineStrip`, but with an additional vertex at the beginning and at the end
/// that represent the vertices adjacent to the first and last ones.
///
/// Adjacency information doesn't do anything per-se, but is passed to the geometry shader if
/// there is any.
LineStripAdjacency,
/// Each vertex forms a line with the next vertex. The last vertex form a line with the first
/// one.
LineLoop,
/// Vertices are grouped by chunks of three vertices. Each chunk represents a triangle.
///
/// The order of the vertices is important, as it determines whether the triangle will be
/// clockwise or counter-clockwise. See `BackfaceCulling` for more infos.
TrianglesList,
/// Vertices are grouped by chunks of six vertices. The first, third and fifth vertices
/// represent a triangle.
///
/// The order of the vertices is important, as it determines whether the triangle will be
/// clockwise or counter-clockwise. See `BackfaceCulling` for more infos.
///
/// Adjacency information doesn't do anything per-se, but is passed to the geometry shader if
/// there is any.
/// The second vertex represents the vertex adjacent to the first and third vertices. The
/// fourth vertex represents the vertex adjacent to the third and fifth vertices. The sixth
/// vertex represents the vertex adjacent to the first and fifth vertices.
TrianglesListAdjacency,
/// Each vertex (except the first one and the last one) forms a triangle with the previous
/// and the next vertices.
///
/// For example vertices `0, 1, 2` form a triangle, `1, 2, 3` form a triangle, `2, 3, 4` form a
/// triangle, `3, 4, 5` form a triangle, etc.
///
/// Each uneven triangle is reversed so that all triangles are facing the same
/// direction.
TriangleStrip,
/// Each even vertex forms a triangle with vertices `n+2` and `n+4`.
///
/// Each uneven vertex is adjacent to the previous and next ones.
/// Adjacency information doesn't do anything per-se, but is passed to the geometry shader if
/// there is any.
TriangleStripAdjacency,
/// Starting at the second vertex, each vertex forms a triangle with the next and the first
/// vertices.
///
/// For example vertices `0, 1, 2` form a triangle, `0, 2, 3` form a triangle, `0, 3, 4` form a
/// triangle, `0, 4, 5` form a triangle, etc.
TriangleFan,
/// Vertices are grouped by chunks of `vertices_per_patch` vertices.
///
/// This primitives type can only be used in conjunction with a tessellation shader. The
/// tessellation shader will indicate how each patch will be divided into lines or triangles.
Patches {
/// Number of vertices per patch.
vertices_per_patch: u16,
},
}
impl PrimitiveType {
/// Returns true if the backend supports this type of primitives.
pub fn is_supported<C: ?Sized>(&self, caps: &C) -> bool where C: CapabilitiesSource {
match self {
&PrimitiveType::Points | &PrimitiveType::LinesList | &PrimitiveType::LineStrip |
&PrimitiveType::LineLoop | &PrimitiveType::TrianglesList |
&PrimitiveType::TriangleStrip | &PrimitiveType::TriangleFan => true,
&PrimitiveType::LinesListAdjacency | &PrimitiveType::LineStripAdjacency |
&PrimitiveType::TrianglesListAdjacency | &PrimitiveType::TriangleStripAdjacency => {
caps.get_version() >= &Version(Api::Gl, 3, 0) ||
caps.get_extensions().gl_arb_geometry_shader4 ||
caps.get_extensions().gl_ext_geometry_shader4 ||
caps.get_extensions().gl_ext_geometry_shader
},
&PrimitiveType::Patches { .. } => {
caps.get_version() >= &Version(Api::Gl, 4, 0) ||
caps.get_extensions().gl_arb_tessellation_shader
},
}
}
}
impl ToGlEnum for PrimitiveType {
#[inline]
fn to_glenum(&self) -> gl::types::GLenum {
match self {
&PrimitiveType::Points => gl::POINTS,
&PrimitiveType::LinesList => gl::LINES,
&PrimitiveType::LinesListAdjacency => gl::LINES_ADJACENCY,
&PrimitiveType::LineStrip => gl::LINE_STRIP,
&PrimitiveType::LineStripAdjacency => gl::LINE_STRIP_ADJACENCY,
&PrimitiveType::LineLoop => gl::LINE_LOOP,
&PrimitiveType::TrianglesList => gl::TRIANGLES,
&PrimitiveType::TrianglesListAdjacency => gl::TRIANGLES_ADJACENCY,
&PrimitiveType::TriangleStrip => gl::TRIANGLE_STRIP,
&PrimitiveType::TriangleStripAdjacency => gl::TRIANGLE_STRIP_ADJACENCY,
&PrimitiveType::TriangleFan => gl::TRIANGLE_FAN,
&PrimitiveType::Patches { .. } => gl::PATCHES,
}
}
}
/// Marker that can be used as an indices source when you don't need indices.
///
/// If you use this, then the primitives will be constructed using the order in which the
/// vertices are in the vertices sources.
#[derive(Copy, Clone, Debug)]
pub struct NoIndices(pub PrimitiveType);
impl<'a> From<NoIndices> for IndicesSource<'a> {
#[inline]
fn from(marker: NoIndices) -> IndicesSource<'a> {
IndicesSource::NoIndices {
primitives: marker.0
}
}
}
impl<'a, 'b> From<&'b NoIndices> for IndicesSource<'a> {
#[inline]
fn from(marker: &'b NoIndices) -> IndicesSource<'a> {
IndicesSource::NoIndices {
primitives: marker.0
}
}
}
/// Type of the indices in an index source.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)] // GLenum
pub enum IndexType {
/// u8
U8 = gl::UNSIGNED_BYTE,
/// u16
U16 = gl::UNSIGNED_SHORT,
/// u32
U32 = gl::UNSIGNED_INT,
}
impl IndexType {
/// Returns the size in bytes of each index of this type.
#[inline]
pub fn get_size(&self) -> usize {
match *self {
IndexType::U8 => mem::size_of::<u8>(),
IndexType::U16 => mem::size_of::<u16>(),
IndexType::U32 => mem::size_of::<u32>(),
}
}
/// Returns true if the backend supports this type of index.
#[inline]
pub fn is_supported<C: ?Sized>(&self, caps: &C) -> bool where C: CapabilitiesSource {
match self {
&IndexType::U8 => true,
&IndexType::U16 => true,
&IndexType::U32 => {
caps.get_version() >= &Version(Api::Gl, 1, 0) ||
caps.get_version() >= &Version(Api::GlEs, 3, 0) ||
caps.get_extensions().gl_oes_element_index_uint
},
}
}
}
impl ToGlEnum for IndexType {
#[inline]
fn to_glenum(&self) -> gl::types::GLenum {
*self as gl::types::GLenum
}
}
/// An index from the index buffer.
pub unsafe trait Index: Copy + Send + 'static {
/// Returns the `IndexType` corresponding to this type.
fn get_type() -> IndexType;
/// Returns true if this type of index is supported by the backend.
fn is_supported<C: ?Sized>(caps: &C) -> bool where C: CapabilitiesSource {
Self::get_type().is_supported(caps)
}
}
unsafe impl Index for u8 {
#[inline]
fn get_type() -> IndexType {
IndexType::U8
}
}
unsafe impl Index for u16 {
#[inline]
fn get_type() -> IndexType {
IndexType::U16
}
}
unsafe impl Index for u32 {
#[inline]
fn get_type() -> IndexType {
IndexType::U32
}
}