Skip to main content

InstanceBuffer

Struct InstanceBuffer 

Source
pub struct InstanceBuffer {
    pub layouts: Vec<(ATTRInfo, u32)>,
    /* private fields */
}
Expand description

A GPU buffer of interleaved per-instance attributes with a CPU-side mirror for random access.

Created by InstanceDesc3D::ship or InstanceDesc2D::ship. Each instance is a single packed row of attributes (position, rotation, scale, colour, and custom data). The buffer is designed for use with glDrawArraysInstanced / glDrawElementsInstanced.

§CPU mirror

An InstanceBuffer keeps a complete CPU copy of all instance data. This enables reads and partial writes without a GPU round-trip. Every mutating method writes through to both the CPU mirror and the GPU buffer transparently.

Read methodSourceLatency
[get_position], [get_color], [get_instance]CPU mirrorInstant
Read from GPUNot supported

§Growth

The buffer grows or shrinks in place via [set_instance_count]. New slots are filled with defaults:

AttributeDefault
Position(0, 0, 0)
RotationIdentity quaternion (0, 0, 0, 1)
Scale(1, 1, 1)
ColourWhite (1, 1, 1, 1)

§Convenience methods

You want to…Use
Move an instance[set_position]
Rotate an instance[set_rotation]
Scale an instance[set_scale]
Recolour an instance[set_color]
Write raw bytes[update_instance]

§Example

use optic_render::handles::{InstanceBuffer, InstanceDesc3D};
use cgmath::Vector3;

// Create 100 red instances along the x-axis
let mut desc = InstanceDesc3D::empty();
for i in 0..100 {
    desc.pos_attr.push([i as f32 * 2.0, 0.0, 0.0]);
    desc.col_attr.push([1.0, 0.0, 0.0, 1.0]);
}
let mut buffer = desc.ship()?;

// Re-position instance 5
buffer.set_position(5, Vector3::new(20.0, 0.0, 0.0))?;

// Add 50 more instances at the end
buffer.set_instance_count(150);

Fields§

§layouts: Vec<(ATTRInfo, u32)>

Implementations§

Source§

impl InstanceBuffer

Source

pub fn count(&self) -> u32

Returns the number of active instances.

Source

pub fn capacity(&self) -> u32

Returns the total capacity (allocated slots, may be larger than count).

Source

pub fn update_instance<D: DataType>( &mut self, index: u32, attr_index: usize, value: D, ) -> OpticResult<()>

Updates a single attribute of one instance by attribute index.

This is the lowest-level update — it writes raw bytes into both the CPU mirror and the GPU buffer in one operation. The attr_index refers to the attribute’s position in the interleaved layout (0 = first attribute).

For convenience wrappers, see:

AttributeConvenience method
Position (3D)set_position
Rotation (3D)set_rotation
Scale (3D)set_scale
Colourset_color
Custom (by name)update_custom
§Type safety

value must be a DataType whose byte count, element count, and format exactly match the attribute’s declared type. A mismatch produces a descriptive error at runtime.

§Errors
  • index >= count — instance index out of bounds.
  • attr_index out of range — invalid attribute slot.
  • D’s type parameters do not match the attribute slot.
Source

pub fn get_instance<D: DataType>( &self, index: u32, attr_index: usize, ) -> OpticResult<D>

Reads a single attribute of one instance from the CPU mirror.

This is the lowest-level read. It copies bytes from the CPU mirror and deserialises them into D. The GPU buffer is not touched — once an instance buffer is shipped, data flows from the CPU mirror to the GPU, never the other way.

For convenience readers, see get_position, get_rotation, get_scale, get_color, and get_custom.

§Errors

Same as update_instance.

Source

pub fn update_custom<D: DataType>( &mut self, index: u32, name: &str, value: D, ) -> OpticResult<()>

Updates a custom attribute of one instance by name.

Use this when you defined a custom attribute via InstanceDesc3D::attach_custom_attr or InstanceDesc2D::attach_custom_attr and ship with that descriptor. The attribute is looked up by name (not by index), making this robust against layout reordering.

§Errors
  • No custom attribute with that name exists.
  • D’s type parameters do not match the attribute’s declared format.
Source

pub fn get_custom<D: DataType>(&self, index: u32, name: &str) -> OpticResult<D>

Reads a custom attribute of one instance by name.

Does not read back from the GPU.

§Errors

Same as update_custom.

Source

pub fn set_position(&mut self, index: u32, pos: Vector3<f32>) -> OpticResult<()>

Sets the position of a single instance in world space.

This is a typed convenience over update_instance. It automatically resolves attr_index = 0 and converts the cgmath vector to the raw [f32; 3] the GPU expects.

§Errors

Returns an error if the buffer has no position attribute (i.e. the descriptor that created it did not push to pos_attr).

Source

pub fn get_position(&self, index: u32) -> OpticResult<Vector3<f32>>

Returns the position of a single instance from the CPU mirror.

The counterpart to set_position. Reads raw bytes from the CPU mirror and wraps them back into a cgmath::Vector3.

§Errors

Returns an error if the buffer has no position attribute.

Source

pub fn set_rotation(&mut self, index: u32, rot: Vector4<f32>) -> OpticResult<()>

Sets the rotation quaternion of a single instance.

The quaternion is stored as [x, y, z, w] in the interleaved buffer. Use cgmath::Quaternion::new(w, x, y, z) to construct the value, then pass .v (a Vector4) or a raw Vector4 to this method.

§Attribute-index resolution

The method skips past the position attribute if present:

Layoutattr_index passed to [update_instance]
Position + Rotation1
Rotation only0
§Errors

Returns an error if the buffer has no rotation attribute.

Source

pub fn get_rotation(&self, index: u32) -> OpticResult<Vector4<f32>>

Returns the rotation quaternion of a single instance.

The counterpart to set_rotation. Uses the same attribute-index resolution logic to locate the correct slot.

§Errors

Returns an error if the buffer has no rotation attribute.

Source

pub fn set_scale(&mut self, index: u32, scale: Vector3<f32>) -> OpticResult<()>

Sets the scale of a single instance.

Each component is applied independently — use a uniform scale like Vector3::new(2.0, 2.0, 2.0) for isotropic scaling or vary components for non-uniform stretching.

§Attribute-index resolution

Skips past position and rotation attributes if present.

§Errors

Returns an error if the buffer has no scale attribute.

Source

pub fn get_scale(&self, index: u32) -> OpticResult<Vector3<f32>>

Returns the scale of a single instance.

The counterpart to set_scale. Uses the same attribute-index resolution logic.

§Errors

Returns an error if the buffer has no scale attribute.

Source

pub fn set_color(&mut self, index: u32, color: RGBA) -> OpticResult<()>

Sets the colour of a single instance.

Accepts an optic_core::RGBA value constructed with RGBA::new(r, g, b, a) or from an integer hex like RGBA::from(0xFF8800FF).

§Attribute-index resolution

Skips past position, rotation, and scale attributes if present.

§Errors

Returns an error if the buffer has no colour attribute.

Source

pub fn get_color(&self, index: u32) -> OpticResult<RGBA>

Returns the colour of a single instance.

The counterpart to set_color. Uses the same attribute-index resolution logic. Returns an optic_core::RGBA.

§Errors

Returns an error if the buffer has no colour attribute.

Source

pub fn set_instance_count(&mut self, new_count: u32)

Resizes the instance count, filling new slots with defaults.

Use this to add or remove instances at the end of the buffer without creating a new descriptor and re-shipping. New slots are filled with sensible defaults:

AttributeDefault
Position(0, 0, 0)
RotationIdentity quaternion (0, 0, 0, 1)
Scale(1, 1, 1)
ColourWhite (1, 1, 1, 1)
§Capacity

If new_count exceeds the current capacity the allocation doubles each time (amortized O(1) growth). If new_count is smaller, excess instances become inaccessible but memory is not reclaimed — call shrink_to_fit if the buffer is persistently oversized.

§Example
buffer.set_instance_count(200);  // grow from 100 to 200
buffer.set_instance_count(50);   // shrink: last 150 are inaccessible
buffer.shrink_to_fit();          // release GPU memory
Source

pub fn reserve(&mut self, additional: u32)

Reserves capacity for additional extra instances without changing the active count. Useful before a batch of push_raw calls to avoid repeated reallocations.

Source

pub fn shrink_to_fit(&mut self)

Shrinks the GPU allocation to exactly fit the current instance count.

Use after a large set_instance_count shrink to free GPU memory. Calling this frequently (e.g. every frame) may cause performance churn.

Source

pub fn push_raw(&mut self, bytes: &[u8]) -> OpticResult<u32>

Appends a raw, pre-interleaved instance at the end of the buffer.

Use this when you have already packed instance bytes (e.g. from reading a binary file or from a previous buffer’s CPU mirror). For structured appends, prefer set_instance_count plus the typed setters.

§Errors

Returns an error if bytes.len() does not match self.stride.

Source

pub fn remove_instance(&mut self, index: u32) -> OpticResult<()>

Removes the instance at index by swapping it with the last instance (unordered, O(1)).

This is the fastest removal — it simply copies the last instance over the target and decrements the count. Instance ordering is not preserved. Use remove_instance_ordered if index stability matters.

§Errors

Returns an error if index >= count.

Source

pub fn remove_instance_ordered(&mut self, index: u32) -> OpticResult<()>

Removes the instance at index while preserving the order of remaining instances (O(n)).

Shifts all subsequent instances down by one. Prefer the O(1) unordered remove_instance when order does not matter.

Source

pub fn write_all(&mut self, desc: &InstanceDesc3D) -> OpticResult<()>

Replaces the entire buffer’s data from a 3D instance descriptor.

This is a full re-ship: the old GPU buffer handle is replaced and the old handle is leaked. If you need explicit GPU-side cleanup, free the old handle via glDeleteBuffers before calling this method.

Use this when the attribute layout has changed (e.g. added or removed a custom attribute) so the old interleaved format is incompatible.

Source

pub fn write_range(&mut self, start: u32, bytes: &[u8]) -> OpticResult<()>

Overwrites a contiguous range of instances with raw interleaved bytes.

Useful when you have pre-computed instance data externally (e.g. a particle system updating all particles each frame). The byte slice must be aligned to stride boundaries.

§Errors
  • bytes.len() is not a multiple of stride.
  • The range [start, start + instance_count) exceeds self.count.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> Downcast<T> for T

Source§

fn downcast(&self) -> &T

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> Upcast<T> for T

Source§

fn upcast(&self) -> Option<&T>