mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-07 18:42:10 +00:00
Lock unlock object. (#304)
Co-authored-by: Quicksticks-oss <chongobongotoday@gmail.com> Co-authored-by: Victor <victor@storyteller.ai>
This commit is contained in:
3 files changed
+122
-12
No files matched your search
@@ -1,9 +1,11 @@
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { useContext, useEffect, useId, useState } from "react";
|
||||
import { Transition } from "@headlessui/react";
|
||||
import {
|
||||
faChevronDown,
|
||||
faChevronUp,
|
||||
faCube,
|
||||
faLock,
|
||||
faLockOpen,
|
||||
faTrash,
|
||||
} from "@fortawesome/pro-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
@@ -66,6 +68,12 @@ export const ControlPanelSceneObject = () => {
|
||||
const [inputsUpdated, inputsUpdatedSet] = useState(false);
|
||||
const [inputsFocused, inputsFocusedSet] = useState(false);
|
||||
|
||||
const [locked, lockedSet] = useState(false);
|
||||
|
||||
const [color, colorSet] = useState("#ffffff");
|
||||
|
||||
const colorInputId = useId();
|
||||
|
||||
// clears leading and trailing zeros
|
||||
const sanitizeNumericInput = (input: string): number => {
|
||||
const regex = /(\-?\d+)(\.\d+)?/;
|
||||
@@ -132,7 +140,7 @@ export const ControlPanelSceneObject = () => {
|
||||
|
||||
useEffect(() => {
|
||||
const isCurrentObj =
|
||||
appUiState.controlPanel.currentSceneObject.object_uuid === initializedObj;
|
||||
(editorEngine?.selected?.uuid || "") === initializedObj;
|
||||
// TODO this causes a subtle bug because it renders way too many times.
|
||||
if (!appUiState.controlPanel.currentSceneObject) {
|
||||
return;
|
||||
@@ -175,11 +183,19 @@ export const ControlPanelSceneObject = () => {
|
||||
localPositionSet(numsToStrings(vectors.position));
|
||||
localRotationSet(numsToStrings(vectors.rotation));
|
||||
localScaleSet(numsToStrings(vectors.scale));
|
||||
|
||||
lockedSet(
|
||||
editorEngine.isObjectLocked(editorEngine?.selected?.uuid || ""),
|
||||
);
|
||||
colorSet(editorEngine?.selected?.userData.color);
|
||||
} else if (!appUiState.controlPanel.isShowing && isCurrentObj) {
|
||||
initializedObjSet("");
|
||||
localPositionSet(defaultAxises);
|
||||
localRotationSet(defaultAxises);
|
||||
localScaleSet(defaultAxises);
|
||||
|
||||
lockedSet(false);
|
||||
colorSet("#ffffff");
|
||||
}
|
||||
|
||||
// updating engine if values originate from the inputs and are valid
|
||||
@@ -213,6 +229,11 @@ export const ControlPanelSceneObject = () => {
|
||||
return null;
|
||||
}
|
||||
|
||||
const toggleLock = () => {
|
||||
lockedSet((lockState: boolean) => !lockState);
|
||||
editorEngine.lockUnlockObject(editorEngine?.selected?.uuid || "");
|
||||
};
|
||||
|
||||
const handlePositionChange = (xyz: XYZ) => {
|
||||
localPositionSet(xyz);
|
||||
inputsUpdatedSet(true);
|
||||
@@ -398,6 +419,35 @@ export const ControlPanelSceneObject = () => {
|
||||
leaveFrom="opacity-100 max-h-96"
|
||||
leaveTo="opacity-0 max-h-0"
|
||||
className={"flex flex-col gap-2 overflow-y-auto"}>
|
||||
<Button
|
||||
variant="secondary"
|
||||
icon={locked ? faLockOpen : faLock}
|
||||
onClick={toggleLock}>
|
||||
{locked ? "Unlock" : "Lock"} object
|
||||
</Button>
|
||||
|
||||
<div className="flex flex-col gap-1">
|
||||
<H5>Color</H5>
|
||||
<input
|
||||
className="h-0 w-0 cursor-pointer opacity-0"
|
||||
id={colorInputId}
|
||||
onChange={(e: React.ChangeEvent) => {
|
||||
editorEngine.setColor(
|
||||
editorEngine?.selected?.uuid || "",
|
||||
e.target.value,
|
||||
);
|
||||
colorSet(e.target.value);
|
||||
}}
|
||||
type="color"
|
||||
value={color}
|
||||
/>
|
||||
<Button
|
||||
className="cursor-pointer p-3.5"
|
||||
htmlFor={colorInputId}
|
||||
style={{
|
||||
backgroundColor: color,
|
||||
}}></Button>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<H5>Location</H5>
|
||||
<InputVector
|
||||
|
||||
@@ -558,6 +558,44 @@ class Editor {
|
||||
});
|
||||
}
|
||||
|
||||
isObjectLocked(object_uuid: string) {
|
||||
let object = this.activeScene.get_object_by_uuid(object_uuid);
|
||||
if(object){
|
||||
if(object.userData["locked"] == undefined){
|
||||
object.userData["locked"] = false;
|
||||
}
|
||||
return object.userData["locked"];
|
||||
}
|
||||
console.log("No object found.");
|
||||
return false;
|
||||
}
|
||||
|
||||
lockUnlockObject(object_uuid: string) {
|
||||
let object = this.activeScene.get_object_by_uuid(object_uuid);
|
||||
if(object){
|
||||
if(object.userData["locked"] == undefined){
|
||||
object.userData["locked"] = false;
|
||||
}
|
||||
object.userData["locked"] = !object.userData["locked"];
|
||||
|
||||
if(object.userData["locked"]){
|
||||
this.removeTransformControls(false);
|
||||
}
|
||||
else if (this.control) {
|
||||
this.activeScene.scene.add(this.control);
|
||||
this.control.attach(this.selected);
|
||||
}
|
||||
|
||||
return object.userData["locked"];
|
||||
}
|
||||
console.log("No object found.");
|
||||
return false;
|
||||
}
|
||||
|
||||
setColor(object_uuid: string, hex_color: string) {
|
||||
this.activeScene.setColor(object_uuid, hex_color);
|
||||
}
|
||||
|
||||
// TO UPDATE selected objects in the scene might want to add to the scene ...
|
||||
async setSelectedObject(position: XYZ, rotation: XYZ, scale: XYZ) {
|
||||
if (this.selected != undefined || this.selected != null) {
|
||||
@@ -625,19 +663,22 @@ class Editor {
|
||||
* Doesn't retain those controls.
|
||||
* @returns
|
||||
*/
|
||||
private removeTransformControls() {
|
||||
if (this.control == undefined) {
|
||||
return;
|
||||
private removeTransformControls(remove_outline:boolean=true) {
|
||||
if (this.control == undefined) {
|
||||
return;
|
||||
}
|
||||
if (this.outlinePass == undefined) {
|
||||
return;
|
||||
}
|
||||
if(remove_outline){
|
||||
this.last_selected = this.selected;
|
||||
this.selected = undefined;
|
||||
this.publishSelect();
|
||||
}
|
||||
if (this.outlinePass == undefined) {
|
||||
return;
|
||||
}
|
||||
this.last_selected = this.selected;
|
||||
this.selected = undefined;
|
||||
this.publishSelect();
|
||||
this.control.detach();
|
||||
this.activeScene.scene.remove(this.control);
|
||||
this.outlinePass.selectedObjects = [];
|
||||
if(remove_outline)
|
||||
this.outlinePass.selectedObjects = [];
|
||||
}
|
||||
|
||||
switchCameraView() {
|
||||
|
||||
@@ -228,6 +228,24 @@ class Scene {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
setColor(object_uuid: string, hex_color: string) {
|
||||
let object = this.get_object_by_uuid(object_uuid);
|
||||
if(object) {
|
||||
object.userData["color"] = hex_color;
|
||||
object.traverse((c: THREE.Object3D) => {
|
||||
if (c instanceof THREE.Mesh) {
|
||||
if (c.userData["base"] == undefined) {
|
||||
c.userData["base"] = c.material.color.getHex();
|
||||
}
|
||||
var currentColor = new THREE.Color(c.userData["base"]);
|
||||
var tint = new THREE.Color(hex_color);
|
||||
currentColor.multiply(tint);
|
||||
c.material.color.set(new THREE.Color(currentColor));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async loadGlbWithPlaceholder(
|
||||
media_id: string,
|
||||
name: string,
|
||||
@@ -294,6 +312,7 @@ class Scene {
|
||||
throw Error("GLB Did not contain an object or children.");
|
||||
}
|
||||
|
||||
|
||||
return child_result;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user