diff options
Diffstat (limited to 'client/assets/javascripts/rectangles/engine/rooms')
4 files changed, 521 insertions, 0 deletions
diff --git a/client/assets/javascripts/rectangles/engine/rooms/_rooms.js b/client/assets/javascripts/rectangles/engine/rooms/_rooms.js new file mode 100644 index 0000000..411a093 --- /dev/null +++ b/client/assets/javascripts/rectangles/engine/rooms/_rooms.js @@ -0,0 +1,41 @@ +var Rooms = new function(){ + + var base = this + + base.list = [] + base.regions = [] + + base.init = function(){ + Rooms.builder.init() + Rooms.clipper.init() + Rooms.mover.init() + } + + base.filter = function(f){ + return base.list.filter(f) + } + + base.add_with_rect = function(rect){ + var room = new Room({ + id: base.list.length, + rect: rect, + height: quantize(randrange(300,800), 50), + }) + base.list.push(room) + } + + base.forEach = function(f){ + return base.list.forEach(f) + } + + base.sorted_by_position = function(){ + return sort_rooms_by_position( base.list ) + } + base.sorted_by_height = function(){ + return sort_rooms_by_height( base.list ) + } + base.sorted_by_area = function(){ + return sort_rooms_by_area( base.list ) + } + +} diff --git a/client/assets/javascripts/rectangles/engine/rooms/builder.js b/client/assets/javascripts/rectangles/engine/rooms/builder.js new file mode 100644 index 0000000..8586a7b --- /dev/null +++ b/client/assets/javascripts/rectangles/engine/rooms/builder.js @@ -0,0 +1,294 @@ + +Rooms.builder = new function(){ + var base = this + + var els = [] + + base.init = function(){ + base.bind() + } + + base.bind = function(){ + app.on("clip", rebuild) + } + + function rebuild(){ + if (window.scene) { + clear() + build() + bind() + } + } + function build (){ + Rooms.regions.forEach(function(room){ + build_walls(room).forEach(function(el){ + els.push(el) + scene.add(el) + }) + }) + + Rooms.sorted_by_height().forEach(function(room){ + build_floors(room).forEach(function(el){ + els.push(el) + scene.add(el) + }) + }) + } + + function bind (){ + Rooms.forEach(function(room){ + room.walls = room.group_mx_walls() + room.walls.forEach(function(wall){ + wall.bind() + wall.randomize_colors() + }) + }) + } + + function clear (){ + els.forEach(function(el){ + scene.remove(el) + el.destroy && el.destroy() + }) + els = [] + } + + function build_walls (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 = 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 = 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 = 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 = 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 + } + + function build_floors(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.contains(region)) { + intersected = true + // r.sides = 0xf + // half_sides + } + else if (constructed[i].rect.intersects(region)) { + intersected = true + if (room.height < constructed[i].height) { + var ceiling_walls = make_ceiling_walls( room, constructed[i], region ) + list = list.concat(ceiling_walls) + } + } + } + if (! intersected) { + el = make_floor(room, region) + list.push( el ) + room.mx_floor.push(el) + + el = make_ceiling(room, region) + list.push( el ) + room.mx_ceiling.push(el) + } + }) + + } + else { + // render floor and ceiling for the entire rectangle + el = make_floor(room, room.rect) + list.push( el ) + room.mx_floor.push(el) + + el = make_ceiling(room, room.rect) + list.push( el ) + room.mx_ceiling.push(el) + } + + room.constructed = true + return list + } + + function make_ceiling_walls( 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 = 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 = 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 = 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 = 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 + } + + function make_floor(room, region){ + var width = region.x.length() + var depth = region.y.length() + + var el = 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 + } + function make_ceiling(room, region){ + var width = region.x.length() + var depth = region.y.length() + var height = room.height + + var el = 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 + } + + function make_wall(klass){ + 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 = null + } + + // possible if walls are opaque + // el.el.classList.add("backface-hidden") + + return el + } + +} + diff --git a/client/assets/javascripts/rectangles/engine/rooms/clipper.js b/client/assets/javascripts/rectangles/engine/rooms/clipper.js new file mode 100644 index 0000000..8989ba8 --- /dev/null +++ b/client/assets/javascripts/rectangles/engine/rooms/clipper.js @@ -0,0 +1,104 @@ + +Rooms.clipper = new function(){ + var base = this + + base.init = function(){ + base.bind() + base.update() + } + + base.bind = function(){ + map.ui.mouse.tube.on("up", function(){ base.update() }) + } + + base.update = function(){ + base.solve_rects() + app.tube("clip") + } + + var rooms, regions + + // Given a set of overlapping rooms, clip any intersections, then cull any duplicate polygons + base.solve_rects = function(){ + if (Rooms.list.length == 0) return + + base.reset_rects() + base.clip_rects() + base.cull_rects() + + Rooms.regions = sort_rects_by_position(regions) + } + + // Reset the clipping/culling states of each of the rooms + base.reset_rects = function(){ + for (var i = 0; i < Rooms.list.length; i++) { + Rooms.list[i].reset() + } + } + + // Compare each room to the rooms it overlaps, and subdivide + base.clip_rects = function(){ + var rooms = Rooms.sorted_by_position() + regions = [] + + var left, right + for (var i = 0; i < rooms.length; i++) { + left = rooms[i] + for (var j = i+1; j < rooms.length; j++) { + right = rooms[j] + if (left.rect.intersects(right.rect)) { + left.clipTo(right.rect) + right.clipTo(left.rect) + left.intersects.push(right) + right.intersects.push(left) + } + if (left.rect.x.b < right.rect.x.a) { + break + } + } + } + for (var i = 0; i < rooms.length; i++) { + rooms[i].regions = rooms[i].regions.filter(function(r){ return !!r }) + regions = regions.concat(rooms[i].regions) + } + } + + // Find overlapping regions (of the same size) and dedupe + base.cull_rects = function(){ + regions = sort_rects_by_area( regions ) + + var ty = new Tree (regions[0].y.a, [regions[0]]) + var tx = new Tree (regions[0].x.a, ty) + var ttx, tty + + for (var i = 1; i < regions.length; i++) { + ttx = tx.add (regions[i].x.a, null) + if (ttx.data) { + tty = ttx.data.add (regions[i].y.a, null) + // duplicate polygon? + if (tty.data) { + tty.data.forEach(function(yy, ii){ + if (yy.intersects(regions[i])) { + if (yy.area() > regions[i].area()) { + regions[i].dupe = true + } + else { + yy.dupe = true + tty.data[ii] = regions[i] + } + } + }) + } + else { + tty.data = [regions[i]] + } + } + else { + ttx.data = new Tree (regions[i].y.a, [regions[i]]) + } + } + } + + return base +} + diff --git a/client/assets/javascripts/rectangles/engine/rooms/mover.js b/client/assets/javascripts/rectangles/engine/rooms/mover.js new file mode 100644 index 0000000..e67d9bc --- /dev/null +++ b/client/assets/javascripts/rectangles/engine/rooms/mover.js @@ -0,0 +1,82 @@ +Rooms.mover = new function(){ + + var base = this + base.room = null + base.noclip = false + + base.init = function(){ + base.bind() + base.update(scene.camera) + } + + base.bind = function(){ + app.on("move", base.update) + keys.on("backslash", function(){ + base.noclip = ! base.noclip + base.room = null + app.movements.gravity( ! base.noclip ) + }) + } + + base.update = function(pos){ + var radius = scene.camera.radius + + if (base.noclip) { + cam.x = pos.x + cam.y = pos.y + cam.z = pos.z + return + } + + cam.y = pos.y + + // if we were in a room already.. + if (base.room) { + // check if we're still in the room + if (base.room.rect.containsDisc(pos.x, pos.z, radius)) { + cam.x = pos.x + cam.z = pos.z + return + } + + // check if we've breached one of the walls.. clamp position if so + var collision = base.room.collidesDisc(pos.x, pos.z, radius) + + if (collision) { + if (! (collision & LEFT_RIGHT)) { + cam.x = base.room.rect.x.clampDisc(pos.x, radius) + } + else { + // cam.x = base.room.rect.x.clampDisc(pos.x, radius) + } + if (! (collision & FRONT_BACK)) { + cam.z = base.room.rect.y.clampDisc(pos.z, radius) + } + return + } + + // in this case, we appear to have left the room.. + $(".face.active").removeClass("active") + base.room = null + } + + // collision test failed, so update position + cam.x = pos.x + cam.z = pos.z + + // determine what room we are in now + var intersects = Rooms.filter(function(r){ + return r.rect.contains(pos.x, pos.z) + }) + + // did we actually enter a room? + if (intersects.length) { + base.room = intersects[0] + base.room.mx_floor.forEach(function(w){ $(w.el).addClass("active") }) + base.room.mx_ceiling.forEach(function(w){ $(w.el).addClass("active") }) + base.room.mx_walls.forEach(function(w){ $(w.el).addClass("active") }) + } + + } + +} |
