(function(){ var Rooms, sort if ('window' in this) { Rooms = window.Rooms sort = window.sort } else { MX = require('../../../../../../test/mocks/mx.js') scene = MX.Scene Rooms = require('./_rooms') sort = require('../../util/sort') FRONT = 0x1, BACK = 0x2, LEFT = 0x4, RIGHT = 0x8, FLOOR = 0x10, CEILING = 0x20 PI = Math.PI HALF_PI = PI/2 TOP = CEILING, BOTTOM = FLOOR function sidesToString(sides){ var s = "" if (sides & FRONT) s += "front " if (sides & BACK) s += "back " if (sides & LEFT) s += "left " if (sides & RIGHT) s += "right " if (sides & TOP) s += "top " if (sides & BOTTOM) s += "bottom " return s } } Rooms.builder = new function(){ var base = this var els = [] base.init = function(){ base.bind() } base.bind = function(){ app.on("clip", base.rebuild.bind(base)) } base.rebuild = function(){ if (window.scene) { base.clear() base.build() Rooms.grouper.build() app.tube("rooms-built") } } base.build = function (){ Rooms.regions.forEach(function(region){ this.build_walls(region).forEach(function(el){ els.push(el) scene.add(el) }) }.bind(this)) Rooms.sorted_by_height().forEach(function(room){ this.build_floors(room).forEach(function(el){ els.push(el) scene.add(el) }) }.bind(this)) } base.clear = function (){ els.forEach(function(el){ scene.remove(el) el.destroy && el.destroy() }) els = [] } this.build_walls = function (region) { var room = Rooms.list[ region.id ] var list = [], el = null var width = region.x.length() var depth = region.y.length() var height = room.height if (region.sides & FRONT) { el = this.make_wall('.front') el.width = width el.height = height el.rotationY = PI el.x = region.x.a + width/2 el.y = height/2 el.z = region.y.a el.rect = region el.side = FRONT room.mx_walls.push(el) list.push(el) } if (region.sides & BACK) { var el = this.make_wall('.back') el.width = width el.height = height el.rotationY = 0 el.x = region.x.b - width/2 el.y = height/2 el.z = region.y.b el.rect = region el.side = BACK room.mx_walls.push(el) list.push(el) } if (region.sides & LEFT) { el = this.make_wall('.left') el.rotationY = HALF_PI el.height = height el.width = depth el.x = region.x.a el.y = height/2 el.z = region.y.a + depth/2 el.rect = region el.side = LEFT room.mx_walls.push(el) list.push(el) } if (region.sides & RIGHT) { el = this.make_wall('.right') el.rotationY = -HALF_PI el.height = height el.width = depth el.x = region.x.b el.y = height/2 el.z = region.y.b - depth/2 el.rect = region el.side = RIGHT room.mx_walls.push(el) list.push(el) } return list } this.build_floors = function (room){ var list = [], el = null var constructed = room.intersects.filter(function(room){ return room.constructed }) sort.rooms_by_height(constructed) if (constructed.length > 0) { // render the regions that don't intersect with anything we've already rendered // if the height is different, calculate the overlapping sides and render half-walls room.regions.forEach(function(region){ var intersected = false for (var i = 0; i < constructed.length; i++) { if (constructed[i].rect.overlaps(region)) { intersected = true if (room.height < constructed[i].height) { var ceiling_walls = this.make_ceiling_walls( room, constructed[i], region ) list = list.concat(ceiling_walls) } } } if (! intersected) { el = this.make_floor(room, region) list.push( el ) room.mx_floor.push(el) el = this.make_ceiling(room, region) list.push( el ) room.mx_ceiling.push(el) } }.bind(this)) } else { // render floor and ceiling for the entire rectangle el = this.make_floor(room, room.rect) list.push( el ) room.mx_floor.push(el) el = this.make_ceiling(room, room.rect) list.push( el ) room.mx_ceiling.push(el) } room.constructed = true return list } this.make_ceiling_walls = function ( lo, hi, region ){ var list = [] var width = region.x.length() var depth = region.y.length() var height = hi.height - lo.height if (! (region.half_sides & LEFT) && region.x.a == hi.rect.x.a) { el = this.make_wall('.left') el.rotationY = HALF_PI el.height = height el.width = depth el.x = region.x.a el.y = lo.height + height/2 el.z = region.y.a + depth/2 el.rect = region list.push(el) hi.mx_walls.push(el) region.half_sides |= LEFT el.half_side = LEFT } if (! (region.half_sides & RIGHT) && region.x.b == hi.rect.x.b) { el = this.make_wall('.right') el.rotationY = -HALF_PI el.height = height el.width = depth el.x = region.x.b el.y = lo.height + height/2 el.z = region.y.b - depth/2 el.rect = region list.push(el) hi.mx_walls.push(el) region.half_sides |= RIGHT el.half_side = RIGHT } if (! (region.half_sides & FRONT) && region.y.a == hi.rect.y.a) { el = this.make_wall('.front') el.width = width el.height = height el.rotationY = PI el.x = region.x.a + width/2 el.y = lo.height + height/2 el.z = region.y.a el.rect = region list.push(el) hi.mx_walls.push(el) region.half_sides |= FRONT el.half_side = FRONT } if (! (region.half_sides & BACK) && region.y.b == hi.rect.y.b) { el = this.make_wall('.back') el.width = width el.height = height el.rotationY = 0 el.x = region.x.b - width/2 el.y = lo.height + height/2 el.z = region.y.b el.rect = region list.push(el) hi.mx_walls.push(el) region.half_sides |= BACK el.half_side = BACK } return list } this.make_floor = function (room, region) { var width = region.x.length() var depth = region.y.length() var el = this.make_wall('.floor') el.height = depth el.width = width el.x = region.x.a + width/2 el.y = 0 el.z = region.y.a + depth/2 el.rotationX = PI/2 el.rect = region el.side = FLOOR return el } this.make_ceiling = function (room, region) { var width = region.x.length() var depth = region.y.length() var height = room.height var el = this.make_wall('.ceiling') el.height = depth el.width = width el.x = region.x.a + width/2 el.y = height el.z = region.y.a + depth/2 el.rotationX = -PI/2 el.rect = region el.side = CEILING return el } this.make_wall = function (klass) { // klass += ".backface-hidden" var el = new MX.Object3D(".face" + (klass || "")) el.width = el.height = el.scaleX = el.scaleY = el.scaleZ = 1 el.z = el.y = el.x = 0 el.side = 0 el.type = "Face" el.el.style.opacity = 1.0 el.side = 0 el.rect = null el.destroy = function(){ this.el = this.rect = this.face = null } // possible if walls are opaque // el.el.classList.add("backface-hidden") return el } } })()