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 method | Source | Latency |
|---|---|---|
[get_position], [get_color], [get_instance] | CPU mirror | Instant |
| Read from GPU | Not supported | — |
§Growth
The buffer grows or shrinks in place via [set_instance_count]. New slots
are filled with defaults:
| Attribute | Default |
|---|---|
| Position | (0, 0, 0) |
| Rotation | Identity quaternion (0, 0, 0, 1) |
| Scale | (1, 1, 1) |
| Colour | White (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
impl InstanceBuffer
Sourcepub fn capacity(&self) -> u32
pub fn capacity(&self) -> u32
Returns the total capacity (allocated slots, may be larger than count).
Sourcepub fn update_instance<D: DataType>(
&mut self,
index: u32,
attr_index: usize,
value: D,
) -> OpticResult<()>
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:
| Attribute | Convenience method |
|---|---|
| Position (3D) | set_position |
| Rotation (3D) | set_rotation |
| Scale (3D) | set_scale |
| Colour | set_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_indexout of range — invalid attribute slot.D’s type parameters do not match the attribute slot.
Sourcepub fn get_instance<D: DataType>(
&self,
index: u32,
attr_index: usize,
) -> OpticResult<D>
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.
Sourcepub fn update_custom<D: DataType>(
&mut self,
index: u32,
name: &str,
value: D,
) -> OpticResult<()>
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.
Sourcepub fn get_custom<D: DataType>(&self, index: u32, name: &str) -> OpticResult<D>
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.
Sourcepub fn set_position(&mut self, index: u32, pos: Vector3<f32>) -> OpticResult<()>
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).
Sourcepub fn get_position(&self, index: u32) -> OpticResult<Vector3<f32>>
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.
Sourcepub fn set_rotation(&mut self, index: u32, rot: Vector4<f32>) -> OpticResult<()>
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:
| Layout | attr_index passed to [update_instance] |
|---|---|
| Position + Rotation | 1 |
| Rotation only | 0 |
§Errors
Returns an error if the buffer has no rotation attribute.
Sourcepub fn get_rotation(&self, index: u32) -> OpticResult<Vector4<f32>>
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.
Sourcepub fn set_scale(&mut self, index: u32, scale: Vector3<f32>) -> OpticResult<()>
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.
Sourcepub fn set_color(&mut self, index: u32, color: RGBA) -> OpticResult<()>
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.
Sourcepub fn get_color(&self, index: u32) -> OpticResult<RGBA>
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.
Sourcepub fn set_instance_count(&mut self, new_count: u32)
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:
| Attribute | Default |
|---|---|
| Position | (0, 0, 0) |
| Rotation | Identity quaternion (0, 0, 0, 1) |
| Scale | (1, 1, 1) |
| Colour | White (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 memorySourcepub fn reserve(&mut self, additional: u32)
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.
Sourcepub fn shrink_to_fit(&mut self)
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.
Sourcepub fn push_raw(&mut self, bytes: &[u8]) -> OpticResult<u32>
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.
Sourcepub fn remove_instance(&mut self, index: u32) -> OpticResult<()>
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.
Sourcepub fn remove_instance_ordered(&mut self, index: u32) -> OpticResult<()>
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.
Sourcepub fn write_all(&mut self, desc: &InstanceDesc3D) -> OpticResult<()>
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.
Sourcepub fn write_range(&mut self, start: u32, bytes: &[u8]) -> OpticResult<()>
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 ofstride.- The range
[start, start + instance_count)exceedsself.count.
Auto Trait Implementations§
impl Freeze for InstanceBuffer
impl RefUnwindSafe for InstanceBuffer
impl Send for InstanceBuffer
impl Sync for InstanceBuffer
impl Unpin for InstanceBuffer
impl UnsafeUnpin for InstanceBuffer
impl UnwindSafe for InstanceBuffer
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
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