Browse Source

Clean up texenv API a bit and add some docs

pull/33/head
Ian Chamberlain 1 year ago
parent
commit
c47c5a93eb
No known key found for this signature in database
GPG Key ID: AE5484D09405AA60
  1. 7
      citro3d/examples/triangle.rs
  2. 48
      citro3d/src/lib.rs
  3. 84
      citro3d/src/texenv.rs

7
citro3d/examples/triangle.rs

@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
use citro3d::macros::include_shader;
use citro3d::math::{AspectRatio, ClipPlanes, Matrix4, Projection, StereoDisplacement};
use citro3d::render::ClearFlags;
use citro3d::texenv::{self, CombineFunc, TexEnv};
use citro3d::texenv;
use citro3d::{attrib, buffer, render, shader};
use ctru::prelude::*;
use ctru::services::gfx::{RawFrameBuffer, Screen, TopScreen3D};
@ -91,9 +91,10 @@ fn main() { @@ -91,9 +91,10 @@ fn main() {
// Configure the first fragment shading substage to just pass through the vertex color
// See https://www.opengl.org/sdk/docs/man2/xhtml/glTexEnv.xml for more insight
TexEnv::get(&mut instance, texenv::Id(0))
instance
.texenv(texenv::Stage::new(0).unwrap())
.src(texenv::Mode::BOTH, texenv::Source::PrimaryColor, None, None)
.func(texenv::Mode::BOTH, CombineFunc::Replace);
.func(texenv::Mode::BOTH, texenv::CombineFunc::Replace);
let projection_uniform_idx = program.get_uniform("projection").unwrap();

48
citro3d/src/lib.rs

@ -18,8 +18,12 @@ pub mod shader; @@ -18,8 +18,12 @@ pub mod shader;
pub mod texenv;
pub mod uniform;
use std::cell::OnceCell;
use std::fmt;
pub use error::{Error, Result};
use self::texenv::TexEnv;
use self::uniform::Uniform;
pub mod macros {
@ -31,8 +35,15 @@ pub mod macros { @@ -31,8 +35,15 @@ pub mod macros {
/// should instantiate to use this library.
#[non_exhaustive]
#[must_use]
#[derive(Debug)]
pub struct Instance;
pub struct Instance {
texenvs: [OnceCell<TexEnv>; texenv::TEXENV_COUNT],
}
impl fmt::Debug for Instance {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Instance").finish_non_exhaustive()
}
}
impl Instance {
/// Initialize the default `citro3d` instance.
@ -52,7 +63,17 @@ impl Instance { @@ -52,7 +63,17 @@ impl Instance {
#[doc(alias = "C3D_Init")]
pub fn with_cmdbuf_size(size: usize) -> Result<Self> {
if unsafe { citro3d_sys::C3D_Init(size) } {
Ok(Self)
Ok(Self {
texenvs: [
// thank goodness there's only six of them!
OnceCell::new(),
OnceCell::new(),
OnceCell::new(),
OnceCell::new(),
OnceCell::new(),
OnceCell::new(),
],
})
} else {
Err(Error::FailedToInitialize)
}
@ -185,6 +206,27 @@ impl Instance { @@ -185,6 +206,27 @@ impl Instance {
pub fn bind_geometry_uniform(&mut self, index: uniform::Index, uniform: impl Uniform) {
uniform.bind(self, shader::Type::Geometry, index);
}
/// Retrieve the [`TexEnv`] for the given stage, initializing it first if necessary.
///
/// # Example
///
/// ```
/// # use citro3d::texenv;
/// # let _runner = test_runner::GdbRunner::default();
/// # let mut instance = citro3d::Instance::new().unwrap();
/// let stage0 = texenv::Stage::new(0).unwrap();
/// let texenv0 = instance.texenv(stage0);
/// ```
#[doc(alias = "C3D_GetTexEnv")]
#[doc(alias = "C3D_TexEnvInit")]
pub fn texenv(&mut self, stage: texenv::Stage) -> &mut texenv::TexEnv {
let texenv = &mut self.texenvs[stage.0];
texenv.get_or_init(|| TexEnv::new(stage));
// We have to do this weird unwrap to get a mutable reference,
// since there is no `get_mut_or_init` or equivalent
texenv.get_mut().unwrap()
}
}
impl Drop for Instance {

84
citro3d/src/texenv.rs

@ -1,52 +1,70 @@ @@ -1,52 +1,70 @@
//! Texture environment support. See `<c3d/texenv.h>` for more information.
//! Texture combiner support. See <https://www.khronos.org/opengl/wiki/Texture_Combiners>
//! for more details.
use bitflags::bitflags;
use crate::Instance;
/// A texture combiner, also called a "texture environment" (hence the struct name).
/// See also [`texenv.h` documentation](https://oreo639.github.io/citro3d/texenv_8h.html).
#[doc(alias = "C3D_TexEnv")]
pub struct TexEnv<'a> {
pub struct TexEnv {
raw: *mut citro3d_sys::C3D_TexEnv,
_instance: &'a mut Instance,
}
impl<'a> TexEnv<'a> {
#[doc(alias = "C3D_TexEnvInit")]
pub fn set(&self, _instance: &mut Instance, id: Id) {
unsafe {
// SAFETY: pointee is only copied from, not modified
citro3d_sys::C3D_SetTexEnv(id.0, self.raw);
// https://oreo639.github.io/citro3d/texenv_8h.html#a9eda91f8e7252c91f873b1d43e3728b6
pub(crate) const TEXENV_COUNT: usize = 6;
impl TexEnv {
pub(crate) fn new(stage: Stage) -> Self {
let mut result = unsafe {
Self {
raw: citro3d_sys::C3D_GetTexEnv(stage.0 as _),
}
};
result.reset();
result
}
pub fn get(instance: &'a mut Instance, id: Id) -> Self {
/// Re-initialize the texture combiner to its default state.
pub fn reset(&mut self) {
unsafe {
Self {
raw: citro3d_sys::C3D_GetTexEnv(id.0),
_instance: instance,
}
citro3d_sys::C3D_TexEnvInit(self.raw);
}
}
/// Configure the source values of the texture combiner.
///
/// # Parameters
///
/// - `mode`: which [`Mode`]\(s) to set the sourc operand(s) for.
/// - `source0`: the first [`Source`] operand to the texture combiner
/// - `source1` and `source2`: optional additional [`Source`] operands to use
#[doc(alias = "C3D_TexEnvSrc")]
pub fn src(
&mut self,
mode: Mode,
s1: Source,
s2: Option<Source>,
s3: Option<Source>,
source0: Source,
source1: Option<Source>,
source2: Option<Source>,
) -> &mut Self {
unsafe {
citro3d_sys::C3D_TexEnvSrc(
self.raw,
mode.bits(),
s1 as _,
s2.unwrap_or(Source::PrimaryColor) as _,
s3.unwrap_or(Source::PrimaryColor) as _,
)
source0 as _,
source1.unwrap_or(Source::PrimaryColor) as _,
source2.unwrap_or(Source::PrimaryColor) as _,
);
}
self
}
/// Configure the texture combination function.
///
/// # Parameters
///
/// - `mode`: the [`Mode`]\(s) the combination function will apply to.
/// - `func`: the [`CombineFunc`] used to combine textures.
#[doc(alias = "C3D_TexEnvFunc")]
pub fn func(&mut self, mode: Mode, func: CombineFunc) -> &mut Self {
unsafe {
citro3d_sys::C3D_TexEnvFunc(self.raw, mode.bits(), func as _);
@ -57,17 +75,23 @@ impl<'a> TexEnv<'a> { @@ -57,17 +75,23 @@ impl<'a> TexEnv<'a> {
}
bitflags! {
/// Whether to operate on colors, alpha values, or both.
#[doc(alias = "C3D_TexEnvMode")]
pub struct Mode: citro3d_sys::C3D_TexEnvMode {
#[allow(missing_docs)]
const RGB = citro3d_sys::C3D_RGB;
#[allow(missing_docs)]
const ALPHA = citro3d_sys::C3D_Alpha;
#[allow(missing_docs)]
const BOTH = citro3d_sys::C3D_Both;
}
}
/// A source operand of a [`TexEnv`]'s texture combination.
#[derive(Debug, Clone, Copy)]
#[repr(u32)]
#[doc(alias = "GPU_TEVSRC")]
#[allow(missing_docs)]
pub enum Source {
PrimaryColor = ctru_sys::GPU_PRIMARY_COLOR,
FragmentPrimaryColor = ctru_sys::GPU_FRAGMENT_PRIMARY_COLOR,
@ -81,9 +105,11 @@ pub enum Source { @@ -81,9 +105,11 @@ pub enum Source {
Previous = ctru_sys::GPU_PREVIOUS,
}
/// The combination function to apply to the [`TexEnv`] operands.
#[derive(Debug, Clone, Copy)]
#[repr(u32)]
#[doc(alias = "GPU_COMBINEFUNC")]
#[allow(missing_docs)]
pub enum CombineFunc {
Replace = ctru_sys::GPU_REPLACE,
Modulate = ctru_sys::GPU_MODULATE,
@ -95,5 +121,15 @@ pub enum CombineFunc { @@ -95,5 +121,15 @@ pub enum CombineFunc {
Dot3Rgba = ctru_sys::GPU_DOT3_RGBA,
}
/// A texture combination stage identifier. This index doubles as the order
/// in which texture combinations will be applied.
// (I think?)
#[derive(Copy, Clone, Debug)]
pub struct Id(/* TODO maybe non pub? idk */ pub libc::c_int);
pub struct Stage(pub(crate) usize);
impl Stage {
/// Get a stage index. Valid indices range from 0 to 5.
pub fn new(index: usize) -> Option<Self> {
(index < 6).then_some(Self(index))
}
}

Loading…
Cancel
Save