Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions api/mesh.js
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ export const flockMesh = {
? flock.getGroundLevelAt(px, pz)
: py;

mesh.position = new flock.BABYLON.Vector3(px, resolvedY, pz);
flock.setBlockPositionOnMesh(mesh, { x: px, y: resolvedY, z: pz, useY: true });

mesh.metadata = { ...(mesh.metadata || {}), shapeType };
mesh.metadata.blockKey = mesh.name;
Expand All @@ -293,7 +293,7 @@ export const flockMesh = {
if (shouldResolveGroundLevel && !flock.ground) {
flock.waitForGroundReady().then(() => {
const groundY = flock.getGroundLevelAt(px, pz);
mesh.position.y = groundY;
flock.setBlockPositionOnMesh(mesh, { x: px, y: groundY, z: pz, useY: true });
if (mesh.physics) {
mesh.physics.setTargetTransform(
mesh.position,
Expand Down
16 changes: 7 additions & 9 deletions api/shapes.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,6 @@ export const flockShapes = {
// Initialise the mesh with position, color, and other properties
flock.initializeMesh(newBox, position, color, "Box", alpha);

newBox.position.y += height / 2; // Middle of the box
newBox.metadata = newBox.metadata || {};
newBox.metadata.blockKey = blockKey;

Expand Down Expand Up @@ -349,7 +348,6 @@ export const flockShapes = {

// Initialise the mesh with position, color, and other properties
flock.initializeMesh(newSphere, position, color, "Sphere", alpha);
newSphere.position.y += diameterY / 2;

newSphere.metadata = newSphere.metadata || {};
newSphere.metadata.blockKey = blockKey;
Expand Down Expand Up @@ -433,7 +431,6 @@ export const flockShapes = {

// Initialise the mesh with position, color, and other properties
flock.initializeMesh(newCylinder, position, color, "Cylinder", alpha);
newCylinder.position.y += height / 2;
// Initialise the mesh with position, color, and other properties

newCylinder.metadata = newCylinder.metadata || {};
Expand Down Expand Up @@ -504,7 +501,6 @@ export const flockShapes = {

// Initialise the mesh with position, color, and other properties
flock.initializeMesh(newCapsule, position, color, "Capsule", alpha);
newCapsule.position.y += height / 2;

flock.setCapsuleUVs(newCapsule, radius, height, 1); // Adjust texturePhysicalSize as needed

Expand Down Expand Up @@ -576,11 +572,13 @@ export const flockShapes = {
newPlane.metadata.shape = "plane";
newPlane.metadata.blockKey = blockKey;

newPlane.position = new flock.BABYLON.Vector3(
position[0],
position[1] + height / 2,
position[2],
);
flock.setBlockPositionOnMesh(newPlane, {
x: position[0],
y: position[1],
z: position[2],
useY: true,
meshName: newPlane.name,
});

const planeBody = new flock.BABYLON.PhysicsBody(
newPlane,
Expand Down
130 changes: 100 additions & 30 deletions api/transform.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,89 @@
let flock;

function resolvePositionInputs(
mesh,
{ x = 0, y = 0, z = 0, useY = true, meshName = "" } = {},
) {
const nextX = x ?? mesh.position.x;
const nextY = y ?? mesh.position.y;
const nextZ = z ?? mesh.position.z;

return {
x: nextX,
y: nextY,
z: nextZ,
useY,
isCamera: meshName === "__active_camera__",
};
}

function applyPositionWithCurrentBaseRule(
mesh,
{ x = 0, y = 0, z = 0, useY = true, meshName = "" } = {},
) {
const { x: nextX, y: nextY, z: nextZ, isCamera } = resolvePositionInputs(
mesh,
{
x,
y,
z,
useY,
meshName,
},
);

mesh.position.set(nextX, useY ? nextY : mesh.position.y, nextZ);

if (useY && !isCamera && typeof mesh.getBoundingInfo === "function") {
mesh.computeWorldMatrix(true);
mesh.refreshBoundingInfo?.();
const boundingInfo = mesh.getBoundingInfo();
const minWorldY = boundingInfo?.boundingBox?.minimumWorld?.y;

if (Number.isFinite(minWorldY)) {
const deltaY = nextY - minWorldY;
if (Math.abs(deltaY) > 1e-6) {
mesh.position.y += deltaY;
}
}
}

mesh.computeWorldMatrix(true);

return {
x: mesh.position.x,
y: mesh.position.y,
z: mesh.position.z,
};
}

export function setFlockReference(ref) {
flock = ref;
}

export const flockTransform = {
async setBlockPositionOnMesh(
mesh,
{ x = 0, y = 0, z = 0, useY = true, meshName = "" } = {},
) {
if (!mesh) return;

let nextY = y;
const groundLevelSentinel = -999999;
const numericY = typeof nextY === "string" ? Number(nextY) : nextY;
if (nextY === "__ground__level__" || numericY === groundLevelSentinel) {
await flock.waitForGroundReady();
nextY = flock.getGroundLevelAt(x, z);
}

applyPositionWithCurrentBaseRule(mesh, {
x,
y: nextY,
z,
useY,
meshName: meshName || mesh.name || "",
});
},
positionAt(meshName, { x = 0, y = 0, z = 0, useY = true } = {}) {
return new Promise((resolve, reject) => {
flock.whenModelReady(meshName, async (mesh) => {
Expand All @@ -17,13 +96,6 @@ export const flockTransform = {
y ??= mesh.position.y;
z ??= mesh.position.z;

const groundLevelSentinel = -999999;
const numericY = typeof y === "string" ? Number(y) : y;
if (y === "__ground__level__" || numericY === groundLevelSentinel) {
await flock.waitForGroundReady();
y = flock.getGroundLevelAt(x, z);
}

if (mesh.physics) {
if (
mesh.physics.getMotionType() !==
Expand All @@ -35,31 +107,13 @@ export const flockTransform = {
}
}

// Use a consistent placement rule: requested Y is mesh base (minimumWorld.y)
// so imported models and primitives share the same semantics.
mesh.position.set(
await this.setBlockPositionOnMesh(mesh, {
x,
useY ? y : mesh.position.y,
y,
z,
);

if (
useY &&
meshName !== "__active_camera__" &&
typeof mesh.getBoundingInfo === "function"
) {
mesh.computeWorldMatrix(true);
mesh.refreshBoundingInfo?.();
const boundingInfo = mesh.getBoundingInfo();
const minWorldY = boundingInfo?.boundingBox?.minimumWorld?.y;

if (Number.isFinite(minWorldY)) {
const deltaY = y - minWorldY;
if (Math.abs(deltaY) > 1e-6) {
mesh.position.y += deltaY;
}
}
}
useY,
meshName,
});

// Update physics and world matrix
if (mesh.physics) {
Expand Down Expand Up @@ -837,6 +891,22 @@ export const flockTransform = {
});
});
},

getBlockPositionFromMesh(mesh) {
if (!mesh) return { x: 0, y: 0, z: 0 };

mesh.computeWorldMatrix?.(true);
mesh.refreshBoundingInfo?.();

const boundingInfo = mesh.getBoundingInfo?.();
const minY = boundingInfo?.boundingBox?.minimumWorld?.y;

return {
x: mesh.position?.x ?? 0,
y: Number.isFinite(minY) ? minY : (mesh.position?.y ?? 0),
z: mesh.position?.z ?? 0,
};
},
_getAnchor(mesh) {
if (!mesh) return null;

Expand Down
19 changes: 14 additions & 5 deletions ui/gizmos.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
setBlockXYZ,
duplicateBlockAndInsert,
findParentWithBlockId,
calculateYPosition,
setNumberInputs,
getNumberInput,
} from "./blocklyutil.js";
Expand Down Expand Up @@ -732,8 +731,13 @@ export function toggleGizmo(gizmoType) {
const block = meshMap[mesh.metadata.blockKey];

if (block) {
const meshY = calculateYPosition(mesh, block);
setBlockXYZ(block, mesh.position.x, meshY, mesh.position.z);
const blockPosition = flock.getBlockPositionFromMesh(mesh);
setBlockXYZ(
block,
blockPosition.x,
blockPosition.y,
blockPosition.z,
);
}
});

Expand Down Expand Up @@ -779,8 +783,13 @@ export function toggleGizmo(gizmoType) {
const block = meshMap[mesh.metadata.blockKey];

if (block) {
const meshY = calculateYPosition(mesh, block);
setBlockXYZ(block, mesh.position.x, meshY, mesh.position.z);
const blockPosition = flock.getBlockPositionFromMesh(mesh);
setBlockXYZ(
block,
blockPosition.x,
blockPosition.y,
blockPosition.z,
);
}
});

Expand Down