FyroxEngine/Fyrox · error

Invalid pixel position

Error message

Invalid pixel position: ({}, {}) within ({}, {})

What it means

StrokeChunks::pixel_index converts a 2D position into a linear index into a chunk's texture data, after validating it with `is_valid_pixel`. It panics when the position lies outside the chunk's `[0, chunk_size)` bounds, preventing an out-of-bounds write into texture memory.

Solutions

  1. Call `is_valid_pixel(position)` first and skip/handle invalid positions instead of panicking.
  2. Convert global terrain positions to chunk-local positions before calling pixel_index.
  3. Clamp or split the brush footprint so each position stays within the owning chunk's chunk_size.

Example fix

// before
let idx = chunk.pixel_index(position);
// after
if chunk.is_valid_pixel(position) {
    let idx = chunk.pixel_index(position);
}
Defensive patterns

Strategy: validation

Validate before calling

if chunk.is_valid_pixel(position) {
    let idx = chunk.pixel_index(position);
}

Try / catch

// Rust panic - avoid instead with is_valid_pixel pre-check (see validationCode).

Prevention

When it happens

Trigger: Calling `pixel_index(position)` where `position.x < 0 || position.y < 0 || position.x >= chunk_size.x || position.y >= chunk_size.y` — e.g. painting at a terrain coordinate that maps into a neighboring chunk or beyond the chunk's edge.

Common situations: Custom brush code not clamping positions to chunk bounds; brush radius extending past chunk edges; using global terrain coordinates instead of chunk-local coordinates.

Related errors


AI-assisted analysis of FyroxEngine/Fyrox@76c91aad8e (2026-09-10). Data as JSON: /api/errors/cc62cf026c1c4314. Report an issue: GitHub.

Appendix: source

Thrown at fyrox-impl/src/scene/terrain/brushstroke/strokechunks.rs:161

    pub fn chunk_to_origin(&self, grid_position: Vector2<i32>) -> Vector2<i32> {
        Vector2::new(
            grid_position.x * self.chunk_size.x as i32,
            grid_position.y * self.chunk_size.y as i32,
        )
    }
    /// The width of the texture in pixels.
    pub fn row_size(&self) -> usize {
        match self.kind {
            TerrainTextureKind::Height => (self.chunk_size.x + 3) as usize,
            TerrainTextureKind::Mask => self.chunk_size.x as usize,
        }
    }
    /// Calculate the index of a pixel at the given position within texture data,
    /// based on the row size. The given position is relative to the origin of the texture
    /// and must be within the bounds of the texture.
    pub fn pixel_index(&self, position: Vector2<i32>) -> usize {
        if !self.is_valid_pixel(position) {
            panic!(
                "Invalid pixel position: ({}, {}) within ({}, {})",
                position.x, position.y, self.chunk_size.x, self.chunk_size.y
            );
        }
        let p = match self.kind {
            TerrainTextureKind::Height => position.map(|x| (x + 1) as usize),
            TerrainTextureKind::Mask => position.map(|x| x as usize),
        };
        p.x + p.y * self.row_size()
    }
    /// True if the given pixel position is within the bounds of a chunk for the current kind of chunk data.
    /// Due to the margins of the height textures, it is permitted to index height textures to -1 and chunk_size.x + 1.
    pub fn is_valid_pixel(&self, position: Vector2<i32>) -> bool {
        let size = self.chunk_size.map(|x| x as i32);
        match self.kind {
            TerrainTextureKind::Height => {
                (-1..=size.x + 1).contains(&position.x) && (-1..=size.y + 1).contains(&position.y)
            }

View on GitHub (pinned to 76c91aad8e)