Skip to content

Commit

Permalink
Merge pull request #9 from Solvro/things-regarding-animation-start-an…
Browse files Browse the repository at this point in the history
…d-stop

Things regarding animation start and stop
  • Loading branch information
stepkos authored Oct 14, 2024
2 parents ef62e8c + 02cce32 commit fdec500
Show file tree
Hide file tree
Showing 9 changed files with 450 additions and 242 deletions.
18 changes: 13 additions & 5 deletions src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,18 @@ body {
flex-direction: row;
}

.cube-scene {
.main-scene {
flex-grow: 1;
overflow: auto;
position: relative;
/* transition: all 0.3s ease-in-out; */
}
.coord-scene {
position: absolute;
top: 25px;
height: 18.5vh;
width: 18.5vh;
}

.resizer {
position: absolute;
Expand Down Expand Up @@ -56,6 +62,7 @@ body {
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 1000;

width: 100%;
height: 100%;
Expand Down Expand Up @@ -250,9 +257,10 @@ body {

#coord-button {
position: absolute;
left: 10px;
top: 5px;
height: 25px;
z-index: 0;
width: 100%;
top: -25px;

background-color: #191b20;
box-shadow: none;
Expand All @@ -261,7 +269,7 @@ body {
border-top-left-radius: 0.3rem;
border-top-right-radius: 0.3rem;

font-size: 0.8vw; /* Adjust the text size based on viewport width */
font-size: 1.2vh; /* Adjust the text size based on viewport width */
text-align: center;
white-space: nowrap;
overflow: hidden;
Expand All @@ -286,7 +294,7 @@ body {
/* transition: 0.5s; */
}

.cube-scene {
.main-scene {
width: 100%;
height: 100%;
}
Expand Down
18 changes: 14 additions & 4 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
import "./App.css";
import CubeScene from "./components/CubeScene";
import Scenes from "./components/Scenes";
import CodeEditor from "./components/CodeEditor";
import { useState, useRef } from "react";

import { VscChevronDown, VscChevronUp } from "react-icons/vsc";

function App() {
const [code, setCode] = useState("");


const [execute, setExecute] = useState(0); // that's stupid and temporary aproach to trigger useEffect even when the code does not change
const [reset, setReset] = useState(0); // same aproach for reset button - easy to correct but I have no idea


const [isError, setIsError] = useState(false);
const [editorWidth, setEditorWidth] = useState(600);
const [isEditorVisible, setIsEditorVisible] = useState(true);
const [cubeSceneVisible, setCubeSceneVisible] = useState(true); // State for visibility
const [cubeSceneKey, setCubeSceneKey] = useState(0); // State for CubeScene key
const [numCubes, setNumCubes] = useState(5);
const minEditorWidth = 200;
const previousMouseX = useRef(null);

const handleExecuteCode = (newCode) => {
setCode(newCode);
setExecute(prev => ++prev);
};

const handleMouseDown = (event) => {
Expand Down Expand Up @@ -57,12 +65,14 @@ function App() {
return (
<div className="App">
<div className="container">
<CubeScene
<Scenes
execute={execute}
reset={reset}
key={cubeSceneKey}
code={code}
setIsError={setIsError}
isEditorVisible={isEditorVisible}
className={`cube-scene ${cubeSceneVisible ? "" : "hidden"}`}
numCubes={numCubes}
/>
<div
className={`code-editor ${isEditorVisible ? "" : "hidden"}`}
Expand All @@ -72,7 +82,7 @@ function App() {
{isEditorVisible ? <VscChevronDown /> : <VscChevronUp />}
</button>
<div className="resizer" onMouseDown={handleMouseDown} />
<CodeEditor onExecute={handleExecuteCode} isError={isError} />
<CodeEditor onExecute={handleExecuteCode} isError={isError} numCubes={numCubes} setNumCubes={setNumCubes} setReset={setReset} />
</div>
</div>
</div>
Expand Down
23 changes: 22 additions & 1 deletion src/components/CodeEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ import { VscDiffAdded, VscDiffRemoved, VscDebugStart } from "react-icons/vsc";
import { BiSolidPlusCircle } from "react-icons/bi";
import { BiWindowClose } from "react-icons/bi";

const CodeEditor = ({ onExecute, isError }) => {
const CodeEditor = ({ onExecute, isError , numCubes, setNumCubes, setReset }) => {
const [tempCubes, setTempCubes] = useState(numCubes);
const [code, setCode] = useState(() => {
const savedCode = localStorage.getItem("code");
return savedCode !== null
? JSON.parse(savedCode)
: ["/* Kod idzie tutaj */"];
});



useEffect(() => {
localStorage.setItem("code", JSON.stringify(code));
}, [code]);
Expand All @@ -38,9 +41,20 @@ const CodeEditor = ({ onExecute, isError }) => {
setCode(newCode);
};

const handleSliderChange = (event) => {
setTempCubes(event.target.value);
};

const handleSliderBlur = () => {
setNumCubes(tempCubes);
}

const handleExecute = () => {
onExecute(code[visibleIndex]);
};
const handleResetScene = () => {
setReset(prev => ++prev);
};

const addTextarea = () => {
setCode([...code, ""]);
Expand All @@ -57,6 +71,10 @@ const CodeEditor = ({ onExecute, isError }) => {

return (
<div className="code-editor-container">
<div className="slidecontainer">
<input type="range" min="5" max="10" step="1" value={tempCubes} onChange={handleSliderChange} onBlur={handleSliderBlur}/>
<div style={{color: "white"}}>{tempCubes}</div>
</div>
<div className="tab-container">
{code.map((_, index) => (
// <button
Expand Down Expand Up @@ -106,6 +124,9 @@ const CodeEditor = ({ onExecute, isError }) => {
<button onClick={handleExecute}>
<VscDebugStart />
</button>
<button onClick={handleResetScene}>
Reset Scene
</button>
</div>
);
};
Expand Down
135 changes: 135 additions & 0 deletions src/components/CoordScene.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import * as THREE from "three";
import { createSecondaryScene } from "./SecondarySceneCreation";

export const initializeCoordScene = (coordRefs) => {
const {
mountRef,
coordSceneRef,
coordCamRef,
coordRendererRef,
coordCubeRef,
mainCamera,
stopRenderRef,
} = coordRefs;
if (!mountRef.current) return;

cleanupCoordScene(coordRefs);

stopRenderRef.current = false;

const coordRenderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true,
});

const { secondaryScene, secondaryCamera, coordCube } = createSecondaryScene();
coordSceneRef.current = secondaryScene;
coordCamRef.current = secondaryCamera;
coordCubeRef.current = coordCube;
coordRendererRef.current = coordRenderer;

coordRendererRef.current.setSize(
mountRef.current.clientHeight,
mountRef.current.clientHeight
);
coordRendererRef.current.setClearColor(0x191b20, 0.8);

// Attach secondary renderer to the main component
const secondaryCubeDiv = document.createElement("div");
secondaryCubeDiv.style.position = "absolute";
secondaryCubeDiv.style.top = "0px";
secondaryCubeDiv.style.left = "0px";
secondaryCubeDiv.style.pointerEvents = "none"; // ignore pointer events for this overlay
mountRef.current.appendChild(secondaryCubeDiv);
secondaryCubeDiv.appendChild(coordRendererRef.current.domElement);

coordRefs.secondaryCubeDiv = secondaryCubeDiv;

// coord-button functionality
let button = document.getElementById("coord-button");

button.addEventListener("click", () => {
if (secondaryCubeDiv.style.display === "none") {
secondaryCubeDiv.style.display = "block";
button.innerHTML = "Hide Coordinates";
button.classList.remove("coord-button-closed");
} else {
secondaryCubeDiv.style.display = "none";
button.innerHTML = "Show Coordinates";
button.className = "coord-button-closed";
}
});

const renderLoop = () => {
if (!stopRenderRef.current) {
const fixedDistance = 1.9;

const direction = new THREE.Vector3();
direction
.subVectors(coordCamRef.current.position, coordCubeRef.current.position)
.normalize();

const mainCameraDirection = new THREE.Vector3();
mainCamera.current.getWorldDirection(mainCameraDirection);

const newPosition = new THREE.Vector3();
newPosition
.copy(coordCubeRef.current.position)
.add(mainCameraDirection.multiplyScalar(-fixedDistance));
coordCamRef.current.position.copy(newPosition);
coordCamRef.current.lookAt(coordCubeRef.current.position);

coordRendererRef.current.render(
coordSceneRef.current,
coordCamRef.current
);

requestAnimationFrame(renderLoop);
}
};

renderLoop();

const handleResize = () => {
if (!mountRef.current) return;
coordCamRef.current.aspect =
mountRef.current.clientHeight / mountRef.current.clientHeight;
coordCamRef.current.updateProjectionMatrix();
coordRendererRef.current.setSize(
mountRef.current.clientHeight,
mountRef.current.clientHeight
);
};

window.addEventListener("resize", handleResize);

// cleanup listener on unmount
return () => {
window.removeEventListener("resize", handleResize);
};
};

export const cleanupCoordScene = (coordRefs) => {
const { coordSceneRef, coordRendererRef, secondaryCubeDiv } = coordRefs;

if (coordRendererRef.current) {
if (secondaryCubeDiv && secondaryCubeDiv.parentNode) {
secondaryCubeDiv.parentNode.removeChild(secondaryCubeDiv);
}
coordRendererRef.current.dispose();
}

if (coordSceneRef.current) {
coordSceneRef.current.traverse((object) => {
if (object.geometry) object.geometry.dispose();
if (object.material) {
if (Array.isArray(object.material)) {
object.material.forEach((mat) => mat.dispose());
} else {
object.material.dispose();
}
}
});
coordSceneRef.current.clear(); // explicitly remove objects
}
};
64 changes: 64 additions & 0 deletions src/components/CreateCubes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import * as THREE from "three";
export const createCubes = (numCubes) => {
const color1 = new THREE.Color(0xff0000); // Red
const color2 = new THREE.Color(0x00ff00); // Green
const color3 = new THREE.Color(0x0000ff); // Blue

const cubesInRow = numCubes;
const smallCubeSize = 0.01;
const cubes = [];

// calculate the total size of the grid
const gridSize = cubesInRow * 0.1; // 0.1 is the spacing between each cube
const gridOffset = gridSize / 2 - 0.1 / 2; // center offset

for (let x = 0; x < cubesInRow; x++) {
cubes[x] = [];

for (let y = 0; y < cubesInRow; y++) {
cubes[x][y] = [];

for (let z = 0; z < cubesInRow; z++) {
const geometry = new THREE.BoxGeometry(
smallCubeSize,
smallCubeSize,
smallCubeSize
);

const normalizedX = x / (cubesInRow - 1);
const normalizedY = y / (cubesInRow - 1);
const normalizedZ = z / (cubesInRow - 1);

const averageRatio = (normalizedX + normalizedY + normalizedZ) / 3;

let color;
if (averageRatio < 0.5) {
const ratio = averageRatio * 2; // Scale to [0, 1]
color = color1.clone().lerp(color2, ratio);
} else {
const ratio = (averageRatio - 0.5) * 2; // Scale to [0, 1]
color = color2.clone().lerp(color3, ratio);
}

const material = new THREE.MeshPhongMaterial({
color: color,
emissive: color,
emissiveIntensity: 2,
});

const mesh = new THREE.Mesh(geometry, material);

// set the position with offset to ensure the grid is centered
mesh.position.set(
x * 0.1 - gridOffset,
y * 0.1 - gridOffset,
z * 0.1 - gridOffset
);

cubes[x][y][z] = mesh;
}
}
}

return cubes;
};
Loading

0 comments on commit fdec500

Please sign in to comment.