ris-framework 0.2.0-dev.13 → 0.2.0-dev.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/CHANGELOG.md +43 -2
  2. package/README.md +13 -5
  3. package/dist/api/IFramework.d.ts +3 -3
  4. package/dist/api/IFramework.d.ts.map +1 -1
  5. package/dist/api/_export.d.ts +3 -0
  6. package/dist/api/_export.d.ts.map +1 -1
  7. package/dist/api/camera/CameraTransformUtilities.d.ts +65 -0
  8. package/dist/api/camera/CameraTransformUtilities.d.ts.map +1 -0
  9. package/dist/api/camera/ICamera.d.ts +36 -2
  10. package/dist/api/camera/ICamera.d.ts.map +1 -1
  11. package/dist/api/camera/OrbitCamera.d.ts +22 -14
  12. package/dist/api/camera/OrbitCamera.d.ts.map +1 -1
  13. package/dist/api/camera/OrthographicCamera.d.ts +33 -11
  14. package/dist/api/camera/OrthographicCamera.d.ts.map +1 -1
  15. package/dist/api/camera/PerspectiveCamera.d.ts +32 -18
  16. package/dist/api/camera/PerspectiveCamera.d.ts.map +1 -1
  17. package/dist/api/content/ContentManager.d.ts +2 -2
  18. package/dist/api/content/ContentManager.d.ts.map +1 -1
  19. package/dist/api/content/IContentManager.d.ts +2 -2
  20. package/dist/api/content/IContentManager.d.ts.map +1 -1
  21. package/dist/api/lights/AmbientLight.d.ts +7 -2
  22. package/dist/api/lights/AmbientLight.d.ts.map +1 -1
  23. package/dist/api/lights/DirectionalLight.d.ts +18 -4
  24. package/dist/api/lights/DirectionalLight.d.ts.map +1 -1
  25. package/dist/api/lights/ILight.d.ts +18 -0
  26. package/dist/api/lights/ILight.d.ts.map +1 -0
  27. package/dist/api/lights/PointLight.d.ts +17 -4
  28. package/dist/api/lights/PointLight.d.ts.map +1 -1
  29. package/dist/api/lights/_export.d.ts +1 -0
  30. package/dist/api/lights/_export.d.ts.map +1 -1
  31. package/dist/api/material/ForwardBlinnPhongMaterial.d.ts +2 -2
  32. package/dist/api/material/ForwardBlinnPhongMaterial.d.ts.map +1 -1
  33. package/dist/api/material/IMaterial.d.ts +7 -0
  34. package/dist/api/material/IMaterial.d.ts.map +1 -1
  35. package/dist/api/material/IMaterialFactory.d.ts +3 -2
  36. package/dist/api/material/IMaterialFactory.d.ts.map +1 -1
  37. package/dist/api/material/IUnlitMaterialDescriptor.d.ts +16 -0
  38. package/dist/api/material/IUnlitMaterialDescriptor.d.ts.map +1 -0
  39. package/dist/api/material/MaterialFactory.d.ts +3 -2
  40. package/dist/api/material/MaterialFactory.d.ts.map +1 -1
  41. package/dist/api/material/SpriteMaterial.d.ts +3 -0
  42. package/dist/api/material/SpriteMaterial.d.ts.map +1 -1
  43. package/dist/api/material/UnlitMaterial.d.ts +5 -12
  44. package/dist/api/material/UnlitMaterial.d.ts.map +1 -1
  45. package/dist/api/material/_export.d.ts +1 -1
  46. package/dist/api/material/_export.d.ts.map +1 -1
  47. package/dist/api/meshes/IRenderableMesh.d.ts +3 -14
  48. package/dist/api/meshes/IRenderableMesh.d.ts.map +1 -1
  49. package/dist/api/meshes/RenderableMesh.d.ts +5 -20
  50. package/dist/api/meshes/RenderableMesh.d.ts.map +1 -1
  51. package/dist/api/rendering/IGraphicsDevice.d.ts +2 -2
  52. package/dist/api/rendering/IGraphicsDevice.d.ts.map +1 -1
  53. package/dist/api/rendering/IRenderer.d.ts +13 -6
  54. package/dist/api/rendering/IRenderer.d.ts.map +1 -1
  55. package/dist/api/rendering/_export-rendering.d.ts +1 -0
  56. package/dist/api/rendering/_export-rendering.d.ts.map +1 -1
  57. package/dist/api/rendering/enums.d.ts +5 -5
  58. package/dist/api/rendering/enums.d.ts.map +1 -1
  59. package/dist/api/rendering/primitive/IPrimitiveStateDescriptor.d.ts +24 -0
  60. package/dist/api/rendering/primitive/IPrimitiveStateDescriptor.d.ts.map +1 -0
  61. package/dist/api/rendering/primitive/_export.d.ts +1 -1
  62. package/dist/api/rendering/primitive/_export.d.ts.map +1 -1
  63. package/dist/api/rendering/render-pipelines/IMainRenderTargetRenderPipeline.d.ts +5 -0
  64. package/dist/api/rendering/render-pipelines/IMainRenderTargetRenderPipeline.d.ts.map +1 -1
  65. package/dist/api/rendering/texture/ITextureDescriptor.d.ts +53 -0
  66. package/dist/api/rendering/texture/ITextureDescriptor.d.ts.map +1 -0
  67. package/dist/api/rendering/texture/ITextureFactory.d.ts +5 -3
  68. package/dist/api/rendering/texture/ITextureFactory.d.ts.map +1 -1
  69. package/dist/api/rendering/texture/TextureUtilities.d.ts +29 -21
  70. package/dist/api/rendering/texture/TextureUtilities.d.ts.map +1 -1
  71. package/dist/api/rendering/texture/_export-texture.d.ts +1 -1
  72. package/dist/api/rendering/texture/_export-texture.d.ts.map +1 -1
  73. package/dist/api/scene/ISceneObject.d.ts +12 -0
  74. package/dist/api/scene/ISceneObject.d.ts.map +1 -0
  75. package/dist/api/scene/Scene.d.ts +17 -6
  76. package/dist/api/scene/Scene.d.ts.map +1 -1
  77. package/dist/api/scene/node/Node.d.ts +26 -0
  78. package/dist/api/scene/node/Node.d.ts.map +1 -0
  79. package/dist/api/scene/node/TransformNode.d.ts +46 -0
  80. package/dist/api/scene/node/TransformNode.d.ts.map +1 -0
  81. package/dist/core/material/UnlitMaterialDescriptorUtilities.d.ts +17 -0
  82. package/dist/core/material/UnlitMaterialDescriptorUtilities.d.ts.map +1 -0
  83. package/dist/core/rendering/AGraphicsDevice.d.ts +2 -2
  84. package/dist/core/rendering/AGraphicsDevice.d.ts.map +1 -1
  85. package/dist/core/rendering/ARenderer.d.ts +7 -1
  86. package/dist/core/rendering/ARenderer.d.ts.map +1 -1
  87. package/dist/core/rendering/primitive/PrimitiveStateDescriptorUtilities.d.ts +15 -0
  88. package/dist/core/rendering/primitive/PrimitiveStateDescriptorUtilities.d.ts.map +1 -0
  89. package/dist/core/rendering/texture/TextureDescriptorUtilities.d.ts +14 -0
  90. package/dist/core/rendering/texture/TextureDescriptorUtilities.d.ts.map +1 -0
  91. package/dist/core/rendering/texture/texture.d.ts +3 -2
  92. package/dist/core/rendering/texture/texture.d.ts.map +1 -1
  93. package/dist/index.js +959 -540
  94. package/dist/webgl/WebGlGraphicsDevice.d.ts +2 -2
  95. package/dist/webgl/WebGlGraphicsDevice.d.ts.map +1 -1
  96. package/dist/webgl/lights/WebGlLightsBuffer.d.ts.map +1 -1
  97. package/dist/webgl/primitive/WebGlPrimitiveState.d.ts +3 -3
  98. package/dist/webgl/primitive/WebGlPrimitiveState.d.ts.map +1 -1
  99. package/dist/webgl/render-pipelines/WebGlMainRenderTargetRenderPipeline.d.ts +8 -0
  100. package/dist/webgl/render-pipelines/WebGlMainRenderTargetRenderPipeline.d.ts.map +1 -1
  101. package/dist/webgl/texture/WebGlTexture2D.d.ts +3 -2
  102. package/dist/webgl/texture/WebGlTexture2D.d.ts.map +1 -1
  103. package/dist/webgl/texture/WebGlTextureFactory.d.ts +2 -9
  104. package/dist/webgl/texture/WebGlTextureFactory.d.ts.map +1 -1
  105. package/dist/webgl/utilities/WebGlErrorUtilities.d.ts.map +1 -1
  106. package/dist/webgl/utilities/WebGlTextureUtilities.d.ts.map +1 -1
  107. package/dist/webgpu/WebGpuGraphicsDevice.d.ts +2 -2
  108. package/dist/webgpu/WebGpuGraphicsDevice.d.ts.map +1 -1
  109. package/dist/webgpu/primitive/WebGpuPrimitiveState.d.ts +2 -2
  110. package/dist/webgpu/primitive/WebGpuPrimitiveState.d.ts.map +1 -1
  111. package/dist/webgpu/render-pipelines/WebGpuMainRenderTargetRenderPipeline.d.ts +5 -0
  112. package/dist/webgpu/render-pipelines/WebGpuMainRenderTargetRenderPipeline.d.ts.map +1 -1
  113. package/dist/webgpu/texture/WebGpuTexture2D.d.ts +3 -2
  114. package/dist/webgpu/texture/WebGpuTexture2D.d.ts.map +1 -1
  115. package/dist/webgpu/texture/WebGpuTextureFactory.d.ts +2 -2
  116. package/dist/webgpu/texture/WebGpuTextureFactory.d.ts.map +1 -1
  117. package/package.json +2 -2
  118. package/src/Framework.ts +2 -2
  119. package/src/api/IFramework.ts +3 -3
  120. package/src/api/_export.ts +3 -0
  121. package/src/api/camera/CameraTransformUtilities.ts +182 -0
  122. package/src/api/camera/ICamera.ts +42 -2
  123. package/src/api/camera/OrbitCamera.ts +71 -38
  124. package/src/api/camera/OrthographicCamera.ts +71 -28
  125. package/src/api/camera/PerspectiveCamera.ts +69 -33
  126. package/src/api/content/ContentManager.ts +18 -12
  127. package/src/api/content/IContentManager.ts +2 -2
  128. package/src/api/lights/AmbientLight.ts +8 -2
  129. package/src/api/lights/DirectionalLight.ts +30 -5
  130. package/src/api/lights/ILight.ts +22 -0
  131. package/src/api/lights/PointLight.ts +26 -5
  132. package/src/api/lights/_export.ts +1 -0
  133. package/src/api/material/ForwardBlinnPhongMaterial.ts +2 -2
  134. package/src/api/material/IMaterial.ts +8 -0
  135. package/src/api/material/IMaterialFactory.ts +3 -2
  136. package/src/api/material/IUnlitMaterialDescriptor.ts +18 -0
  137. package/src/api/material/MaterialFactory.ts +4 -3
  138. package/src/api/material/SpriteMaterial.ts +4 -0
  139. package/src/api/material/UnlitMaterial.ts +11 -18
  140. package/src/api/material/_export.ts +1 -1
  141. package/src/api/meshes/IRenderableMesh.ts +3 -18
  142. package/src/api/meshes/RenderableMesh.ts +15 -45
  143. package/src/api/rendering/IGraphicsDevice.ts +2 -2
  144. package/src/api/rendering/IRenderer.ts +14 -6
  145. package/src/api/rendering/_export-rendering.ts +2 -1
  146. package/src/api/rendering/enums.ts +5 -5
  147. package/src/api/rendering/primitive/IPrimitiveStateDescriptor.ts +27 -0
  148. package/src/api/rendering/primitive/_export.ts +1 -1
  149. package/src/api/rendering/render-pipelines/IMainRenderTargetRenderPipeline.ts +6 -0
  150. package/src/api/rendering/texture/ITextureDescriptor.ts +62 -0
  151. package/src/api/rendering/texture/ITextureFactory.ts +5 -3
  152. package/src/api/rendering/texture/TextureUtilities.ts +59 -61
  153. package/src/api/rendering/texture/_export-texture.ts +1 -1
  154. package/src/api/scene/ISceneObject.ts +13 -0
  155. package/src/api/scene/Scene.ts +52 -11
  156. package/src/api/scene/node/Node.ts +54 -0
  157. package/src/api/scene/node/TransformNode.ts +88 -0
  158. package/src/core/material/UnlitMaterialDescriptorUtilities.ts +21 -0
  159. package/src/core/rendering/AGraphicsDevice.ts +2 -2
  160. package/src/core/rendering/ARenderer.ts +26 -4
  161. package/src/core/rendering/primitive/PrimitiveStateDescriptorUtilities.ts +22 -0
  162. package/src/core/rendering/texture/TextureDescriptorUtilities.ts +28 -0
  163. package/src/core/rendering/texture/texture.ts +2 -2
  164. package/src/main.ts +5 -4
  165. package/src/webgl/WebGlGraphicsDevice.ts +2 -3
  166. package/src/webgl/lights/WebGlLightsBuffer.ts +21 -8
  167. package/src/webgl/primitive/WebGlPrimitiveState.ts +8 -6
  168. package/src/webgl/render-pipelines/WebGlMainRenderTargetRenderPipeline.ts +14 -0
  169. package/src/webgl/texture/WebGlTexture2D.ts +9 -8
  170. package/src/webgl/texture/WebGlTextureFactory.ts +62 -65
  171. package/src/webgl/utilities/WebGlErrorUtilities.ts +3 -2
  172. package/src/webgl/utilities/WebGlTextureUtilities.ts +10 -4
  173. package/src/webgpu/WebGpuGraphicsDevice.ts +3 -3
  174. package/src/webgpu/primitive/WebGpuPrimitiveState.ts +7 -5
  175. package/src/webgpu/render-pipelines/WebGpuMainRenderTargetRenderPipeline.ts +6 -0
  176. package/src/webgpu/texture/WebGpuTexture2D.ts +10 -9
  177. package/src/webgpu/texture/WebGpuTextureFactory.ts +20 -17
  178. package/dist/api/material/ICameraMaterial.d.ts +0 -18
  179. package/dist/api/material/ICameraMaterial.d.ts.map +0 -1
  180. package/dist/api/rendering/primitive/PrimitiveStateDescriptor.d.ts +0 -24
  181. package/dist/api/rendering/primitive/PrimitiveStateDescriptor.d.ts.map +0 -1
  182. package/dist/api/rendering/texture/TextureDescriptor.d.ts +0 -42
  183. package/dist/api/rendering/texture/TextureDescriptor.d.ts.map +0 -1
  184. package/src/api/material/ICameraMaterial.ts +0 -22
  185. package/src/api/rendering/primitive/PrimitiveStateDescriptor.ts +0 -27
  186. package/src/api/rendering/texture/TextureDescriptor.ts +0 -52
@@ -1,5 +1,6 @@
1
1
  import type { IRenderPipeline } from "./IRenderPipeline.ts";
2
2
  import type { ITexture2D } from "../texture/ITexture2D.ts";
3
+ import type {ColorSpace} from "../enums.ts";
3
4
 
4
5
  /**
5
6
  * Pipeline that is used in renderer as
@@ -13,6 +14,11 @@ export interface IMainRenderTargetRenderPipeline extends IRenderPipeline {
13
14
  */
14
15
  readonly mainRenderTarget: ITexture2D;
15
16
 
17
+ /**
18
+ * Gets or sets the preferred color space. Only relevant for WebGL2 renderer.
19
+ */
20
+ colorSpace: ColorSpace;
21
+
16
22
  /**
17
23
  * Render to the screen.
18
24
  */
@@ -0,0 +1,62 @@
1
+ import type {TextureFormat} from "./TextureFormat.ts";
2
+ import type {TextureUsage} from "./TextureUsage.ts";
3
+ import type {vec2} from "gl-matrix";
4
+ import type {ColorSpace} from "../enums.ts";
5
+
6
+ /**
7
+ * The texture descriptor. Every field is optional; factories fill in the defaults for missing fields.
8
+ */
9
+ export interface ITextureDescriptor {
10
+
11
+ /**
12
+ * The texture width.
13
+ * By default, it is 0.
14
+ */
15
+ width?: number;
16
+
17
+ /**
18
+ * The texture height.
19
+ * By default, it is 0.
20
+ */
21
+ height?: number;
22
+
23
+ /**
24
+ * The texture format. When loading texture preferred format can be set.
25
+ * This overrides framework preferred color space when loading or ktx2 transcoding.
26
+ * By default, it is UNDEFINED.
27
+ */
28
+ textureFormat?: TextureFormat;
29
+
30
+ /** The preferred color space. If not defined, it is specified by framework. */
31
+ preferredColorSpace?: ColorSpace;
32
+
33
+ /**
34
+ * The texture usage.
35
+ * By default, it is TEXTURE_BINDING | COPY_DST.
36
+ */
37
+ textureUsage?: TextureUsage;
38
+
39
+ /**
40
+ * The texture label.
41
+ * By default, it is null.
42
+ */
43
+ label?: string | null;
44
+
45
+ /**
46
+ * The data per mip level.
47
+ * By default, it is undefined.
48
+ */
49
+ data?: Uint8Array[];
50
+
51
+ /**
52
+ * Should mipmaps be generated.
53
+ * By default, it is false.
54
+ */
55
+ generateMipmaps?: boolean;
56
+
57
+ /**
58
+ * The block size of a texture, which must be set for compressed textures.
59
+ * By default, it is undefined.
60
+ */
61
+ blockSize?: vec2;
62
+ }
@@ -2,7 +2,7 @@ import {Color} from "../../data/Color.ts";
2
2
  import {TextureUsage} from "./TextureUsage.ts";
3
3
  import {TextureFormat} from "./TextureFormat.ts";
4
4
  import type { ITexture2D } from "./ITexture2D.ts";
5
- import {TextureDescriptor} from "./TextureDescriptor.ts";
5
+ import type {ITextureDescriptor} from "./ITextureDescriptor.ts";
6
6
  import type {IKtx2Texture} from "ris-ktx2";
7
7
 
8
8
  /**
@@ -34,7 +34,9 @@ export interface ITextureFactory {
34
34
  * @param channels - The number of channels.
35
35
  * @param label - The label.
36
36
  * @param usage - Texture usage. By default, it is COPY_DST | TEXTURE_BINDING.
37
- * @param textureFormat - The texture format. By default, it is undefined. If so, the preferred texture format is used.
37
+ * @param textureFormat - The texture format. By default (or when UNDEFINED), the renderer's current
38
+ * {@link IRenderer.preferredTextureFormat} is used, so it follows {@link IRenderer.colorSpace}.
39
+ * Pass {@link TextureFormat.RGBA_8_UNORM} explicitly for raw data that must stay linear.
38
40
  * @param generateMipMaps - Indicates if texture should generate mipmap levels.
39
41
  * @returns The texture.
40
42
  */
@@ -52,5 +54,5 @@ export interface ITextureFactory {
52
54
  * @param descriptor - The optional texture descriptor.
53
55
  * @returns The 2D texture.
54
56
  */
55
- createFromKtx2(ktxTexture: IKtx2Texture, descriptor?: TextureDescriptor): ITexture2D;
57
+ createFromKtx2(ktxTexture: IKtx2Texture, descriptor?: ITextureDescriptor): ITexture2D;
56
58
  }
@@ -195,6 +195,7 @@ export class TextureUtilities {
195
195
  [TextureFormat.BC7_RGBA_UNORM]: KtxTranscodeFormat.BC7_RGBA,
196
196
  [TextureFormat.ETC2_RGBA8_UNORM]: KtxTranscodeFormat.ETC2_RGBA,
197
197
  [TextureFormat.PVRTC_4BPPV1_RGBA] : KtxTranscodeFormat.PVRTC1_4_RGBA,
198
+ [TextureFormat.PVRTC_4BPPV1_RGB] : KtxTranscodeFormat.PVRTC1_4_RGB,
198
199
  // Basis transcodes to the same blocks for sRGB; only the GPU format differs.
199
200
  [TextureFormat.RGBA_8_UNORM_SRGB]: KtxTranscodeFormat.RGBA32,
200
201
  [TextureFormat.ASTC_4X4_RGBA_SRGB]: KtxTranscodeFormat.ASTC_4X4_RGBA,
@@ -204,77 +205,33 @@ export class TextureUtilities {
204
205
  };
205
206
 
206
207
  private static readonly _mapKtxTranscodeFormatVkFormat: { [key: number]: number } = {
207
- [KtxTranscodeFormat.KTX_TTF_ETC1_RGB]: VkFormat.ETC2_R8G8B8_UNORM_BLOCK,
208
+ [KtxTranscodeFormat.ETC1_RGB]: VkFormat.ETC2_R8G8B8_UNORM_BLOCK,
208
209
  [KtxTranscodeFormat.ETC2_RGBA]: VkFormat.ETC2_R8G8B8A8_UNORM_BLOCK,
209
- [KtxTranscodeFormat.KTX_TTF_BC1_RGB]: VkFormat.BC1_RGB_UNORM_BLOCK,
210
+ [KtxTranscodeFormat.BC1_RGB]: VkFormat.BC1_RGB_UNORM_BLOCK,
210
211
  [KtxTranscodeFormat.BC3_RGBA]: VkFormat.BC3_UNORM_BLOCK,
211
- [KtxTranscodeFormat.KTX_TTF_BC4_R]: VkFormat.BC4_UNORM_BLOCK,
212
- [KtxTranscodeFormat.KTX_TTF_BC5_RG]: VkFormat.BC5_UNORM_BLOCK,
212
+ [KtxTranscodeFormat.BC4_R]: VkFormat.BC4_UNORM_BLOCK,
213
+ [KtxTranscodeFormat.BC5_RG]: VkFormat.BC5_UNORM_BLOCK,
213
214
  [KtxTranscodeFormat.BC7_RGBA]: VkFormat.BC7_UNORM_BLOCK,
214
- [KtxTranscodeFormat.KTX_TTF_PVRTC1_4_RGB]: VkFormat.PVRTC1_4BPP_UNORM_BLOCK_IMG,
215
+ [KtxTranscodeFormat.PVRTC1_4_RGB]: VkFormat.PVRTC1_4BPP_UNORM_BLOCK_IMG,
215
216
  [KtxTranscodeFormat.PVRTC1_4_RGBA]: VkFormat.PVRTC1_4BPP_UNORM_BLOCK_IMG,
216
217
  [KtxTranscodeFormat.ASTC_4X4_RGBA]: VkFormat.ASTC_4X4_UNORM_BLOCK,
217
218
  [KtxTranscodeFormat.RGBA32]: VkFormat.R8G8B8A8_UNORM,
218
- [KtxTranscodeFormat.KTX_TTF_RGB565]: VkFormat.R5G6B5_UNORM_PACK16,
219
- [KtxTranscodeFormat.KTX_TTF_BGR565]: VkFormat.B5G6R5_UNORM_PACK16,
220
- [KtxTranscodeFormat.KTX_TTF_RGBA4444]: VkFormat.R4G4B4A4_UNORM_PACK16,
221
- [KtxTranscodeFormat.KTX_TTF_PVRTC2_4_RGB]: VkFormat.PVRTC2_4BPP_UNORM_BLOCK_IMG,
219
+ [KtxTranscodeFormat.RGB565]: VkFormat.R5G6B5_UNORM_PACK16,
220
+ [KtxTranscodeFormat.BGR565]: VkFormat.B5G6R5_UNORM_PACK16,
221
+ [KtxTranscodeFormat.RGBA4444]: VkFormat.R4G4B4A4_UNORM_PACK16,
222
+ [KtxTranscodeFormat.PVRTC2_4_RGB]: VkFormat.PVRTC2_4BPP_UNORM_BLOCK_IMG,
222
223
  [KtxTranscodeFormat.PVRTC2_4_RGBA]: VkFormat.PVRTC2_4BPP_UNORM_BLOCK_IMG,
223
- [KtxTranscodeFormat.KTX_TTF_ETC2_EAC_R11]: VkFormat.EAC_R11_UNORM_BLOCK,
224
- [KtxTranscodeFormat.KTX_TTF_ETC2_EAC_RG11]: VkFormat.EAC_R11G11_UNORM_BLOCK,
224
+ [KtxTranscodeFormat.ETC2_EAC_R11]: VkFormat.EAC_R11_UNORM_BLOCK,
225
+ [KtxTranscodeFormat.ETC2_EAC_RG11]: VkFormat.EAC_R11G11_UNORM_BLOCK,
225
226
  };
226
227
 
227
- /**
228
- * Whether the format stores sRGB-encoded colour (sampled as linear by the GPU).
229
- * @param format The texture format.
230
- */
231
- public static isSrgbFormat(format: TextureFormat): boolean {
232
- return format.endsWith("_SRGB");
233
- }
228
+ /** sRGB format → its linear variant. */
229
+ private static readonly _linearVariant: { [key: string]: TextureFormat } = Object.fromEntries(
230
+ Object.entries(TextureUtilities._srgbVariant).map(([linear, srgb]) => [srgb, linear as TextureFormat])
231
+ );
234
232
 
235
- /**
236
- * Gets the sRGB variant of a linear format, or the format itself if it has none or is already sRGB.
237
- * @param format The texture format.
238
- */
239
- public static toSrgbFormat(format: TextureFormat): TextureFormat {
240
- return this._srgbVariant[format] ?? format;
241
- }
242
-
243
- /**
244
- * Gets the linear variant of an sRGB format, or the format itself.
245
- * @param format The texture format.
246
- */
247
- public static toLinearFormat(format: TextureFormat): TextureFormat {
248
- for (const linear in this._srgbVariant) {
249
- if (this._srgbVariant[linear] === format) return linear as TextureFormat;
250
- }
251
- return format;
252
- }
253
-
254
- /**
255
- * Gets the block size (width, height) of a format: 1x1 for uncompressed, 4x4 for BC/ETC2, and the ASTC block.
256
- * Returns null for formats it does not know.
257
- * @param format The texture format.
258
- */
259
- public static getBlockSize(format: TextureFormat): [number, number] | null {
260
- if (!this.isCompressedTextureFormat(format)) {
261
- return [1, 1];
262
- }
263
- const astc = /^ASTC_(\d+)X(\d+)_/.exec(format);
264
- if (astc) {
265
- return [Number(astc[1]), Number(astc[2])];
266
- }
267
- if (format.startsWith("BC") || format.startsWith("ETC2")) {
268
- return [4, 4];
269
- }
270
- if (format.startsWith("PVRTC_2BPP")) {
271
- return [8, 4];
272
- }
273
- if (format.startsWith("PVRTC_4BPP")) {
274
- return [4, 4];
275
- }
276
- return null;
277
- }
233
+ /** Every sRGB format. */
234
+ private static readonly _srgbFormats: TextureFormat[] = Object.values(TextureUtilities._srgbVariant);
278
235
 
279
236
  /**
280
237
  * Checks if the given texture format is a compressed texture format.
@@ -361,4 +318,45 @@ export class TextureUtilities {
361
318
  return format;
362
319
  }
363
320
 
321
+ /**
322
+ * Maps the linear format to the srgb variant.
323
+ * @param textureFormat The linear format.
324
+ * @return The srgb variant, or the format itself if it is already sRGB or has no sRGB variant (e.g. PVRTC).
325
+ */
326
+ public static convertToSrgbVariant(textureFormat: TextureFormat) : TextureFormat {
327
+ return this._srgbVariant[textureFormat] ?? textureFormat;
328
+ }
329
+
330
+ /**
331
+ * Maps the srgb format to the linear variant.
332
+ * @param textureFormat The srgb format.
333
+ * @return The linear variant, or the format itself if it is already linear.
334
+ */
335
+ public static convertToLinearVariant(textureFormat: TextureFormat) : TextureFormat {
336
+ return this._linearVariant[textureFormat] ?? textureFormat;
337
+ }
338
+
339
+ /**
340
+ * Checks whether the texture format is an sRGB format.
341
+ * @param textureFormat The texture format to check.
342
+ * @return True if srgb texture format.
343
+ */
344
+ public static isSrgbFormat(textureFormat: TextureFormat) : boolean {
345
+ return this._srgbFormats.includes(textureFormat);
346
+ }
347
+
348
+ /**
349
+ * Returns the requested format if it is the file's format or its sRGB/linear variant.
350
+ * @param fileFormat The format the data is stored in.
351
+ * @param requested The explicitly requested format.
352
+ * @throws If the requested format cannot reinterpret the data.
353
+ */
354
+ public static resolveExplicitFormat(fileFormat: TextureFormat, requested: TextureFormat): TextureFormat {
355
+ if (requested == fileFormat
356
+ || requested == TextureUtilities.convertToSrgbVariant(fileFormat)
357
+ || requested == TextureUtilities.convertToLinearVariant(fileFormat)) {
358
+ return requested;
359
+ }
360
+ throw new Error(`Texture format ${requested} is not compatible with the file's format ${fileFormat}; only its sRGB or linear variant can be used.`);
361
+ }
364
362
  }
@@ -5,5 +5,5 @@ export * from "./TextureViewDimension.ts";
5
5
  export * from "./TextureFormat.ts";
6
6
  export * from "./ITextureView.ts";
7
7
  export * from "./ITextureFactory.ts";
8
- export * from "./TextureDescriptor.ts";
8
+ export * from "./ITextureDescriptor.ts";
9
9
  export * from "./TextureUtilities.ts";
@@ -0,0 +1,13 @@
1
+ import type {TransformNode} from "./node/TransformNode.ts";
2
+
3
+ /**
4
+ * An object that can be placed in a scene: it has a transform.
5
+ * @public
6
+ */
7
+ export interface ISceneObject {
8
+
9
+ /**
10
+ * The transform node.
11
+ */
12
+ transform: TransformNode;
13
+ }
@@ -5,13 +5,14 @@ import type {IDisposable} from "../core/IDisposable.ts";
5
5
  import type {IFramework} from "../IFramework.ts";
6
6
  import type {IRenderableMesh} from "../meshes/IRenderableMesh.ts";
7
7
  import {SceneMesh} from "./SceneMesh.ts";
8
- import {isCameraMaterial} from "../material/ICameraMaterial.ts";
9
8
  import {isLightsMaterial} from "../material/ILightsMaterial.ts";
10
9
  import type {GameTime} from "../time/GameTime.ts";
11
10
  import type {ICamera} from "../camera/ICamera.ts";
11
+ import type {ISceneObject} from "./ISceneObject.ts";
12
+ import {TransformNode} from "./node/TransformNode.ts";
12
13
 
13
- /** Anything a scene can hold: a mesh, a light (ambient, directional, point) or a camera. */
14
- export type SceneItem = IRenderableMesh | SceneMesh | AmbientLight | DirectionalLight | PointLight | ICamera;
14
+ /** Anything a scene can hold: a mesh, a scene object, a light (ambient, directional, point) or a camera. */
15
+ export type SceneItem = IRenderableMesh | SceneMesh | ISceneObject | AmbientLight | DirectionalLight | PointLight | ICamera;
15
16
 
16
17
  /**
17
18
  * The scene. Lights and cameras given a scene in their constructor add themselves through {@link add};
@@ -22,6 +23,7 @@ export type SceneItem = IRenderableMesh | SceneMesh | AmbientLight | Directional
22
23
  export class Scene implements IDisposable {
23
24
 
24
25
  private readonly _sceneMeshes: SceneMesh[] = [];
26
+ private readonly _nodes: ISceneObject[] = [];
25
27
  private readonly _directionalLights: DirectionalLight[] = [];
26
28
  private readonly _pointLights: PointLight[] = [];
27
29
 
@@ -71,6 +73,11 @@ export class Scene implements IDisposable {
71
73
  return this._sceneMeshes;
72
74
  }
73
75
 
76
+ /** The scene objects (anything with a transform, including root meshes), in the order they were added. */
77
+ public get nodes(): readonly ISceneObject[] {
78
+ return this._nodes;
79
+ }
80
+
74
81
  /** The root meshes in this scene, in the order they were added. */
75
82
  public get meshes(): readonly IRenderableMesh[] {
76
83
  return this._sceneMeshes.map(s => s.mesh);
@@ -103,9 +110,13 @@ export class Scene implements IDisposable {
103
110
  * Adds a mesh, a light or a camera. Adding an item that is already in the scene does nothing.
104
111
  * - Renderable mesh or {@link SceneMesh}: drawn by {@link render}; its materials get the scene camera and lights.
105
112
  * A mesh is wrapped in a `SceneMesh`, so {@link dispose} also disposes its materials.
106
- * - Ambient light: added to {@link ambientLights} (use {@link activeAmbientLight} to make it the lit one).
113
+ * The mesh is also added to {@link nodes}.
114
+ * - {@link ISceneObject} (anything with a `transform`): added to {@link nodes}; {@link update} updates its transform.
115
+ * - Lights are also added to {@link nodes} (they are scene objects).
116
+ * - Ambient light: added to {@link ambientLights} (use {@link activeAmbientLight} to make it the lit one).
107
117
  * - Directional / point light: added to {@link directionalLights} / {@link pointLights}.
108
- * - Camera: becomes the scene {@link camera}.
118
+ * - Camera: becomes the scene {@link camera} and is added to {@link nodes} (cameras are scene objects).
119
+ * Checked before the generic scene object case.
109
120
  * Constructors given a scene (lights, the perspective camera) call this themselves.
110
121
  * @param item The item to add.
111
122
  * @throws Error when all slots for a light kind are in use (3 directional, 5 point), or for an unsupported item.
@@ -113,10 +124,15 @@ export class Scene implements IDisposable {
113
124
  public add(item: SceneItem): void {
114
125
  if (item instanceof AmbientLight) {
115
126
  this._addAmbientLight(item);
127
+ this._addNode(item);
116
128
  } else if (item instanceof DirectionalLight || item instanceof PointLight) {
117
129
  this._addLight(item);
130
+ this._addNode(item);
118
131
  } else if (Scene._isCamera(item)) {
119
132
  this.camera = item;
133
+ if (Scene._isSceneObject(item)) {
134
+ this._addNode(item);
135
+ }
120
136
  } else if (item instanceof SceneMesh || Scene._isMesh(item)) {
121
137
  const mesh = item instanceof SceneMesh ? item.mesh : item;
122
138
  if (!this._sceneMeshes.some(s => s.mesh === mesh)) {
@@ -124,8 +140,11 @@ export class Scene implements IDisposable {
124
140
  this._sceneMeshes.push(sceneMesh);
125
141
  this._bind(sceneMesh);
126
142
  }
143
+ this._addNode(mesh);
144
+ } else if (Scene._isSceneObject(item)) {
145
+ this._addNode(item);
127
146
  } else {
128
- throw new Error("Scene.add: expected a mesh, an AmbientLight, DirectionalLight, PointLight or a camera.");
147
+ throw new Error("Scene.add: expected a mesh, a scene object, an AmbientLight, DirectionalLight, PointLight or a camera.");
129
148
  }
130
149
  }
131
150
 
@@ -133,7 +152,7 @@ export class Scene implements IDisposable {
133
152
  * Removes a mesh (or scene mesh), a light or a camera. The mesh and its materials are not disposed.
134
153
  * Removing the active camera clears {@link camera}.
135
154
  * @param item The item to remove.
136
- * @returns True when the item was in the scene (for a camera: was the active camera).
155
+ * @returns True when the item was in the scene.
137
156
  * @throws Error when removing the active ambient light (set another {@link activeAmbientLight} first), or for an unsupported item.
138
157
  */
139
158
  public remove(item: SceneItem): boolean {
@@ -141,16 +160,19 @@ export class Scene implements IDisposable {
141
160
  if (item === this._activeAmbientLight) {
142
161
  throw new Error("Scene.remove: cannot remove the active ambient light; set scene.activeAmbientLight to another light first.");
143
162
  }
163
+ Scene._removeFrom(this._nodes, item);
144
164
  return Scene._removeFrom(this.ambientLights, item);
145
165
  }
146
166
  if (item instanceof DirectionalLight || item instanceof PointLight) {
167
+ Scene._removeFrom(this._nodes, item);
147
168
  return item instanceof DirectionalLight
148
169
  ? Scene._removeFrom(this._directionalLights, item)
149
170
  : Scene._removeFrom(this._pointLights, item);
150
171
  }
151
172
  if (Scene._isCamera(item)) {
173
+ const wasNode = Scene._removeFrom(this._nodes, item);
152
174
  if (item !== this._activeCamera) {
153
- return false;
175
+ return wasNode;
154
176
  }
155
177
  this._activeCamera = undefined;
156
178
  return true;
@@ -158,13 +180,17 @@ export class Scene implements IDisposable {
158
180
  if (item instanceof SceneMesh || Scene._isMesh(item)) {
159
181
  const mesh = item instanceof SceneMesh ? item.mesh : item;
160
182
  const index = this._sceneMeshes.findIndex(s => s.mesh === mesh);
183
+ Scene._removeFrom(this._nodes, mesh);
161
184
  if (index < 0) {
162
185
  return false;
163
186
  }
164
187
  this._sceneMeshes.splice(index, 1);
165
188
  return true;
166
189
  }
167
- throw new Error("Scene.remove: expected a mesh, an AmbientLight, DirectionalLight, PointLight or a camera.");
190
+ if (Scene._isSceneObject(item)) {
191
+ return Scene._removeFrom(this._nodes, item);
192
+ }
193
+ throw new Error("Scene.remove: expected a mesh, a scene object, an AmbientLight, DirectionalLight, PointLight or a camera.");
168
194
  }
169
195
 
170
196
  /**
@@ -220,6 +246,17 @@ export class Scene implements IDisposable {
220
246
  && "projectionViewBuffer" in camera && "viewMatrix" in camera && typeof camera.updateBuffers === "function";
221
247
  }
222
248
 
249
+ /** Scene objects have a TransformNode as transform. */
250
+ private static _isSceneObject(item: unknown): item is ISceneObject {
251
+ return typeof item === "object" && item !== null && (item as Partial<ISceneObject>).transform instanceof TransformNode;
252
+ }
253
+
254
+ private _addNode(node: ISceneObject): void {
255
+ if (!this._nodes.includes(node)) {
256
+ this._nodes.push(node);
257
+ }
258
+ }
259
+
223
260
  /** Renderable meshes have render() and sub meshes. */
224
261
  private static _isMesh(item: unknown): item is IRenderableMesh {
225
262
  const mesh = item as Partial<IRenderableMesh> | null;
@@ -227,12 +264,15 @@ export class Scene implements IDisposable {
227
264
  }
228
265
 
229
266
  /**
230
- * Updates the scene: assigns {@link camera}, the active ambient light and the light lists to the mesh materials.
267
+ * Updates the scene: updates the transforms of {@link nodes}, assigns {@link camera}, the active ambient light and the light lists to the mesh materials.
231
268
  * Each lights material uploads its lights buffer when drawn, only if the lights changed.
232
269
  * @param _time The game time.
233
270
  * @public
234
271
  */
235
272
  update(_time: GameTime): void {
273
+ for (const node of this._nodes) {
274
+ node.transform.update(_time);
275
+ }
236
276
  for (const sceneMesh of this._sceneMeshes) {
237
277
  this._bind(sceneMesh);
238
278
  }
@@ -266,7 +306,7 @@ export class Scene implements IDisposable {
266
306
  }
267
307
  for (const material of sceneMesh.materials) {
268
308
  // The setter rebinds buffers, so skip when unchanged.
269
- if (isCameraMaterial(material) && material.camera !== camera) {
309
+ if (material.camera !== camera) {
270
310
  material.camera = camera;
271
311
  }
272
312
  }
@@ -293,5 +333,6 @@ export class Scene implements IDisposable {
293
333
  sceneMesh.dispose();
294
334
  }
295
335
  this._sceneMeshes.length = 0;
336
+ this._nodes.length = 0;
296
337
  }
297
338
  }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * A node in a hierarchy. A node has at most one parent; use {@link addChild} and {@link removeChild}
3
+ * to change the hierarchy (they keep `parent` and `children` in sync).
4
+ * @public
5
+ */
6
+ export class Node {
7
+
8
+ private readonly _children: Node[] = [];
9
+ private _parent?: Node;
10
+
11
+ /** The child nodes of this node. */
12
+ public get children(): readonly Node[] {
13
+ return this._children;
14
+ }
15
+
16
+ /** The parent node of this node, if any. */
17
+ public get parent(): Node | undefined {
18
+ return this._parent;
19
+ }
20
+
21
+ /**
22
+ * Adds a child. It is removed from its previous parent first. Adding an existing child does nothing.
23
+ * @param child The child to add.
24
+ * @throws Error when adding the node to itself or to one of its descendants.
25
+ */
26
+ public addChild(child: Node): void {
27
+ if (child._parent === this) {
28
+ return;
29
+ }
30
+ for (let n: Node | undefined = this; n; n = n._parent) {
31
+ if (n === child) {
32
+ throw new Error("Node.addChild: a node cannot be added to itself or to one of its descendants.");
33
+ }
34
+ }
35
+ child._parent?.removeChild(child);
36
+ child._parent = this;
37
+ this._children.push(child);
38
+ }
39
+
40
+ /**
41
+ * Removes a child.
42
+ * @param child The child to remove.
43
+ * @returns True when it was a child of this node.
44
+ */
45
+ public removeChild(child: Node): boolean {
46
+ const index = this._children.indexOf(child);
47
+ if (index < 0) {
48
+ return false;
49
+ }
50
+ this._children.splice(index, 1);
51
+ child._parent = undefined;
52
+ return true;
53
+ }
54
+ }
@@ -0,0 +1,88 @@
1
+ import {mat4, quat, vec3} from "gl-matrix";
2
+ import type {GameTime} from "../../time/GameTime.ts";
3
+ import {Node} from "./Node.ts";
4
+
5
+ /**
6
+ * The node responsible for transformations in the world.
7
+ *
8
+ * The matrices are computed lazily: reading {@link modelMatrix} recomputes them when position, rotation or scale
9
+ * changed (also through in-place edits), so {@link update} does not have to be called before the first render.
10
+ * When the parent is a `TransformNode`, {@link modelMatrix} is the world matrix `parent.modelMatrix * localMatrix`.
11
+ * @public
12
+ */
13
+ export class TransformNode extends Node {
14
+
15
+ private readonly _rotationQuat = quat.create();
16
+ private readonly _localMatrix = mat4.create();
17
+ private readonly _worldMatrix = mat4.create();
18
+ // Cached copies to detect in-place edits; NaN forces the first computation.
19
+ private readonly _lastPosition = vec3.fromValues(NaN, NaN, NaN);
20
+ private readonly _lastRotation = vec3.create();
21
+ private readonly _lastScale = vec3.create();
22
+
23
+ /**
24
+ * The constructor.
25
+ */
26
+ public constructor() {
27
+ super();
28
+
29
+ this.position = vec3.fromValues(0, 0, 0);
30
+ this.rotation = vec3.fromValues(0, 0, 0);
31
+ this.scale = vec3.fromValues(1, 1, 1);
32
+ }
33
+
34
+ /** Position relative to the parent (the world, without one). Defaults to the origin. In-place edits are detected. */
35
+ public position: vec3;
36
+
37
+ /**
38
+ * Euler rotation in radians, applied in Y, X, Z order (yaw, pitch, roll): `R = Ry * Rx * Rz`.
39
+ * Defaults to (0, 0, 0). In-place edits are detected.
40
+ */
41
+ public rotation: vec3;
42
+
43
+ /** Scale. Defaults to (1, 1, 1). In-place edits are detected. */
44
+ public scale: vec3;
45
+
46
+ /** The local matrix `T * R * S`, recomputed only when position, rotation or scale changed. */
47
+ public get localMatrix(): mat4 {
48
+ if (!vec3.exactEquals(this._lastPosition, this.position)
49
+ || !vec3.exactEquals(this._lastRotation, this.rotation)
50
+ || !vec3.exactEquals(this._lastScale, this.scale)) {
51
+ vec3.copy(this._lastPosition, this.position);
52
+ vec3.copy(this._lastRotation, this.rotation);
53
+ vec3.copy(this._lastScale, this.scale);
54
+ const q = quat.identity(this._rotationQuat);
55
+ quat.rotateY(q, q, this.rotation[1]);
56
+ quat.rotateX(q, q, this.rotation[0]);
57
+ quat.rotateZ(q, q, this.rotation[2]);
58
+ mat4.fromRotationTranslationScale(this._localMatrix, q, this.position, this.scale);
59
+ }
60
+ return this._localMatrix;
61
+ }
62
+
63
+ /**
64
+ * The model (world) matrix: {@link localMatrix}, or `parent.modelMatrix * localMatrix` when the parent is a
65
+ * `TransformNode`. Always the same matrix object for a node without a parent transform.
66
+ */
67
+ public get modelMatrix(): mat4 {
68
+ const parent = this.parent;
69
+ if (parent instanceof TransformNode) {
70
+ return mat4.multiply(this._worldMatrix, parent.modelMatrix, this.localMatrix);
71
+ }
72
+ return this.localMatrix;
73
+ }
74
+
75
+ /**
76
+ * Updates the node and its transform children, recomputing the matrices if needed.
77
+ * Called by `Scene.update` for scene nodes; optional otherwise.
78
+ * @param gameTime The {@link GameTime}
79
+ */
80
+ public update(gameTime: GameTime): void {
81
+ void this.modelMatrix;
82
+ for (const child of this.children) {
83
+ if (child instanceof TransformNode) {
84
+ child.update(gameTime);
85
+ }
86
+ }
87
+ }
88
+ }
@@ -0,0 +1,21 @@
1
+ import type {IUnlitMaterialDescriptor} from "../../api/material/IUnlitMaterialDescriptor.ts";
2
+
3
+ /**
4
+ * An unlit material descriptor with every field present. `undefined` means "use the default":
5
+ * the pipeline's default primitive state, and no camera (a placeholder projection view buffer).
6
+ * @internal
7
+ */
8
+ export type ResolvedUnlitMaterialDescriptor = { [K in keyof Required<IUnlitMaterialDescriptor>]: IUnlitMaterialDescriptor[K] };
9
+
10
+ /**
11
+ * Fills in the defaults for every missing field of an unlit material descriptor.
12
+ * @param desc The descriptor, possibly partial or missing.
13
+ * @returns A new descriptor with the defaults applied.
14
+ * @internal
15
+ */
16
+ export function resolveUnlitMaterialDescriptor(desc?: IUnlitMaterialDescriptor): ResolvedUnlitMaterialDescriptor {
17
+ return {
18
+ primitiveState: desc?.primitiveState,
19
+ camera: desc?.camera,
20
+ };
21
+ }
@@ -8,7 +8,7 @@ import {
8
8
  type IBlendState,
9
9
  type IPrimitiveState,
10
10
  type IGraphicsDevice, SwapChainDescriptor, type RenderPassDescriptor, SamplerFilter, MipMapSamplerFilter,
11
- type ISwapChain, type IRenderPass, type PrimitiveStateDescriptor
11
+ type ISwapChain, type IRenderPass, type IPrimitiveStateDescriptor
12
12
  } from "../../api/index.ts";
13
13
  import {PowerPreferenceType} from "../../api/rendering/PowerPreference.ts";
14
14
 
@@ -103,7 +103,7 @@ export abstract class AGraphicsDevice implements IGraphicsDevice {
103
103
  public abstract createBlendState(descriptor: BlendStateDescriptor): IBlendState;
104
104
 
105
105
  /** @inheritdoc */
106
- public abstract createPrimitiveState(descriptor?: PrimitiveStateDescriptor ): IPrimitiveState;
106
+ public abstract createPrimitiveState(descriptor?: IPrimitiveStateDescriptor): IPrimitiveState;
107
107
 
108
108
  /** @inheritDoc */
109
109
  public abstract setupDebugCallback(): void;