summaryrefslogtreecommitdiff
path: root/client/assets/javascripts/rectangles/engine/rooms
diff options
context:
space:
mode:
authorJules Laplace <jules@okfoc.us>2014-06-03 16:24:10 -0400
committerJules Laplace <jules@okfoc.us>2014-06-03 16:24:28 -0400
commit607f69c67a5b4dc72d2754192e3cdf67d0ad11d0 (patch)
tree6556e7922c5bedb274bb1650e5dd100643a7895d /client/assets/javascripts/rectangles/engine/rooms
parentd31259291d807c851de4396921e0c26b6dd8dce2 (diff)
partitioning client and serveR
Diffstat (limited to 'client/assets/javascripts/rectangles/engine/rooms')
-rw-r--r--client/assets/javascripts/rectangles/engine/rooms/_rooms.js41
-rw-r--r--client/assets/javascripts/rectangles/engine/rooms/builder.js294
-rw-r--r--client/assets/javascripts/rectangles/engine/rooms/clipper.js104
-rw-r--r--client/assets/javascripts/rectangles/engine/rooms/mover.js82
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") })
+ }
+
+ }
+
+}