ris-framework 0.1.0-dev.9 → 0.2.0-dev.11

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 (217) hide show
  1. package/CHANGELOG.md +49 -1
  2. package/README.md +15 -4
  3. package/dist/Framework.d.ts +9 -3
  4. package/dist/Framework.d.ts.map +1 -1
  5. package/dist/api/IFramework.d.ts +7 -6
  6. package/dist/api/IFramework.d.ts.map +1 -1
  7. package/dist/api/_export.d.ts +2 -0
  8. package/dist/api/_export.d.ts.map +1 -1
  9. package/dist/api/camera/CameraFactory.d.ts +3 -2
  10. package/dist/api/camera/CameraFactory.d.ts.map +1 -1
  11. package/dist/api/camera/ICamera.d.ts +5 -0
  12. package/dist/api/camera/ICamera.d.ts.map +1 -1
  13. package/dist/api/camera/ICameraFactory.d.ts +5 -6
  14. package/dist/api/camera/ICameraFactory.d.ts.map +1 -1
  15. package/dist/api/camera/OrthographicCamera.d.ts +7 -0
  16. package/dist/api/camera/OrthographicCamera.d.ts.map +1 -1
  17. package/dist/api/camera/PerspectiveCamera.d.ts +30 -6
  18. package/dist/api/camera/PerspectiveCamera.d.ts.map +1 -1
  19. package/dist/api/content/ContentManager.d.ts +67 -2
  20. package/dist/api/content/ContentManager.d.ts.map +1 -1
  21. package/dist/api/content/IContentManager.d.ts +32 -1
  22. package/dist/api/content/IContentManager.d.ts.map +1 -1
  23. package/dist/api/content/ShaderModuleContent.d.ts.map +1 -1
  24. package/dist/api/data/Color.d.ts +5 -0
  25. package/dist/api/data/Color.d.ts.map +1 -1
  26. package/dist/api/geometry/BaseGeometry.d.ts +9 -0
  27. package/dist/api/geometry/BaseGeometry.d.ts.map +1 -1
  28. package/dist/api/geometry/GeometryBuilder.d.ts +3 -1
  29. package/dist/api/geometry/GeometryBuilder.d.ts.map +1 -1
  30. package/dist/api/geometry/IGeometryBuilder.d.ts +24 -0
  31. package/dist/api/geometry/IGeometryBuilder.d.ts.map +1 -1
  32. package/dist/api/geometry/_export-geometry.d.ts +1 -0
  33. package/dist/api/geometry/_export-geometry.d.ts.map +1 -1
  34. package/dist/api/input/InputManager.d.ts +4 -0
  35. package/dist/api/input/InputManager.d.ts.map +1 -1
  36. package/dist/api/lights/AmbientLight.d.ts +35 -0
  37. package/dist/api/lights/AmbientLight.d.ts.map +1 -0
  38. package/dist/api/lights/DirectionalLight.d.ts +40 -0
  39. package/dist/api/lights/DirectionalLight.d.ts.map +1 -0
  40. package/dist/api/lights/LightFactory.d.ts +18 -0
  41. package/dist/api/lights/LightFactory.d.ts.map +1 -0
  42. package/dist/api/lights/LightId.d.ts +6 -0
  43. package/dist/api/lights/LightId.d.ts.map +1 -0
  44. package/dist/api/lights/LightsBuffer.d.ts +70 -0
  45. package/dist/api/lights/LightsBuffer.d.ts.map +1 -0
  46. package/dist/api/lights/PointLight.d.ts +59 -0
  47. package/dist/api/lights/PointLight.d.ts.map +1 -0
  48. package/dist/api/lights/_export.d.ts +6 -0
  49. package/dist/api/lights/_export.d.ts.map +1 -0
  50. package/dist/api/loaders/ObjGeometryMapper.d.ts +19 -0
  51. package/dist/api/loaders/ObjGeometryMapper.d.ts.map +1 -0
  52. package/dist/api/loaders/_export.d.ts +1 -0
  53. package/dist/api/loaders/_export.d.ts.map +1 -1
  54. package/dist/api/loaders/obj/ObjLoader.d.ts +29 -0
  55. package/dist/api/loaders/obj/ObjLoader.d.ts.map +1 -0
  56. package/dist/api/loaders/obj/ObjTypes.d.ts +103 -0
  57. package/dist/api/loaders/obj/ObjTypes.d.ts.map +1 -0
  58. package/dist/api/loaders/obj/index.d.ts +3 -0
  59. package/dist/api/loaders/obj/index.d.ts.map +1 -0
  60. package/dist/api/material/ForwardBlinnPhongMaterial.d.ts +127 -0
  61. package/dist/api/material/ForwardBlinnPhongMaterial.d.ts.map +1 -0
  62. package/dist/api/material/IMaterial.d.ts +15 -6
  63. package/dist/api/material/IMaterial.d.ts.map +1 -1
  64. package/dist/api/material/IMaterialFactory.d.ts +17 -2
  65. package/dist/api/material/IMaterialFactory.d.ts.map +1 -1
  66. package/dist/api/material/InspectTextureMipsMaterial.d.ts +16 -7
  67. package/dist/api/material/InspectTextureMipsMaterial.d.ts.map +1 -1
  68. package/dist/api/material/MaterialFactory.d.ts +6 -0
  69. package/dist/api/material/MaterialFactory.d.ts.map +1 -1
  70. package/dist/api/material/SpriteMaterial.d.ts +51 -0
  71. package/dist/api/material/SpriteMaterial.d.ts.map +1 -0
  72. package/dist/api/material/UnlitMaterial.d.ts +28 -10
  73. package/dist/api/material/UnlitMaterial.d.ts.map +1 -1
  74. package/dist/api/material/_export.d.ts +2 -0
  75. package/dist/api/material/_export.d.ts.map +1 -1
  76. package/dist/api/meshes/IMesh.d.ts +35 -5
  77. package/dist/api/meshes/IMesh.d.ts.map +1 -1
  78. package/dist/api/meshes/IMeshFactory.d.ts +25 -4
  79. package/dist/api/meshes/IMeshFactory.d.ts.map +1 -1
  80. package/dist/api/meshes/Mesh.d.ts +58 -6
  81. package/dist/api/meshes/Mesh.d.ts.map +1 -1
  82. package/dist/api/meshes/MeshFactory.d.ts +7 -3
  83. package/dist/api/meshes/MeshFactory.d.ts.map +1 -1
  84. package/dist/api/meshes/QuadMesh.d.ts +5 -1
  85. package/dist/api/meshes/QuadMesh.d.ts.map +1 -1
  86. package/dist/api/meshes/SubMesh.d.ts +47 -0
  87. package/dist/api/meshes/SubMesh.d.ts.map +1 -0
  88. package/dist/api/meshes/_export.d.ts +1 -0
  89. package/dist/api/meshes/_export.d.ts.map +1 -1
  90. package/dist/api/rendering/render-pipelines/IForwardBlinnPhongRenderPipeline.d.ts +56 -0
  91. package/dist/api/rendering/render-pipelines/IForwardBlinnPhongRenderPipeline.d.ts.map +1 -0
  92. package/dist/api/rendering/render-pipelines/IRenderPipeline.d.ts +3 -0
  93. package/dist/api/rendering/render-pipelines/IRenderPipeline.d.ts.map +1 -1
  94. package/dist/api/rendering/render-pipelines/IRenderPipelineFactory.d.ts +29 -0
  95. package/dist/api/rendering/render-pipelines/IRenderPipelineFactory.d.ts.map +1 -1
  96. package/dist/api/rendering/render-pipelines/_export-render-pipelines.d.ts +1 -0
  97. package/dist/api/rendering/render-pipelines/_export-render-pipelines.d.ts.map +1 -1
  98. package/dist/api/scene/Scene.d.ts +104 -0
  99. package/dist/api/scene/Scene.d.ts.map +1 -0
  100. package/dist/api/shader/IShaderModuleLoader.d.ts +4 -1
  101. package/dist/api/shader/IShaderModuleLoader.d.ts.map +1 -1
  102. package/dist/api/shader/{shader-loader.d.ts → ShaderLoader.d.ts} +1 -1
  103. package/dist/api/shader/ShaderLoader.d.ts.map +1 -0
  104. package/dist/api/sprites/SpriteBatchDrawable.d.ts +1 -1
  105. package/dist/api/sprites/SpriteBatchDrawable.d.ts.map +1 -1
  106. package/dist/api/sprites/SpriteBatchMesh.d.ts +14 -1
  107. package/dist/api/sprites/SpriteBatchMesh.d.ts.map +1 -1
  108. package/dist/api/utilities/GeometryUtilities.d.ts.map +1 -1
  109. package/dist/api/window/WindowManager.d.ts +4 -0
  110. package/dist/api/window/WindowManager.d.ts.map +1 -1
  111. package/dist/core/rendering/vertex-buffer-layout.d.ts +1 -0
  112. package/dist/core/rendering/vertex-buffer-layout.d.ts.map +1 -1
  113. package/dist/index.js +2252 -260
  114. package/dist/webgl/WebGlGraphicsDevice.d.ts.map +1 -1
  115. package/dist/webgl/lights/WebGlAmbientLightFactory.d.ts +17 -0
  116. package/dist/webgl/lights/WebGlAmbientLightFactory.d.ts.map +1 -0
  117. package/dist/webgl/lights/WebGlLightsBuffer.d.ts +55 -0
  118. package/dist/webgl/lights/WebGlLightsBuffer.d.ts.map +1 -0
  119. package/dist/webgl/render-pipelines/AWebGlRenderPipeline.d.ts +3 -1
  120. package/dist/webgl/render-pipelines/AWebGlRenderPipeline.d.ts.map +1 -1
  121. package/dist/webgl/render-pipelines/WebGlMainRenderTargetRenderPipeline.d.ts +3 -0
  122. package/dist/webgl/render-pipelines/WebGlMainRenderTargetRenderPipeline.d.ts.map +1 -1
  123. package/dist/webgl/render-pipelines/WebGlRenderPipelineFactory.d.ts +3 -1
  124. package/dist/webgl/render-pipelines/WebGlRenderPipelineFactory.d.ts.map +1 -1
  125. package/dist/webgl/render-pipelines/inspect/WebGlInspectTextureMipsRenderPipeline.d.ts +3 -1
  126. package/dist/webgl/render-pipelines/inspect/WebGlInspectTextureMipsRenderPipeline.d.ts.map +1 -1
  127. package/dist/webgl/render-pipelines/material/WebGlBlinnPhongRenderPipeline.d.ts +88 -0
  128. package/dist/webgl/render-pipelines/material/WebGlBlinnPhongRenderPipeline.d.ts.map +1 -0
  129. package/dist/webgl/render-pipelines/material/WebGlUnlitRenderPipeline.d.ts +3 -1
  130. package/dist/webgl/render-pipelines/material/WebGlUnlitRenderPipeline.d.ts.map +1 -1
  131. package/dist/webgl/render-pipelines/sprite/WebGlSpriteRenderPipeline.d.ts +3 -1
  132. package/dist/webgl/render-pipelines/sprite/WebGlSpriteRenderPipeline.d.ts.map +1 -1
  133. package/dist/webgl/shader/WebGlShaderModule.d.ts +4 -1
  134. package/dist/webgl/shader/WebGlShaderModule.d.ts.map +1 -1
  135. package/dist/webgl/shader/WebGlShaderModuleLoader.d.ts +16 -5
  136. package/dist/webgl/shader/WebGlShaderModuleLoader.d.ts.map +1 -1
  137. package/dist/webgl/texture/WebGlTexture2D.d.ts +8 -1
  138. package/dist/webgl/texture/WebGlTexture2D.d.ts.map +1 -1
  139. package/dist/webgl/utilities/webgl-filter-anisotropic-utilities.d.ts +0 -1
  140. package/dist/webgl/utilities/webgl-filter-anisotropic-utilities.d.ts.map +1 -1
  141. package/package.json +4 -4
  142. package/shaders/glsl/forward_blinn_phong_material_fs.glsl +110 -0
  143. package/shaders/glsl/forward_blinn_phong_material_vs.glsl +32 -0
  144. package/shaders/glsl/sprite_fs.glsl +1 -1
  145. package/shaders/glsl/unlit_material_fs.glsl +1 -1
  146. package/src/Framework.ts +37 -13
  147. package/src/api/IFramework.ts +8 -6
  148. package/src/api/_export.ts +2 -0
  149. package/src/api/camera/CameraFactory.ts +6 -6
  150. package/src/api/camera/ICamera.ts +6 -0
  151. package/src/api/camera/ICameraFactory.ts +5 -10
  152. package/src/api/camera/OrthographicCamera.ts +23 -1
  153. package/src/api/camera/PerspectiveCamera.ts +60 -15
  154. package/src/api/content/ContentManager.ts +201 -5
  155. package/src/api/content/IContentManager.ts +33 -1
  156. package/src/api/content/ShaderModuleContent.ts +9 -0
  157. package/src/api/data/Color.ts +7 -1
  158. package/src/api/geometry/BaseGeometry.ts +23 -0
  159. package/src/api/geometry/GeometryBuilder.ts +14 -2
  160. package/src/api/geometry/IGeometryBuilder.ts +31 -1
  161. package/src/api/geometry/_export-geometry.ts +2 -1
  162. package/src/api/input/InputManager.ts +14 -5
  163. package/src/api/lights/AmbientLight.ts +53 -0
  164. package/src/api/lights/DirectionalLight.ts +60 -0
  165. package/src/api/lights/LightFactory.ts +21 -0
  166. package/src/api/lights/LightId.ts +9 -0
  167. package/src/api/lights/LightsBuffer.ts +87 -0
  168. package/src/api/lights/PointLight.ts +91 -0
  169. package/src/api/lights/_export.ts +5 -0
  170. package/src/api/loaders/ObjGeometryMapper.ts +28 -0
  171. package/src/api/loaders/_export.ts +2 -1
  172. package/src/api/loaders/obj/ObjLoader.ts +270 -0
  173. package/src/api/loaders/obj/ObjTypes.ts +124 -0
  174. package/src/api/loaders/obj/index.ts +5 -0
  175. package/src/api/material/ForwardBlinnPhongMaterial.ts +302 -0
  176. package/src/api/material/IMaterial.ts +16 -6
  177. package/src/api/material/IMaterialFactory.ts +19 -2
  178. package/src/api/material/InspectTextureMipsMaterial.ts +63 -24
  179. package/src/api/material/MaterialFactory.ts +12 -0
  180. package/src/api/material/SpriteMaterial.ts +83 -0
  181. package/src/api/material/UnlitMaterial.ts +101 -29
  182. package/src/api/material/_export.ts +3 -1
  183. package/src/api/meshes/IMesh.ts +45 -6
  184. package/src/api/meshes/IMeshFactory.ts +27 -4
  185. package/src/api/meshes/Mesh.ts +163 -41
  186. package/src/api/meshes/MeshFactory.ts +30 -6
  187. package/src/api/meshes/QuadMesh.ts +6 -2
  188. package/src/api/meshes/SubMesh.ts +71 -0
  189. package/src/api/meshes/_export.ts +1 -0
  190. package/src/api/rendering/render-pipelines/IForwardBlinnPhongRenderPipeline.ts +66 -0
  191. package/src/api/rendering/render-pipelines/IRenderPipeline.ts +4 -0
  192. package/src/api/rendering/render-pipelines/IRenderPipelineFactory.ts +39 -0
  193. package/src/api/rendering/render-pipelines/_export-render-pipelines.ts +2 -1
  194. package/src/api/scene/Scene.ts +264 -0
  195. package/src/api/shader/IShaderModuleLoader.ts +2 -1
  196. package/src/api/sprites/SpriteBatchDrawable.ts +12 -16
  197. package/src/api/sprites/SpriteBatchMesh.ts +23 -4
  198. package/src/api/utilities/GeometryUtilities.ts +2 -0
  199. package/src/api/window/WindowManager.ts +22 -2
  200. package/src/core/rendering/vertex-buffer-layout.ts +32 -1
  201. package/src/main.ts +0 -1
  202. package/src/webgl/WebGlGraphicsDevice.ts +0 -1
  203. package/src/webgl/lights/WebGlAmbientLightFactory.ts +35 -0
  204. package/src/webgl/lights/WebGlLightsBuffer.ts +215 -0
  205. package/src/webgl/render-pipelines/AWebGlRenderPipeline.ts +7 -1
  206. package/src/webgl/render-pipelines/WebGlMainRenderTargetRenderPipeline.ts +3 -0
  207. package/src/webgl/render-pipelines/WebGlRenderPipelineFactory.ts +24 -2
  208. package/src/webgl/render-pipelines/inspect/WebGlInspectTextureMipsRenderPipeline.ts +16 -6
  209. package/src/webgl/render-pipelines/material/WebGlBlinnPhongRenderPipeline.ts +300 -0
  210. package/src/webgl/render-pipelines/material/WebGlUnlitRenderPipeline.ts +16 -6
  211. package/src/webgl/render-pipelines/sprite/WebGlSpriteRenderPipeline.ts +11 -7
  212. package/src/webgl/shader/WebGlShaderModule.ts +11 -4
  213. package/src/webgl/shader/WebGlShaderModuleLoader.ts +29 -10
  214. package/src/webgl/texture/WebGlTexture2D.ts +19 -5
  215. package/src/webgl/utilities/webgl-filter-anisotropic-utilities.ts +9 -6
  216. package/dist/api/shader/shader-loader.d.ts.map +0 -1
  217. /package/src/api/shader/{shader-loader.ts → ShaderLoader.ts} +0 -0
@@ -12,6 +12,7 @@ import {BufferUsage} from "../rendering/buffers/BufferUsage.ts";
12
12
  import {Color} from "../data/Color.ts";
13
13
  import type { IUnlitRenderPipeline } from "../rendering/render-pipelines/IUnlitRenderPipeline.ts";
14
14
  import type { IPrimitiveState } from "../rendering/primitive/IPrimitiveState.ts";
15
+ import type {ICamera} from "../camera/ICamera.ts";
15
16
 
16
17
  /** The additional material config options */
17
18
  export class UnlitMaterialDescriptor {
@@ -19,8 +20,8 @@ export class UnlitMaterialDescriptor {
19
20
  /** The primitive state. */
20
21
  public primitiveState?: IPrimitiveState;
21
22
 
22
- /** The projection view buffer to use */
23
- public projectionViewBuffer?: IUniformBuffer;
23
+ /** The camera used to render this material. */
24
+ public camera?: ICamera;
24
25
  }
25
26
 
26
27
 
@@ -32,13 +33,19 @@ export class UnlitMaterial {
32
33
  private readonly _framework: IFramework;
33
34
  private _color = Color.white();
34
35
  private _materialData = [1,1,1,1];
35
- private _pipeline: IUnlitRenderPipeline;
36
+ /** Created when the model buffer is assigned (the pipeline requires one). */
37
+ private _pipeline?: IUnlitRenderPipeline;
38
+ private readonly _primitiveState?: IPrimitiveState;
39
+ /** Texture and sampler set before the pipeline exists; applied when it is created. */
40
+ private _pendingTexture?: ITexture2D;
41
+ private _pendingSampler?: ISampler;
42
+ private _samplerSet = false;
36
43
  private _projectionViewBuffer: IUniformBuffer;
37
44
  /** False when the projection view buffer came from the descriptor. The caller owns that one. */
38
- private readonly _ownsProjectionViewBuffer: boolean;
45
+ private _ownsProjectionViewBuffer: boolean;
46
+ private _camera?: ICamera;
39
47
  private _materialBuffer: IUniformBuffer;
40
- private _modelBuffer: IUniformBuffer;
41
- private _previousModelMatrix = mat4.create();
48
+ private _modelBuffer?: IUniformBuffer;
42
49
 
43
50
  /**
44
51
  * The constructor.
@@ -47,18 +54,59 @@ export class UnlitMaterial {
47
54
  */
48
55
  public constructor(framework: IFramework, config? :UnlitMaterialDescriptor) {
49
56
  this._framework = framework;
50
- void this._framework;
51
57
  const usage = BufferUsage.UNIFORM | BufferUsage.COPY_DST;
52
- this._ownsProjectionViewBuffer = !config?.projectionViewBuffer;
53
- this._projectionViewBuffer = config?.projectionViewBuffer ?? framework.bufferFactory.createUniformBuffer(this._previousModelMatrix, usage);
54
- this._modelBuffer = framework.bufferFactory.createUniformBuffer(this._previousModelMatrix, usage);
58
+ this._camera = config?.camera;
59
+ // Without a camera an own zero buffer is bound, so rendering before the scene assigns one does not crash.
60
+ this._ownsProjectionViewBuffer = !config?.camera?.projectionViewBuffer;
61
+ this._projectionViewBuffer = config?.camera?.projectionViewBuffer ?? framework.bufferFactory.createUniformBuffer(mat4.create(), usage);
55
62
  this._materialBuffer = framework.bufferFactory.createUniformBuffer(this._materialData, usage);
56
- this._pipeline = framework.renderPipelineFactory.createUnlitRenderPipeline(
63
+ this._primitiveState = config?.primitiveState;
64
+ // The pipeline is created once a model buffer is assigned (see modelBuffer).
65
+ }
66
+
67
+ /** Creates the pipeline with the current bindings. */
68
+ private _createPipeline(modelBuffer: IUniformBuffer): IUnlitRenderPipeline {
69
+ const pipeline = this._framework.renderPipelineFactory.createUnlitRenderPipeline(
57
70
  this._projectionViewBuffer,
58
- this._modelBuffer,
71
+ modelBuffer,
59
72
  this._materialBuffer,
60
- config?.primitiveState
73
+ this._primitiveState
61
74
  );
75
+ if (this._pendingTexture) {
76
+ pipeline.diffuseTexture = this._pendingTexture;
77
+ }
78
+ if (this._samplerSet) {
79
+ pipeline.diffuseTextureSampler = this._pendingSampler;
80
+ }
81
+ this._pipeline = pipeline;
82
+ return pipeline;
83
+ }
84
+
85
+ /**
86
+ * The camera. Setting it binds the camera's projection view buffer to the pipeline
87
+ * (the material's own placeholder buffer is disposed). Setting undefined keeps the last bound buffer.
88
+ */
89
+ public get camera(): ICamera | undefined {
90
+ return this._camera;
91
+ }
92
+
93
+ /** @inheritDoc */
94
+ public set camera(camera: ICamera | undefined) {
95
+ if (camera === this._camera) {
96
+ return;
97
+ }
98
+ this._camera = camera;
99
+ if (!camera) {
100
+ return;
101
+ }
102
+ if (this._ownsProjectionViewBuffer) {
103
+ this._projectionViewBuffer.dispose();
104
+ this._ownsProjectionViewBuffer = false;
105
+ }
106
+ this._projectionViewBuffer = camera.projectionViewBuffer;
107
+ if (this._pipeline) {
108
+ this._pipeline.projectionViewBuffer = this._projectionViewBuffer;
109
+ }
62
110
  }
63
111
 
64
112
  /**
@@ -70,34 +118,60 @@ export class UnlitMaterial {
70
118
  * The texture to inspect.
71
119
  */
72
120
  public get diffuseTexture(): ITexture2D {
73
- return this._pipeline.diffuseTexture;
121
+ return this._pipeline?.diffuseTexture ?? this._pendingTexture!;
74
122
  }
75
123
 
76
124
  /**
77
125
  * The texture to inspect.
78
126
  */
79
127
  public set diffuseTexture(value: ITexture2D) {
80
- this._pipeline.diffuseTexture = value;
128
+ this._pendingTexture = value;
129
+ if (this._pipeline) {
130
+ this._pipeline.diffuseTexture = value;
131
+ }
81
132
  }
82
133
 
83
134
  /**
84
135
  * The texture sampler.
85
136
  */
86
137
  public get diffuseTextureSampler(): ISampler | undefined {
87
- return this._pipeline.diffuseTextureSampler;
138
+ return this._pipeline ? this._pipeline.diffuseTextureSampler : this._pendingSampler;
88
139
  }
89
140
 
90
141
  /**
91
142
  * The texture sampler.
92
143
  */
93
144
  public set diffuseTextureSampler(value: ISampler | undefined) {
94
- this._pipeline.diffuseTextureSampler = value;
145
+ this._pendingSampler = value;
146
+ this._samplerSet = true;
147
+ if (this._pipeline) {
148
+ this._pipeline.diffuseTextureSampler = value;
149
+ }
95
150
  }
96
151
 
97
152
  /**
98
- * The model matrix.
153
+ * The model buffer (std140 `mat4`). Owned by the mesh, which assigns it before drawing; never disposed by this material.
154
+ * Undefined until assigned: rendering without one throws.
99
155
  */
100
- public modelMatrix: mat4 = mat4.create();
156
+ public get modelBuffer(): IUniformBuffer | undefined {
157
+ return this._modelBuffer;
158
+ }
159
+
160
+ /** Binds the model buffer to the pipeline. */
161
+ public set modelBuffer(value: IUniformBuffer | undefined) {
162
+ if (value === this._modelBuffer) {
163
+ return;
164
+ }
165
+ this._modelBuffer = value;
166
+ if (!value) {
167
+ return;
168
+ }
169
+ if (this._pipeline) {
170
+ this._pipeline.modelBuffer = value;
171
+ } else {
172
+ this._createPipeline(value);
173
+ }
174
+ }
101
175
 
102
176
  /**
103
177
  * The geometry format.
@@ -114,30 +188,28 @@ export class UnlitMaterial {
114
188
  this._materialData[3] = this._color.a;
115
189
  this._materialBuffer.update(this._materialData);
116
190
  }
117
-
118
- if (!mat4.equals(this._previousModelMatrix, this.modelMatrix)) {
119
- mat4.copy(this._previousModelMatrix, this.modelMatrix);
120
- this._modelBuffer.update(this._previousModelMatrix);
121
- }
122
191
  }
123
192
 
124
193
  /** @inheritDoc */
125
194
  public renderMesh(mesh: IMesh): void {
126
- this.render(mesh.vertexBuffer!, mesh.indexBuffer!);
195
+ this.render(mesh.vertexBuffer!, mesh.indexBuffer!, mesh.indexCount ?? -1, mesh.indexStart ?? 0);
127
196
  }
128
197
 
129
198
  /** @inheritDoc */
130
- public render(vertexBuffer: IVertexBuffer, indexBuffer: IIndexBuffer): void {
131
- this._pipeline.render(vertexBuffer, indexBuffer);
199
+ public render(vertexBuffer: IVertexBuffer, indexBuffer: IIndexBuffer, indicesCount?: number, indicesOffset?: number): void {
200
+ if (!this._modelBuffer) {
201
+ throw new Error("UnlitMaterial: no modelBuffer. Render it through a mesh (the mesh assigns its model buffer) or set material.modelBuffer.");
202
+ }
203
+ (this._pipeline ?? this._createPipeline(this._modelBuffer)).render(vertexBuffer, indexBuffer, indicesCount, indicesOffset);
132
204
  }
133
205
 
134
206
  /** @inheritDoc */
135
207
  public dispose(): void {
136
- this._pipeline.dispose();
208
+ this._pipeline?.dispose();
209
+ this._pipeline = undefined;
137
210
  if (this._ownsProjectionViewBuffer) {
138
211
  this._projectionViewBuffer.dispose();
139
212
  }
140
- this._modelBuffer.dispose();
141
213
  this._materialBuffer.dispose();
142
214
  }
143
215
  }
@@ -2,4 +2,6 @@ export * from "./IMaterial.ts"
2
2
  export * from "./IMaterialFactory.ts"
3
3
  export * from "./InspectTextureMipsMaterial.ts"
4
4
  export * from "./MaterialFactory.ts"
5
- export * from "./UnlitMaterial.ts"
5
+ export * from "./SpriteMaterial.ts"
6
+ export * from "./UnlitMaterial.ts"
7
+ export * from "./ForwardBlinnPhongMaterial.ts"
@@ -1,20 +1,59 @@
1
1
  import type { IVertexBuffer } from "../rendering/buffers/IVertexBuffer.ts";
2
2
  import type { IDisposable } from "../core/IDisposable.ts";
3
3
  import type { IIndexBuffer } from "../rendering/buffers/IIndexBuffer.ts";
4
+ import type { IMaterial } from "../material/IMaterial.ts";
5
+ import type { mat4, vec3 } from "gl-matrix";
6
+ import type { IUniformBuffer } from "../rendering/buffers/IUniformBuffer.ts";
4
7
 
5
8
  /**
6
- * The mesh interface.
9
+ * Represents a mesh containing geometry, material information, and optionally child submeshes.
10
+ * A mesh may contain vertex and index buffers directly, or act as a container for submeshes.
11
+ * @public
7
12
  */
8
13
  export interface IMesh extends IDisposable {
9
14
 
15
+ /** The vertex buffer containing the mesh's vertex data, if any. */
16
+ readonly vertexBuffer?: IVertexBuffer;
17
+
18
+ /** The index buffer containing the mesh's index data, if any. */
19
+ readonly indexBuffer?: IIndexBuffer;
20
+
21
+ /** The material assigned to this mesh, if any. */
22
+ material?: IMaterial;
23
+
24
+ /** First index in {@link indexBuffer} to draw. Undefined draws from 0. */
25
+ readonly indexStart?: number;
26
+
27
+ /** Number of indices to draw. Undefined draws the whole index buffer. */
28
+ readonly indexCount?: number;
29
+
30
+ /** The child submeshes contained in this mesh, if any. */
31
+ readonly subMeshes?: IMesh[];
32
+
33
+ /** World position. Defaults to the origin. In-place edits are detected. */
34
+ position: vec3;
35
+
10
36
  /**
11
- * The positions buffer.
37
+ * Euler rotation in radians, applied in Y, X, Z order (yaw, pitch, roll): `R = Ry * Rx * Rz`.
38
+ * Defaults to (0, 0, 0). In-place edits are detected.
12
39
  */
13
- readonly vertexBuffer?: IVertexBuffer;
40
+ rotation: vec3;
41
+
42
+ /** Scale. Defaults to (1, 1, 1). In-place edits are detected. */
43
+ scale: vec3;
14
44
 
15
45
  /**
16
- * The indices buffer.
46
+ * The model matrix `T * R * S`, recomputed only when position, rotation or scale changed.
17
47
  */
18
- readonly indexBuffer?: IIndexBuffer;
48
+ readonly modelMatrix: mat4;
49
+
50
+ /**
51
+ * The model buffer (std140 `mat4`) holding {@link modelMatrix}. Owned by the mesh (submeshes share the parent's),
52
+ * uploaded when the transform changed and assigned to the material(s) before drawing.
53
+ * Created on first use.
54
+ */
55
+ readonly modelBuffer: IUniformBuffer;
19
56
 
20
- }
57
+ /** Render the mesh. */
58
+ render(): void;
59
+ }
@@ -1,8 +1,19 @@
1
1
  import type { IGeometry } from "../geometry/IGeometry.ts";
2
- import {GeometryFormat} from "../geometry/GeometryFormat.ts";
3
2
  import {QuadMesh} from "./QuadMesh.ts";
4
3
  import {vec2} from "gl-matrix";
5
4
  import type { IMesh } from "./IMesh.ts";
5
+ import type { IMaterial } from "../material/IMaterial.ts";
6
+ import type { Scene } from "../scene/Scene.ts";
7
+
8
+ /** Describes one submesh: a material and the index range it draws. */
9
+ export interface SubMeshDescriptor {
10
+ /** The material. */
11
+ readonly material: IMaterial;
12
+ /** The first index of the range. */
13
+ readonly indexStart: number;
14
+ /** The number of indices in the range. */
15
+ readonly indexCount: number;
16
+ }
6
17
 
7
18
  /**
8
19
  * The mesh factory.
@@ -10,12 +21,24 @@ import type { IMesh } from "./IMesh.ts";
10
21
  export interface IMeshFactory {
11
22
 
12
23
  /**
13
- * Creates a mesh.
24
+ * Creates a mesh and adds it to the scene.
25
+ * @param scene - The scene the mesh adds itself to.
26
+ * @param geometry - The geometry.
27
+ * @param material - The material.
28
+ * @returns The mesh.
29
+ */
30
+ create(scene: Scene, geometry: IGeometry, material: IMaterial): IMesh;
31
+
32
+ /**
33
+ * Creates a mesh made of submeshes that share one vertex and one index buffer.
34
+ * The mesh itself has no material; `scene.render()` (or `mesh.render()`) draws its submeshes.
35
+ * Only the mesh is added to the scene, not the submeshes.
36
+ * @param scene - The scene the mesh adds itself to.
14
37
  * @param geometry - The geometry.
15
- * @param geometryFormat - The geometry format.
38
+ * @param subMeshes - One entry per submesh. All materials must use the same geometry format.
16
39
  * @returns The mesh.
17
40
  */
18
- create(geometry: IGeometry, geometryFormat: GeometryFormat): IMesh;
41
+ createWithSubMeshes(scene: Scene, geometry: IGeometry, subMeshes: SubMeshDescriptor[]): IMesh;
19
42
 
20
43
  /**
21
44
  * Creates the quad mesh.
@@ -1,23 +1,27 @@
1
1
  /**
2
2
  * The mesh is a building class for a world shape.
3
3
  */
4
+ import {mat4, quat, vec3} from "gl-matrix";
4
5
  import {State} from "../data/State.ts";
5
- import type { IVertexBuffer } from "../rendering/buffers/IVertexBuffer.ts";
6
- import type { IIndexBuffer } from "../rendering/buffers/IIndexBuffer.ts";
7
- import type { IFramework } from "../IFramework.ts";
8
- import type { IMesh } from "./IMesh.ts";
6
+ import type {IVertexBuffer} from "../rendering/buffers/IVertexBuffer.ts";
7
+ import type {IIndexBuffer} from "../rendering/buffers/IIndexBuffer.ts";
8
+ import type {IUniformBuffer} from "../rendering/buffers/IUniformBuffer.ts";
9
+ import type {IFramework} from "../IFramework.ts";
10
+ import type {IMesh} from "./IMesh.ts";
9
11
  import {BufferUsage} from "../rendering/buffers/BufferUsage.ts";
10
- import type { IGeometry } from "../geometry/IGeometry.ts";
11
- import {GeometryFormat} from "../geometry/GeometryFormat.ts";
12
+ import type {IGeometry} from "../geometry/IGeometry.ts";
12
13
  import {MeshParameters} from "./MeshParameters.ts";
13
14
  import {GeometryUtilities} from "../utilities/GeometryUtilities.ts";
15
+ import type {IMaterial} from "../material/IMaterial.ts";
16
+ import type {GeometryFormat} from "../geometry/GeometryFormat.ts";
17
+ import {SubMesh} from "./SubMesh.ts";
18
+ import type {Scene} from "../scene/Scene.ts";
14
19
 
15
20
  /**
16
21
  * The mesh.
17
22
  */
18
23
  export class Mesh implements IMesh {
19
24
 
20
- protected readonly _framework: IFramework;
21
25
  protected _bufferUsage = BufferUsage.VERTEX;
22
26
  protected _state = State.CREATED;
23
27
  protected _vertexData?: number[];
@@ -28,13 +32,116 @@ export class Mesh implements IMesh {
28
32
  protected _normals?: number[];
29
33
  protected _vertexBuffer?: IVertexBuffer;
30
34
  protected _indexBuffer?: IIndexBuffer;
35
+ protected _subMeshes: SubMesh[] = [];
36
+ private readonly _modelMatrix = mat4.create();
37
+ private readonly _rotationQuat = quat.create();
38
+ // Cached copies to detect in-place edits; NaN forces the first computation.
39
+ private readonly _lastPosition = vec3.fromValues(NaN, NaN, NaN);
40
+ private readonly _lastRotation = vec3.create();
41
+ private readonly _lastScale = vec3.create();
42
+ private _modelBuffer?: IUniformBuffer;
43
+ /** The matrix last uploaded to the model buffer. */
44
+ private readonly _uploadedMatrix = mat4.create();
45
+
46
+ /** @inheritDoc */
47
+ public position: vec3 = vec3.create();
48
+
49
+ /** @inheritDoc */
50
+ public rotation: vec3 = vec3.create();
51
+
52
+ /** @inheritDoc */
53
+ public scale: vec3 = vec3.fromValues(1, 1, 1);
54
+
55
+ /** @inheritDoc */
56
+ public get modelMatrix(): mat4 {
57
+ if (!vec3.exactEquals(this._lastPosition, this.position)
58
+ || !vec3.exactEquals(this._lastRotation, this.rotation)
59
+ || !vec3.exactEquals(this._lastScale, this.scale)) {
60
+ vec3.copy(this._lastPosition, this.position);
61
+ vec3.copy(this._lastRotation, this.rotation);
62
+ vec3.copy(this._lastScale, this.scale);
63
+ const q = quat.identity(this._rotationQuat);
64
+ quat.rotateY(q, q, this.rotation[1]);
65
+ quat.rotateX(q, q, this.rotation[0]);
66
+ quat.rotateZ(q, q, this.rotation[2]);
67
+ mat4.fromRotationTranslationScale(this._modelMatrix, q, this.position, this.scale);
68
+ }
69
+ return this._modelMatrix;
70
+ }
71
+
72
+ /** @inheritDoc Created on first access and disposed with the mesh. */
73
+ public get modelBuffer(): IUniformBuffer {
74
+ if (!this._modelBuffer) {
75
+ mat4.copy(this._uploadedMatrix, this.modelMatrix);
76
+ this._modelBuffer = this._framework.bufferFactory.createUniformBuffer(
77
+ this._uploadedMatrix, BufferUsage.UNIFORM | BufferUsage.COPY_DST, "Mesh.modelBuffer");
78
+ }
79
+ return this._modelBuffer;
80
+ }
81
+
82
+ /** Uploads the model matrix when the transform changed since the last upload. */
83
+ private _updateModelBuffer(): IUniformBuffer {
84
+ const buffer = this.modelBuffer;
85
+ const matrix = this.modelMatrix;
86
+ if (!mat4.exactEquals(this._uploadedMatrix, matrix)) {
87
+ mat4.copy(this._uploadedMatrix, matrix);
88
+ buffer.update(this._uploadedMatrix);
89
+ }
90
+ return buffer;
91
+ }
92
+
93
+ /**
94
+ * Assigns this mesh's model buffer to a material that uses one (has a `modelBuffer` property),
95
+ * only when it differs. Materials without one (e.g. sprites) are skipped and no buffer is created for them.
96
+ * @internal
97
+ */
98
+ __assignModelBuffer(material: IMaterial): void {
99
+ if (!("modelBuffer" in material)) {
100
+ return;
101
+ }
102
+ const buffer = this._updateModelBuffer();
103
+ if (material.modelBuffer !== buffer) {
104
+ material.modelBuffer = buffer;
105
+ }
106
+ }
31
107
 
32
108
  /**
33
109
  * The constructor.
34
- * @param framework The framework.
110
+ * @param _framework The framework.
111
+ * @param scene The scene. The mesh adds itself to it and removes itself on dispose.
112
+ * `null` only for internal meshes drawn outside a scene (e.g. the sprite batch).
113
+ * @param _material The material. Optional for a mesh that only holds submeshes.
35
114
  */
36
- public constructor(framework: IFramework) {
37
- this._framework = framework;
115
+ public constructor(protected readonly _framework: IFramework, public readonly scene: Scene | null, protected _material?: IMaterial) {
116
+ scene?.add(this);
117
+ }
118
+
119
+ /** The material. Undefined for a mesh drawn through its submeshes. */
120
+ public get material(): IMaterial | undefined {
121
+ return this._material;
122
+ }
123
+
124
+ /** Sets the material. */
125
+ public set material(material: IMaterial | undefined) {
126
+ this._material = material;
127
+ }
128
+
129
+ /** The submeshes. They share this mesh's vertex and index buffers. */
130
+ public get subMeshes(): SubMesh[] {
131
+ return this._subMeshes;
132
+ }
133
+
134
+ /**
135
+ * Adds a submesh that draws a range of this mesh's index buffer with its own material.
136
+ * @param material The material of the submesh.
137
+ * @param indexStart The first index of the range.
138
+ * @param indexCount The number of indices in the range.
139
+ * @returns The submesh.
140
+ */
141
+ public addSubMesh(material: IMaterial, indexStart: number, indexCount: number): SubMesh {
142
+ const subMesh = new SubMesh(this, material, indexStart, indexCount);
143
+ this._subMeshes.push(subMesh);
144
+ return subMesh;
38
145
  }
39
146
 
40
147
  /**
@@ -90,7 +197,7 @@ export class Mesh implements IMesh {
90
197
  * The index buffer.
91
198
  */
92
199
  public get indexBuffer(): IIndexBuffer | undefined {
93
- return this._indexBuffer ;
200
+ return this._indexBuffer;
94
201
  }
95
202
 
96
203
  /**
@@ -100,25 +207,24 @@ export class Mesh implements IMesh {
100
207
  this.applyChanges();
101
208
  }
102
209
 
103
- private _fillColors(index: {vertexDataIndex: number, colorIndex: number}, colors: number[]): void {
210
+ private _fillColors(index: { vertexDataIndex: number, colorIndex: number }, colors: number[]): void {
104
211
 
105
- if(!this._vertexData) {
212
+ if (!this._vertexData) {
106
213
  throw new Error("Vertex data is not initialized");
107
214
  }
108
215
 
109
216
  let v = index.vertexDataIndex;
110
217
  let c = index.colorIndex;
111
218
 
112
- if(colors.length > index.colorIndex) {
219
+ if (colors.length > index.colorIndex) {
113
220
  this._vertexData[v++] = colors[c++];
114
221
  this._vertexData[v++] = colors[c++];
115
222
  this._vertexData[v++] = colors[c++];
116
223
  this._vertexData[v++] = colors[c++];
117
224
  index.vertexDataIndex = v;
118
- }
119
- else {
225
+ } else {
120
226
  // Just prefill with white color
121
- this._vertexData[v++] =1;
227
+ this._vertexData[v++] = 1;
122
228
  this._vertexData[v++] = 1;
123
229
  this._vertexData[v++] = 1;
124
230
  this._vertexData[v++] = 1;
@@ -131,10 +237,8 @@ export class Mesh implements IMesh {
131
237
  /**
132
238
  * Apply changes to the mesh.
133
239
  */
134
- public applyChanges()
135
- {
136
- if (!this._positions ||this._positions.length == 0)
137
- {
240
+ public applyChanges() {
241
+ if (!this._positions || this._positions.length == 0) {
138
242
  //_framework.Logger.LogWarning("Cannot create buffers for a Mesh as Mesh has no positions.");
139
243
  throw new Error(`Cannot create buffers for a Mesh as Mesh has no positions`);
140
244
  }
@@ -152,31 +256,27 @@ export class Mesh implements IMesh {
152
256
  let normalIndex = 0;
153
257
  let uvsIndex = 0;
154
258
 
155
- for (let i = 0; i < vertexCount; i++)
156
- {
259
+ for (let i = 0; i < vertexCount; i++) {
157
260
  // Positions.
158
261
  this._vertexData[vertexIndex++] = this._positions[positionsIndex++];
159
262
  this._vertexData[vertexIndex++] = this._positions[positionsIndex++];
160
263
  this._vertexData[vertexIndex++] = this._positions[positionsIndex++];
161
264
 
162
265
  // Colors.
163
- if (this._colors)
164
- {
266
+ if (this._colors) {
165
267
  const index = {vertexDataIndex: vertexIndex, colorIndex: colorIndex};
166
268
  this._fillColors(index, this._colors);
167
269
  vertexIndex = index.vertexDataIndex;
168
270
  colorIndex = index.colorIndex;
169
271
  }
170
272
 
171
- if (this._textureCoords)
172
- {
273
+ if (this._textureCoords) {
173
274
  // Uvs.
174
275
  this._vertexData[vertexIndex++] = this._textureCoords[uvsIndex++];
175
276
  this._vertexData[vertexIndex++] = this._textureCoords[uvsIndex++];
176
277
  }
177
278
 
178
- if (this._normals)
179
- {
279
+ if (this._normals) {
180
280
  this._vertexData[vertexIndex++] = this._normals[normalIndex++];
181
281
  this._vertexData[vertexIndex++] = this._normals[normalIndex++];
182
282
  this._vertexData[vertexIndex++] = this._normals[normalIndex++];
@@ -186,13 +286,12 @@ export class Mesh implements IMesh {
186
286
  // Vertices
187
287
  this._vertexBuffer?.dispose();
188
288
  this._vertexBuffer = this._framework.bufferFactory.createVertexBuffer(
189
- this._vertexData, stride, this._bufferUsage);
289
+ this._vertexData, stride, this._bufferUsage);
190
290
 
191
291
  // Indices
192
292
  this._indexBuffer?.dispose();
193
- if (this._indices && this._indices.length > 0)
194
- {
195
- this._indexBuffer= this._framework.bufferFactory.createIndexBuffer(
293
+ if (this._indices && this._indices.length > 0) {
294
+ this._indexBuffer = this._framework.bufferFactory.createIndexBuffer(
196
295
  this._indices);
197
296
  }
198
297
  }
@@ -201,15 +300,18 @@ export class Mesh implements IMesh {
201
300
  * Sets the mesh from a geometry.
202
301
  *
203
302
  * This will create vertex buffer and index buffer from geometry.
204
- * Positions, Colors, TextureCoordinates and Normals will be ignored.
205
303
  * @param geometry - The geometry.
206
- * @param format - The format for geometry.
304
+ * @param geometryFormat - The vertex layout. Defaults to the material's geometry format.
207
305
  */
208
- public setGeometry(geometry: IGeometry, format: GeometryFormat): void {
209
- if (geometry.vertexCount == 0)
210
- {
306
+ public setGeometry(geometry: IGeometry, geometryFormat?: GeometryFormat): void {
307
+
308
+ const format = geometryFormat ?? this._material?.geometryFormat;
309
+ if (format === undefined) {
310
+ throw new Error("Cannot create buffers for a Mesh without a material or geometry format.");
311
+ }
312
+ if (geometry.vertexCount == 0) {
211
313
  const message =
212
- "Cannot create buffers for a Mesh as Mesh has no positions. Check that geometry.vertexCount is set.";
314
+ "Cannot create buffers for a Mesh as Mesh has no positions. Check that geometry.vertexCount is set.";
213
315
  //_framework.Logger.LogError(message);
214
316
  throw new Error(message);
215
317
  }
@@ -226,8 +328,7 @@ export class Mesh implements IMesh {
226
328
 
227
329
  // Indices
228
330
  this._indexBuffer?.dispose();
229
- if (geometry.indices)
230
- {
331
+ if (geometry.indices) {
231
332
  this._indexBuffer = this._framework.bufferFactory.createIndexBuffer(geometry.indices);
232
333
  }
233
334
  }
@@ -244,13 +345,34 @@ export class Mesh implements IMesh {
244
345
  this.applyChanges();
245
346
  }
246
347
 
348
+ /** @inheritDoc */
349
+ public render(): void {
350
+
351
+ // Render submeshes.
352
+ if (this.subMeshes?.length > 0) {
353
+ for (let i = 0; i < this.subMeshes.length; ++i) {
354
+ this.subMeshes[i].render();
355
+ }
356
+ }
357
+
358
+ if (this.material) {
359
+ this.__assignModelBuffer(this.material);
360
+ this.material.beforeRender();
361
+ this.material.renderMesh(this);
362
+ }
363
+ }
364
+
247
365
  /**
248
366
  * Dispose of the mesh.
249
367
  */
250
368
  public dispose(): void {
369
+ this.scene?.remove(this);
370
+ this._subMeshes.length = 0;
251
371
  this._vertexBuffer?.dispose();
252
372
  this._vertexBuffer = undefined;
253
373
  this._indexBuffer?.dispose();
254
374
  this._indexBuffer = undefined;
375
+ this._modelBuffer?.dispose();
376
+ this._modelBuffer = undefined;
255
377
  }
256
378
  }