const ORIGIN_FIXED = 1 ; const ORIGIN_CENTER = 2 ; const ORIGIN_AUTO = 3 ; const ORIGIN_TO = 4 ; class Voxel { name = null ; size = 0 ; size2 = 0 ; dirty = false ; generation = 0 ; $Mesh = null; $Geometry = null; euler = new THREE.Euler(0,0,0,'YXZ'); origin_mode = ORIGIN_CENTER ; Origin = new V3() ; Origin_to = new V3() ; Obb_min = new V3() ; Obb_max = new V3() ; is_cloned = false ; is_shadow = true ; order = 50 ; index = 0; DEF = null; VERTEX = null; COLOR = null; INDEX = null; NORMAL = null; constructor(name ,size) { this.name = name ; this.size = Math.max(1,size); this.size2 = this.size*this.size ; this.DEF = [] ; this.dirty = true ; this.Origin.z = -0.5 ; this.Obb_min.All(this.size); this.Obb_max.All(0); this.$Mesh = new THREE.Mesh(); this.$Mesh.material = µB.$D3.MATERIAL["normal"]; µB.$D3.$Root.add(this.$Mesh); } Dispose() { if( this.$Mesh ) { µB.$D3.$Root.remove(this.$Mesh); this.$Mesh =null; } if( this.$Geometry ) { this.$Geometry.dispose(); this.$Geometry = null; } } Index(x, y, z) { return x + z*this.size + y*this.size2 ; } Dirty() { this.dirty = true ; µB.$Sprite.DIRTY[this.name] = true ; } Finalize() { this.$Geometry = new THREE.BufferGeometry(); this.$Geometry.setIndex( this.INDEX ) ; this.$Geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( this.VERTEX, 3 ) ); this.$Geometry.setAttribute( 'color', new THREE.Float32BufferAttribute( this.COLOR, 4 ) ); if( this.NORMAL.length ) { this.$Geometry.setAttribute( 'normal', new THREE.Float32BufferAttribute( this.NORMAL, 3 ) ); } else { this.$Geometry.computeVertexNormals(); } this.$Mesh.geometry = this.$Geometry ; this.$Mesh.receiveShadow = this.is_shadow; this.$Mesh.castShadow = this.is_shadow; this.$Mesh.renderOrder = this.order; this.VERTEX = null; this.COLOR = null; this.INDEX = null; this.NORMAL = null; } SetOrigin( mode, x,y,z ) { this.origin_mode = mode ; if( mode === ORIGIN_TO ) { this.Origin_to.Set(x-.5,y-.5,z-.5); } this.ProcessOBB() ; } ProcessOBB() { if( this.$Geometry && this.index ) { if( this.dirty ) { } else if( this.origin_mode == ORIGIN_FIXED ) { } else { if( this.origin_mode === ORIGIN_TO ) { var $x = -this.Origin_to.x ; var $y = -this.Origin_to.y ; var $z = -this.Origin_to.z ; } else { var $x = -((this.Obb_max.x +1 - this.Obb_min.x)/2 + this.Obb_min.x) ; var $y = -((this.Obb_max.y +1 - this.Obb_min.y)/2 + this.Obb_min.y) ; var $z = -((this.Obb_max.z +1 - this.Obb_min.z)/2 + this.Obb_min.z) ; } let $xr = $x - this.Origin.x ; let $yr = $y - this.Origin.y ; let $zr = $z - this.Origin.z ; this.$Geometry.applyMatrix4( new THREE.Matrix4().makeTranslation($xr,$yr,$zr) ); this.Origin.Set($x,$y,$z) ; if( this.origin_mode === ORIGIN_AUTO ) { } else { this.origin_mode = ORIGIN_FIXED ; } } } } Is(x, y, z) { if( x<0 || y<0 || z<0 ) { return false; } else if( x>=this.size || y>=this.size || z>=this.size ) { return false; } else { let index = this.Index(x,y,z); return this.DEF[index] ?? 0; } } Face( $Rgba ) { this.COLOR.push( $Rgba.r, $Rgba.g, $Rgba.b, $Rgba.a ); this.COLOR.push( $Rgba.r, $Rgba.g, $Rgba.b, $Rgba.a ); this.COLOR.push( $Rgba.r, $Rgba.g, $Rgba.b, $Rgba.a ); this.COLOR.push( $Rgba.r, $Rgba.g, $Rgba.b, $Rgba.a ); /* $Structure.$Object.UV.push( $Structure.$Object.VERTEX[i]/r + $Structure.$Object.VERTEX[i+2]/r, $Structure.$Object.VERTEX[i+1]/r ); i+=3; $Structure.$Object.UV.push( $Structure.$Object.VERTEX[i]/r + $Structure.$Object.VERTEX[i+2]/r, $Structure.$Object.VERTEX[i+1]/r ); i+=3; $Structure.$Object.UV.push( $Structure.$Object.VERTEX[i]/r + $Structure.$Object.VERTEX[i+2]/r, $Structure.$Object.VERTEX[i+1]/r ); i+=3; $Structure.$Object.UV.push( $Structure.$Object.VERTEX[i]/r + $Structure.$Object.VERTEX[i+2]/r, $Structure.$Object.VERTEX[i+1]/r ); i+=3; */ this.INDEX.push( this.index, this.index+1, this.index+2); this.INDEX.push( this.index+1, this.index+3, this.index+2 ); this.index +=4; } Cube( $bloc, $x, $y, $z ) { this.Obb_min.Min($x,$y,$z); this.Obb_max.Max($x,$y,$z); var Y = []; Y[0] = $y + this.Origin.y ; Y[1] = Y[0] + 1; var X = [[],[]]; var Z = [[],[]]; X[0][0] = X[0][2] = $x + this.Origin.x ; X[0][1] = X[0][3] = X[0][0] +1 ; Z[0][0] = Z[0][1] = $z + this.Origin.z ; Z[0][2] = Z[0][3] = Z[0][0] +1; X[1][0] = X[0][0]; X[1][1] = X[0][1]; X[1][2] = X[0][2]; X[1][3] = X[0][3]; Z[1][0] = Z[0][0]; Z[1][1] = Z[0][1]; Z[1][2] = Z[0][2]; Z[1][3] = Z[0][3]; var $is_left = this.Is($x-1,$y,$z); var $is_right = this.Is($x+1,$y,$z); var $is_front = this.Is($x,$y,$z+1); var $is_back = this.Is($x,$y,$z-1); var $is_top = this.Is($x,$y+1,$z); var $is_down = this.Is($x,$y-1,$z); var $Rgba = µB.$Config.Color2Rgba($bloc) ; if( ! $is_back ) { this.VERTEX.push( X[1][0],Y[1],Z[1][0] ); this.VERTEX.push( X[1][1],Y[1],Z[1][1] ); this.VERTEX.push( X[0][0],Y[0],Z[0][0] ); this.VERTEX.push( X[0][1],Y[0],Z[0][1] ); this.Face($Rgba); } if( ! $is_front ) { this.VERTEX.push( X[1][2],Y[1],Z[1][2] ); this.VERTEX.push( X[0][2],Y[0],Z[0][2] ); this.VERTEX.push( X[1][3],Y[1],Z[1][3] ); this.VERTEX.push( X[0][3],Y[0],Z[0][3] ); this.Face($Rgba); } if( ! $is_left ) { this.VERTEX.push( X[0][0],Y[0],Z[0][0] ); this.VERTEX.push( X[0][2],Y[0],Z[0][2] ); this.VERTEX.push( X[1][0],Y[1],Z[1][0] ); this.VERTEX.push( X[1][2],Y[1],Z[1][2] ); this.Face($Rgba); } if( ! $is_right ) { this.VERTEX.push( X[0][1],Y[0],Z[0][1] ); this.VERTEX.push( X[1][1],Y[1],Z[1][1] ); this.VERTEX.push( X[0][3],Y[0],Z[0][3] ); this.VERTEX.push( X[1][3],Y[1],Z[1][3] ); this.Face($Rgba); } if( ! $is_top ) { this.VERTEX.push( X[1][0],Y[1],Z[1][0] ); this.VERTEX.push( X[1][2],Y[1],Z[1][2] ); this.VERTEX.push( X[1][1],Y[1],Z[1][1] ); this.VERTEX.push( X[1][3],Y[1],Z[1][3] ); this.Face($Rgba); } if( ! $is_down ) { this.VERTEX.push( X[0][0],Y[0],Z[0][0] ); this.VERTEX.push( X[0][1],Y[0],Z[0][1] ); this.VERTEX.push( X[0][2],Y[0],Z[0][2] ); this.VERTEX.push( X[0][3],Y[0],Z[0][3] ); this.Face($Rgba); } } Peek(x, y, z) { x = Math.round(x) ; y = Math.round(y) ; z = Math.round(z) ; if( x>=0 && x< this.size ) { if( y>=0 && y< this.size ) { if( z>=0 && z< this.size2 ) { let index = this.Index(x,y,z); return this.DEF[index] ?? 0 ; } } } return -1 ; } Poke( $color, $x,$y,$z ) { $x = Math.round($x) ; $y = Math.round($y) ; $z = Math.round($z) ; if( $x>=0 && $x< this.size ) { if( $z>=0 && $z< this.size ) { if( $y>=0 && $y< this.size2 ) { let index = this.Index($x,$y,$z); this.DEF[index] = $color; } } } } Define( DEF ) { for( let val of DEF ) { this.DEF.push(val*1); } } Reset() { this.VERTEX = []; this.COLOR = []; this.INDEX = []; this.NORMAL = []; this.index = 0 ; if( this.$Geometry ) { this.$Geometry.dispose(); this.$Geometry = null ; } } Build() { if( this.DEF.length == 0 ) { this.DEF = [1] ; } if( this.dirty ) { this.generation ++ ; this.Reset(); for( let i in this.DEF ) { let x = i % this.size ; let y = Math.floor(i / this.size2); let z = Math.floor((i-y*this.size2) / this.size) ; let bloc = this.DEF[i]??0; if( bloc ) { this.Cube(bloc, x,y,z) ; } } this.Finalize(); this.dirty = false ; this.ProcessOBB(); } } };