Skip to content

Commit

Permalink
Format compatibility checking.
Browse files Browse the repository at this point in the history
  • Loading branch information
Lakuna committed Mar 7, 2024
1 parent 6892a91 commit dcd0bb5
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 31 deletions.
67 changes: 50 additions & 17 deletions src/core/textures/Texture.ts
Expand Up @@ -27,13 +27,14 @@ import type { TextureSizedInternalFormat } from "#TextureSizedInternalFormat";
import type MipmapTarget from "#MipmapTarget";
import type Box from "#Box";
import type { MipData } from "#MipData";
import type TextureDataType from "#TextureDataType";
import type TextureFormat from "#TextureFormat";
import TextureDataType from "#TextureDataType";
import TextureFormat from "#TextureFormat";
import type { TextureInternalFormat } from "#TextureInternalFormat";
import TextureUncompressedUnsizedInternalFormat from "#TextureUncompressedUnsizedInternalFormat";
import ImmutableError from "#ImmutableError";
import getTextureFormatForTextureInternalFormat from "#getTextureFormatForTextureInternalFormat";
import TextureFormatError from "#TextureFormatError";
import getTextureDataTypesForTextureInternalFormat from "#getTextureDataTypesForTextureInternalFormat";

/**
* A randomly-accessible array.
Expand Down Expand Up @@ -517,58 +518,90 @@ export default abstract class Texture extends ContextDependent {
* Sets the data in a mip.
* @param target The mipmap that the mip belongs to.
* @param level The level of the mip within its mipmap.
* @param data The data to fill the mip with.
* @param bounds The bounds of the mip to be updated. Defaults to the
* entire mip if not set.
* @param format The format of the given data. Must be compatible with the
* format of the texture.
* @param type The type of the given data. Must be compatible with the
* format of the given data.
* @param data The data to fill the mip with.
* @param bounds The bounds of the mip to be updated. Defaults to the entire mip if not set.
* @internal
*/
public setMip(
target: MipmapTarget,
level: number,
format: TextureFormat,
type: TextureDataType,
data: MipData,
bounds?: Box
bounds?: Box,
format?: TextureFormat,
type?: TextureDataType
): void {
// TODO: Ensure that format, internal format, and data type are compatible.
// Ensure that the format and internal format are compatible.
const expectedFormat: TextureFormat | null =
getTextureFormatForTextureInternalFormat(this.format);
format ??= expectedFormat ?? TextureFormat.RGBA;
if (expectedFormat !== null && format !== expectedFormat) {
throw new TextureFormatError();
}

if (expectedFormat !== format) {
if (this.isImmutableFormat || level > 0) {
throw new TextureFormatError();
}
// Ensure that the data type and internal format are compatible.
const expectedDataTypes: TextureDataType[] | null =
getTextureDataTypesForTextureInternalFormat(this.format);
type ??= expectedDataTypes?.[0] ?? TextureDataType.UNSIGNED_BYTE;
if (expectedDataTypes !== null && !expectedDataTypes.includes(type)) {
throw new TextureFormatError();
}

// TODO: Use a new default internal format if using an incompatible format for the top mip(?)
// Ensure that the specified bounds (if any) are no bigger than the mip.
const mipDims: number[] = this.getSizeOfMip(level);
if (typeof bounds === "undefined") {
// Default to the entire mip for immutable-format textures.
if (this.isImmutableFormat) {
bounds = {
x: 0,
y: 0,
z: 0,
width: mipDims[0] ?? 0,
height: mipDims[1] ?? 0,
depth: mipDims[2] ?? 0
};
}
} else {
// Throw an error if the specified bounding box (if any) is larger than the specified mip.
if (
bounds.x + bounds.width > (mipDims[0] ?? 0) ||
bounds.y + bounds.height > (mipDims[1] ?? 0) ||
(bounds.z ?? 0) + (bounds.depth ?? 0) > (mipDims[2] ?? 0)
) {
throw new RangeError();
}
}

// TODO: May need to clear certain cache values when updating data? i.e. dims, max level, max/min LOD, etc.

// TODO: Unpack alignment.

this.setMipInternal(target, level, format, type, data, bounds);
this.setMipInternal(target, level, data, format, type, bounds);
}

/**
* Sets the data in a mip.
* @param target The mipmap that the mip belongs to.
* @param level The level of the mip within its mipmap.
* @param data The data to fill the mip with.
* @param format The format of the given data. Must be compatible with the
* format of the texture.
* @param type The type of the given data. Must be compatible with the
* format of the given data.
* @param data The data to fill the mip with.
* @param bounds The bounds of the mip to be updated. Defaults to the entire mip if not set.
* @param bounds The bounds of the mip to be updated. Defaults to the
* entire mip if not set.
* @internal
*/
protected abstract setMipInternal(
target: MipmapTarget,
level: number,
data: MipData,
format: TextureFormat,
type: TextureDataType,
data: MipData,
bounds?: Box
): void;

Expand Down
12 changes: 7 additions & 5 deletions src/core/textures/Texture2d.ts
Expand Up @@ -79,23 +79,25 @@ export default class Texture2d extends Texture {
* Sets the data in a mip.
* @param target The mipmap that the mip belongs to.
* @param level The level of the mip within its mipmap.
* @param data The data to fill the mip with.
* @param format The format of the given data. Must be compatible with the
* format of the texture.
* @param type The type of the given data. Must be compatible with the
* format of the given data.
* @param data The data to fill the mip with.
* @param bounds The bounds of the mip to be updated. Defaults to the entire mip if not set.
* @param bounds The bounds of the mip to be updated. Defaults to the
* entire mip if not set.
* @internal
*/
protected override setMipInternal(
target: MipmapTarget,
level: number,
data: MipData,
format: TextureFormat,
type: TextureDataType,
data: MipData,
bounds?: Box | undefined
bounds?: Box
): void {
throw new Error(
`Method not implemented: Texture2d.setMipInternal(${target}, ${level}, ${format}, ${type}, ${typeof data}, ${typeof bounds})`
`Method not implemented: Texture2d.setMipInternal(${target}, ${level}, ${typeof data}, ${format}, ${type}, ${typeof bounds})`
);
}
}
8 changes: 7 additions & 1 deletion src/types/Box.ts
@@ -1,14 +1,20 @@
/** A rectangle. */
/** A rectangle or rectangular prism. */
export default interface Box {
/** The X-coordinate of the box. */
x: number;

/** The Y-coordinate of the box. */
y: number;

/** The Z-coordinate of the box if it is a prism. */
z?: number;

/** The width of the box. */
width: number;

/** The height of the box. */
height: number;

/** The depth of the box if it is a prism. */
depth?: number;
}
Expand Up @@ -9,7 +9,9 @@ import type { TextureCompressedInternalFormat } from "#TextureCompressedInternal
* Gets a list of data types that can be supplied to the given texture internal
* format.
* @param internalFormat The texture internal format.
* @returns A list of data types.
* @returns A list of data types. If the return value is not null, it is
* guaranteed to contain at least one data type. The first data type in the
* list is a sensible default.
* @see [`glTexImage2D`](https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml)
* @internal
*/
Expand All @@ -21,7 +23,9 @@ export default function getTextureDataTypesForTextureInternalFormat(
* Gets a list of data types that can be supplied to the given texture internal
* format.
* @param internalFormat The texture internal format.
* @returns A list of data types.
* @returns A list of data types. If the return value is not null, it is
* guaranteed to contain at least one data type. The first data type in the
* list is a sensible default.
* @see [`glTexImage2D`](https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml)
* @internal
*/
Expand All @@ -33,7 +37,9 @@ export default function getTextureDataTypesForTextureInternalFormat(
* Gets a list of data types that can be supplied to the given texture internal
* format.
* @param internalFormat The texture internal format.
* @returns A list of data types.
* @returns A list of data types. If the return value is not null, it is
* guaranteed to contain at least one data type. The first data type in the
* list is a sensible default.
* @see [`glTexImage2D`](https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml)
* @internal
*/
Expand Down Expand Up @@ -84,7 +90,7 @@ export default function getTextureDataTypesForTextureInternalFormat(
case TextureUncompressedSizedInternalFormat.RG16F:
case TextureUncompressedSizedInternalFormat.RGB16F:
case TextureUncompressedSizedInternalFormat.RGBA16F:
return [TextureDataType.HALF_FLOAT, TextureDataType.FLOAT];
return [TextureDataType.FLOAT, TextureDataType.HALF_FLOAT];
case TextureUncompressedSizedInternalFormat.R32F:
case TextureUncompressedSizedInternalFormat.RG32F:
case TextureUncompressedSizedInternalFormat.RGB32F:
Expand Down Expand Up @@ -114,15 +120,15 @@ export default function getTextureDataTypesForTextureInternalFormat(
return [TextureDataType.INT];
case TextureUncompressedSizedInternalFormat.R11F_G11F_B10F:
return [
TextureDataType.FLOAT,
TextureDataType.UNSIGNED_INT_10F_11F_11F_REV,
TextureDataType.HALF_FLOAT,
TextureDataType.FLOAT
TextureDataType.HALF_FLOAT
];
case TextureUncompressedSizedInternalFormat.RGB9_E5:
return [
TextureDataType.FLOAT,
TextureDataType.UNSIGNED_INT_5_9_9_9_REV,
TextureDataType.HALF_FLOAT,
TextureDataType.FLOAT
TextureDataType.HALF_FLOAT
];
case TextureUncompressedSizedInternalFormat.RGB5_A1:
return [
Expand Down

0 comments on commit dcd0bb5

Please sign in to comment.