import java.util.Collections; import java.util.ArrayList; import java.util.Comparator; class RibbonMesh { RibbonMesh() { minNoise = 0.499; maxNoise = 0.501; _doRenderHead = true; _doUpdate = true; _tailSize = 100; _tailRenderSegments = 0; _tailWidth = 11.0; _initPos = new Vector3(); _headSize = 8*3; _head = new Vector3(); _target = new Vector3(); _right = new Vector3(); _add = new Vector3(); _damp = 0.95; _age = 0; _ageFactor = 0; _timeToLive = 100; _invTimeToLive = 1.0 / _timeToLive; _facets = 5; _colour = new Vector4( 1, 1, 1, 1 ); } RibbonMesh( int tailSize, float tailWidth, float headSize, boolean renderHead ) { _doRenderHead = renderHead; _doUpdate = true; _tailSize = tailSize; _tailRenderSegments = 0; _tailWidth = tailWidth; _initPos = new Vector3(); _headSize = headSize; _head = new Vector3(); _target = new Vector3(); _right = new Vector3(); _add = new Vector3(); _damp = 0.95; _age = 0; _ageFactor = 0; _timeToLive = 100; _invTimeToLive = 1.0 / _timeToLive; _colour = new Vector4( 1, 1, 1, 1 ); _facets = 8; } void setCylinderDetail( int d ) { _facets = d; } void setCylinderRadius( int r ) { _tailWidth = r; } void loadHeadTexture( int id ) { _headTexID = id; } void computeTail() { if( _tail == null ) { _tail = new Vector3[_tailSize]; } for( int i=0; i<_tailSize; i++ ) { _tail[i] = new Vector3(); _tail[i] = _head.copy(); } // some pre-calc yTable = new int[_tailSize]; for( int i=0; i<_tailSize; i++ ) yTable[i] = i * (_facets+1); // arrays for the surrounding mesh _vertices = new Vector3[ ((_tailSize)*(_facets+1)) ]; _normals = new Vector3[ ((_tailSize)*(_facets+1)) ]; _texcoords = new Vector3[ ((_tailSize)*(_facets+1)) ]; for( int i=0; i<((_tailSize)*(_facets+1)); i++ ) { _vertices[i] = new Vector3(); _normals[i] = new Vector3(); _texcoords[i] = new Vector3(); } } boolean isDead() { if( _age >= _timeToLive ) return true; return false; } void setTailSize( int t ) { _tailSize = t; computeTail(); } void setTimeToLive( float t ) { _timeToLive = t; _invTimeToLive = 1.0 / _timeToLive; } void setHeadY( float y ) { _head.y = y; _initPos = _head.copy(); } void setHead( float x, float y ) { _head.set( x, y, 0 ); _initPos = _head.copy(); _target = _head.copy(); } void setHead( float x, float y, float z ) { _head.set( x, y, z ); _initPos = _head.copy(); } void setHead( Vector3 h ) { _head = h; _initPos = _head.copy(); } void addHead( float x, float y ) { _head.add( x, y, 0 ); } void addHead( float x, float y, float z ) { _head.x += x; _head.y += y; _head.z += z; } void addHead( Vector3 a ) { _head.add( a ); } void renderHead( boolean f ) { _doRenderHead = f; } void update( float time ) { if( _age < _timeToLive ) { if( _tailRenderSegments < _tailSize ) { // for( int i=_tailSize-1; i>0; i-- ) for( int i=_tailRenderSegments; i>0; i-- ) { _tail[i] = _tail[i-1]; } _tail[0] = _head.copy(); _tailRenderSegments++; } else { _doUpdate = false; } } if( _doUpdate) _head.add( _add ); _age ++; _ageFactor = _age * _invTimeToLive; } void draw( float time ) { if( _age < _timeToLive ) { /* if( _doRenderHead ) { _headTex.enable(); renderHead(); _headTex.disable(); }*/ /* vgl.gl().glDisable( GL.GL_CULL_FACE ); vgl.setDepthWrite( true ); // vgl.setDepthMask( false ); vgl.setAlphaBlend();*/ // renderTail(); renderTailCylinder(); // Stop head motion once it completes its growth if( !_doUpdate ) _head = _tail[0].copy(); // Render base of each tail (not needed for most cases) // renderBase(); } } void drawCylinder( float time ) { if( _age < _timeToLive ) { vgl.gl().glDisable( GL.GL_CULL_FACE ); vgl.setDepthWrite( true ); // vgl.setDepthMask( false ); vgl.setAlphaBlend(); renderTailCylinder(); } } void renderHead() { // Draw activator center vgl.setDepthWrite( false ); vgl.setAlphaBlend(); //activeNoteTex.enable(); vgl.fill( 1, 1.0-_ageFactor ); vgl.pushMatrix(); vgl.translate( _head.x, _head.y, _head.z ); vgl.rotateX( 90 ); vgl.quad( _headSize ); vgl.popMatrix(); vgl.setDepthWrite( true ); } void transformRect( Vector3 up, Vector3 V, Vector3 offset, Vector3[] rect ) { for( int i=0; i<4; i++ ) { Vector3 v = rect[i]; Vector3 P = new Vector3( v.x, v.y, v.z ); Vector3 NY = up.copy(); NY.normalize(); Vector3 NV = V.copy(); NV.normalize(); Vector3 N = NY.cross( NV ); // axis of rotation N.normalize(); float dot = NY.dot( NV ); // cos angle float rad = ( acos(dot) ); // angle of rotation (radians) // quat from an angle and a rotation axis Quaternion quat = new Quaternion(); quat.rotateAxis( N, rad ); // Vector3 axis = Vector3.sub( N, NY ); // quat.rotateAxis( axis, rad ); // transform vertex Vector3 dv = quat.mul( P ); v.set( dv ); // translate to right position // Vector3 disp = N.copy(); // disp.mul( _tailWidth*0.125 ); // offset.add( disp ); v.add( offset ); } } void renderTailCylinder() { float invsteps = 1.0 / (float)(_tailSize-1); float invfacets = 1.0 / (float)(_facets); float pi2OverSteps = TWO_PI / (_tailSize-1); float pi2OverFacets = TWO_PI / _facets; float pi2MulInvsteps = TWO_PI * invsteps; float pi2MulInvfacets = TWO_PI * invfacets; // float _p = 5; // float _q = 5; // float _scale = 20; // float _thickness = 10; /////////////////////////////////////////////////////////// // Draw vine mesh /////////////////////////////////////////////////////////// float factor; int hlen = (int)((_tailSize-1)*0.5); for( int jj=-hlen; jj 50 ) _colour.set( 1, 1, 1, 1 ); else _colour.set( 0, 0, 0, 1 ); } float minNoise, maxNoise; int _facets; int[] yTable; Vector3[] _vertices; Vector3[] _texcoords; Vector3[] _normals; int _headTexID; Vector4 _colour; boolean _doRenderHead; boolean _doUpdate; float _age; float _ageFactor; float _timeToLive; float _invTimeToLive; Vector3 _initPos; float _headSize; Vector3 _head; Vector3 _right; Vector3 _target; Vector3 _add; float _damp; float _tailWidth; int _tailRenderSegments; // counts number of tail segments to render int _tailSize; Vector3[] _tail; }