|
@@ -320,7 +320,13 @@
|
|
|
this._modelRenderCache.dispose();
|
|
|
this._modelRenderCache = null;
|
|
|
}
|
|
|
- this._instanceDataParts = null;
|
|
|
+
|
|
|
+ if (this._instanceDataParts) {
|
|
|
+ this._instanceDataParts.forEach(p => {
|
|
|
+ p.freeElements();
|
|
|
+ });
|
|
|
+ this._instanceDataParts = null;
|
|
|
+ }
|
|
|
|
|
|
return true;
|
|
|
}
|
|
@@ -337,6 +343,9 @@
|
|
|
// Need to create the model?
|
|
|
let setupModelRenderCache = false;
|
|
|
if (!this._modelRenderCache || this._modelDirty) {
|
|
|
+ if (this._modelRenderCache) {
|
|
|
+ this._modelRenderCache.dispose();
|
|
|
+ }
|
|
|
this._modelRenderCache = this.owner.engineData.GetOrAddModelCache(this.modelKey, (key: string) => {
|
|
|
let mrc = this.createModelRenderCache(key, this.isTransparent);
|
|
|
setupModelRenderCache = true;
|
|
@@ -350,14 +359,19 @@
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Need to create the instance?
|
|
|
let gii: GroupInstanceInfo;
|
|
|
let newInstance = false;
|
|
|
+
|
|
|
+ // Need to create the instance data parts?
|
|
|
if (!this._modelRenderInstanceID) {
|
|
|
+ // Yes, flag it for later, more processing will have to be done
|
|
|
newInstance = true;
|
|
|
+
|
|
|
+ // Create the instance data parts of the primitive and store them
|
|
|
let parts = this.createInstanceDataParts();
|
|
|
this._instanceDataParts = parts;
|
|
|
|
|
|
+ // Check if the ModelRenderCache for this particular instance is also brand new, initialize it if it's the case
|
|
|
if (!this._modelRenderCache._partsDataStride) {
|
|
|
let ctiArray = new Array<ClassTreeInfo<InstanceClassInfo, InstancePropInfo>>();
|
|
|
let dataStrides = new Array<number>();
|
|
@@ -371,7 +385,7 @@
|
|
|
// Make sure the instance is visible other the properties won't be set and their size/offset wont be computed
|
|
|
let curVisible = this.isVisible;
|
|
|
this.isVisible = true;
|
|
|
- // We manually trigger refreshInstanceData for the only sake of evaluating each isntance property size and offset in the instance data, this can only be made at runtime. Once it's done we have all the information to create the instance data buffer.
|
|
|
+ // We manually trigger refreshInstanceData for the only sake of evaluating each instance property size and offset in the instance data, this can only be made at runtime. Once it's done we have all the information to create the instance data buffer.
|
|
|
//console.log("Build Prop Layout for " + Tools.getClassName(this._instanceDataParts[0]));
|
|
|
let joinCat = cat.join(";");
|
|
|
joinedUsedCatList.push(joinCat);
|
|
@@ -401,6 +415,9 @@
|
|
|
this._modelRenderCache._partIdList = partIdList;
|
|
|
}
|
|
|
|
|
|
+ // The Rendering resources (Effect, VB, IB, Textures) are stored in the ModelRenderCache
|
|
|
+ // But it's the RenderGroup that will store all the Instanced related data to render all the primitive it owns.
|
|
|
+ // So for a given ModelKey we getOrAdd a GroupInstanceInfo that will store all these data
|
|
|
gii = this.renderGroup.groupRenderInfo.getOrAddWithFactory(this.modelKey, k => new GroupInstanceInfo(this.renderGroup, this._modelRenderCache));
|
|
|
|
|
|
// First time init of the GroupInstanceInfo
|
|
@@ -416,26 +433,39 @@
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // For each instance data part of the primitive, allocate the instanced element it needs for render
|
|
|
for (let i = 0; i < parts.length; i++) {
|
|
|
let part = parts[i];
|
|
|
part.dataBuffer = gii._instancesPartsData[i];
|
|
|
part.allocElements();
|
|
|
}
|
|
|
|
|
|
+ // Add the instance data parts in the ModelRenderCache they belong, track them by storing their ID in the primitive in case we need to change the model later on, so we'll have to release the allocated instance data parts because they won't fit anymore
|
|
|
this._modelRenderInstanceID = this._modelRenderCache.addInstanceDataParts(this._instanceDataParts);
|
|
|
}
|
|
|
|
|
|
+ // If the ModelRenderCache is brand new, now is the time to call the implementation's specific setup method to create the rendering resources
|
|
|
if (setupModelRenderCache) {
|
|
|
this.setupModelRenderCache(this._modelRenderCache);
|
|
|
}
|
|
|
|
|
|
- if (context.forceRefreshPrimitive || newInstance || (this._instanceDirtyFlags !== 0) || (this._globalTransformProcessStep !== this._globalTransformStep)) {
|
|
|
+ // At this stage we have everything correctly initialized, ModelRenderCache is setup, Model Instance data are good too, they have allocated elements in the Instanced DynamicFloatArray.
|
|
|
+
|
|
|
+ // The last thing to do is check if the instanced related data must be updated because a InstanceLevel property had changed or the primitive visibility changed.
|
|
|
+ if (this._visibilityChanged || context.forceRefreshPrimitive || newInstance || (this._instanceDirtyFlags !== 0) || (this._globalTransformProcessStep !== this._globalTransformStep)) {
|
|
|
+
|
|
|
+ // Fetch the GroupInstanceInfo if we don't already have it
|
|
|
if (!gii) {
|
|
|
gii = this.renderGroup.groupRenderInfo.get(this.modelKey);
|
|
|
}
|
|
|
|
|
|
+ // For each Instance Data part, refresh it to update the data in the DynamicFloatArray
|
|
|
for (let part of this._instanceDataParts) {
|
|
|
- let cat = this.getUsedShaderCategories(part);
|
|
|
+ // Check if we need to allocate data elements (hidden prim which becomes visible again)
|
|
|
+ if (this._visibilityChanged && !part.dataElements) {
|
|
|
+ part.allocElements();
|
|
|
+ }
|
|
|
+
|
|
|
InstanceClassInfo._CurCategories = gii._instancesPartsUsedShaderCategories[gii._partIndexFromId.get(part.id.toString())];
|
|
|
|
|
|
// Will return false if the instance should not be rendered (not visible or other any reasons)
|
|
@@ -449,6 +479,7 @@
|
|
|
this._instanceDirtyFlags = 0;
|
|
|
|
|
|
gii._dirtyInstancesData = true;
|
|
|
+ this._visibilityChanged = false; // Reset the flag as we've handled the case
|
|
|
}
|
|
|
}
|
|
|
|