/**
* @file
*
* Summary.
* <p>R3F application for rendering a {@link https://visao.ca/what-is-glb-file/ glb} model
* of a {@link Engine Radial Pneumatic Engine}.</p>
*
* {@link external:react-three/fiber React-three-fiber} is a React renderer for three.js.<br>
* Build your scene declaratively with re-usable, self-contained components that react to state.
*
* <p>Usage: </p>
* <ul>
* <li>To install jsdoc and yarn:</li>
* <ul>
* <li>sudo npm install --global yarn</li>
* <li>sudo npm install -g jsdoc</li>
* </ul>
*
* <li>To run the version with modules and Node.js version {@link https://nodejs.org/en/blog/release/v16.16.0 16}
* or {@link https://nodejs.org/en/blog/release/v18.16.0 18}:</li>
* <ul>
* <li>cd rpe-app</li>
* <li>{@link https://www.npmjs.com npm} or {@link https://yarnpkg.com yarn} install</li>
* <li>{@link https://www.npmjs.com/package/react npm} or {@link https://yarnpkg.com/package/react yarn} start</li>
* </ul>
*
* <li>To use vercel {@link https://vercel.com/docs/cli cli} to run
* vercel {@link https://vercel.com/docs/cli/dev dev} before deploying:</li>
* <ul>
* <li>cd rpe-app</li>
* <li>{@link https://pnpm.io pnpm} i -g vercel or
* {@link https://pnpm.io pnpm} i -g vercel@latest (to update to the latest version)</li>
* <li>{@link https://www.npmjs.com npm} or {@link https://yarnpkg.com yarn} install</li>
* <li>{@link https://vercel.com vercel} dev</li>
* </ul>
* </ul>
*
* @author {@link https://sketchfab.com/slava Slava Z.}
* @author Paulo Roma.
* @since 26/09/2024
* @see <a href="../src/App.js">source</a>
* @see <a href="../package.json">package.json</a>
* @see {@link https://www.youtube.com/watch?app=desktop&v=DPl34H2ISsk I wish I knew this before using React Three Fiber}
* @see {@link https://r3f.docs.pmnd.rs/getting-started/examples R3F Examples}
*/
import { Suspense, useRef } from "react"
import { Canvas } from "@react-three/fiber"
import { Html, Bounds, Lightformer, Environment, OrbitControls, PerspectiveCamera, useEnvironment } from "@react-three/drei"
import { EffectComposer, SSAO, N8AO, SMAA, Selection, Outline } from "@react-three/postprocessing"
import { Engine } from "./Engine"
/**
* Three.js module.
* @external THREE
* @see {@link https://threejs.org/docs/#manual/en/introduction/Installation Installation}
* @see {@link https://discoverthreejs.com DISCOVER three.js}
* @see {@link https://riptutorial.com/ebook/three-js Learning three.js}
*/
/**
* <p>React</p>
* The library for web and native user interfaces
* @external react
* @see {@link https://react.dev/ React Top-Level API}
* @see {@link https://react.dev/reference/react/Suspense Suspense}
*/
/**
* <p>React DOM.</p>
* The react-dom package contains methods that are only supported
* for the web applications (which run in the browser DOM environment).
* <p>They are not supported for React Native.</p>
* @external react-dom
* @see {@link https://react.dev/reference/react-dom React DOM APIs}
*/
/**
* <p>A React renderer for three.js.</p>
* Build your scene declaratively with re-usable,
* self-contained components that react to state,
* are readily interactive and can participate in React's ecosystem.
* @external react-three/fiber
* @see {@link https://r3f.docs.pmnd.rs/api/canvas Canvas}
* @see {@link https://r3f.docs.pmnd.rs/api/events Events}
* @see {@link https://r3f.docs.pmnd.rs/getting-started/introduction R3F introduction}
* @see {@link https://byteofdev.com/posts/how-to-use-esm/ How to use ESM}
* @see {@link https://www.youtube.com/watch?v=DPl34H2ISsk I wish I knew this before using React Three Fiber}
* @see {@link https://r3f.docs.pmnd.rs/tutorials/how-it-works How does it work?}
*/
/**
* A growing collection of useful helpers and fully functional,
* ready-made abstractions for @react-three/fiber.
* @external react-three/drei
* @see {@link https://github.com/pmndrs/drei drei}
* @see {@link https://drei.docs.pmnd.rs/cameras/perspective-camera PerspectiveCamera}
* @see {@link https://drei.docs.pmnd.rs/controls/introduction Controls}
* @see {@link https://sbcode.net/react-three-fiber/orbit-controls/ OrbitControls}
* @see {@link http://drei.docs.pmnd.rs/misc/select Select}
* @see {@link https://drei.docs.pmnd.rs/staging/bounds Bounds}
* @see {@link http://drei.docs.pmnd.rs/staging/environment Environment}
* @see {@link http://drei.docs.pmnd.rs/staging/lightformer Lightformer}
*/
/**
* <p>A postprocessing wrapper for @react-three/fiber. </p>
* This is not (yet) meant for complex orchestration of effects,
* but can save you hundreds of LOC for a straight forward effects-chain.
* @external react-three/postprocessing
* @see {@link https://github.com/pmndrs/react-postprocessing react-postprocessing}
* @see {@link https://react-postprocessing.docs.pmnd.rs/introduction Introduction}
* @see {@link https://react-postprocessing.docs.pmnd.rs/effect-composer EffectComposer}
* @see {@link https://react-postprocessing.docs.pmnd.rs/selection Selection}
* @see {@link https://react-postprocessing.docs.pmnd.rs/effects/smaa SMAA}
* @see {@link https://react-postprocessing.docs.pmnd.rs/effects/ssao SSAO}
* @see {@link https://react-postprocessing.docs.pmnd.rs/effects/outline Outline}
*/
/**
* <p>A react Hook that lets you add a state variable to your component.</p>
* @function useState
* @memberof external:react
* @see {@link https://react.dev/reference/react/useState useState}
* @see {@link https://sbcode.net/react-three-fiber/use-state/ useState in R3F}
*/
/**
* <p>A react Hook that lets you reference a value that’s not needed for rendering.</p>
* @function useRef
* @memberof external:react
* @see {@link https://react.dev/reference/react/useRef useRef}
*/
/**
* <p>This hook gives you access to the state model which contains the
* default renderer, the scene, your camera, and so on.
* It also gives you the current size of the canvas in screen and viewport coordinates.</p>
* @function useThree
* @memberof external:react-three/fiber
* @see {@link https://r3f.docs.pmnd.rs/api/hooks Hooks}
* @see {@link https://sbcode.net/react-three-fiber/use-three/ useThree}
*/
/**
* Define the scene lighting and environment.
* @returns {ThreeElements} light elements.
*/
function ThreeScene() {
const envMap = useEnvironment({ preset: "warehouse" })
return (
<>
<ambientLight intensity={0.75} />
<Environment preset="warehouse" map={envMap} background></Environment>
</>
)
}
/**
* Creates a sphere.
* @param {Object} props information that you pass to a JSX tag.
* @param {Array<Number>} props.position sphere position.
* @param {Object} props.children e.g., material.
* @returns {ThreeElements} mesh with a sphere geometry.
*/
const Sphere = (props) => {
const sphereRef = useRef()
return (
<mesh ref={sphereRef} position={props.position}>
<sphereGeometry args={[10, 24, 24]} />
{props.children}
</mesh>
)
}
/**
* Creates a reflective sphere.
* @param {Object} props information that you pass to a JSX tag.
* @param {Array<Number>} props.position reflective sphere position.
* @returns {ThreeElements} sphere with standard material.
*/
function ReflectiveSphere(props) {
return (
<Sphere position={props.position}>
<meshStandardMaterial roughness={0.1} metalness={1} />
</Sphere>
)
}
/**
* Display a fallback until its children have finished loading.
* @returns {HTMLElement} fall back message.
*/
function Loading() {
return (
<Html>
<h2 style={{ color: "red" }}>🌀 Loading...</h2>
</Html>
)
}
/**
* <p>Returns a {@link https://legacy.reactjs.org/docs/introducing-jsx.html JSX}
* element with a R3F canvas.</p>
* In R3F, {@link external:react.useRef useRef()}
* can be used to encapsulate a reference to an instance
* of an object, as its current value.<br>
* This reference can then be passed to a component as a
* {@link https://react.dev/learn/passing-props-to-a-component prop}.
* @module
* @function App
* @returns {HTMLCanvasElement} R3F {@link external:react-three/fiber Canvas}.
* @see {@link external:react-three/postprocessing Postprocessing Effects}
*/
export default function App() {
return (
<Canvas dpr={[1, 2]}>
<PerspectiveCamera makeDefault fov={35} position={[0, 0, 200]} near={0.01} far={1000} />
<OrbitControls makeDefault />
<axesHelper args={[40]} />
<Suspense fallback={<Loading />}>
<ThreeScene />
<Selection>
<EffectComposer disableNormalPass multisampling={0} autoClear={false}>
<SSAO radius={0.05} intensity={150} luminanceInfluence={0.5} color="black" />
<SMAA />
<Outline visibleEdgeColor="white" hiddenEdgeColor="yellow" blur width={3000} edgeStrength={100} />
</EffectComposer>
<Bounds fit clip margin={1.2} damping={0}>
<Engine rotation={[Math.PI / 2, 0, 0]} />
<ReflectiveSphere position={[50, 0, 0]} />
<ReflectiveSphere position={[0, 0, 50]} />
<ReflectiveSphere position={[0, 45, 0]} />
</Bounds>
</Selection>
</Suspense>
</Canvas>
)
}