summaryrefslogtreecommitdiff
path: root/client/assets/javascripts/rectangles/models
diff options
context:
space:
mode:
Diffstat (limited to 'client/assets/javascripts/rectangles/models')
-rw-r--r--client/assets/javascripts/rectangles/models/rect.js176
-rw-r--r--client/assets/javascripts/rectangles/models/room.js213
-rw-r--r--client/assets/javascripts/rectangles/models/tree.js37
-rw-r--r--client/assets/javascripts/rectangles/models/vec2.js99
-rw-r--r--client/assets/javascripts/rectangles/models/vec3.js5
-rw-r--r--client/assets/javascripts/rectangles/models/wall.js120
6 files changed, 650 insertions, 0 deletions
diff --git a/client/assets/javascripts/rectangles/models/rect.js b/client/assets/javascripts/rectangles/models/rect.js
new file mode 100644
index 0000000..7a2ac6f
--- /dev/null
+++ b/client/assets/javascripts/rectangles/models/rect.js
@@ -0,0 +1,176 @@
+
+window.Rect = (function(){
+ var Rect = function (x0,y0,x1,y1){
+ if (x0 instanceof vec2) {
+ this.x = x0
+ this.y = y0
+ }
+ else if (x1 === undefined) {
+ this.x = new vec2(x0,x0)
+ this.y = new vec2(y0,y0)
+ }
+ else {
+ this.x = new vec2(x0,x1)
+ this.y = new vec2(y0,y1)
+ }
+ this.translation = new vec2(0,0)
+ this.sides = FRONT | BACK | LEFT | RIGHT
+ }
+ Rect.prototype.clone = function(){
+ return new Rect( this.x.clone(), this.y.clone() )
+ }
+ Rect.prototype.center = function(){
+ return new vec2(this.x.midpoint(), this.y.midpoint())
+ }
+ Rect.prototype.area = function(){
+ return this.x.length() * this.y.length()
+ }
+
+ Rect.prototype.mul = function(n){
+ this.x.mul(n)
+ this.y.mul(n)
+ return this
+ }
+ Rect.prototype.div = function(n){
+ this.x.div(n)
+ this.y.div(n)
+ return this
+ }
+
+ Rect.prototype.translate = function(translation){
+ var translation = translation || this.translation
+ this.x.abs().add(translation.a)
+ this.y.abs().add(translation.b)
+ this.translation.a = this.translation.b = 0
+ return this
+ }
+ Rect.prototype.resize = function(translation, sides){
+ var translation = translation || this.translation
+ sides = sides || translation.sides
+
+ if (sides & LEFT) {
+ this.x.a += translation.a
+ }
+ if (sides & RIGHT) {
+ this.x.b += translation.a
+ }
+ if (sides & FRONT) {
+ this.y.a += translation.b
+ }
+ if (sides & BACK) {
+ this.y.b += translation.b
+ }
+ this.translation.a = this.translation.b = 0
+ }
+ Rect.prototype.contains = function(x,y){
+ return this.x.contains(x) && this.y.contains(y)
+ }
+ Rect.prototype.containsDisc = function(x,y,r){
+ return this.x.containsDisc(x,r) && this.y.containsDisc(y,r)
+ }
+ Rect.prototype.intersects = function(r){
+ return this.x.intersects(r.x) && this.y.intersects(r.y)
+ }
+ Rect.prototype.nearEdge = function (x, y, r) {
+ var edges = 0
+ if (x < this.x.a+r) {
+ edges |= LEFT
+ }
+ else if (x > this.x.b-r) {
+ edges |= RIGHT
+ }
+ if (y < this.y.a+r) {
+ edges |= FRONT
+ }
+ else if (y > this.y.b-r) {
+ edges |= BACK
+ }
+ return edges
+ }
+ Rect.prototype.width = function(){ return this.x.length() }
+ Rect.prototype.height = function(){ return this.y.length() }
+ Rect.prototype.toString = function(){
+ var sides = sidesToString(this.sides)
+ var s = "[" + this.x.toString() + " " + this.y.toString() + "] " + sides
+ return s
+ }
+ Rect.prototype.quantize = function(n){
+ this.x.quantize(n)
+ this.y.quantize(n)
+ return this
+ }
+ Rect.prototype.split = function(r){
+ var rz = this
+ var splits = []
+ var split_contains = 0
+ var x_intervals = [], y_intervals = []
+ var sides = this.sides
+
+ // Split vertically
+ if (this.x.contains(r.x.a) && r.x.contains(this.x.b)) {
+ x_intervals.push([ new vec2( this.x.a, r.x.a ), LEFT ])
+ x_intervals.push([ new vec2( r.x.a, this.x.b ), RIGHT ])
+ split_contains |= RIGHT
+ }
+
+ else if (r.x.contains(this.x.a) && this.x.contains(r.x.b)) {
+ x_intervals.push([ new vec2( this.x.a, r.x.b ), LEFT ])
+ x_intervals.push([ new vec2( r.x.b, this.x.b ), RIGHT ])
+ split_contains |= LEFT
+ }
+
+ else if (this.x.contains(r.x.a) && this.x.contains(r.x.b)) {
+ x_intervals.push([ new vec2( this.x.a, r.x.a ), LEFT ])
+ x_intervals.push([ new vec2( r.x.a, r.x.b ), 0 ])
+ x_intervals.push([ new vec2( r.x.b, this.x.b ), RIGHT ])
+ split_contains |= LEFT | RIGHT
+ }
+
+ else { // if (r.x.contains(this.x.a) && r.x.contains(r.x.b)) {
+ x_intervals.push([ new vec2( this.x.a, this.x.b ), LEFT | RIGHT ])
+ split_contains |= LEFT | RIGHT
+ }
+
+ // Split horizontally
+ if (this.y.contains(r.y.a) && r.y.contains(this.y.b)) {
+ y_intervals.push([ new vec2( this.y.a, r.y.a ), FRONT ])
+ y_intervals.push([ new vec2( r.y.a, this.y.b ), BACK ])
+ split_contains |= BACK
+ }
+
+ else if (r.y.contains(this.y.a) && this.y.contains(r.y.b)) {
+ y_intervals.push([ new vec2( this.y.a, r.y.b ), FRONT ])
+ y_intervals.push([ new vec2( r.y.b, this.y.b ), BACK ])
+ split_contains |= FRONT
+ }
+
+ else if (this.y.contains(r.y.a) && this.y.contains(r.y.b)) {
+ y_intervals.push([ new vec2( this.y.a, r.y.a ), FRONT ])
+ y_intervals.push([ new vec2( r.y.a, r.y.b ), 0 ])
+ y_intervals.push([ new vec2( r.y.b, this.y.b ), BACK ])
+ split_contains |= FRONT | BACK
+ }
+
+ else { // if (r.y.contains(this.y.a) && this.y.contains(r.y.b)) {
+ y_intervals.push([ new vec2( this.y.a, this.y.b ), FRONT | BACK ])
+ split_contains |= FRONT | BACK
+ }
+
+ x_intervals.forEach(function(x){
+ y_intervals.forEach(function(y){
+ var rn = new Rect(x[0], y[0])
+ rn.id = rz.id
+ rn.sides = ((x[1] | y[1]) & sides)
+ if (r.intersects(rn)) {
+ rn.sides = 0
+ }
+ rn.focused = rz.focused
+ splits.push(rn)
+ })
+ })
+ return splits
+ }
+
+ return Rect
+
+})()
diff --git a/client/assets/javascripts/rectangles/models/room.js b/client/assets/javascripts/rectangles/models/room.js
new file mode 100644
index 0000000..731411c
--- /dev/null
+++ b/client/assets/javascripts/rectangles/models/room.js
@@ -0,0 +1,213 @@
+window.Room = (function(){
+
+ var Room = function(opt){
+ this.id = opt.id || Rooms.list.length
+ this.rect = opt.rect
+ this.regions = []
+ this.walls = []
+ this.floor = []
+ this.ceiling = []
+
+ this.height = opt.height || 200
+ this.focused = false
+ }
+
+ Room.prototype.toString = function(){
+ return this.rect.toString()
+ }
+
+ Room.prototype.reset = function(){
+ var copy = this.rect.clone()
+ copy.id = this.id
+ copy.sides = FRONT | BACK | LEFT | RIGHT
+ this.regions = [ copy ]
+
+ this.intersects = []
+ this.constructed = false
+
+ this.walls = []
+
+ this.mx_walls = []
+ this.mx_floor = []
+ this.mx_ceiling = []
+ }
+
+ Room.prototype.bind = function(){
+ var base = this
+ base.mx_walls.forEach(function(wall){
+ $(wall.el).bind({
+ mouseover: function(){
+ },
+ mousemove: function(e){
+ var color = choice(window.palettes.colors)
+ base.mx_walls.forEach(function(wall){
+ $(wall.el).css("background-color", color)
+ })
+ },
+ mousedown: function(){
+ }
+ })
+ })
+ }
+
+ Room.prototype.group_mx_walls = function(){
+ var base = this
+ var side_groups = {}, walls = []
+
+ // group the walls by side
+ base.mx_walls.forEach(function(wall){
+
+ // ignore half-walls for now
+ var side = wall.side || wall.half_side
+
+ if (side_groups[side]) {
+ side_groups[side].push(wall)
+ }
+ else {
+ side_groups[side] = [wall]
+ }
+ })
+
+ // sort the subgroups, and then combine mx objects under wall objects
+ pairs(side_groups).forEach(function(pair){
+ var side = pair[0], els = pair[1]
+
+ if (side & LEFT_RIGHT) {
+ els.sort(compare_x)
+ }
+ else if (side & FRONT_BACK) {
+ els.sort(compare_z)
+ }
+
+ var wall
+
+ els.forEach(function(el){
+ if (el.half_side) {
+ wall = new_wall(el)
+ walls.push(wall)
+ wall = null
+ }
+ else if (! wall) {
+ wall = new_wall(el)
+ walls.push(wall)
+ }
+ else if (side & FRONT_BACK && wall.rect.x.b == el.rect.x.a) {
+ wall.rect.x.b = el.rect.x.b
+ wall.mx.push(el)
+ }
+ else if (side & LEFT_RIGHT && wall.rect.y.b == el.rect.y.a) {
+ wall.rect.y.b = el.rect.y.b
+ wall.mx.push(el)
+ }
+ else {
+ wall = new_wall(el)
+ walls.push(wall)
+ }
+ })
+ })
+
+ function new_wall (el) {
+ return new Wall ({
+ room: base.id,
+ side: el.side | el.half_side,
+ half_side: el.half_side,
+ rect: el.rect.clone(),
+ el: el,
+ })
+ }
+
+ return walls
+ }
+
+ Room.prototype.clipTo = function(r){
+ // for each of this rect's regions split the region if necessary
+ var regions = this.regions
+ var splits
+ for (var i = 0, len = regions.length; i < len; i++) {
+ if (regions[i] && regions[i].intersects(r)) {
+ splits = regions[i].split(r)
+ regions = regions.concat(splits)
+ regions[i] = null
+ }
+ }
+ this.regions = regions
+ }
+
+ Room.prototype.collides = function(x,y){
+ var collision = 0, wall_collision, contains_x, contains_y
+ this.regions.forEach(function(r){
+ if (! r.sides) return
+
+ wall_collision = 0
+
+ if ((r.sides & FRONT) && y < r.y.a) {
+ wall_collision |= FRONT
+ }
+ if ((r.sides & BACK) && r.y.b < y) {
+ wall_collision |= BACK
+ }
+ if ((r.sides & LEFT) && x < r.x.a) {
+ wall_collision |= LEFT
+ }
+ if ((r.sides & RIGHT) && r.x.b < x) {
+ wall_collision |= RIGHT
+ }
+ if (! wall_collision) return
+
+ contains_y = r.y.contains(y)
+ contains_x = r.x.contains(x)
+
+ if (contains_x) {
+ collision |= wall_collision & FRONT_BACK
+ }
+ else if (contains_y) {
+ collision |= wall_collision & LEFT_RIGHT
+ }
+ else if (bitcount(wall_collision) > 1) {
+ collision |= wall_collision
+ }
+ })
+ return collision
+ }
+
+ Room.prototype.collidesDisc = function(x,y,radius){
+ var collision = 0, wall_collision, contains_x, contains_y
+ this.regions.forEach(function(r){
+ if (! r.sides) return
+
+ wall_collision = 0
+
+ if ((r.sides & FRONT) && y-radius < r.y.a) {
+ wall_collision |= FRONT
+ }
+ if ((r.sides & BACK) && r.y.b < y+radius) {
+ wall_collision |= BACK
+ }
+ if ((r.sides & LEFT) && x-radius < r.x.a) {
+ wall_collision |= LEFT
+ }
+ if ((r.sides & RIGHT) && r.x.b < x+radius) {
+ wall_collision |= RIGHT
+ }
+ if (! wall_collision) return
+
+ contains_x = r.x.contains(x, radius)
+ contains_y = r.y.contains(y, radius)
+
+ if (contains_x) {
+ collision |= wall_collision & FRONT_BACK
+ }
+ else if (contains_y) {
+ collision |= wall_collision & LEFT_RIGHT
+ }
+ else if (bitcount(wall_collision) > 1) {
+ collision |= wall_collision
+ }
+ })
+ return collision
+ }
+
+ return Room
+
+})()
+
diff --git a/client/assets/javascripts/rectangles/models/tree.js b/client/assets/javascripts/rectangles/models/tree.js
new file mode 100644
index 0000000..8193988
--- /dev/null
+++ b/client/assets/javascripts/rectangles/models/tree.js
@@ -0,0 +1,37 @@
+var Tree = function(n, data){
+ this.lo = null
+ this.hi = null
+ this.value = n
+ this.data = data
+}
+Tree.prototype.find = function(n){
+ if (n == this.value) return this
+ if (n < this.value) return this.lo ? this.lo.find(n) : this
+ if (n > this.value) return this.hi ? this.hi.find(n) : this
+}
+Tree.prototype.add = function(n, data){
+ var closest = this.find(n)
+ if (n == closest.value) return closest
+ if (n < closest.value) return closest.lo = new Tree(n, data)
+ if (n > closest.value) return closest.hi = new Tree(n, data)
+}
+Tree.prototype.toArray = function(){
+ var a = []
+ if (this.lo) a = a.concat(this.lo.toArray())
+ a.push(this.data)
+ if (this.hi) a = a.concat(this.hi.toArray())
+ return a
+}
+Tree.prototype.toString = function(){
+ var s = "";
+ if (this.lo) s += this.lo.toString()
+ s += this.value + ","
+ if (this.hi) s += this.hi.toString()
+ return s
+}
+Tree.prototype.depth = function(){
+ if (this.lo && this.hi) return 1 + max(this.lo.depth(), this.hi.depth())
+ else if (this.lo) return 1 + this.lo.depth()
+ else if (this.hi) return 1 + this.hi.depth()
+ else return 0
+}
diff --git a/client/assets/javascripts/rectangles/models/vec2.js b/client/assets/javascripts/rectangles/models/vec2.js
new file mode 100644
index 0000000..9b0447c
--- /dev/null
+++ b/client/assets/javascripts/rectangles/models/vec2.js
@@ -0,0 +1,99 @@
+function vec2(a,b){
+ this.a = a
+ this.b = b
+}
+vec2.prototype.magnitude = function(){
+ return this.b-this.a
+}
+vec2.prototype.length = function(){
+ return abs(this.b-this.a)
+}
+vec2.prototype.clone = function(){
+ return new vec2(this.a, this.b)
+}
+vec2.prototype.abs = function(){
+ if (this.b < this.a) {
+ this.invert()
+ }
+ return this
+}
+vec2.prototype.invert = function(){
+ this.a = this.a ^ this.b
+ this.b = this.a ^ this.b
+ this.a = this.a ^ this.b
+ return this
+}
+vec2.prototype.midpoint = function(){
+ return lerp(0.5, this.a, this.b)
+}
+vec2.prototype.eq = function(v){
+ return this.a == v.a && this.b == v.b
+}
+vec2.prototype.add = function(n){
+ this.a += n
+ this.b += n
+ return this
+}
+vec2.prototype.sub = function(n){
+ this.a -= n
+ this.b -= n
+ return this
+}
+vec2.prototype.mul = function(n){
+ this.a *= n
+ this.b *= n
+ return this
+}
+vec2.prototype.div = function(n){
+ this.a /= n
+ this.b /= n
+ return this
+}
+vec2.prototype.normalize = function(){
+ var dim = max(this.a, this.b)
+ this.a = this.a/dim
+ this.b = this.b/dim
+ return this
+}
+vec2.prototype.contains = function(n){
+ return this.a <= n && n <= this.b
+}
+vec2.prototype.containsDisc = function(n,r){
+ return this.a <= n-r && n+r <= this.b
+}
+vec2.prototype.clamp = function(n){
+ return clamp(n, this.a, this.b)
+}
+vec2.prototype.clampDisc = function(n,r){
+ return clamp(n, this.a+r, this.b-r)
+}
+vec2.prototype.intersects = function(v){
+ if (this.a < v.a) {
+ return (v.a < this.b && this.b <= v.b) || (this.a < v.b && v.b <= this.b)
+ }
+ else if (this.a == v.a) {
+ return true
+ }
+ else if (this.a > v.a) {
+ return (this.a < v.b && v.b <= this.b) || (v.a < this.b && this.b <= v.b)
+ }
+}
+vec2.prototype.union = function(v){
+ if (this.intersects(v)) {
+ return new vec2( min(this.a,v.a), max(this.b, v.b) )
+ }
+}
+vec2.prototype.intersection = function(v){
+ if (this.intersects(v)) {
+ return new vec2( max(this.a,v.a), min(this.b, v.b) )
+ }
+}
+vec2.prototype.toString = function(){
+ return "[" + ~~this.a + " " + ~~this.b + "]"
+}
+vec2.prototype.quantize = function(n){
+ n = n || 10
+ this.a = quantize(this.a, n)
+ this.b = quantize(this.b, n)
+}
+
diff --git a/client/assets/javascripts/rectangles/models/vec3.js b/client/assets/javascripts/rectangles/models/vec3.js
new file mode 100644
index 0000000..4e9f3cb
--- /dev/null
+++ b/client/assets/javascripts/rectangles/models/vec3.js
@@ -0,0 +1,5 @@
+function vec3(a,b,c){
+ this.a = a
+ this.b = b
+ this.c = c
+}
diff --git a/client/assets/javascripts/rectangles/models/wall.js b/client/assets/javascripts/rectangles/models/wall.js
new file mode 100644
index 0000000..4270551
--- /dev/null
+++ b/client/assets/javascripts/rectangles/models/wall.js
@@ -0,0 +1,120 @@
+window.Wall = (function(){
+
+ var Wall = function(opt){
+ this.id = opt.id
+ this.uid = Uid()
+ this.room = opt.room
+ this.rect = opt.rect || new Rect (0,0,0,0)
+ this.rect.sides = opt.side
+ this.side = opt.side
+ this.mx = []
+ this.els = []
+ if (opt.el) {
+ this.mx.push(opt.el)
+ }
+ }
+
+ Wall.prototype.toString = function(){
+ return this.rect.toString()
+ }
+
+ Wall.prototype.reset = function(){
+ }
+
+ Wall.prototype.destroy = function(){
+ this.mx.forEach(function(mx){
+ mx.destroy && mx.destroy()
+ })
+ this.room = this.rect = this.mx = this.els = null
+ }
+
+ Wall.prototype.bind = function(){
+ var base = this
+ base.$walls = $( this.mx.map(function(mx){ return mx.el }) )
+ base.$walls.bind({
+ mouseover: function(){
+ },
+ mouseenter: function(e){
+ Scenery.mouse.mouseenter(e, base)
+ },
+ mousemove: function(e){
+ },
+ mousedown: function(){
+ base.randomize_colors()
+ console.log(sidesToString(base.side))
+ }
+ })
+ }
+
+ Wall.prototype.bounds_for = function(img) {
+ var coord = this.side & FRONT_BACK ? this.rect.x : this.rect.y
+ return new Rect( new vec2( coord.a + img.width/2, coord.b - img.width/2 ),
+ new vec2( img.height/2, Rooms.list[this.room].height - img.height/2 ) )
+ }
+ Wall.prototype.fits = function(img){
+ if (this.side & FRONT_BACK && this.rect.x.length() < img.width) {
+ return false
+ }
+ if (this.side & LEFT_RIGHT && this.rect.y.length() < img.width) {
+ return false
+ }
+ return true
+ }
+
+ Wall.prototype.center = function(offset){
+
+ offset = offset || 0
+
+ var major_axis, minor_axis
+ if (this.side & FRONT_BACK) {
+ major_axis = this.rect.x
+ minor_axis = this.rect.y
+ }
+ else {
+ major_axis = this.rect.y
+ minor_axis = this.rect.x
+ }
+
+ switch (this.side) {
+ case FRONT:
+ x = major_axis.midpoint()
+ z = minor_axis.a + painting_distance_from_wall + offset
+ break
+ case BACK:
+ x = major_axis.midpoint()
+ z = minor_axis.b - painting_distance_from_wall + offset
+ break
+ case LEFT:
+ x = minor_axis.a + painting_distance_from_wall + offset
+ z = major_axis.midpoint()
+ break
+ case RIGHT:
+ x = minor_axis.b - painting_distance_from_wall + offset
+ z = major_axis.midpoint()
+ break
+ }
+
+ return new vec2 (x, z)
+ }
+
+ Wall.prototype.color = function(color){
+ this.$walls && this.$walls.css("background-color", color)
+ }
+
+ Wall.prototype.siblings = function(){
+ var base = this
+ var match = base.side | base.half_side
+ var walls = Rooms.list[this.room].walls.filter(function(w){
+ return (w.side | w.half_side) & match
+ })
+ return walls;
+ }
+
+ Wall.prototype.randomize_colors = function(){
+ var color = choice(window.colors)
+ this.siblings().forEach(function(w){ w.color(color) })
+ }
+
+ return Wall
+
+})()