Improve typing of the 3D object editor renderers (#7410)

- Don't show in changelog
This commit is contained in:
D8H
2025-02-17 12:57:27 +01:00
committed by GitHub
parent 303ebfaf1b
commit 800c3333d4
2 changed files with 129 additions and 85 deletions

View File

@@ -3,28 +3,28 @@ namespace gdjs {
export interface Cube3DObjectData extends Object3DData {
/** The base parameters of the Cube3D object */
content: Object3DDataContent & {
enableTextureTransparency: boolean;
facesOrientation: 'Y' | 'Z';
enableTextureTransparency: boolean | undefined;
facesOrientation: 'Y' | 'Z' | undefined;
frontFaceResourceName: string;
backFaceResourceName: string;
backFaceUpThroughWhichAxisRotation: 'X' | 'Y';
backFaceUpThroughWhichAxisRotation: 'X' | 'Y' | undefined;
leftFaceResourceName: string;
rightFaceResourceName: string;
topFaceResourceName: string;
bottomFaceResourceName: string;
frontFaceResourceRepeat: boolean;
backFaceResourceRepeat: boolean;
leftFaceResourceRepeat: boolean;
rightFaceResourceRepeat: boolean;
topFaceResourceRepeat: boolean;
bottomFaceResourceRepeat: boolean;
frontFaceResourceRepeat: boolean | undefined;
backFaceResourceRepeat: boolean | undefined;
leftFaceResourceRepeat: boolean | undefined;
rightFaceResourceRepeat: boolean | undefined;
topFaceResourceRepeat: boolean | undefined;
bottomFaceResourceRepeat: boolean | undefined;
frontFaceVisible: boolean;
backFaceVisible: boolean;
leftFaceVisible: boolean;
rightFaceVisible: boolean;
topFaceVisible: boolean;
bottomFaceVisible: boolean;
tint: string;
tint: string | undefined;
materialType: 'Basic' | 'StandardWithoutMetalness';
};
}
@@ -308,7 +308,7 @@ namespace gdjs {
);
}
if (oldObjectData.content.tint !== newObjectData.content.tint) {
this.setColor(newObjectData.content.tint);
this.setColor(newObjectData.content.tint || '255;255;255');
}
if (
@@ -362,7 +362,7 @@ namespace gdjs {
) {
this.setRepeatTextureOnFace(
'front',
newObjectData.content.frontFaceResourceRepeat
newObjectData.content.frontFaceResourceRepeat || false
);
}
if (
@@ -371,7 +371,7 @@ namespace gdjs {
) {
this.setRepeatTextureOnFace(
'back',
newObjectData.content.backFaceResourceRepeat
newObjectData.content.backFaceResourceRepeat || false
);
}
if (
@@ -380,7 +380,7 @@ namespace gdjs {
) {
this.setRepeatTextureOnFace(
'left',
newObjectData.content.leftFaceResourceRepeat
newObjectData.content.leftFaceResourceRepeat || false
);
}
if (
@@ -389,7 +389,7 @@ namespace gdjs {
) {
this.setRepeatTextureOnFace(
'right',
newObjectData.content.rightFaceResourceRepeat
newObjectData.content.rightFaceResourceRepeat || false
);
}
if (
@@ -398,7 +398,7 @@ namespace gdjs {
) {
this.setRepeatTextureOnFace(
'top',
newObjectData.content.topFaceResourceRepeat
newObjectData.content.topFaceResourceRepeat || false
);
}
if (
@@ -407,7 +407,7 @@ namespace gdjs {
) {
this.setRepeatTextureOnFace(
'bottom',
newObjectData.content.bottomFaceResourceRepeat
newObjectData.content.bottomFaceResourceRepeat || false
);
}
if (
@@ -415,14 +415,14 @@ namespace gdjs {
newObjectData.content.backFaceUpThroughWhichAxisRotation
) {
this.setBackFaceUpThroughWhichAxisRotation(
newObjectData.content.backFaceUpThroughWhichAxisRotation
newObjectData.content.backFaceUpThroughWhichAxisRotation || 'X'
);
}
if (
oldObjectData.content.facesOrientation !==
newObjectData.content.facesOrientation
) {
this.setFacesOrientation(newObjectData.content.facesOrientation);
this.setFacesOrientation(newObjectData.content.facesOrientation || 'Y');
}
if (
oldObjectData.content.materialType !==

View File

@@ -2099,6 +2099,10 @@ module.exports = {
3: [1, 0],
};
/**
* @param {*} objectConfiguration
* @returns {string | null}
*/
const getFirstVisibleFaceResourceName = (objectConfiguration) => {
const object = gd.castObject(
objectConfiguration,
@@ -2127,25 +2131,44 @@ module.exports = {
return null;
};
/** @type {THREE.MeshBasicMaterial | null} */
let transparentMaterial = null;
/**
* @returns {THREE.MeshBasicMaterial}
*/
const getTransparentMaterial = () => {
if (!transparentMaterial)
transparentMaterial = new THREE.MeshBasicMaterial({
transparent: true,
opacity: 0,
// Set the alpha test to to ensure the faces behind are rendered
// (no "back face culling" that would still be done if alphaTest is not set).
alphaTest: 1,
});
return transparentMaterial;
if (transparentMaterial) {
return transparentMaterial;
}
const newTransparentMaterial = new THREE.MeshBasicMaterial({
transparent: true,
opacity: 0,
// Set the alpha test to to ensure the faces behind are rendered
// (no "back face culling" that would still be done if alphaTest is not set).
alphaTest: 1,
});
transparentMaterial = newTransparentMaterial;
return newTransparentMaterial;
};
class RenderedCube3DObject2DInstance extends RenderedInstance {
/** @type {number} */
_defaultWidth;
/** @type {number} */
_defaultHeight;
/** @type {number} */
_defaultDepth;
/** @type {number} */
_centerX = 0;
/** @type {number} */
_centerY = 0;
/**
* The name of the resource that is rendered.
* If no face is visible, this will be null.
* @type {string | null | undefined}
*/
_renderedResourceName = undefined;
_renderFallbackObject = false;
constructor(
project,
@@ -2161,11 +2184,6 @@ module.exports = {
pixiContainer,
pixiResourcesLoader
);
// Name of the resource that is rendered.
// If no face is visible, this will be null.
this._renderedResourceName = undefined;
const object = gd.castObject(
this._associatedObjectConfiguration,
gd.ObjectJsImplementation
@@ -2182,7 +2200,6 @@ module.exports = {
this._pixiObject.addChild(this._pixiTexturedObject);
this._pixiObject.addChild(this._pixiFallbackObject);
this._pixiContainer.addChild(this._pixiObject);
this._renderFallbackObject = false;
this.updateTexture();
}
@@ -2348,6 +2365,17 @@ module.exports = {
}
class RenderedCube3DObject3DInstance extends Rendered3DInstance {
_defaultWidth = 1;
_defaultHeight = 1;
_defaultDepth = 1;
_faceResourceNames = new Array(6).fill(null);
_faceVisibilities = new Array(6).fill(null);
_shouldRepeatTextureOnFace = new Array(6).fill(null);
_facesOrientation = 'Y';
_backFaceUpThroughWhichAxisRotation = 'X';
_shouldUseTransparentTexture = false;
_tint = '';
constructor(
project,
instance,
@@ -2364,22 +2392,9 @@ module.exports = {
threeGroup,
pixiResourcesLoader
);
this._defaultWidth = 1;
this._defaultHeight = 1;
this._defaultDepth = 1;
this._pixiObject = new PIXI.Graphics();
this._pixiContainer.addChild(this._pixiObject);
this._faceResourceNames = new Array(6).fill(null);
this._faceVisibilities = new Array(6).fill(null);
this._shouldRepeatTextureOnFace = new Array(6).fill(null);
this._facesOrientation = 'Y';
this._backFaceUpThroughWhichAxisRotation = 'X';
this._shouldUseTransparentTexture = false;
this._tint = '';
const geometry = new THREE.BoxGeometry(1, 1, 1);
const materials = [
getTransparentMaterial(),
@@ -2458,6 +2473,8 @@ module.exports = {
}
updateThreeObject() {
/** @type {gdjs.Cube3DObjectData} */
//@ts-ignore This works because the properties are set to `content` in JavaScript.
const object = gd.castObject(
this._associatedObjectConfiguration,
gd.ObjectJsImplementation
@@ -2601,11 +2618,11 @@ module.exports = {
* for the method to work.
*/
_updateTextureUvMapping() {
/** @type {THREE.BufferAttribute} */
// @ts-ignore - position is stored as a Float32BufferAttribute
/** @type {THREE.BufferAttribute} */
const pos = this._threeObject.geometry.getAttribute('position');
// @ts-ignore - uv is stored as a Float32BufferAttribute
/** @type {THREE.BufferAttribute} */
// @ts-ignore - uv is stored as a Float32BufferAttribute
const uvMapping = this._threeObject.geometry.getAttribute('uv');
const startIndex = 0;
const endIndex = 23;
@@ -2853,6 +2870,19 @@ module.exports = {
const epsilon = 1 / (1 << 16);
class Model3DRendered2DInstance extends RenderedInstance {
/** @type {number} */
_defaultWidth;
/** @type {number} */
_defaultHeight;
/** @type {number} */
_defaultDepth;
/** @type {[number, number, number] | null} */
_originPoint;
/** @type {[number, number, number] | null} */
_centerPoint;
/** @type {[number, number, number]} */
_modelOriginPoint = [0, 0, 0];
constructor(
@@ -3095,10 +3125,15 @@ module.exports = {
}
}
/**
* @param {[number, number, number] | null} point1
* @param {[number, number, number] | null} point2
* @returns {boolean}
*/
const isSamePoint = (point1, point2) => {
if (!point1 && !point2) return true;
if (point1 && !point2) return false;
if (!point1 && point2) return false;
if (!!point1 !== !!point2) return false;
// At this point || or && doesn't matter and the type checking prefer ||.
if (!point1 || !point2) return true;
return (
point1[0] === point2[0] &&
point1[1] === point2[1] &&
@@ -3106,6 +3141,10 @@ module.exports = {
);
};
/**
* @param {string} location
* @returns {[number, number, number] | null}
*/
const getPointForLocation = (location) => {
switch (location) {
case 'ModelOrigin':
@@ -3124,8 +3163,27 @@ module.exports = {
};
class Model3DRendered3DInstance extends Rendered3DInstance {
_defaultWidth = 1;
_defaultHeight = 1;
_defaultDepth = 1;
_originalWidth = 1;
_originalHeight = 1;
_originalDepth = 1;
_rotationX = 0;
_rotationY = 0;
_rotationZ = 0;
_keepAspectRatio = false;
/** @type {[number, number, number] | null} */
_originPoint = null;
/** @type {[number, number, number] | null} */
_centerPoint = null;
/** @type {[number, number, number]} */
_modelOriginPoint = [0, 0, 0];
/** @type {THREE.Object3D | null} */
_clonedModel3D = null;
constructor(
project,
instance,
@@ -3143,29 +3201,12 @@ module.exports = {
pixiResourcesLoader
);
this._defaultWidth = 1;
this._defaultHeight = 1;
this._defaultDepth = 1;
this._originalWidth = 1;
this._originalHeight = 1;
this._originalDepth = 1;
this._rotationX = 0;
this._rotationY = 0;
this._rotationZ = 0;
this._keepAspectRatio = false;
this._originPoint = null;
this._centerPoint = null;
this._pixiObject = new PIXI.Graphics();
this._pixiContainer.addChild(this._pixiObject);
this._threeObject = new THREE.Group();
this._threeObject.rotation.order = 'ZYX';
this._threeGroup.add(this._threeObject);
this._threeModelGroup = null;
this._clonedModel3D = null;
}
getOriginX() {
@@ -3207,27 +3248,30 @@ module.exports = {
}
_updateDefaultTransformation() {
if (!this._clonedModel3D) return; // Model is not ready - nothing to do.
if (!this._clonedModel3D || !this._threeModelGroup) {
// Model is not ready - nothing to do.
return;
}
if (this._threeModelGroup) {
// Remove any previous container as we will recreate it just below
this._threeObject.clear();
}
// This group hold the rotation defined by properties.
// Always restart from a new group to avoid miscomputing bounding boxes/sizes.
this._threeModelGroup = new THREE.Group();
this._threeModelGroup.rotation.order = 'ZYX';
this._threeModelGroup.add(this._clonedModel3D);
const threeModelGroup = new THREE.Group();
this._threeModelGroup = threeModelGroup;
threeModelGroup.rotation.order = 'ZYX';
threeModelGroup.add(this._clonedModel3D);
this._threeModelGroup.rotation.set(
threeModelGroup.rotation.set(
(this._rotationX * Math.PI) / 180,
(this._rotationY * Math.PI) / 180,
(this._rotationZ * Math.PI) / 180
);
this._threeModelGroup.updateMatrixWorld(true);
const boundingBox = new THREE.Box3().setFromObject(
this._threeModelGroup
);
threeModelGroup.updateMatrixWorld(true);
const boundingBox = new THREE.Box3().setFromObject(threeModelGroup);
const shouldKeepModelOrigin = !this._originPoint;
if (shouldKeepModelOrigin) {
@@ -3254,7 +3298,7 @@ module.exports = {
// Center the model.
const centerPoint = this._centerPoint;
if (centerPoint) {
this._threeModelGroup.position.set(
threeModelGroup.position.set(
-(boundingBox.min.x + modelWidth * centerPoint[0]),
// The model is flipped on Y axis.
-(boundingBox.min.y + modelHeight * (1 - centerPoint[1])),
@@ -3263,8 +3307,8 @@ module.exports = {
}
// Rotate the model.
this._threeModelGroup.scale.set(1, 1, 1);
this._threeModelGroup.rotation.set(
threeModelGroup.scale.set(1, 1, 1);
threeModelGroup.rotation.set(
(this._rotationX * Math.PI) / 180,
(this._rotationY * Math.PI) / 180,
(this._rotationZ * Math.PI) / 180
@@ -3279,8 +3323,8 @@ module.exports = {
// Flip on Y because the Y axis is on the opposite side of direct basis.
// It avoids models to be like a mirror refection.
scaleMatrix.makeScale(scaleX, -scaleY, scaleZ);
this._threeModelGroup.updateMatrix();
this._threeModelGroup.applyMatrix4(scaleMatrix);
threeModelGroup.updateMatrix();
threeModelGroup.applyMatrix4(scaleMatrix);
if (this._keepAspectRatio) {
// Reduce the object dimensions to keep aspect ratio.
@@ -3347,7 +3391,7 @@ module.exports = {
this._defaultDepth = this._originalDepth;
}
this._threeObject.add(this._threeModelGroup);
this._threeObject.add(threeModelGroup);
}
updateThreeObject() {