mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Improve typing of the 3D object editor renderers (#7410)
- Don't show in changelog
This commit is contained in:
@@ -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 !==
|
||||
|
@@ -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() {
|
||||
|
Reference in New Issue
Block a user