Skip to content

Commit

Permalink
Tint color for 3D cube (#7354)
Browse files Browse the repository at this point in the history
add a tint color property for 3D cube.
  • Loading branch information
NeylMahfouf2608 authored Feb 6, 2025
1 parent 8c98239 commit b6e186e
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 15 deletions.
28 changes: 25 additions & 3 deletions Extensions/3D/Cube3DRuntimeObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ namespace gdjs {
rightFaceVisible: boolean;
topFaceVisible: boolean;
bottomFaceVisible: boolean;
tint: string;
materialType: 'Basic' | 'StandardWithoutMetalness';
};
}

type FaceName = 'front' | 'back' | 'left' | 'right' | 'top' | 'bottom';
const faceNameToBitmaskIndex = {
front: 0,
Expand All @@ -45,6 +45,7 @@ namespace gdjs {
trfb: integer;
frn: [string, string, string, string, string, string];
mt: number;
tint: number;
};

type Cube3DObjectNetworkSyncData = Object3DNetworkSyncData &
Expand All @@ -71,7 +72,7 @@ namespace gdjs {
];
_materialType: gdjs.Cube3DRuntimeObject.MaterialType =
gdjs.Cube3DRuntimeObject.MaterialType.Basic;

_tint: number;
constructor(
instanceContainer: gdjs.RuntimeInstanceContainer,
objectData: Cube3DObjectData
Expand Down Expand Up @@ -117,6 +118,11 @@ namespace gdjs {
objectData.content.topFaceResourceName,
objectData.content.bottomFaceResourceName,
];

this._tint = gdjs.rgbOrHexStringToNumber(
objectData.content.tint || '255;255;255'
);

this._materialType = this._convertMaterialType(
objectData.content.materialType
);
Expand Down Expand Up @@ -203,10 +209,15 @@ namespace gdjs {
if (this._faceResourceNames[faceIndex] === resourceName) {
return;
}

this._faceResourceNames[faceIndex] = resourceName;
this._renderer.updateFace(faceIndex);
}
setTint(tint: string): void {
const tintInHex = gdjs.rgbOrHexStringToNumber(tint);
if (tintInHex === this._tint) return;
this._tint = tintInHex;
this._renderer.updateTint();
}

/** @internal */
getFaceAtIndexResourceName(faceIndex: integer): string {
Expand Down Expand Up @@ -291,6 +302,10 @@ namespace gdjs {
newObjectData.content.frontFaceResourceName
);
}
if (oldObjectData.content.tint !== newObjectData.content.tint) {
this.setTint(newObjectData.content.tint);
}

if (
oldObjectData.content.backFaceResourceName !==
newObjectData.content.backFaceResourceName
Expand Down Expand Up @@ -423,6 +438,7 @@ namespace gdjs {
vfb: this._visibleFacesBitmask,
trfb: this._textureRepeatFacesBitmask,
frn: this._faceResourceNames,
tint: this._tint,
};
}

Expand Down Expand Up @@ -476,6 +492,12 @@ namespace gdjs {
}
}
}
if (networkSyncData.tint !== undefined) {
if (this._tint !== networkSyncData.tint) {
this._tint = networkSyncData.tint;
this._renderer.updateTint();
}
}
}

/**
Expand Down
37 changes: 28 additions & 9 deletions Extensions/3D/Cube3DRuntimeObjectPixiRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,13 @@ namespace gdjs {
instanceContainer: gdjs.RuntimeInstanceContainer
) {
const geometry = new THREE.BoxGeometry(1, 1, 1);
// TODO (3D) - feature: support color instead of texture?
const materials = [
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[0]),
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[1]),
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[2]),
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[3]),
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[4]),
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[5]),
];

const materials: THREE.Material[] = new Array(6)
.fill(0)
.map((_, index) =>
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[index])
);

const boxMesh = new THREE.Mesh(geometry, materials);

super(runtimeObject, instanceContainer, boxMesh);
Expand All @@ -92,6 +90,27 @@ namespace gdjs {
this.updateSize();
this.updatePosition();
this.updateRotation();
this.updateTint();
}
updateTint() {
const tints: number[] = [];

const normalizedTint = gdjs
.hexNumberToRGBArray(this._cube3DRuntimeObject._tint)
.map((component) => component / 255);

for (
let i = 0;
i < this._boxMesh.geometry.attributes.position.count;
i++
) {
tints.push(...normalizedTint);
}

this._boxMesh.geometry.setAttribute(
'color',
new THREE.BufferAttribute(new Float32Array(tints), 3)
);
}

updateFace(faceIndex: integer) {
Expand Down
58 changes: 56 additions & 2 deletions Extensions/3D/JsExtension.js
Original file line number Diff line number Diff line change
Expand Up @@ -822,7 +822,8 @@ module.exports = {
propertyName === 'bottomFaceResourceName' ||
propertyName === 'backFaceUpThroughWhichAxisRotation' ||
propertyName === 'facesOrientation' ||
propertyName === 'materialType'
propertyName === 'materialType' ||
propertyName === 'tint'
) {
objectContent[propertyName] = newValue;
return true;
Expand Down Expand Up @@ -902,6 +903,12 @@ module.exports = {
.setLabel(_('Depth'))
.setMeasurementUnit(gd.MeasurementUnit.getPixel())
.setGroup(_('Default size'));
objectProperties
.getOrCreate('tint')
.setValue(objectContent.tint || '255;255;255')
.setType('Color')
.setLabel(_('Tint'))
.setGroup(_('Texture'));

objectProperties
.getOrCreate('frontFaceResourceName')
Expand Down Expand Up @@ -1092,6 +1099,7 @@ module.exports = {
topFaceResourceRepeat: false,
bottomFaceResourceRepeat: false,
materialType: 'Basic',
tint: '255;255;255',
};

Cube3DObject.updateInitialInstanceProperty = function (
Expand Down Expand Up @@ -1568,6 +1576,21 @@ module.exports = {
.addParameter('imageResource', _('Image'), '', false)
.setFunctionName('setFaceResourceName');

object
.addScopedAction(
'SetTint',
_('Tint'),
_('Change the tint of the cube.'),
_('Change the tint of _PARAM0_ to _PARAM1_'),
_('Tint'),
'res/actions/color24.png',
'res/actions/color.png'
)
.addParameter('object', _('3D Cube'), 'Cube3DObject', false)
.addParameter('color', _('Tint'), '', false)
.getCodeExtraInformation()
.setFunctionName('setTint');

extension
.addExpressionAndConditionAndAction(
'number',
Expand Down Expand Up @@ -2338,6 +2361,7 @@ module.exports = {
this._facesOrientation = 'Y';
this._backFaceUpThroughWhichAxisRotation = 'X';
this._shouldUseTransparentTexture = false;
this._tint = '';

const geometry = new THREE.BoxGeometry(1, 1, 1);
const materials = [
Expand All @@ -2357,8 +2381,9 @@ module.exports = {

async _updateThreeObjectMaterials() {
const getFaceMaterial = async (project, faceIndex) => {
if (!this._faceVisibilities[faceIndex])
if (!this._faceVisibilities[faceIndex]) {
return getTransparentMaterial();
}

return await this._pixiResourcesLoader.getThreeMaterial(
project,
Expand Down Expand Up @@ -2389,6 +2414,28 @@ module.exports = {
this._updateTextureUvMapping();
}

_updateTint() {
const tints = [];
const normalizedTint = objectsRenderingService
.hexNumberToRGBArray(
objectsRenderingService.rgbOrHexToHexNumber(this._tint)
)
.map((component) => component / 255);

for (
let i = 0;
i < this._threeObject.geometry.attributes.position.count;
i++
) {
tints.push(...normalizedTint);
}

this._threeObject.geometry.setAttribute(
'color',
new THREE.BufferAttribute(new Float32Array(tints), 3)
);
}

static _getResourceNameToDisplay(objectConfiguration) {
return getFirstVisibleFaceResourceName(objectConfiguration);
}
Expand Down Expand Up @@ -2421,13 +2468,19 @@ module.exports = {

let materialsDirty = false;
let uvMappingDirty = false;
let tintDirty = false;

const shouldUseTransparentTexture =
object.content.enableTextureTransparency;
if (this._shouldUseTransparentTexture !== shouldUseTransparentTexture) {
this._shouldUseTransparentTexture = shouldUseTransparentTexture;
materialsDirty = true;
}
const tint = object.content.tint || '255;255;255';
if (this._tint !== tint) {
this._tint = tint;
tintDirty = true;
}

const faceResourceNames = [
object.content.frontFaceResourceName,
Expand Down Expand Up @@ -2520,6 +2573,7 @@ module.exports = {

if (materialsDirty) this._updateThreeObjectMaterials();
if (uvMappingDirty) this._updateTextureUvMapping();
if (tintDirty) this._updateTint();
}

/**
Expand Down
1 change: 1 addition & 0 deletions Extensions/JsExtensionTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ declare type ObjectsRenderingService = {
objectConfiguration: gd.ObjectConfiguration
) => string;
rgbOrHexToHexNumber: (value: string) => number;
hexNumberToRGBArray: (value: number) => [number, number, number];
registerClearCache: (clearCache: (_: any) => void) => void;
};

Expand Down
2 changes: 2 additions & 0 deletions GDJS/Runtime/pixi-renderers/pixi-image-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,12 +242,14 @@ namespace gdjs {
map: this.getThreeTexture(resourceName),
side: useTransparentTexture ? THREE.DoubleSide : THREE.FrontSide,
transparent: useTransparentTexture,
vertexColors: true,
})
: new THREE.MeshStandardMaterial({
map: this.getThreeTexture(resourceName),
side: useTransparentTexture ? THREE.DoubleSide : THREE.FrontSide,
transparent: useTransparentTexture,
metalness: 0,
vertexColors: true,
});
this._loadedThreeMaterials.put(cacheKey, material);
return material;
Expand Down
7 changes: 6 additions & 1 deletion newIDE/app/src/ObjectsRendering/ObjectsRenderingService.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ import * as PIXI_SPINE from 'pixi-spine';
import * as THREE from 'three';
import * as SkeletonUtils from 'three/examples/jsm/utils/SkeletonUtils';
import optionalRequire from '../Utils/OptionalRequire';
import { rgbOrHexToHexNumber } from '../Utils/ColorTransformer';
import {
rgbOrHexToHexNumber,
hexNumberToRGBArray,
} from '../Utils/ColorTransformer';

const path = optionalRequire('path');
const electron = optionalRequire('electron');
const gd: libGDevelop = global.gd;
Expand Down Expand Up @@ -277,6 +281,7 @@ const ObjectsRenderingService = {
}
},
rgbOrHexToHexNumber, // Expose a ColorTransformer function, useful to manage different color types for the extensions
hexNumberToRGBArray, // Expose a ColorTransformer function, useful to manage different color types for the extensions
gd, // Expose gd so that it can be used by renderers
PIXI, // Expose PIXI so that it can be used by renderers
THREE, // Expose THREE so that it can be used by renderers
Expand Down
1 change: 1 addition & 0 deletions newIDE/app/src/ObjectsRendering/PixiResourcesLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,7 @@ export default class PixiResourcesLoader {
map: texture,
side: useTransparentTexture ? THREE.DoubleSide : THREE.FrontSide,
transparent: useTransparentTexture,
vertexColors: true,
});

return material;
Expand Down
6 changes: 6 additions & 0 deletions newIDE/app/src/Utils/ColorTransformer.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ export const rgbColorToRGBString = (rgbColor: ?RGBColor) => {
return `${rgbColor.r};${rgbColor.g};${rgbColor.b}`;
};

export const hexNumberToRGBArray = (
hexNumber: number
): [number, number, number] => {
return [(hexNumber >> 16) & 0xff, (hexNumber >> 8) & 0xff, hexNumber & 0xff];
};

/**
* Convert a RGB color value to a Hex string.
* @note No "#" or "0x" are added.
Expand Down

0 comments on commit b6e186e

Please sign in to comment.