Script.as
actionscript · 652 lines · part of Not showing splits · raw
/*
v 004
-----
added colours to shapes
added filled polygon rendering
draws split lines in a different colour (inefficient + doesn't always work!)
added case for camera behind or in front of plane in BSPNode.render (inefficient!)
bodged 3d perspective rendering (look out for those 20's)
v 005
-----
got white lines working properly (but inefficiently)
added debug display
added stop & go buttons
v 007
-----
28/Aug/2005
Fixing bug where faces disappear when cubes are used
*/
//---- Polygon ---------------------------------------------------------------//
/*
Polygon
Polygon.addPoint( point_coordinate_vector )
Polygon.copyOf( polygon_to_copy )
Polygon.render( movie_clip_to_render_into )
Polygon.toString( )
*/
function Polygon ( )
{
//trace("Polygon <9init>")
this.normal = null
this.facing = 0
this.point = new Array()
this.white = new Array()
}
//---- Polygon.addPoint
Polygon.prototype.addPoint = function( p )
{
this.point.push ( p )
//- Calculate normal if we have just added a third point
if(this.point.length == 3 )
{
var a = [ this.point[0][0] - this.point[1][0] ,
this.point[0][1] - this.point[1][1] ,
this.point[0][2] - this.point[1][2] ]
var b = [ this.point[2][0] - this.point[1][0] ,
this.point[2][1] - this.point[1][1] ,
this.point[2][2] - this.point[1][2] ]
this.normal = [ a[1] * b[2] - a[2] * b[1] ,
a[2] * b[0] - a[0] * b[2] ,
a[0] * b[1] - a[1] * b[0] ]
}
}
//---- Polygon.copyOf - duplicates a polygon
Polygon.prototype.copyOf = function ( p )
{
this.point = p.point
this.normal = p.normal
this.col = p.col
this.white = p.white
}
//---- Polygon.render
Polygon.prototype.render = function ( b )
{
if( this.point.length <= 0 ) return
b.lineStyle( 1, 0x000000, 100 )
var i = this.point.length-1;
b.moveTo( 200 + 100 * this.point[ i ][0] / (this.point[i][2] + 20), 200 + 100 *this.point[ i ][1] / (this.point[i][2] + 20) )
b.beginFill( this.col, 75 )
for( i=0; i<this.point.length; i++)
{
ii = i-1; if(ii<0) ii = this.point.length-1
if(this.white[ii]) b.lineStyle( )
b.lineTo( 200 + 100 * this.point[i][0] / (this.point[i][2] + 20), 200 + 100 * this.point[i][1] / (this.point[i][2] + 20))
if(this.white[ii]) b.lineStyle( 1, 0x000000, 100 )
}
b.endFill()
}
//---- Polygon.toString
Polygon.prototype.toString = function ( )
{
return '<poly numpoints="' + this.point.length + '" />\n'
}
//---- Shape -----------------------------------------------------------------//
/*
Shape( point_array, faces_array, colour )
Shape.transformPoint( source_point_coord_array, dest_point_coord_array )
Shape.transform( rx, ry, rz, x, y, z )
*/
function Shape ( points, faces, col )
{
var i, j
this.point = points
this.tpoint = new Array()
this.normal = new Array()
this.tnormal = new Array()
this.poly = new Array()
this.col = col
//- Fill tpoint array
for( i=0; i<this.point.length; i++ ) this.tpoint[i] = [ this.point[i][0], this.point[i][1], this.point[i][2] ]
//- Create array of polygons
for( i=0; i<faces.length; i++)
{
this.poly[i] = new Polygon ( )
// Add points to polygon
for( j=0; j<faces[i].length; j++ ) this.poly[i].addPoint ( this.tpoint[ faces[i][j] ] )
// Get polygon's normal and replace it with transformed normal
this.normal[i] = this.poly[i].normal
this.tnormal[i] = [ this.normal[i][0], this.normal[i][1], this.normal[i][2] ]
this.poly[i].normal = this.tnormal[i]
this.poly[i].col = col
}
//- Set up other vars
this.srx = 0
this.crx = 0
this.sry = 0
this.cry = 0
}
//---- Shape.transformPoint
Shape.prototype.transformPoint = function ( s, d )
{
var x, y, z
var nx, ny, nz
x = s[0]
y = s[1]
z = s[2]
// Y rotate
nx = x * this.cry - this.sry * z
ny = y
nz = x * this.sry + this.cry * z
// X rotate
x = nx
y = ny * this.crx - this.srx * nz
z = ny * this.srx + this.crx * nz
// Z rotate
d[0] = x * this.crz - this.srz * y
d[1] = x * this.srz + this.crz * y
d[2] = z
}
//---- Shape.transform
Shape.prototype.transform = function ( rx, ry, rz, x, y, z )
{
this.srx = Math.sin(rx)
this.crx = Math.cos(rx)
this.sry = Math.sin(ry)
this.cry = Math.cos(ry)
this.srz = Math.sin(rz)
this.crz = Math.cos(rz)
//- Make transformed points
var i
for( i=0; i<this.point.length; i++ )
{
this.transformPoint ( this.point[i], this.tpoint[i] )
this.tpoint[i][0] += x
this.tpoint[i][1] += y
this.tpoint[i][2] += z
}
//- Transform normal
for( i=0; i<this.point.length; i++ )
{
this.transformPoint ( this.normal[i], this.tnormal[i] )
}
}
//---- BSPNode ---------------------------------------------------------------//
/*
BSPNode( polygon_object_to_split_space )
BSPNode.addPolygon( polygon_to_add_to_node_and_split_if_necessary )
BSPNode.inFront = function ( point_to_determine_whether_in_front_or_behind )
BSPNode.splitLine = function ( p1, p2 )
BSPNode.splitPolygon = function ( polygon_to_split, polygon_to_reveive_behind_part, polygon_to_receive_in_front_part )
BSPNode.render = function ( movie_clip_to_render_into )
BSPNode.toString = function ( )
*/
function BSPNode ( poly )
{
//trace( "BSPNode <init> "+poly)
//- Child nodes
this.front = null
this.back = null
//- Polygon attached to this node
this.poly = poly
//- Plane definition
this.normal = this.poly.normal
this.point = this.poly.point[0]
}
//---- BSPNode.addPolygon
BSPNode.prototype.addPolygon = function ( poly )
{
////trace ("BSPNode.addPolygon "+ poly )
/*
if( this.back )
{
this.back.addPolygon ( poly )
}
else
{
this.back = new BSPNode ( poly )
}
*/
//- Split polygon
var poly_back = new Polygon ( )
var poly_front = new Polygon ( )
this.splitPolygon( poly, poly_back, poly_front )
//- Add to child nodes
if( poly_back.point.length )
{
if( this.back != null ) this.back.addPolygon( poly_back )
else this.back = new BSPNode( poly_back )
}
if( poly_front.point.length )
{
if( this.front != null ) this.front.addPolygon( poly_front )
else this.front = new BSPNode( poly_front )
}
}
//---- BSPNode.inFront - returns >0 if the given point is in front of the plane, <0 if it is behind
BSPNode.prototype.inFront = function ( p )
{
//trace ( p+" :: "+this.point+" :: "+this.normal)
return ( p[0] - this.point[0] ) * this.normal[0] +
( p[1] - this.point[1] ) * this.normal[1] +
( p[2] - this.point[2] ) * this.normal[2];
}
//---- BSPNode.splitLine - finds the intersection of the given line and this node's plane
BSPNode.prototype.splitLine = function ( p1, p2 )
{
var a = [ p1[0] - this.point[0] ,
p1[1] - this.point[1] ,
p1[2] - this.point[2] ]
var b = [ p2[0] - this.point[0] ,
p2[1] - this.point[1] ,
p2[2] - this.point[2] ]
var an = a[0]*this.normal[0] + a[1]*this.normal[1] + a[2]*this.normal[2]
var bn = b[0]*this.normal[0] + b[1]*this.normal[1] + b[2]*this.normal[2]
var t = bn / (bn - an)
var tt = 1.0 - t
//- Return intersection point
return [ p1[0] * t + p2[0] * tt ,
p1[1] * t + p2[1] * tt ,
p1[2] * t + p2[2] * tt ]
}
//---- BSPNode.splitPolygon - splits a polygon around this node's plane
BSPNode.prototype.splitPolygon = function ( poly, back, front )
{
//trace ( "BSPNode.splitPolygon" )
//- Check which side of plane each polygon point is on
var infront = true
var behind = true
var pdist = new Array()
for( i = 0; i < poly.point.length; i ++ )
{
pdist[i] = this.inFront( poly.point[i] )
//trace( pdist[i] )
//trace( poly.normal )
if( pdist[i] < 0 ) infront = false
if( pdist[i] > 0 ) behind = false
}
//- Deal with 3 possibilities: totally in front, totally behind, intersecting
if(infront)
{
front.copyOf ( poly )
}
else if(behind)
{
back.copyOf ( poly )
}
else
{
var i, ii
var pt
//- Clip against plane
for( i = 0; i < poly.point.length; i++ )
{
ii = (i+1) % poly.point.length
if( pdist[i] < 0 && pdist[ii] < 0)
{
back.addPoint( poly.point[i] )
back.white.push( 0 + poly.white[i] )
}
else if( pdist[i] < 0 && pdist[ii] > 0)
{
back.addPoint( poly.point[i] )
back.white.push( 0 + poly.white[i] )
pt = this.splitLine( poly.point[i], poly.point[ii] )
back.addPoint( pt )
back.white.push( 1 )
front.addPoint( pt )
front.white.push( 0 + poly.white[i] )
}
else if( pdist[i] > 0 && pdist[ii] > 0)
{
front.addPoint( poly.point[i] )
front.white.push( 0 + poly.white[i] )
}
else if( pdist[i] > 0 && pdist[ii] < 0)
{
front.addPoint( poly.point[i] )
front.white.push( 0 + poly.white[i] )
pt = this.splitLine( poly.point[i], poly.point[ii] )
front.addPoint( pt )
front.white.push( 1 )
back.addPoint( pt )
back.white.push( 0 + poly.white[i] )
}
}
// front.normal = poly.normal
// back.normal = poly.normal
// front.col = ((poly.col >> 1)&0x7F7F7F)+0x7F7F7F
front.col = poly.col
back.col = poly.col
}
}
//---- BSPNode.render
BSPNode.prototype.render = function ( b )
{
////trace ( 'BSPNode.render ::'+this.poly+'::' )
var facing = this.normal[0] * this.point[0] + this.normal[1] * this.point[1] + this.normal[2] * ( this.point[2] + 20)
if( facing < 0)
{
if ( this.back ) this.back.render ( b )
this.poly.render ( b )
if ( this.front ) this.front.render ( b )
}
else
{
if ( this.front ) this.front.render ( b )
this.poly.render ( b )
if ( this.back ) this.back.render ( b )
}
}
//---- BSPNode.toString
BSPNode.prototype.toString = function ( )
{
var a, b
if( this.back )
{
a = ""+this.back
a = " " + a.split("\n").join("\n ")
// a = "<back>\n"+a+"</back>\n"
}
if( this.front )
{
b = ""+this.front
b = " " + b.split("\n").join("\n ")
// b = "<front>\n"+b+"</back>\n"
}
p = "" + this.poly
return p + a + b
return "<node>\n"
+ p
+ a
+ b
+ "</node>"
}
//---- BSPTree ---------------------------------------------------------------//
/*
BSPTree( )
BSPTree.addPolygon = function ( poly )
BSPTree.addShape = function ( shape )
BSPTree.render = function ( b )
BSPTree.toString = function ( )
*/
function BSPTree ( )
{
this.node = null
}
//---- BSPTree.addPolygon - adds a single polygon to the tree
BSPTree.prototype.addPolygon = function ( poly )
{
////trace( "BSPTree.addPolygon" )
if(this.node)
{
this.node.addPolygon ( poly )
}
else
{
this.node = new BSPNode ( poly )
}
}
//---- BSPTree.addShape - adds a shape to the tree
BSPTree.prototype.addShape = function ( shape )
{
var i
for ( i = 0; i < shape.poly.length; i ++ )
{
this.addPolygon ( shape.poly[i] )
}
}
//---- BSPTree.render - renders the shape stored in the tree into the given MovieClip
BSPTree.prototype.render = function ( b )
{
if( this.node ) this.node.render ( b )
}
//---- BSPTree.toString - returns debug info about tree
BSPTree.prototype.toString = function ( )
{
return "" + this.node
}
//---- timer -----------------------------------------------------------------//
function timer ( )
{
// trace('-----frame-----')
rx1 += 0.008//*3
ry1 -= 0.013//*3
rx2 -= 0.009*3
ry2 += 0.007*3
rx3 += 0.011*3
ry3 -= 0.005*3
/*
shapes[0].transform ( rx1, ry1, 0, 1.4, 1.3, -1.2 )
shapes[1].transform ( rx2, 0, ry2, -3.3, -2.1, 1.1 )
shapes[2].transform ( ry2-rx1, rx3, ry3, 1.1, -3.3, 2.4)
shapes[3].transform ( ry1-rx3, rx1-ry2, rx3, 2.1, -1.3, 3.4)
shapes[4].transform ( rx2+rx1, ry3, rx3-ry1, -1.4, 2.3, -2.4)
*/
shapes[0].transform ( rx1, ry1, 0, 1.4, 1.3, -1.2 )
shapes[1].transform ( rx1, ry1, 0, 1.4, 1.3, -1.2 )
buffer.clear()
bsp = new BSPTree ( )
bsp.addShape ( shapes[0] )
bsp.addShape ( shapes[1] )
// bsp.addShape ( shapes[2] )
// bsp.addShape ( shapes[3] )
// bsp.addShape ( shapes[4] )
bsp.render ( buffer )
// bsp2 = new BSPTree ( )
// bsp2.addShape (shapes[1])
// bsp2.render ( buffer )
// debug = bsp
}
//---- DATA ------------------------------------------------------------------//
points1 =
[
[-10, 0, -10],
[ 10, 0, -10],
[ 10, 0, 10],
[-10, 0, 10]
]
faces1 =
[
[0, 1, 2, 3]
]
points2 =
[
[-10, -10, 0],
[ 10, -10, 0],
[ 10, 10, 0],
[-10, 10, 0]
]
faces2 =
[
[0, 1, 2, 3]
]
//---- main ------------------------------------------------------------------//
shapes = new Array ( )
/*
shapes[0] = new Shape ( points, faces, 0xCC0000 )
shapes[1] = new Shape ( points, faces, 0x00CC00 )
shapes[2] = new Shape ( points, faces, 0x0000CC )
shapes[3] = new Shape ( points, faces, 0xCCCC00 )
shapes[4] = new Shape ( points, faces, 0x9900CC )
*/
shapes[0] = new Shape ( points1, faces1, 0xCC0000 )
shapes[1] = new Shape ( points2, faces2, 0x00CC00 )
//- Render buffer
createEmptyMovieClip( "buffer", 1 )
//- Set up timer
onEnterFrame = timer
//timer()