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
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
//! # What is this?
//!
//! [![crates.io](https://img.shields.io/crates/v/luminance.svg)](https://crates.io/crates/luminance)
//! ![License](https://img.shields.io/badge/license-BSD3-blue.svg?style=flat)
//!
//! [luminance] is an effort to make graphics rendering simple and elegant.
//!
//! The aims of [luminance] are:
//!
//!   - Bringing a **safe**, **type-safe** and **stateless** API to the Rust graphics ecosystem.
//!   - Providing a simple and easy interface; that is, exposing core concepts without anything
//!     extra – just the bare stuff. This is not a 3D or a video game engine. It’s a set of building
//!     blocks and graphics primitives you can use to construct more specific abstractions,
//!     libraries and applications.
//!   - To be opinionated enough to allow safety and optimizations but not to force the user into a
//!     too strict design: this is not a framework. Some constructs are restricting by design but
//!     the overall crate tries to adapt to what the user wants to do, not the over way around.
//!   - Easy to read with a good documentation and set of tutorials, so that newcomers don’t have to
//!     learn a lot of new concepts to get their feet wet. For most primitive concepts, they must
//!     be explained and detailed in their corresponding sections / modules.
//!   - Need-driven: every piece of code added in the project must come from a real use case. If you
//!     feel something is missing, feel free to open an issue or even contribute! Issue trackers
//!     exist for bug tracking but also for feature requests.
//!   - The [gfx-hal] crate is already a good crate, so [luminance] must stand out by providing an
//!     easier crate for people who just want to write some graphics code without having to cope
//!     with _too low-level_ details. The crate is low-level but not as much as [gfx-hal], though.
//!     The goal is to be _performant enough_ and still have an elegant and easy interface.
//!
//! An important point before starting: some people ask about how to _easily render something_.
//! [luminance] is flexible enough to allow people to do rendering as they want and, thus, doesn’t
//! include default shaders or such. So if you are looking for something that has already
//! _everything_ embedded, you’re not looking at the right crate.
//!
//! [luminance] is shipped with almost no _data_ — i.e. no default shader, tessellations, etc. You
//! can probably find crates adding those, though. ;)
//!
//! # What’s included?
//!
//! [luminance] is a rendering crate, not a 3D engine nor a video game framework. As so, it doesn’t
//! include specific concepts, such as lights, materials, asset management nor scene description. It
//! only provides a rendering library you can plug in whatever you want to.
//!
//!   > There are several so-called 3D-engines out there on [crates.io](https://crates.io). Feel
//!   > free to have a look around.
//!
//! However, [luminance] comes in with several interesting features that might interest you.
//!
//! ## Features set
//!
//!   - **Buffers**: buffers are ways to communicate with the GPU; they represent regions of memory
//!     you can write to and read from. There’re several kinds of buffers you can create, among
//!     *vertex and index buffers*, *uniform buffers*, and so on and so forth…. They look like
//!     regular array but have some differences you might be aware of.
//!   - **Framebuffers**: framebuffers are used to hold renders. Each time you want to perform a
//!     render, you need to perform it into a framebuffer. Framebuffers can then be combined with
//!     each other to produce effects and design render layers.
//!   - **Shaders**: [luminance] supports five kinds of shader stages:
//!       - Tessellation control shaders.
//!       - Tessellation evaluation shaders.
//!       - Vertex shaders.
//!       - Geometry shaders.
//!       - Fragment shaders.
//!   - **Vertices, indices, primitives and tessellations**: those are used to define a shape you
//!     can render into a framebuffer with a shader.
//!   - **Textures**: textures represent information packed into arrays on the GPU, and can be used
//!     to customize a visual aspect or pass information around in shaders.
//!   - **Blending**: blending is the process of taking two colors from two framebuffers and mixing
//!     them between each other.
//!   - **Control on the render state**: the render state is a set of capabilities you can tweak
//!     to draw frames. It includes:
//!       - The blending equation and factors.
//!       - Whether we should have a depth test performed.
//!       - Face culling.
//!   - And a lot of other cool things like *GPU commands*, *pipelines*, *uniform interfaces* and so on…
//!
//! # How to dig in?
//!
//! [luminance] is written to be fairly simple. The documentation is very transparent about what the
//! library does and several articles will appear as the development goes on. Keep tuned! The
//! [online documentation](https://docs.rs/luminance) is also a good link to have around.
//!
//! # Current implementation
//!
//! Currently, **luminance is powered by OpenGL 3.3**: it’s the default. That version of OpenGL is
//! old enough to support a wide range of devices out there. However, it’s possible that your device
//! is older or that you target the Web or Android / iOS. In that case, you should have a look at
//! the set of feature flags, which offers the possibility to compile [luminance] on several
//! platforms.
//!
//! ## Feature flags
//!
//!   - `default = ["std"]`
//!   - `std`: Compile against the standard library. If you disable that feature, you get a tinier
//!     executable but you’re responsible for lots of stuff. **Currently, that feature is not well
//!     tested and very experimental; use with care and caution and please provide feedback on
//!     the issue tracker if you try it out!**
//!
//! # Windowing
//!
//! [luminance] does not provide a way to create windows because it’s important that it not depend
//! on windowing libraries – so that end-users can use whatever they like. Furthermore, such
//! libraries typically implement windowing and events features, which have nothing to do with our
//! initial purpose.
//!
//! Nevertheless, an ecosystem effort exists towards [luminance]: [luminance-windowing]. That
//! crate provides a windowing API that is implemented by other crates, such as [luminance-glfw].
//! You don’t have to use them, though. If you’re interested into how you should setup windowing for
//! [luminance] to work, this very documentation explains it in the [`GraphicsContext`] section.
//!
//! # User-guide and contributor-guide
//!
//! If you just plan to use [luminance], just read the *User-guide* section.
//!
//! If you plan to contribute to [luminance] (by writing a windowing crate or hacking on [luminance]
//! directly), feel free to read the *Contributor-guide* section after having read the *User-guide*
//! section as well.
//!
//! ## User-guide
//!
//! ### Creating a context
//!
//! In order to get started, you need to create an object which type implements [`GraphicsContext`].
//! [luminance] ships with the trait but no implementor. You need to head over
//! [crates.io and search for luminance crates](https://crates.io/search?q=luminance) to find a
//! windowing backend first.
//!
//! Such a backend should expose a type which implements [`GraphicsContext`]. You can create one per
//! thread. That limitation enables [luminance] not to perform plenty of runtime branching,
//! minimizing the runtime overhead.
//!
//! > If you really want several contexts, you will need several OS threads.
//!
//! [`GraphicsContext`] is the entry-point of everything [luminance] provides. Feel free to dig in
//! its documentation for further information on how to use [luminance]. Most objects you can
//! create will need a mutable reference to such a context object. Even though [luminance] is
//! stateless in terms of global state, it still requires to have an object representing the GPU
//! somehow.
//!
//! ### Understanding the pipeline architecture
//!
//! [luminance] has a very particular way of doing graphics. It represents a typical _graphics
//! pipeline_ via a typed [AST] that is embedded into your code. As you might already know, when you
//! write code, you’re actually creating an [AST]: expressions, assignments, bindings, conditions,
//! function calls, etc. They all represent a typed tree that represents your program.
//!
//! [luminance] uses that property to create a dependency between resources your GPU needs to
//! have in order to perform a render. Typical engines, libraries and frameworks require you to
//! explicitly _bind_ something; instead, [luminance] requires you to go deeper in the [AST] by
//! creating a new lower node to mark the dependency.
//!
//! It might be weird at first but you’ll see how simple and easy it is. If you want to perform a
//! simple draw call of a triangle, you need several resources:
//!
//!   - A [`Tess`] that represents the triangle. It holds three vertices.
//!   - A shader [`Program`], for shading the triangle with a constant color, for short and simple.
//!   - A [`Framebuffer`], to accept and hold the actual render.
//!   - A [`RenderState`], to state how the render should be performed.
//!
//! There is a dependency _graph_ to represent how the resources must behave regarding each other:
//!
//! ```text
//! (AST1)
//!
//! Framebuffer ─> Shader ─> RenderState ─> Tess
//! ```
//!
//! The framebuffer must be _active_, _bound_, _used_ — or whatever verb you want to picture it
//! with — before the shader can start doing things. The shader must also be in use before we can
//! actually render the tessellation.
//!
//! That triple dependency relationship is already a small flat [AST]. Imagine we want to render
//! a second triangle with the same render state and a third triangle with a different render state:
//!
//! ```text
//! (AST2)
//!
//! Framebuffer ─> Shader ─> RenderState ─> Tess
//!                  │            │
//!                  │            └───────> Tess
//!                  │
//!                  └─────> RenderState ─> Tess
//! ```
//!
//! That [AST] looks more complex. Imagine now that we want to shade one other triangle with
//! another shader!
//!
//! ```text
//! (AST3)
//!
//! Framebuffer ─> Shader ─> RenderState ─> Tess
//!      │           │            │
//!      │           │            └───────> Tess
//!      │           │
//!      │           └─────> RenderState ─> Tess
//!      │
//!      └───────> Shader ─> RenderState ─> Tess
//! ```
//!
//! You can now clearly see the [AST]s and the relationships between objects. Those are encoded
//! in [luminance] within your code directly: lambdas / closures.
//!
//! > If you have followed thoroughly, you might have noticed that you cannot, with such [AST]s,
//! > shade a triangle with another shader but using the same render state as another node. That
//! > was a decision that was needed to be made: how should we allow the [AST] to be shared?
//! > In terms of graphics pipeline, [luminance] tries to do the best thing to minimize the number
//! > of GPU context switches and CPU <=> GPU bandwidth congestion.
//!
//! ### The lambda & closure design
//!
//! A function is a perfect candidate to modelize a dependency. When you look at:
//!
//! ```ignore
//! fn tronfibulate(x: Foo) -> Bar;
//! ```
//!
//! `tronfibulate` here is _covariant_ in `Bar` and _contravariant_ in `Foo`. What it implies is
//! that for the function itself, if we have a function that does `Zoo -> Foo`, then we can create
//! a new version of `tronfibulate` that will have, as input, a `Zoo`. Contravariance maps backwards
//! while covariance maps forwards (i.e. if you have `Bar -> Quux`, you can adapt `tronfibulate` to
//! create a new function that will output `Quux` value).
//!
//! All this to say that a dependency (which is contravariant) is pretty interesting in our case
//! since we will be able to adapt and create new functions just by contra-mapping the input. In
//! terms of combinational power, that is gold.
//!
//! Now, let’s try to represent `AST1` with contravariance and, hence, functions, using pseudo-code
//! (this is not real [luminance] excerpt).
//!
//! ```ignore
//! // AST1
//! use_framebuffer(framebuffer, || {
//!   // here, we are passing a closure that will get called whenever the framebuffer is ready to
//!   // receive renders
//!   use_shader(shader, || {
//!     // same thing but for shader
//!     use_render_state(render_state, || {
//!       // ditto for render state
//!       triangle.render(); // render the tessellation
//!     });
//!   );
//! );
//! ```
//!
//! See how simple it is to represent `AST1` with just code and closures? Rust’s lifetimes and
//! existential quantification allows us to ensure that no resource will leave the scope of each
//! closures, hence enforcing memory and coherency safety.
//!
//! Now let’s try to tackle `AST2`.
//!
//! ```ignore
//! // AST2
//! use_framebuffer(framebuffer, || {
//!   use_shader(shader, || {
//!     use_render_state(render_state, || {
//!       first_triangle.render();
//!       second_triangle.render(); // simple and straight-forward
//!     });
//!
//!     // we can just branch a new render state here!
//!     use_render_state(other_render_state, || {
//!       third.render()
//!     });
//!   );
//! );
//! ```
//!
//! And `AST3`:
//!
//! ```ignore
//! // AST3
//! use_framebuffer(framebuffer, || {
//!   use_shader(shader, || {
//!     use_render_state(render_state, || {
//!       first_triangle.render();
//!       second_triangle.render(); // simple and straight-forward
//!     });
//!
//!     // we can just branch a new render state here!
//!     use_render_state(other_render_state, || {
//!       third.render()
//!     });
//!   );
//!
//!   use_shader(other_shader, || {
//!     use_render_state(yet_another_render_state, || {
//!       other_triangle.render();
//!     });
//!   });
//! );
//! ```
//!
//! The [luminance] equivalent is a bit more complex because it implies some objects that need
//! to be introduced first.
//!
//! ### [`Pipeline`]
//!
//! A [`Pipeline`] represents a whole [AST] as seen as just above. It is created by a
//! [`GraphicsContext`] when you ask to create a pipeline and is destroyed as soon as the render has
//! happened. A [`Pipeline`] is a special object you can use to bind some specific scarce resources,
//! such as _textures_ and _buffers_.
//!
//! Creating a [`Pipeline`] requires at least one resource: a [`Framebuffer`] to render to.
//!
//! When you create a pipeline, you’re also handed a [`ShadingGate`]. A [`ShadingGate`] is an object
//! that allows you to create _shader_ nodes in the [AST] you’re building. You have no other way
//! to go deeper in the [AST]. The concept of _gates_ is very important and you should try to
//! familiarize yourself with it.
//!
//! ### [`ShadingGate`]
//!
//! As said above, a [`ShadingGate`] allows you to create a _shader node_ in the graphics pipeline.
//! That node will typically borrow a shader [`Program`] and will move you one level lower in the
//! graph ([AST]). At that level (i.e. in that closure), you are given two objects:
//!
//!   - A [`RenderGate`], discussed below.
//!   - A [`ProgramInterface`], which is parametered by the type of uniform your shader [`Program`]
//!     defines.
//!
//! The [`ProgramInterface`] is the only way for you to access your _uniform interface_. More on
//! this in the dedicated section. It also provides you with the [`ProgramInterface::query`]
//! method, that allows you to perform _dynamic uniform lookup_.
//!
//! ### [`RenderGate`]
//!
//! A [`RenderGate`] is the second to last gate you will be handling. It allows you to create
//! _render state_ nodes in your [AST], creating a new level for you to render tessellations with
//! an obvious, final gate: the [`TessGate`].
//!
//! The kind of object that node manipulates is [`RenderState`].
//!
//! ### [`TessGate`]
//!
//! The [`TessGate`] is the final gate you use in an [AST]. It’s used to create _tessellation
//! nodes_. Those are used to render actual [`Tess`]. You cannot go any deeper in the [AST] at that
//! stage.
//!
//! [`TessGate`]s don’t immediately use [`Tess`] as inputs. They use [`TessSlice`]. That type is
//! a simple GPU slice into a GPU tessellation ([`Tess`]). It can be obtained from a [`Tess`] via
//! the [`TessSliceIndex`] trait.
//!
//! ## Contributor-guide
//!
//! You want to hack around [luminance] or provide a windowing crate? Everything you have to know is
//! described in this section.
//!
//! ### What it means to be a luminance windowing backend
//!
//! [luminance] doesn’t know anything about the context it executes in. That means that it doesn’t
//! know whether it’s used within the SDL, GLFW, glutin, Qt or an embedded specific hardware such
//! as the Nintendo Switch. That is actually powerful, because it allows [luminance] to be
//! completely agnostic of the execution platform it’s running on: one problem less.
//!
//! However, the connection between [luminance] and the execution context must be correctly done.
//! Currently, several points must be enforced:
//!
//!   - The _OpenGL version_ must be **3.3**.
//!   - The _OpenGL profile_ must be **core**.
//!   - OpenGL _forward compatibility_ must be enabled.
//!
//! Those rules might change and be adapted regarding the _feature flags_ that are enabled. For
//! instance, if you use a feature flag that allows to use _OpenGL 2.1_, then you should use a
//! **2.1** _OpenGL version_.
//!
//! ### [`GraphicsContext`], [`GraphicsState`] and TLS
//!
//! In order to implement [`GraphicsContext`], you need to know several points:
//!
//!   - You can get a [`GraphicsState`] with the [`GraphicsState::new`] function. You **have** to match the return
//!     value. Depending on whether your implementation is the first asking a [`GraphicsState`] on the current
//!     thread, you might get (or not) an `Ok(state)`. If not, a descriptive error is returned.
//!   - You’re advised to `map` and `map_err` over the [`GraphicsState::new`] returned value to implement your
//!     own `new` function for your backend type because of the restriction of having only one context per
//!     thread in [luminance].
//!
//! [gfx-hal]: https://crates.io/crates/gfx-hal
//! [`GraphicsContext`]: crate::context::GraphicsContext
//! [`GraphicsState`]: crate::state::GraphicsState
//! [`GraphicsState::new`]: crate::state::GraphicsState::new
//! [`Tess`]: crate::tess::Tess
//! [`TessSlice`]: crate::tess::TessSlice
//! [`TessSliceIndex`]: crate::tess::TessSliceIndex
//! [`Program`]: crate::shader::program::Program
//! [`Framebuffer`]: crate::framebuffer::Framebuffer
//! [`RenderState`]: crate::render_state::RenderState
//! [`Pipeline`]: crate::pipeline::Pipeline
//! [`ShadingGate`]: crate::pipeline::ShadingGate
//! [`RenderGate`]: crate::pipeline::RenderGate
//! [`ProgramInterface`]: crate::shader::program::ProgramInterface
//! [`ProgramInterface::query`]: crate::shader::program::ProgramInterface::query
//! [`TessGate`]: crate::pipeline::TessGate
//! [AST]: https://en.wikipedia.org/wiki/Abstract_syntax_tree
//! [luminance]: crate
//! [luminance-windowing]: https://crates.io/crates/luminance-windowing
//! [luminance-glfw]: https://crates.io/crates/luminance-glfw

#![deny(missing_docs)]

#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature = "std"), feature(alloc))]

pub mod blending;
pub mod buffer;
pub mod context;
pub mod depth_test;
pub mod face_culling;
pub mod framebuffer;
pub mod linear;
mod metagl;
pub mod pipeline;
pub mod pixel;
pub mod render_state;
pub mod shader;
pub mod state;
pub mod tess;
pub mod texture;
pub mod vertex;
pub mod vertex_restart;