🆙 Working landscapes as in V1

This commit is contained in:
duckietm
2026-02-02 10:15:14 +01:00
parent c197de7ea2
commit 7b59a31b0f
@@ -17,7 +17,6 @@ export class RoomPlane implements IRoomPlane
'32': new RoomGeometry(32, new Vector3d(RoomPlane.HORIZONTAL_ANGLE_DEFAULT, RoomPlane.VERTICAL_ANGLE_DEFAULT), new Vector3d(-10, 0, 0)),
'64': new RoomGeometry(64, new Vector3d(RoomPlane.HORIZONTAL_ANGLE_DEFAULT, RoomPlane.VERTICAL_ANGLE_DEFAULT), new Vector3d(-10, 0, 0))
};
private static LANDSCAPE_COLOR: number = 0x0082F0;
private static ANIMATION_UPDATE_INTERVAL: number = 500;
public static TYPE_UNDEFINED: number = 0;
@@ -78,6 +77,12 @@ export class RoomPlane implements IRoomPlane
private _landscapeRenderHeight: number = 0;
private _landscapeOffsetX: number = 0;
private _landscapeOffsetY: number = 0;
private _landscapeBackgroundTexture: Texture = null;
private _landscapeBackgroundTint: number = 0xffffff;
private _landscapeForegroundTexture: Texture = null;
private _landscapeForegroundTint: number = 0xffffff;
private _landscapeBaseAlignBottom: boolean = false;
private _landscapeForegroundAlignBottom: boolean = false;
private _hasWindowMask: boolean = false;
private _windowMasks: { leftSideLoc: number; rightSideLoc: number }[] = [];
@@ -211,9 +216,11 @@ export class RoomPlane implements IRoomPlane
switch(this._type)
{
case RoomPlane.TYPE_FLOOR:
relativeDepth = (relativeDepth - ((this._location.z + Math.min(0, this._leftSide.z, this._rightSide.z)) * 8));
case RoomPlane.TYPE_FLOOR: {
const heightOffset = (this._location.z + Math.min(0, this._leftSide.z, this._rightSide.z)) * geometry.scale;
relativeDepth = (relativeDepth - heightOffset);
break;
}
case RoomPlane.TYPE_LANDSCAPE:
relativeDepth = (relativeDepth + 0.02);
break;
@@ -229,7 +236,7 @@ export class RoomPlane implements IRoomPlane
let height = (this._rightSide.length * geometry.scale);
const normal = geometry.getCoordinatePosition(this._normal);
const getTextureAndColorForPlane = (planeId: string, planeType: number) =>
const getTextureAndColorForPlane = (planeId: string, planeType: number, planeNormal: IVector3D) =>
{
const dataType: keyof IAssetRoomVisualizationData = (planeType === RoomPlane.TYPE_FLOOR) ? 'floorData' : (planeType === RoomPlane.TYPE_WALL) ? 'wallData' : 'landscapeData';
@@ -249,12 +256,99 @@ export class RoomPlane implements IRoomPlane
}
}
const planeVisualization = ((dataType === 'landscapeData') ? plane?.animatedVisualization : plane?.visualizations)?.find(visualization => (visualization.size === planeGeometry.scale)) ?? null;
const planeLayer = planeVisualization?.allLayers?.[0] as IAssetPlaneVisualizationLayer;
const planeMaterialId = planeLayer?.materialId;
const planeColor = planeLayer?.color;
const planeAssetName = planeVisualizationData?.textures?.find(texture => (texture.id === planeMaterialId))?.bitmaps?.[0]?.assetName;
const texture = assetCollection ? GetAssetManager().getAsset(planeAssetName)?.texture : null;
let planeVisualization = null;
if(dataType === 'landscapeData')
{
planeVisualization = plane?.animatedVisualization?.find(visualization => (visualization.size === planeGeometry.scale)) ?? null;
if(!planeVisualization)
{
planeVisualization = plane?.visualizations?.find(visualization => (visualization.size === planeGeometry.scale)) ?? null;
}
}
else
{
planeVisualization = plane?.visualizations?.find(visualization => (visualization.size === planeGeometry.scale)) ?? null;
}
const layers = planeVisualization?.allLayers ?? [];
const colorLayer = layers.find(layer => (layer as IAssetPlaneVisualizationLayer)?.color !== undefined) as IAssetPlaneVisualizationLayer;
const materialLayers = layers.filter(layer => (layer as IAssetPlaneVisualizationLayer)?.materialId) as IAssetPlaneVisualizationLayer[];
const planeColor = colorLayer?.color;
const baseMaterialId = materialLayers[0]?.materialId;
const foregroundMaterialId = materialLayers[1]?.materialId;
const baseAlignBottom = materialLayers[0]?.align === 'bottom';
const foregroundAlignBottom = materialLayers[1]?.align === 'bottom';
const selectMaterialMatrixForNormal = (matrices = [], normal = null) =>
{
if(!matrices.length) return null;
if(!normal) return matrices[0];
const matchesNormal = (matrix) =>
{
const minX = (matrix.normalMinX !== undefined) ? matrix.normalMinX : -1;
const maxX = (matrix.normalMaxX !== undefined) ? matrix.normalMaxX : 1;
const minY = (matrix.normalMinY !== undefined) ? matrix.normalMinY : -1;
const maxY = (matrix.normalMaxY !== undefined) ? matrix.normalMaxY : 1;
return ((normal.x >= minX) && (normal.x <= maxX) && (normal.y >= minY) && (normal.y <= maxY));
};
return matrices.find(matchesNormal) ?? matrices[0];
};
const selectBitmapForNormal = (bitmaps = [], normal = null) =>
{
if(!bitmaps.length) return null;
if(!normal) return bitmaps[0];
const matchesNormal = (bitmap) =>
{
const minX = (bitmap.normalMinX !== undefined) ? bitmap.normalMinX : -1;
const maxX = (bitmap.normalMaxX !== undefined) ? bitmap.normalMaxX : 1;
const minY = (bitmap.normalMinY !== undefined) ? bitmap.normalMinY : -1;
const maxY = (bitmap.normalMaxY !== undefined) ? bitmap.normalMaxY : 1;
return ((normal.x >= minX) && (normal.x <= maxX) && (normal.y >= minY) && (normal.y <= maxY));
};
return bitmaps.find(matchesNormal) ?? bitmaps[0];
};
const getCollectionTexture = (name: string) =>
{
if(!name || !assetCollection) return null;
return assetCollection.getTexture(name) ?? assetCollection.getTexture(`${ assetCollection.name }_${ name }`);
};
const resolveTextureForMaterial = (materialId: string) =>
{
if(!materialId || !assetCollection) return null;
const planeTextureById = planeVisualizationData?.textures?.find(texture => (texture.id === materialId));
const planeMaterial = planeVisualizationData?.materials?.find(material => (material.id === materialId));
const planeMaterialMatrix = selectMaterialMatrixForNormal(planeMaterial?.matrices, planeNormal);
const planeMaterialTextureId = planeMaterialMatrix?.columns?.[0]?.cells?.[0]?.textureId ?? null;
const planeTexture = planeTextureById ?? planeVisualizationData?.textures?.find(texture => (texture.id === planeMaterialTextureId));
const planeBitmap = selectBitmapForNormal(planeTexture?.bitmaps, planeNormal);
const planeAssetName = planeBitmap?.assetName;
if(planeAssetName)
{
return assetCollection.getAsset(planeAssetName)?.texture ?? getCollectionTexture(planeAssetName);
}
if(planeMaterialTextureId)
{
return assetCollection.getAsset(planeMaterialTextureId)?.texture ?? getCollectionTexture(planeMaterialTextureId);
}
return assetCollection.getAsset(materialId)?.texture ?? getCollectionTexture(materialId);
};
const texture = resolveTextureForMaterial(baseMaterialId);
const foregroundTexture = resolveTextureForMaterial(foregroundMaterialId);
const animationLayers: PlaneVisualizationAnimationLayer[] = [];
if(planeType === RoomPlane.TYPE_LANDSCAPE && planeVisualization?.allLayers && assetCollection)
@@ -270,10 +364,10 @@ export class RoomPlane implements IRoomPlane
}
}
return { texture, color: planeColor, animationLayers };
return { texture, foregroundTexture, color: planeColor, baseAlignBottom, foregroundAlignBottom, animationLayers };
};
const planeData = getTextureAndColorForPlane(this._id, this._type);
const planeData = getTextureAndColorForPlane(this._id, this._type, normal);
const texture = this._hasTexture ? planeData.texture ?? Texture.WHITE : Texture.WHITE;
switch(this._type)
@@ -374,16 +468,25 @@ export class RoomPlane implements IRoomPlane
this._animationLayers = planeData.animationLayers || [];
this._isAnimated = this._animationLayers.length > 0;
this._landscapeBackgroundTexture = planeData.texture ?? null;
this._landscapeBackgroundTint = planeData.color ?? 0xffffff;
this._landscapeForegroundTexture = planeData.foregroundTexture ?? null;
const landscapeTint = planeData.color ?? this._color ?? 0xffffff;
this._landscapeForegroundTint = landscapeTint;
this._landscapeBaseAlignBottom = planeData.baseAlignBottom ?? false;
this._landscapeForegroundAlignBottom = planeData.foregroundAlignBottom ?? false;
this._planeSprite = new TilingSprite({
texture,
texture: Texture.WHITE,
width,
height,
tilePosition: {
x: renderOffsetX,
y: renderOffsetY
},
tint: RoomPlane.LANDSCAPE_COLOR
tint: landscapeTint
});
this._landscapeBackgroundTint = landscapeTint;
break;
}
default: {
@@ -438,11 +541,22 @@ export class RoomPlane implements IRoomPlane
transform: this.getMatrixForDimensions(this._planeSprite.width, this._planeSprite.height),
clear: true
});
if(this._isAnimated && this._type === RoomPlane.TYPE_LANDSCAPE && this._animationLayers.length > 0 && this._hasWindowMask)
{
this.renderAnimationLayers(timeSinceStartMs, geometry);
}
if(this._type === RoomPlane.TYPE_LANDSCAPE && this._landscapeBackgroundTexture)
{
this.renderLandscapeLayer(this._landscapeBackgroundTexture, this._landscapeBackgroundTint, this._landscapeBaseAlignBottom);
}
// Render foreground layer for landscapes on top of background/animation
if(this._type === RoomPlane.TYPE_LANDSCAPE && this._landscapeForegroundTexture)
{
this.renderLandscapeLayer(this._landscapeForegroundTexture, this._landscapeForegroundTint, this._landscapeForegroundAlignBottom);
}
}
return true;
@@ -510,6 +624,64 @@ export class RoomPlane implements IRoomPlane
animationCanvas.destroy(true);
}
private renderLandscapeLayer(texture: Texture, tint: number, alignBottom: boolean): void
{
if(!this._planeTexture || !texture) return;
const canvasWidth = this._landscapeRenderWidth;
const canvasHeight = this._landscapeRenderHeight;
if(canvasWidth <= 0 || canvasHeight <= 0) return;
const layerHeight = Math.min(texture.height, canvasHeight);
const layerPositionY = alignBottom ? (canvasHeight - layerHeight) : 0;
const layerSprite = new TilingSprite({
texture,
width: canvasWidth,
height: layerHeight,
tilePosition: {
x: this._landscapeOffsetX,
y: this._landscapeOffsetY
},
tint
});
layerSprite.y = layerPositionY;
const layerContainer = new Container();
layerContainer.addChild(layerSprite);
if(this._maskFilter)
{
layerContainer.filters = [this._maskFilter];
}
if(this._planeSprite && this._planeSprite.children)
{
for(const child of this._planeSprite.children)
{
if(child instanceof Sprite)
{
const maskClone = new Sprite(child.texture);
maskClone.position.copyFrom(child.position);
maskClone.scale.copyFrom(child.scale);
layerContainer.addChild(maskClone);
}
}
}
const transform = this.getMatrixForDimensions(canvasWidth, canvasHeight);
GetRenderer().render({
target: this._planeTexture,
container: layerContainer,
transform,
clear: false
});
layerSprite.destroy();
}
private updateCorners(geometry: IRoomGeometry): void
{
this._cornerA.assign(geometry.getScreenPosition(this._location));