diff --git a/docs/methods.md b/docs/methods.md
index a48fdee..6d626ed 100644
--- a/docs/methods.md
+++ b/docs/methods.md
@@ -28,6 +28,15 @@ tuple `(buffer, byteOffset, byteSize)`. You can obtain an instance by
calling the `range(...)` or `fullRange()` method of a `DeviceVkbBuffer` or
a `MappedVkbBuffer`.
+### MappedVkbBufferRange
+The `MappedVkbBufferRange` represents a range of a `MappedVkbBuffer`,
+which is a tuple `(mappedBuffer, byteOffset, byteSize)`. You can obtain
+an instance by calling the `mappedRange(...)` or `mappedFullRange()`
+method of a `MappedVkbBuffer`. It provides `byteBuffer()`,
+`shortBuffer()`, etc... methods to create Java NIO buffers whose memory
+is backed by the buffer range. It also provides a `range(...)` method to
+create a corresponding `VkbBufferRange`.
+
### Encoding/decoding images
You can use `boiler.buffers.encodeBufferedImageRGBA(...)` to encode/store a
`BufferedImage` in a `MappedVkbBuffer` in RGBA8 format. You can use this to
diff --git a/src/main/java/com/github/knokko/boiler/buffers/MappedVkbBuffer.java b/src/main/java/com/github/knokko/boiler/buffers/MappedVkbBuffer.java
index de79e6f..f34d860 100644
--- a/src/main/java/com/github/knokko/boiler/buffers/MappedVkbBuffer.java
+++ b/src/main/java/com/github/knokko/boiler/buffers/MappedVkbBuffer.java
@@ -5,4 +5,21 @@
* host-visible memory, and must be mapped at hostAddress during its lifetime.
*/
public record MappedVkbBuffer(long vkBuffer, long vmaAllocation, long size, long hostAddress) implements VkbBuffer {
+
+ /**
+ * @return a MappedVkbBufferRange that covers this whole buffer
+ */
+ public MappedVkbBufferRange fullMappedRange() {
+ return new MappedVkbBufferRange(this, 0L, size);
+ }
+
+ /**
+ * @param offset The offset, in bytes
+ * @param rangeSize The size of the range, in bytes
+ * @return a MappedVkbBufferRange that covers the bytes [offset, offset + rangeSize> from this buffer
+ */
+ public MappedVkbBufferRange mappedRange(long offset, long rangeSize) {
+ if (offset + rangeSize > size) throw new IllegalArgumentException(offset + " + " + rangeSize + " > " + size);
+ return new MappedVkbBufferRange(this, offset, rangeSize);
+ }
}
diff --git a/src/main/java/com/github/knokko/boiler/buffers/MappedVkbBufferRange.java b/src/main/java/com/github/knokko/boiler/buffers/MappedVkbBufferRange.java
new file mode 100644
index 0000000..6ea1d00
--- /dev/null
+++ b/src/main/java/com/github/knokko/boiler/buffers/MappedVkbBufferRange.java
@@ -0,0 +1,79 @@
+package com.github.knokko.boiler.buffers;
+
+import java.nio.*;
+
+import static org.lwjgl.system.MemoryUtil.*;
+
+/**
+ * Represents a range/section of a MappedVkbBuffer
+ * @param buffer The mapped buffer
+ * @param offset The offset into the mapped buffer, in bytes
+ * @param size The size of this range, in bytes
+ */
+public record MappedVkbBufferRange(MappedVkbBuffer buffer, long offset, long size) {
+
+ /**
+ * @return The start host address of this buffer range
+ */
+ public long hostAddress() {
+ return buffer.hostAddress() + offset;
+ }
+
+ /**
+ * @return The size of this range in bytes, but represented as integer
+ * @throws UnsupportedOperationException When the size is larger than Integer.MAX_VALUE
+ */
+ public int intSize() {
+ if (size > Integer.MAX_VALUE) throw new UnsupportedOperationException("Size (" + size + ") is too large");
+ return (int) size;
+ }
+
+ /**
+ * @return The corresponding VkbBufferRange
+ */
+ public VkbBufferRange range() {
+ return new VkbBufferRange(buffer, offset, size);
+ }
+
+ /**
+ * @return A direct byte buffer that starts at the start of this range, and has the same capacity
+ */
+ public ByteBuffer byteBuffer() {
+ return memByteBuffer(hostAddress(), intSize());
+ }
+
+ /**
+ * @return A direct short buffer that starts at the start of this range, with a capacity of size / Short.BYTES
+ */
+ public ShortBuffer shortBuffer() {
+ return memShortBuffer(hostAddress(), intSize() / Short.BYTES);
+ }
+
+ /**
+ * @return A direct int buffer that starts at the start of this range, with a capacity of size / Int.BYTES
+ */
+ public IntBuffer intBuffer() {
+ return memIntBuffer(hostAddress(), intSize() / Integer.BYTES);
+ }
+
+ /**
+ * @return A direct float buffer that starts at the start of this range, with a capacity of size / Float.BYTES
+ */
+ public FloatBuffer floatBuffer() {
+ return memFloatBuffer(hostAddress(), intSize() / Float.BYTES);
+ }
+
+ /**
+ * @return A direct long buffer that starts at the start of this range, with a capacity of size / Long.BYTES
+ */
+ public LongBuffer longBuffer() {
+ return memLongBuffer(hostAddress(), intSize() / Long.BYTES);
+ }
+
+ /**
+ * @return A direct double buffer that starts at the start of this range, with a capacity of size / Double.BYTES
+ */
+ public DoubleBuffer doubleBuffer() {
+ return memDoubleBuffer(hostAddress(), intSize() / Double.BYTES);
+ }
+}