diff --git a/dist/index.css b/dist/index.css new file mode 100644 index 0000000..af29d02 --- /dev/null +++ b/dist/index.css @@ -0,0 +1,244 @@ +/* @tailwind base; */ + +.bg-gray-50 { + --tw-bg-opacity: 1; + background-color: rgba(249, 250, 251, var(--tw-bg-opacity)); +} + +.flex { + display: flex; +} + +.table { + display: table; +} + +.flex-col { + flex-direction: column; +} + +.items-center { + align-items: center; +} + +.justify-start { + justify-content: flex-start; +} + +.justify-center { + justify-content: center; +} + +.justify-between { + justify-content: space-between; +} + +.h-6 { + height: 1.5rem; +} + +.text-lg { + font-size: 1.125rem; + line-height: 1.75rem; +} + +.ml-2 { + margin-left: 0.5rem; +} + +.mr-auto { + margin-right: auto; +} + +.ml-auto { + margin-left: auto; +} + +.p-1 { + padding: 0.25rem; +} + +.absolute { + position: absolute; +} + +.right-0 { + right: 0px; +} + +.left-0 { + left: 0px; +} + +.top-36 { + top: 9rem; +} + +* { + --tw-shadow: 0 0 #0000; +} + +* { + --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/); + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgba(59, 130, 246, 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; +} + +.visible { + visibility: visible; +} + +.w-6 { + width: 1.5rem; +} + +.w-40 { + width: 10rem; +} + +.w-full { + width: 100%; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + +@keyframes ping { + 75%, 100% { + transform: scale(2); + opacity: 0; + } +} + +@keyframes pulse { + 50% { + opacity: .5; + } +} + +@keyframes bounce { + 0%, 100% { + transform: translateY(-25%); + animation-timing-function: cubic-bezier(0.8,0,1,1); + } + + 50% { + transform: none; + animation-timing-function: cubic-bezier(0,0,0.2,1); + } +} + +html, +body { + margin: 0; + height: 100%; + font-family: sans-serif; + overflow: hidden; +} + +#c { + position: absolute; + width: 100%; + height: 100%; + display: block; +} + +#react > div { +} + +.btn-red { + cursor: pointer; + --tw-bg-opacity: 1; + background-color: rgba(239, 68, 68, var(--tw-bg-opacity)); +} + +.btn-red:hover { + --tw-bg-opacity: 1; + background-color: rgba(220, 38, 38, var(--tw-bg-opacity)); +} + +.btn-red { + --tw-text-opacity: 1; + color: rgba(249, 250, 251, var(--tw-text-opacity)); +} + +.btn-grn { + cursor: pointer; + --tw-bg-opacity: 1; + background-color: rgba(16, 185, 129, var(--tw-bg-opacity)); +} + +.btn-grn:hover { + --tw-bg-opacity: 1; + background-color: rgba(5, 150, 105, var(--tw-bg-opacity)); +} + +.btn-grn { + --tw-text-opacity: 1; + color: rgba(249, 250, 251, var(--tw-text-opacity)); +} + +.btn-blu { + cursor: pointer; + --tw-bg-opacity: 1; + background-color: rgba(59, 130, 246, var(--tw-bg-opacity)); +} + +.btn-blu:hover { + --tw-bg-opacity: 1; + background-color: rgba(37, 99, 235, var(--tw-bg-opacity)); +} + +.btn-blu { + --tw-text-opacity: 1; + color: rgba(249, 250, 251, var(--tw-text-opacity)); +} + +#labels > div { + position: absolute; + border: solid 1px black; +} + +.btn { + cursor: pointer; + --tw-bg-opacity: 1; + background-color: rgba(243, 244, 246, var(--tw-bg-opacity)); +} + +.btn:hover { + --tw-bg-opacity: 1; + background-color: rgba(229, 231, 235, var(--tw-bg-opacity)); +} + +.btn { + fill: currentColor; + --tw-text-opacity: 1; + color: rgba(5, 150, 105, var(--tw-text-opacity)); +} + +.btn:hover { + --tw-text-opacity: 1; + color: rgba(4, 120, 87, var(--tw-text-opacity)); +} + +@media (min-width: 640px) { +} + +@media (min-width: 768px) { +} + +@media (min-width: 1024px) { +} + +@media (min-width: 1280px) { +} + +@media (min-width: 1536px) { +} + diff --git a/src/Scene.js b/src/Scene.js index 743f36e..e5bfa26 100644 --- a/src/Scene.js +++ b/src/Scene.js @@ -9,9 +9,9 @@ import Stats from './stats.module.js'; import { add3DPoint } from './datums' import { extrude } from './extrude' import { onHover, onPick } from './mouseEvents'; -import { _vec2, _vec3, color, awaitSelection, ptObj} from './shared' +import { _vec2, _vec3, color, awaitSelection, ptObj } from './shared' -import {AxesHelper} from './axes' +import { AxesHelper } from './axes' import CSG from "./three-csg.js" @@ -38,7 +38,7 @@ export class Scene { this.rect = this.canvas.getBoundingClientRect().toJSON() - this.renderer = new THREE.WebGLRenderer({ canvas: this.canvas, antialias:true }); + this.renderer = new THREE.WebGLRenderer({ canvas: this.canvas }); const size = 1; const near = 0; @@ -60,83 +60,70 @@ export class Scene { this.obj3d = new THREE.Scene() - this.obj3d.background = new THREE.Color(color.background); + // this.obj3d.background = new THREE.Color(color.background); const helpersGroup = new THREE.Group(); - helpersGroup.name = "helpersGroup"; + helpersGroup.name = "helpers"; this.obj3d.add(helpersGroup); - for (let i=0; i<4;i ++) { + for (let i = 0; i < 4; i++) { const freePt = ptObj() freePt.matrixAutoUpdate = false - freePt.material.size=8 + freePt.material.size = 4 + freePt.material.color.set(color.selpoint) freePt.visible = false freePt.depthTest = false - freePt.userData.type = 'point' + freePt.userData.type = 'selpoint' helpersGroup.add(freePt); } - this.fptIdx = 0; this.fptObj = {} - this.axes = new AxesHelper(this.camera.zoom) - this.axes.visible = false - helpersGroup.add(this.axes); - const planeGeom = new THREE.PlaneGeometry(5, 5) - const pxy = new THREE.Mesh( planeGeom, new THREE.MeshBasicMaterial({ color: color.plane, - opacity: 0.05, + opacity: 0.02, side: THREE.DoubleSide, transparent: true, depthWrite: false, toneMapped: false }) ); - - pxy.userData.type = 'plane' - pxy.layers.enable(1) - pxy.add( new THREE.LineSegments( new THREE.EdgesGeometry(planeGeom), new THREE.LineBasicMaterial({ color: color.planeBorder }) ) ) - + pxy.userData.type = 'plane' + pxy.layers.enable(1) + pxy.children[0].layers.disable(1) const pyz = pxy.clone().rotateY(Math.PI / 2); - pyz.material = pyz.material.clone(); const pxz = pxy.clone().rotateX(-Math.PI / 2); - pxz.material = pxz.material.clone(); - - helpersGroup.add(pxy); - helpersGroup.add(pyz); - helpersGroup.add(pxz); + [pxz, pyz].forEach(e => { + e.traverse(f => f.material = f.material.clone()) + helpersGroup.add(e); + }); + + this.axes = new AxesHelper(this.camera.zoom) + this.axes.visible = false + helpersGroup.add(this.axes); - - - const intensity = 0.5; - const light1 = new THREE.DirectionalLight(color.lighting, intensity); - light1.position.set(10, 10, 10); + const dist = 50 + const light1 = new THREE.PointLight(color.lighting, 0.7); + light1.position.set(dist, dist, dist); this.obj3d.add(light1); - - const light2 = new THREE.DirectionalLight(color.lighting, intensity); - light2.position.set(-10, -10, -5); + const light2 = new THREE.PointLight(color.lighting, 0.6); + light2.position.set(-dist, -dist, -dist); this.obj3d.add(light2); - const ambient = new THREE.AmbientLight(color.lighting, intensity); - this.obj3d.add(ambient); - - - this.render = render.bind(this); this.addSketch = addSketch.bind(this); this.extrude = extrude.bind(this); @@ -212,14 +199,25 @@ export class Scene { clearSelection() { for (let x = 0; x < this.selected.length; x++) { const obj = this.selected[x] - obj.material.color.set(color[obj.userData.type]) - if (obj.userData.type == 'point') obj.visible = false + if (obj.userData.type == 'plane') { + obj.material.opacity = 0.05 + obj.children[0].material.color.set(color['planeBorder']) + } else { + obj.material.color.set(color[obj.userData.type]) + } + if (obj.userData.type == 'selpoint') obj.visible = false } this.selected = [] for (let x = 0; x < this.hovered.length; x++) { const obj = this.selected[x] obj.material.color.set(color[obj.userData.type]) + if (obj.userData.type == 'plane') { + obj.material.opacity = 0.05 + obj.children[0].material.color.set(color['planeBorder']) + } else { + obj.material.color.set(color[obj.userData.type]) + } } this.obj3d.dispatchEvent({ type: 'change' }) @@ -227,39 +225,34 @@ export class Scene { - subtract (m1, m2) { + subtract(m1, m2) { let bspA = CSG.fromMesh(m1) let bspB = CSG.fromMesh(m2) - m1.traverse(e=>e.layers.disableAll()) - m2.traverse(e=>e.layers.disableAll()) - + m1.traverse(e => e.layers.disableAll()) + m2.traverse(e => e.layers.disableAll()) + // // Subtract one bsp from the other via .subtract... other supported modes are .union and .intersect - + let bspResult = bspA.subtract(bspB) - + // //Get the resulting mesh from the result bsp, and assign meshA.material to the resulting mesh - + let mesh = CSG.toMesh(bspResult, m1.matrix, m1.material) mesh.userData.type = 'mesh' mesh.name = `${m1.name}-${m2.name}` mesh.layers.enable(1) - - const edges = new THREE.EdgesGeometry( mesh.geometry, 15 ); - edges.type = 'BufferGeometry' - edges.parameters = undefined - - const line = new THREE.LineSegments( edges, new THREE.LineBasicMaterial( { color: 0x000000 } ) ); - line.userData.type = 'line' - - // const vertices = new THREE.Points( edges, new THREE.PointsMaterial({ color: 0x000000, size:4}) ); - const vertices = new THREE.Points( edges, new THREE.PointsMaterial() ); + + + + const vertices = new THREE.Points(mesh.geometry, new THREE.PointsMaterial()); vertices.userData.type = 'point' + vertices.layers.disable(0) vertices.layers.enable(1) - - mesh.add(line) + + // mesh.add(line) mesh.add(vertices) - - + + sc.obj3d.add(mesh) return mesh } @@ -280,7 +273,7 @@ function render() { } - this.axes.resize(this.camera.zoom) + if (this.axes) this.axes.resize(this.camera.zoom) this.renderer.render(this.obj3d, this.camera); @@ -320,7 +313,7 @@ async function addSketch() { let sketch; - const references = await this.awaitSelection({ point: 3 }, { plane: 1 }); + const references = await this.awaitSelection({ selpoint: 3 }, { plane: 1 }); if (!references) return; diff --git a/src/constraintEvents.js b/src/constraintEvents.js index ccf2a47..50cf6c3 100644 --- a/src/constraintEvents.js +++ b/src/constraintEvents.js @@ -1,4 +1,4 @@ - +import {color} from './shared' export async function setCoincident() { let selection = await this.awaitSelection({ point: 2 }, { point: 1, line: 1 }) @@ -32,11 +32,11 @@ export async function setCoincident() { this.solve() this.updateBoundingSpheres() - // update state of points - // for (let obj of this.selected) { - // obj.geometry.computeBoundingSphere() - // obj.material.color.set(0x555555) - // } + for (let x = 0; x < this.selected.length; x++) { + const obj = this.selected[x] + obj.material.color.set(color[obj.userData.type]) + } + this.selected = [] this.obj3d.dispatchEvent({ type: 'change' }) } diff --git a/src/extrude.js b/src/extrude.js index 8492ee2..2a3e0f1 100644 --- a/src/extrude.js +++ b/src/extrude.js @@ -79,8 +79,8 @@ export function extrude(sketch) { const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings); - const material = new THREE.MeshLambertMaterial({ - // const material = new THREE.MeshPhongMaterial({ + // const material = new THREE.MeshLambertMaterial({ + const material = new THREE.MeshPhongMaterial({ color: color.mesh, emissive: color.emissive, // flatShading:true, @@ -90,39 +90,16 @@ export function extrude(sketch) { mesh.userData.type = 'mesh' mesh.layers.enable(1) - const edges = new THREE.EdgesGeometry( geometry, 15 ); - edges.type = 'BufferGeometry' - edges.parameters = undefined - - const line = new THREE.LineSegments( edges, new THREE.LineBasicMaterial( { color: 0x000000 } ) ); - line.userData.type = 'line' - - const vertices = new THREE.Points( edges, new THREE.PointsMaterial() ); + const vertices = new THREE.Points( mesh.geometry, new THREE.PointsMaterial() ); vertices.userData.type = 'point' + vertices.layers.disable(0) vertices.layers.enable(1) - mesh.add(line) mesh.add(vertices) - - // for (let i = 0; i < offSetPts.length; i += 2) { - // if ( - // offSetPts[i] == offSetPts[i - 2] && - // offSetPts[i + 1] == offSetPts[i - 1] - // ) continue; - // mesh.add( - // ptObj([offSetPts[i], offSetPts[i + 1], 0], false), - // ptObj([offSetPts[i], offSetPts[i + 1], 8], false), - // ) - // } - - mesh.matrixAutoUpdate = false; mesh.matrix.multiply(sketch.obj3d.matrix) this.obj3d.add(mesh) - - - this.render() // sketch.visible = false diff --git a/src/mouseEvents.js b/src/mouseEvents.js index 01e50cc..7833f92 100644 --- a/src/mouseEvents.js +++ b/src/mouseEvents.js @@ -57,18 +57,15 @@ export function onHover(e) { for (let x = 0; x < this.hovered.length; x++) { // first clear old hovers that are not selected const obj = this.hovered[x] - if (!this.selected.includes(obj)) { - if (typeof obj == 'object') { + if (typeof obj == 'object' && !this.selected.includes(obj)) { + if (obj.userData.type == 'plane') { + obj.material.opacity = 0.02 + obj.children[0].material.color.set(color['planeBorder']) + } else { obj.material.color.set(color[obj.userData.type]) - if (this.obj3d.userData.type != 'sketch') { - if (obj.userData.type == 'mesh') { - obj.children[0].material.color.set(color['line']) - } - } } } } - this.hovered = [] for (let x = 0; x < idx.length; x++) { @@ -79,9 +76,10 @@ export function onHover(e) { } else { if (obj.userData.type == 'mesh') { - obj.children[0].material.color.set(hoverColor['line']) + obj.material.color.set(color['meshTempHover']) } else if (obj.userData.type == 'plane') { - obj.material.color.set(hoverColor[obj.userData.type]) + obj.material.opacity = 0.06 + obj.children[0].material.color.set(hoverColor['planeBorder']) } else if (obj.userData.type == 'point') { ptLoc = obj.geometry.attributes.position.array @@ -116,14 +114,12 @@ export function onHover(e) { for (let x = 0; x < this.hovered.length; x++) { const obj = this.hovered[x] - if (!this.selected.includes(obj)) { - if (typeof obj == 'object') { + if (typeof obj == 'object' && !this.selected.includes(obj)) { + if (obj.userData.type == 'plane') { + obj.material.opacity = 0.02 + obj.children[0].material.color.set(color['planeBorder']) + } else { obj.material.color.set(color[obj.userData.type]) - if (this.obj3d.userData.type != 'sketch') { - if (obj.userData.type == 'mesh') { - obj.children[0].material.color.set(color['line']) - } - } } } } @@ -149,7 +145,10 @@ export function onPick(e) { this.selected.push(obj) } else { if (typeof obj == 'object') { - if (obj.userData.type == "mesh") { + if (obj.userData.type == 'plane') { + obj.material.opacity = 0.06 + obj.children[0].material.color.set(hoverColor['planeBorder']) + } else { obj.material.color.set(hoverColor[obj.userData.type]) } } else { @@ -200,11 +199,14 @@ export function onPick(e) { for (let x = 0; x < this.selected.length; x++) { const obj = this.selected[x] obj.material.color.set(color[obj.userData.type]) - if (this.obj3d.userData.type != 'sketch') { - if (obj.userData.type == 'mesh') { - obj.children[0].material.color.set(color['line']) - } else if (obj.userData.type == 'point') { - obj.visible = false + if (obj.userData.type == 'selpoint') { + obj.visible = false + } else { + if (obj.userData.type == 'plane') { + obj.material.opacity = 0.02 + obj.children[0].material.color.set(color['planeBorder']) + } else { + obj.material.color.set(color[obj.userData.type]) } } } diff --git a/src/react/app.css b/src/react/app.css index 8000c5a..8e93353 100644 --- a/src/react/app.css +++ b/src/react/app.css @@ -42,7 +42,7 @@ body { #labels > div { position: absolute; - border: solid 1px black; + color: white; } .btn { @@ -63,11 +63,12 @@ body { .btn-green { cursor: pointer; @apply fill-current - bg-transparent text-gray-700 - hover:bg-gray-300 hover:text-green-200; + bg-transparent text-gray-200 + hover:bg-transparent hover:text-green-200; } + .tooltip { position: fixed; display: block; @@ -77,6 +78,7 @@ body { border-radius: 4px; padding: 4px; visibility: hidden; + border: solid 1px white; } @@ -86,6 +88,6 @@ body { left: 50%; margin-left: -6px; border: solid 6px transparent; - border-bottom-color: black; + border-bottom-color: white; border-top: none; } \ No newline at end of file diff --git a/src/react/navBar.jsx b/src/react/navBar.jsx index f5f661b..dcb74ac 100644 --- a/src/react/navBar.jsx +++ b/src/react/navBar.jsx @@ -32,10 +32,9 @@ export const NavBar = () => { activeSketchId ? [MdDone, () => { treeEntries.byId[activeSketchId].deactivate() - dispatch({ type: 'update-descendents', sketch}) - - + // dispatch({ type: 'update-descendents', sketch}) sc.activeSketch = null + sc.render() // sc.activeDim = this.activeSketch.obj3d.children[1].children }, 'Finish'] : [FaEdit, sc.addSketch, 'Sketch [s]'] @@ -60,7 +59,7 @@ export const NavBar = () => { const [_, forceUpdate] = useReducer(x => x + 1, 0); - return
+ return
{ btnz.map(([Icon, fcn, txt, shortcut], idx) => ( { const treeEntries = useSelector(state => state.treeEntries) - return
+ return
{treeEntries.allIds.map((entId, idx) => ( ))} @@ -48,7 +48,7 @@ const TreeEntry = ({ entId }) => { // const vis = obj3d.visible const vis = obj3d.layers.mask & 1 - return
{ activeSketchId && treeEntries[activeSketchId].deactivate() @@ -59,7 +59,7 @@ const TreeEntry = ({ entId }) => { }} > -
{ if (entId[0] == 'm') { // entry.material.color.set(color.hover) diff --git a/src/shared.js b/src/shared.js index 63f6c13..64cb667 100644 --- a/src/shared.js +++ b/src/shared.js @@ -12,27 +12,28 @@ raycaster.params.Points.threshold = 0.1; const color = { - background:0xdae1e7, + background: 0x18181B, lighting: 0xFFFFFF, emissive: 0x072534, + meshTempHover: 0x9DCFED, - hover: 0x00ff00, - point: 0x555555, //points - line: 0x000000, //lines - mesh: 0x9DCFED, //mesh: - dimension: 0x0000ff, // - - plane: 0x88adcd, // - planeBorder: 0xa7cae8, // + point: 0xffffff, + selpoint: 0xff0000, + line: 0xffffff, + mesh: 0x9DCFED, + dimension: 0x0000ff, + plane: 0xffff00, + planeBorder: 0x2e2e00, } const hoverColor = { - hover: 0x00ff00, - point: 0x00ff00, //points - line: 0x00ff00, //lines - mesh: 0xFAB601, //mesh: - dimension: 0x00ff00, // - plane: 0x005dff, // + point: 0x00ff00, + selpoint: 0xff0000, + line: 0x00ff00, + mesh: 0xFAB601, + dimension: 0x00ff00, + plane: 0xffff00, + planeBorder: 0x919100, } diff --git a/tailwind.config.js b/tailwind.config.js index 5d7b357..e4a6284 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,3 +1,5 @@ +const colors = require('tailwindcss/colors') + module.exports = { purge: [ './src/**/*.jsx', @@ -6,6 +8,12 @@ module.exports = { darkMode: false, // or 'media' or 'class' theme: { extend: {}, + colors: { + transparent: 'transparent', + current: 'currentColor', + gray: colors.trueGray, + green: colors.emerald, + } }, variants: { extend: {},