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
    }
}