From c01f4bd8c624e4379ee834486666c2784bc84a09 Mon Sep 17 00:00:00 2001 From: Peaceultime Date: Sat, 15 Jun 2024 23:32:42 +0200 Subject: [PATCH] Working on transform gizmo --- bun.lockb | Bin 23330 -> 22918 bytes package.json | 5 +- src/assets/asset.class.ts | 106 ++++++++++++--------------------- src/main.ts | 9 +-- src/renderer/renderer.class.ts | 2 + src/renderer/selector.class.ts | 79 +++++++++++++++++++++--- 6 files changed, 117 insertions(+), 84 deletions(-) diff --git a/bun.lockb b/bun.lockb index a6ce7f551f41245f9fb3f4c88a8eb8857ca2c837..453f990bea95a6d29752f72909547c8c662647ca 100644 GIT binary patch delta 3425 zcmc&$dr(wW7(Zv(Wm#lFSe3o(g1lKkS3p2uVec*=rQ0;AO;;-|^AR{Y8rcIYSbMJ1 z(1c%)k*tZHRMx<3R@6{qPjsxz!6tf5PVbka&SYYf_B;3P<@QGpvu3)p_xJmq@B8j| z&Ys7;-$T#wTci9=Z}EY3_Q(1w_hdc4W$xxhTOWQWT9|V0laC%aeBR*Ln*2AOIecs} zQ?I%nWqQi~TCJgBVo$d#<1ln8W8s6~6!0k64jy4WuNK-IaazmPb0od%LknYRaJ>a~ zfTQ3k;J%o>JJ#M5^S8$A=f~`R@HE7i#M%yUI@-UQHT!p9k@tPD$oo22^f#cjyTZK? zBEfB75!eo%3SOoKgwKxoD`V|kut?Cpe(l<;HZZm+nXya}4|aotv9<>+p`8fM0)K@G z$Opd(&Ib2`v)F|!d<#S#3@gC7;AZf2a6yc%V3FXPB+b4TEIJwlyTFft5fV(_xkQWi(`!O*`V~gw=2P9_u)VhHdrSLMLppIi9f=YDn-| zu7)~WRWCy|tIA~6ZS$eDxI3XV@92croxs>R>JzO{T9yH*b5+~P3GaN{L>4G5?gJ<- zpBodQ*;Ybn`39i0evd)TSMvoX>2VP#EpBwe=Elsb`S^OOO_nY9Vks}8hGd`RDAW>F zg|NRh+hb6RRNFYzQdM0rnXxuiy#lpdRoOThn)e2%%T?PKP^(lm4}0qpRrOCOEB2-K z#7Zd5`x=xs0ynm`BA(z^Qb(F>dT|Q9m{!+?bHKzcuHUoJ`2Xs4I*i#6=Rv&$W6_yY zYyKhQ@UdBpb*Ui`{}XHdi;?`}0bt%)F!tOTbFBY=pC~pELH}e)yZ&lz&u~rEp`7N7 zcAe4Giylt1gTINx{Qo}Df3l|P|3A&Wfj9J@uRU#>wvkq)hiGxSorcpxJdSKmg%X^0 zTIUSmbvlIB3ut9ZA#SBMNugHBPH&@SBPm1SiF5^U679}VXe7f{j?>+6+vkF<=^%XDZx5TYyvOAaE+xW+{9c^#If9TcDGI(-kh!Hed!F0lH{j zw!+=i2h5~#U=}UNQTTLv0+>xaSK&Fd1ei;Mz&x_$DLkK+0}E&fSV*b)3NNBIpoew= zi%BX_cnMtrET!GR8I)6~@R`&B^wN94SyWu4@G{yAET=JG1(kagKAX096pDE4^rI)l ztEjeE;nmawoI~FNYbaQv@Y?9Mk~mHSrAfS!hD%rQ2PkKT!}M7ky6@bJ}1w zQ<68qaw%T&DYUC}5zJ;D-7w2LDbZP{E%l5#8mkLroIIsn!YGQJ#W8oikLK4G(#5{X zGsS5WrwYl$$5=h8`1Ub;*BHK83|}U7KbC_l=x(3SBHp1A9q=jB#9I{=h$vfFs}F!{ zZ9P)w)`;H3qvEA&!p(7ubRw-tFWv~KM_3W=6x?D6Vkk6N?@By{kCZx?BpR!~$c7IP zs}X)`XpoaVP!HAvaMd-@tqnV>SFc{XeB&y{Ui#QA|qx^ZXaT<1E65pbAA_xVlSbrXh<(S>_vUD#c? zv!Qkh-vEm!xbC1I<=NQRIROc~(-)9jdWrSvr?1@qRK;+unU{Gh@MEl!)(502y(C-c z-&g9+Onuz&>qVRM#EJ5Sd#YC%o^~2WX1&NOYwW$``S=u*;qRp*0m(FgJrQ)e^&+ut zsJ_24e%)6_*!yM*1f5lSRr$~poofyy6zn$w^t$t@mbRtsa?y6f?I>=6Qwjt)p}J-z8~_|boWLKzg{=*`m(3r zk$%?Ch9_#FWsS~iz0gib^_RZD@7ikw=%sk|IeVY$+xqM#!}CZI?P#np4JOfNjm|2) z0Nr`&hogxZdkW0F(pz5REn`eCQ5WYqG@ zCy{=|0Q90nqm)GX!eC4Hp*zM@Ye^Xx`cq)FTNBTW=(4v3S- pXr#F;;~CUo;(**-Q?-|0n|$(kEbh=^N}Jn4IW4Z}yK@&!{S7MFQKSF> delta 3750 zcmcgvdr(x@8NX-QWfx?5KlZX9FL^A;Wfxck7Iv41m=wmw*IdDT&YhcY7 zOPXYg{rZno8;LdvX`C_H8XvVun%GgJ@zvI;8EnSb=>#TZYR%9|tJ2@OcduJ#+SJsU zp4t2Te&_qX^PRKjb-%kKz+Qfv4NJC9yTl{6Uq9kX+V|19n85Y;SPP5+ z+JR=^9JcdV-r%M%wblXT(H?Jqe3NgTAawMudD7RtPN)bMgm~z4fC<1DAR_y38&v%S zkk>B*x&1^?e=w*Y0VYGgBUs-AOhLU>)ericKzPH_phG5*cNi6{PwUkH*MZ#c954xZ z49Gj)AG8k#>jOaEzGqW+_mfWu!ez`&I`;>r0rv#!+kv7mDEQZd%!Z*JI0u*w#GLx| zLH#vMRu1a#0<(d8ff>MUL0k*u?Hhyj0wC|m4739IWaH<@>?$)n6u$j$O}`r$F}mwp zqQVOM$^y%EvAQ@3=0@(0V#H&hEPXybrZ=&z5c#JLEHZbS6E$ZglGw=xNgE zHavtyZKNrq%kTnNlfo{6J*2Qy3`e!D0#kLbfN{SXW~4%sM{m*${a`IhvlDl9Q4xZ$ zP|>x4sn%D(lmL1VHD)!d6#b{loCHcXTs5J~O=YKKrn(rD^fzlg2j+pZ@uZ zUyRqiRQ~11Y3A10lglFZef;pDM`G5{RI-H*Bsa4#`YKtb*HX;1GNqXrXe>ph8khAEhC{t&unbK36nVEd4GFhx<`Utfc60I_erOl9W zbQ&_AveIOhKuogLXk?(hbNgdN@mF*)$57LtjD8p+(s;%cU{MJYqRA%coYz0(ukDMiFylR!HrT zMRXK$F2&`_teAX|68##ogv30V*=aMRgHA)1QdYjq%IK+lnFKo1Y__;|*n zii4w4atK-~+x*O-^7)pH2|8AYpuDuOzzelHX8iENOc&?@(=3B0CEW&mSjg z%w5Jh=&D<^YRPZW@Avgw{LWkGVUqk}}4v*1=EYozrBUWfR?)$kCuvrI16bf$Uz3Q%kfjj>e{+D46(m$U#fR z3*!sQ*z?y%LzWSG+ACVM)O}6zt%#V6#OaXz1ik4M*=0HdFD>yW*XKE1FOCd_yl&Hs zSFF%J6i!Y1Gq&zuMj^ZQDPf9p7ad_gJ{z)Bgww)0i%u|8XI-hzY^L3HmNYG&J~Z?B zUn5gL%+<4U3A+G`)M%y)brz?VfQR>8TGxHn&;87s0&z1C^!!xX=`GtB}`PA6p zrJ)9UY9zjXa1HslS31wK{^&cE^HrB0w9%!8rfB8B6>se5?JQoirIT(fv6kJdDk(0x dS5d4SRjF^ocipv_cFEy%NOs;XP}aC4>7T-bvv2?a diff --git a/package.json b/package.json index 2977f61..40a65a9 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "version": "0.0.0", "type": "module", "scripts": { - "dev": "bunx --bun vite", + "dev": "bunx --bun vite --port 3000 --cors", "build": "tsc && vite build", "preview": "vite preview" }, @@ -15,7 +15,6 @@ "dependencies": { "@types/three": "^0.165.0", "stats.js": "^0.17.0", - "three": "^0.165.0", - "three-mesh-bvh": "^0.7.5" + "three": "^0.165.0" } } diff --git a/src/assets/asset.class.ts b/src/assets/asset.class.ts index 63f8195..361a832 100644 --- a/src/assets/asset.class.ts +++ b/src/assets/asset.class.ts @@ -18,6 +18,12 @@ export default class Asset //@ts-expect-error #aabb: AABB; + #posX: number; + #posY: number; + #rot: number; + #scaleX: number; + #scaleY: number; + #index: number; #quad?: number; @@ -27,6 +33,14 @@ export default class Asset constructor(mat?: Three.Matrix4, layer?: number) { this.mat = mat ?? new Three.Matrix4(); + this.mat.decompose(_position, _rotation, _scale); + + this.#posX = _position.x; + this.#posY = _position.y; + this.#rot = _euler.setFromQuaternion(_rotation).z; + this.#scaleX = _position.x; + this.#scaleY = _position.y; + this.#updateAABB(); this.layer = layer ?? 0; @@ -36,14 +50,6 @@ export default class Asset { return this.#aabb; } - insert(quad: Quadtree): void - { - this.#quad = quad.insert(this.#index, this.#aabb); - } - remove(quad: Quadtree): void - { - this.#quad !== undefined && quad.remove(this.#quad); - } #updateAABB(): void { const aabb = { x1: -0.5, x2: 0.5, y1: -0.5, y2: 0.5 }; @@ -65,89 +71,53 @@ export default class Asset y2: Math.max(y1, y2, y3, y4) }; } - move(x: number, y: number): Asset + insert(quad: Quadtree): void { - this.mat.decompose(_position, _rotation, _scale); - - _position.x += x; - _position.y += y; - - this.mat.compose(_position, _rotation, _scale); - - this.#updateAABB(); - - return this; + this.#quad = quad.insert(this.#index, this.#aabb); + } + remove(quad: Quadtree): void + { + this.#quad !== undefined && quad.remove(this.#quad); } moveTo(x: number, y: number): Asset { - this.mat.decompose(_position, _rotation, _scale); + const e = this.mat.elements; - _position.x = x; - _position.y = y; - - this.mat.compose(_position, _rotation, _scale); + e[12] = this.#posX = x; + e[13] = this.#posY = y; this.#updateAABB(); - - return this; - } - rotate(rad: number): Asset - { - this.mat.decompose(_position, _rotation, _scale); - - _euler.setFromQuaternion(_rotation); - _euler.z += rad; - _rotation.setFromEuler(_euler); - - this.mat.compose(_position, _rotation, _scale); - - this.#updateAABB(); - return this; } rotateTo(rad: number): Asset { - this.mat.decompose(_position, _rotation, _scale); + this.#rot = rad; - _euler.setFromQuaternion(_rotation); - _euler.z = rad; - _rotation.setFromEuler(_euler); + const e = this.mat.elements; + const cos = Math.cos(rad), sin = Math.sin(rad); - this.mat.compose(_position, _rotation, _scale); + e[0] = cos * this.#scaleX; + e[1] = -sin * this.#scaleX; + e[4] = sin * this.#scaleY; + e[5] = cos * this.#scaleY; this.#updateAABB(); - - return this; - } - scale(x: number, y: number): Asset - { - this.mat.decompose(_position, _rotation, _scale); - - _scale.x *= x; - _scale.y *= y; - - this.mat.compose(_position, _rotation, _scale); - - this.#updateAABB(); - return this; } scaleTo(x: number, y: number): Asset { - this.mat.decompose(_position, _rotation, _scale); + this.#scaleX = x; + this.#scaleY = y; - _scale.x = x; - _scale.y = y; + const e = this.mat.elements; + const cos = Math.cos(this.#rot), sin = Math.sin(this.#rot); - this.mat.compose(_position, _rotation, _scale); + e[0] = cos * this.#scaleX; + e[1] = -sin * this.#scaleX; + e[4] = sin * this.#scaleY; + e[5] = cos * this.#scaleY; this.#updateAABB(); - - return this; - } - shapeTo(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number): Asset - { - return this; } } \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 4d603f4..846e852 100644 --- a/src/main.ts +++ b/src/main.ts @@ -14,13 +14,14 @@ Selector.init(); const r = new Random(0); const quad = new Quadtree({ x1: -RESOLUTION_X / 2, x2: RESOLUTION_X / 2, y1: -RESOLUTION_Y / 2, y2: RESOLUTION_Y / 2 }, 6, 10); -for(let i = 0; i < 10000; i++) +for(let i = 0; i < 2; i++) { const asset = new Asset(new THREE.Matrix4(), 1); - asset.move(r.nextInt(-0.5 * RESOLUTION_X, 0.5 * RESOLUTION_X), r.nextInt(-0.5 * RESOLUTION_Y, 0.5 * RESOLUTION_Y)) - .rotate(r.nextFloat(Math.PI * 2)) - .scale(r.nextFloat(10, 30), r.nextFloat(10, 30)); + asset + .rotateTo(r.nextFloat(Math.PI * 2)) + .scaleTo(r.nextFloat(100, 300), r.nextFloat(100, 300)) + .moveTo(r.nextInt(-0.5 * RESOLUTION_X, 0.5 * RESOLUTION_X), r.nextInt(-0.5 * RESOLUTION_Y, 0.5 * RESOLUTION_Y)); Asset.instance.setMatrixAt(i, asset.mat); asset.insert(quad); diff --git a/src/renderer/renderer.class.ts b/src/renderer/renderer.class.ts index b810d0e..9f4789e 100644 --- a/src/renderer/renderer.class.ts +++ b/src/renderer/renderer.class.ts @@ -2,6 +2,7 @@ import * as Three from 'three'; import { RESOLUTION_X, RESOLUTION_Y } from '../consts'; import Stats from 'stats.js'; import { Point } from '../physics/common'; +import Selector from './selector.class'; export default class Renderer { @@ -84,6 +85,7 @@ export default class Renderer static render(delta?: number): void { this.#stats.begin(); + Selector.update(); this.renderer.render(this.scene, this.camera); this.#stats.end(); } diff --git a/src/renderer/selector.class.ts b/src/renderer/selector.class.ts index 6a3b610..0234094 100644 --- a/src/renderer/selector.class.ts +++ b/src/renderer/selector.class.ts @@ -2,16 +2,20 @@ import * as Three from "three"; import Asset from "../assets/asset.class"; import { Point } from "../physics/common"; import Renderer from "./renderer.class"; +import { QUAD } from '../consts'; export default class Selector { static #assets: Asset[]; static #selected: boolean = false; + static #previousZoom: number = 1; static #previewMesh: Three.Box3Helper; static #ghostMesh: Three.Box3Helper; static #selectionMesh: Three.Box3Helper; + static gizmoScale: Three.Mesh[]; + static get selected(): boolean { return Selector.#selected; @@ -25,10 +29,31 @@ export default class Selector Selector.#previewMesh = new Three.Box3Helper(new Three.Box3(), 0x2980B9); Selector.#ghostMesh = new Three.Box3Helper(new Three.Box3(), 0xffffff); Selector.#selectionMesh = new Three.Box3Helper(new Three.Box3(), 0xffffff); - + + Selector.gizmoScale = []; + Selector.gizmoScale[0] = new Three.Mesh(QUAD, new Three.MeshBasicMaterial({ depthTest: false, depthWrite: false, fog: false, toneMapped: false, transparent: true, color: 0x3498DB, opacity: 0.5 })); + Selector.gizmoScale[1] = new Three.Mesh(QUAD, Selector.gizmoScale[0].material); + Selector.gizmoScale[2] = new Three.Mesh(QUAD, Selector.gizmoScale[0].material); + Selector.gizmoScale[3] = new Three.Mesh(QUAD, Selector.gizmoScale[0].material); + + Selector.gizmoScale[0].renderOrder = Infinity; + Selector.gizmoScale[1].renderOrder = Infinity; + Selector.gizmoScale[2].renderOrder = Infinity; + Selector.gizmoScale[3].renderOrder = Infinity; + + Selector.gizmoScale[0].name = "Gizmo for scale (TL)"; + Selector.gizmoScale[1].name = "Gizmo for scale (TR)"; + Selector.gizmoScale[2].name = "Gizmo for scale (BL)"; + Selector.gizmoScale[3].name = "Gizmo for scale (BR)"; + Renderer.scene.add(Selector.#previewMesh); Renderer.scene.add(Selector.#ghostMesh); Renderer.scene.add(Selector.#selectionMesh); + + Renderer.scene.add(Selector.gizmoScale[0]); + Renderer.scene.add(Selector.gizmoScale[1]); + Renderer.scene.add(Selector.gizmoScale[2]); + Renderer.scene.add(Selector.gizmoScale[3]); Selector.hide(); } @@ -64,16 +89,35 @@ export default class Selector Selector.#selected = true; - Selector.#selectionMesh.box.setFromArray([ - assets.map(e => e.aabb.x1).reduce((p, v) => Math.min(p, v), Infinity), - assets.map(e => e.aabb.y1).reduce((p, v) => Math.min(p, v), Infinity), - 0, - assets.map(e => e.aabb.x2).reduce((p, v) => Math.max(p, v), -Infinity), - assets.map(e => e.aabb.y2).reduce((p, v) => Math.max(p, v), -Infinity), - 0 - ]); + let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity; + for (let i = 0; i < assets.length; i++) + { + minX = Math.min(minX, assets[i].aabb.x1); + minY = Math.min(minY, assets[i].aabb.y1); + maxX = Math.max(maxX, assets[i].aabb.x2); + maxY = Math.max(maxY, assets[i].aabb.y2); + } + + const scale = Math.max((maxX - minX) / 2, (maxY - minY) / 2) + + Selector.#selectionMesh.box.setFromArray([minX, minY, 0, maxX, maxY, 0]); Selector.#selectionMesh.updateMatrix(); + Selector.gizmoScale[0].position.set(minX, minY, 0); + Selector.gizmoScale[1].position.set(maxX, minY, 0); + Selector.gizmoScale[2].position.set(minX, maxY, 0); + Selector.gizmoScale[3].position.set(maxX, maxY, 0); + + Selector.gizmoScale[0].scale.set(20 / Renderer.zoom, 20 / Renderer.zoom, 1); + Selector.gizmoScale[1].scale.set(20 / Renderer.zoom, 20 / Renderer.zoom, 1); + Selector.gizmoScale[2].scale.set(20 / Renderer.zoom, 20 / Renderer.zoom, 1); + Selector.gizmoScale[3].scale.set(20 / Renderer.zoom, 20 / Renderer.zoom, 1); + + Selector.gizmoScale[0].visible = true; + Selector.gizmoScale[1].visible = true; + Selector.gizmoScale[2].visible = true; + Selector.gizmoScale[3].visible = true; + Selector.#selectionMesh.visible = true; } static toggle(assets: Asset[]): void @@ -100,5 +144,22 @@ export default class Selector Selector.#previewMesh.visible = false; Selector.#ghostMesh.visible = false; Selector.#selectionMesh.visible = false; + + Selector.gizmoScale[0].visible = false; + Selector.gizmoScale[1].visible = false; + Selector.gizmoScale[2].visible = false; + Selector.gizmoScale[3].visible = false; + } + static update(): void + { + if (Selector.#previousZoom !== Renderer.zoom && Selector.#selected) + { + Selector.#previousZoom = Renderer.zoom; + + Selector.gizmoScale[0].scale.set(20 / Renderer.zoom, 20 / Renderer.zoom, 1); + Selector.gizmoScale[1].scale.set(20 / Renderer.zoom, 20 / Renderer.zoom, 1); + Selector.gizmoScale[2].scale.set(20 / Renderer.zoom, 20 / Renderer.zoom, 1); + Selector.gizmoScale[3].scale.set(20 / Renderer.zoom, 20 / Renderer.zoom, 1); + } } } \ No newline at end of file