Skip to content

Commit

Permalink
feat(component): utils to handle light component in entity
Browse files Browse the repository at this point in the history
  • Loading branch information
sheilaXu authored and mumanity committed Oct 23, 2023
1 parent 592c435 commit 26a1494
Show file tree
Hide file tree
Showing 19 changed files with 611 additions and 92 deletions.
7 changes: 6 additions & 1 deletion packages/scene-composer/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,10 @@ module.exports = {
},
},
],
ignorePatterns: ['src/three/GLTFLoader.js', 'src/three/tiles3d/*', 'tools/watch-build.js'],
ignorePatterns: [
'src/three/GLTFLoader.js',
'src/three/tiles3d/*',
'tools/watch-build.js',
'src/assets/auto-gen/icons/*',
],
};
2 changes: 1 addition & 1 deletion packages/scene-composer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"convert-svg": "npx @svgr/cli --out-dir src/assets/auto-gen/icons/ --typescript --index-template tools/index-template.js -- src/assets/icons/",
"release": "run-s compile copy-assets",
"copy-assets": "copyfiles -e \"**/*.tsx\" -e \"**/*.ts\" -e \"**/*.snap\" -e \"**/*.js\" -e \"**/*.jsx\" -e \"**/*.json\" \"src/**/*\" dist/",
"lint": "eslint . --max-warnings=510",
"lint": "eslint . --max-warnings=484",
"fix": "eslint --fix .",
"test": "jest --config jest.config.ts --coverage --silent",
"test:dev": "jest --config jest.config.ts --coverage",
Expand Down
10 changes: 5 additions & 5 deletions packages/scene-composer/src/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,27 +74,27 @@ export const DEFAULT_CAMERA_SETTINGS = {
};

const DEFAULT_DIRECTIONAL_LIGHT_SETTINGS: Component.IDirectionalLightSettings = {
color: 0xffffff,
color: '#ffffff',
intensity: 1,
castShadow: true,
};

const DEFAULT_POINT_LIGHT_SETTINGS: Component.IPointLightSettings = {
color: 0xffffff,
color: '#ffffff',
intensity: 1,
decay: 2.0,
distance: 0,
castShadow: true,
};

const DEFAULT_AMBIENT_LIGHT_SETTINGS: Component.IAmbientLightSettings = {
color: 0xffffff,
color: '#ffffff',
intensity: 1,
};

const DEFAULT_HEMISPHERE_LIGHT_SETTINGS: Component.IHemisphereLightSettings = {
color: 0xffffff,
groundColor: 0x333333,
color: '#ffffff',
groundColor: '#333333',
intensity: 1,
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,18 @@
import React, { useContext, useEffect, useLayoutEffect, useState, useCallback } from 'react';
import { useIntl, defineMessages } from 'react-intl';
import { Checkbox, FormField, Select, SpaceBetween } from '@awsui/components-react';
import { ColorRepresentation } from 'three';

import useLogger from '../../../logger/react-logger/hooks/useLogger';
import { Color, LightType } from '../../../models/SceneModels';
import { Component, LightType } from '../../../models/SceneModels';
import { ILightComponentInternal, useStore } from '../../../store';
import { sceneComposerIdContext } from '../../../common/sceneComposerIdContext';
import { IComponentEditorProps } from '../ComponentEditor';
import { DEFAULT_LIGHT_SETTINGS_MAP } from '../../../common/constants';
import { decToHexString, hexStringToDec, parseFloatOrDefault } from '../../../utils/mathUtils';
import { parseFloatOrDefault } from '../../../utils/mathUtils';
import { NumericInput } from '../CommonPanelComponents';
import { ColorPicker } from '../ColorPicker/ColorPicker';
import { hexString } from '../ColorPicker/ColorPickerHelpers';

type OnLightSettingsUpdatedCallback = (lightSettings: unknown) => void;

export function colorToHexString(color: Color) {
if (typeof color === 'string') {
// assume the string color is css-style hex
return color;
}

return decToHexString(color);
}
type OnLightSettingsUpdatedCallback = (lightSettings: Component.ILightSettings) => void;

function createInputForField(
fieldName: string,
Expand All @@ -37,9 +26,9 @@ function createInputForField(
return (
<FormField key={index} label={intl.formatMessage({ defaultMessage: 'Color', description: 'Form Field label' })}>
<ColorPicker
color={colorToHexString(lightSettings.color)}
onChange={(newColor: ColorRepresentation) => {
setLightSettings({ ...lightSettings, color: hexStringToDec(hexString(newColor)) });
color={lightSettings.color}
onChange={(newColor: string) => {
setLightSettings({ ...lightSettings, color: newColor });
setDirty(true);
}}
/>
Expand Down Expand Up @@ -124,9 +113,9 @@ function createInputForField(
label={intl.formatMessage({ defaultMessage: 'Ground Color', description: 'Form Field label' })}
>
<ColorPicker
color={colorToHexString(lightSettings.groundColor)}
onChange={(newColor: ColorRepresentation) => {
setLightSettings({ ...lightSettings, groundColor: hexStringToDec(hexString(newColor)) });
color={lightSettings.groundColor}
onChange={(newColor: string) => {
setLightSettings({ ...lightSettings, groundColor: newColor });
setDirty(true);
}}
/>
Expand All @@ -135,7 +124,10 @@ function createInputForField(
}
}

function LightSettingsEditor(props: { lightSettings: any; onSettingsUpdated: OnLightSettingsUpdatedCallback }) {
function LightSettingsEditor(props: {
lightSettings: Component.ILightSettings;
onSettingsUpdated: OnLightSettingsUpdatedCallback;
}) {
const [lightSettings, setLightSettings] = useState(props.lightSettings);
const [dirty, setDirty] = useState(false);

Expand Down Expand Up @@ -209,7 +201,7 @@ export const LightComponentEditor: React.FC<IComponentEditorProps> = ({ node, co
}));

const onLightSettingsUpdated = useCallback(
(lightSettings: any) => {
(lightSettings: Component.ILightSettings) => {
log?.verbose('updated on light settings', lightSettings);

const currentLightComponent = getSceneNodeByRef(node.ref)?.components.find(
Expand All @@ -223,7 +215,7 @@ export const LightComponentEditor: React.FC<IComponentEditorProps> = ({ node, co

updateComponentInternal(node.ref, updatedLightComponent, true);
},
[log, updateComponentInternal],
[log, updateComponentInternal, node.ref, component.ref],
);

const onLightTypeUpdated = (lightType: string) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import React from 'react';
import { create } from 'react-test-renderer';

import LightComponent from '..';
import { LightType } from '../../../../models/SceneModels';
import { Component, LightType } from '../../../../models/SceneModels';
import { ISceneNodeInternal } from '../../../../store';
import { KnownComponentType } from '../../../../interfaces';

jest.mock('@react-three/fiber', () => {
const originalModule = jest.requireActual('@react-three/fiber');
Expand All @@ -23,7 +25,7 @@ describe('LightComponent', () => {
distance: 100,
decay: 0.1,
groundColor: 'white',
} as any;
} as Component.ILightSettings;

[
['Point', LightType.Point],
Expand All @@ -35,8 +37,13 @@ describe('LightComponent', () => {
it(`should render correctly for ${value[0]} light`, () => {
const container = create(
<LightComponent
node={{ name: 'Light' } as any}
component={{ ref: 'light-ref', lightType: value[1] as any, lightSettings } as any}
node={{ name: 'Light' } as ISceneNodeInternal}
component={{
ref: 'light-ref',
type: KnownComponentType.Light,
lightType: value[1] as LightType,
lightSettings,
}}
/>,
);

Expand Down
12 changes: 9 additions & 3 deletions packages/scene-composer/src/models/SceneModels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ export namespace Component {
}

interface ILightSettingsBase {
color: Color;
color: string;
intensity: number;
}

Expand All @@ -266,11 +266,17 @@ export namespace Component {
export interface IAmbientLightSettings extends ILightSettingsBase {}

export interface IHemisphereLightSettings extends ILightSettingsBase {
groundColor: Color;
groundColor: string;
}

export type ILightSettings =
| IDirectionalLightSettings
| IAmbientLightSettings
| IHemisphereLightSettings
| IPointLightSettings;

export interface Light extends IComponent {
lightType: LightType;
lightSettings: IDirectionalLightSettings | IAmbientLightSettings | IHemisphereLightSettings | IPointLightSettings;
lightSettings: ILightSettings;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import SerializationHelpers, { exportsForTesting } from '../serializationHelpers';
import { ERROR_MESSAGE_DICT, ErrorCode, ErrorLevel, IModelRefComponent, KnownComponentType } from '../../..';
import { generateUUID } from '../../../utils/mathUtils';
import { Component, Node } from '../../../models/SceneModels';
import { Component, LightType, ModelType, Node } from '../../../models/SceneModels';
import { ISceneComponentInternal, ISceneDocumentInternal, ISceneNodeInternal } from '../..';

jest.mock('../../../utils/mathUtils', () => ({
Expand All @@ -20,14 +20,17 @@ describe('serializationHelpers', () => {

const errorCollector = [];
const glb = exportsForTesting.createModelRefComponent(
{ modelType: 'GLB' } as any,
{ modelType: 'GLB' } as Component.ModelRef,
errorCollector,
) as unknown as ISceneNodeInternal;
const gltf = exportsForTesting.createModelRefComponent(
{ modelType: 'GLTF' } as any,
{ modelType: 'GLTF' } as Component.ModelRef,
errorCollector,
) as unknown as ISceneNodeInternal;
const error = exportsForTesting.createModelRefComponent({ modelType: 'OBJ' } as any, errorCollector);
const error = exportsForTesting.createModelRefComponent(
{ modelType: 'OBJ' as ModelType } as Component.ModelRef,
errorCollector,
);

expect(glb.ref).toEqual('test-uuid');
expect(gltf.ref).toEqual('other-test-uuid');
Expand Down Expand Up @@ -91,7 +94,7 @@ describe('serializationHelpers', () => {
type: 'Light',
lightType: 'Ambient',
lightSettings: {
color: 0xffffff,
color: '#ffffff',
intensity: 1,
volume: 'full',
},
Expand Down Expand Up @@ -432,19 +435,26 @@ describe('serializationHelpers', () => {
const component = {
type: Component.Type.Light,
ref: 'test-uuid',
lightType: 'Ambient',
lightType: LightType.Ambient,
lightSettings: {
color: 0xffffff,
intensity: 1,
volume: 'full',
},
} as Component.Light;
};
const expected: Component.Light = {
...component,
lightSettings: {
...component.lightSettings,
color: '#ffffff',
},
};

const node = {} as ISceneNodeInternal;

const deserializedComponent = exportsForTesting.deserializeComponent(component, node, resolver, [], {});

expect(deserializedComponent).toEqual(component);
expect(deserializedComponent).toEqual(expected);
});

it('should create a modelShader', () => {
Expand Down Expand Up @@ -542,7 +552,7 @@ describe('serializationHelpers', () => {
type: Component.Type.Light,
lightType: 'Ambient',
lightSettings: {
color: 0xffffff,
color: '#ffffff',
intensity: 1,
volume: 'full',
},
Expand Down Expand Up @@ -756,7 +766,7 @@ describe('serializationHelpers', () => {
type: Component.Type.Light,
lightType: 'Ambient',
lightSettings: {
color: 0xffffff,
color: '#ffffff',
intensity: 1,
volume: 'full',
},
Expand Down
20 changes: 14 additions & 6 deletions packages/scene-composer/src/store/helpers/serializationHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { KnownComponentType } from '../../interfaces';
import DebugLogger from '../../logger/DebugLogger';
import { Component, DistanceUnit, ModelType, Node, Scene } from '../../models/SceneModels';
import { isDynamicNode } from '../../utils/entityModelUtils/sceneUtils';
import { generateUUID } from '../../utils/mathUtils';
import { colorToHexString, generateUUID } from '../../utils/mathUtils';
import {
IAnchorComponentInternal,
IAnimationComponentInternal,
Expand Down Expand Up @@ -164,12 +164,20 @@ function createLightComponent(

// merge light settings with default settings so that all fields have valid default values
const defaultLightSettings = DEFAULT_LIGHT_SETTINGS_MAP[light.lightType];
const lightSettings = Object.assign({}, defaultLightSettings, light.lightSettings);
if (lightSettings.color) {
lightSettings.color = colorToHexString(lightSettings.color);
}
const groundColor = (lightSettings as Component.IHemisphereLightSettings).groundColor;
if (groundColor) {
(lightSettings as Component.IHemisphereLightSettings).groundColor = colorToHexString(groundColor);
}

return {
ref: generateUUID(),
type: 'Light',
type: KnownComponentType.Light,
lightType: light.lightType,
lightSettings: Object.assign({}, defaultLightSettings, light.lightSettings),
lightSettings,
};
}

Expand All @@ -193,7 +201,7 @@ function createMotionIndicatorComponent(
const defaultSpeed = component.config.defaultSpeed !== undefined ? Number(component.config.defaultSpeed) : undefined;
return {
ref: generateUUID(),
type: 'MotionIndicator',
type: KnownComponentType.MotionIndicator,
shape: component.shape,
valueDataBindings: component.valueDataBindings,
config: { ...component.config, defaultSpeed },
Expand Down Expand Up @@ -638,7 +646,7 @@ function convertNodes(
}
const cameraArray = indexedObjectCollector[KnownComponentType.Camera]!;
const len = cameraArray.length;
const { ref, type, ...cameraComponent } = convertComponent(camera) as ICameraComponentInternal;
const { ref: _ref, type: _type, ...cameraComponent } = convertComponent(camera) as ICameraComponentInternal;
cameraArray.push(cameraComponent);
const indexedCameraComponent: Component.Camera = {
type: Component.Type.Camera,
Expand Down Expand Up @@ -692,7 +700,7 @@ function convertNodeIndexes(nodeRefs: string[], indexMap: Record<string, number>

// Component is really flexible so what this function does is just a shape change
function convertComponent(component: ISceneComponentInternal): Component.IComponent {
const { ref, ...componentWithoutRef } = component;
const { ref: _ref, ...componentWithoutRef } = component;

// TODO: we may add some more validations here.
return componentWithoutRef as unknown as Component.IComponent;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { createMotionIndicatorEntityComponent } from './motionIndicatorComponent
import { createModelRefComponent } from './modelRefComponent';
import { createNodeEntity } from './createNodeEntity';
import { createModelShaderEntityComponent } from './modelShaderComponent';
import { createLightEntityComponent } from './lightComponent';

jest.mock('./nodeComponent', () => ({
createNodeEntityComponent: jest.fn().mockReturnValue({ componentTypeId: '3d.node' }),
Expand All @@ -34,6 +35,9 @@ jest.mock('./modelRefComponent', () => ({
jest.mock('./modelShaderComponent', () => ({
createModelShaderEntityComponent: jest.fn().mockReturnValue({ componentTypeId: '3d.modelShader' }),
}));
jest.mock('./lightComponent', () => ({
createLightEntityComponent: jest.fn().mockReturnValue({ componentTypeId: '3d.light' }),
}));

describe('createNodeEntity', () => {
const createSceneEntity = jest.fn();
Expand Down Expand Up @@ -71,7 +75,8 @@ describe('createNodeEntity', () => {
const motionIndicator = { type: KnownComponentType.MotionIndicator, ref: 'indicator-ref' };
const modelRef = { type: KnownComponentType.ModelRef, ref: 'modelref-ref' };
const modelShader = { type: KnownComponentType.ModelShader, ref: 'modelShader-ref' };
const node = { ...defaultNode, components: [tag, overlay, camera, motionIndicator, modelRef, modelShader] };
const light = { type: KnownComponentType.Light, ref: 'light-ref' };
const node = { ...defaultNode, components: [tag, overlay, camera, motionIndicator, modelRef, modelShader, light] };

await createNodeEntity(node, 'parent', 'layer');

Expand All @@ -89,6 +94,7 @@ describe('createNodeEntity', () => {
MotionIndicator: { componentTypeId: '3d.motionIndicator' },
ModelRef: { componentTypeId: '3d.modelRef' },
ModelShader: { componentTypeId: '3d.modelShader' },
Light: { componentTypeId: '3d.light' },
},
});

Expand All @@ -106,5 +112,7 @@ describe('createNodeEntity', () => {
expect(createModelRefComponent).toHaveBeenCalledWith(modelRef);
expect(createModelShaderEntityComponent).toHaveBeenCalledTimes(1);
expect(createModelShaderEntityComponent).toHaveBeenCalledWith(modelShader);
expect(createLightEntityComponent).toHaveBeenCalledTimes(1);
expect(createLightEntityComponent).toHaveBeenCalledWith(light);
});
});

0 comments on commit 26a1494

Please sign in to comment.