package org.andork.curves; import static org.andork.jogl.util.JOGLUtils.checkGLError; import static org.andork.jogl.util.JOGLUtils.loadShader; import java.nio.ByteBuffer; import java.nio.ByteOrder; import javax.media.opengl.GL3; import org.andork.math.discrete.DiscreteMathUtils; import org.andork.math3d.MatrixUtils; import org.andork.util.ArrayUtils; public class CurveVisualizer { // ////////////////////////////////////////////////////////////////////////////// private String vShaderCode; private String fShaderCode; private static int program; private int vao; private int vbo; private int ebo; private ByteBuffer verts; private ByteBuffer indices; private int[ ] xpow; private int[ ] ypow; // ////////////////////////////////////////////////////////////////////////////// public final int degree; public final int numDimensions; public final int numPoints; public final double[ ] controlPoints; // ////////////////////////////////////////////////////////////////////////////// private int[ ][ ] monomials; private double[ ] solnMatrix; private double[ ] coefficients; private float[ ] floatCoefficients; public CurveVisualizer( int degree , int numDimensions ) { this.degree = degree; this.numDimensions = numDimensions; monomials = DiscreteMathUtils.generateMonomials( degree , numDimensions + 1 ); numPoints = monomials.length - 1; controlPoints = new double[ numDimensions * numPoints ]; solnMatrix = new double[ monomials.length * numPoints ]; coefficients = new double[ numPoints ]; floatCoefficients = new float[ numPoints ]; xpow = new int[ numPoints ]; ypow = new int[ numPoints ]; for( int i = 0 ; i < numPoints ; i++ ) { xpow[ i ] = monomials[ i ][ 0 ]; ypow[ i ] = monomials[ i ][ 1 ]; } } public double eval( double[ ] point ) { double sum = 0; for( int i = 0 ; i < numPoints ; i++ ) { double product = coefficients[ i ]; int[ ] monomial = monomials[ i ]; for( int term = 0 ; term < monomial.length - 1 ; term++ ) { product *= Math.pow( point[ term ] , monomial[ term ] ); } sum += product; } return sum + 1; } public void recalculate( ) { int m = monomials.length - 1; int n = monomials.length; for( int row = 0 ; row < m ; row++ ) { solnMatrix[ row * n + m ] = 1; } for( int col = 0 ; col < m ; col++ ) { int[ ] monomial = monomials[ col ]; for( int row = 0 ; row < m ; row++ ) { double product = 1; for( int dim = 0 ; dim < numDimensions ; dim++ ) { product *= Math.pow( controlPoints[ row * numDimensions + dim ] , monomial[ dim ] ); } solnMatrix[ row * n + col ] = product; } } int[ ] row_perms = new int[ n ]; for( int i = 0 ; i < n ; i++ ) { row_perms[ i ] = i; } MatrixUtils.gauss( solnMatrix , m , n , row_perms ); MatrixUtils.backsubstitute( solnMatrix , m , n , row_perms , coefficients ); for( int i = 0 ; i < m ; i++ ) { floatCoefficients[ i ] = ( float ) coefficients[ i ]; } } public void setCoefficient( int index , double value ) { coefficients[ index ] = value; floatCoefficients[ index ] = ( float ) value; } public void initGL( GL3 gl ) { vShaderCode = "uniform mat4 u_mvpMatrix;" + "attribute vec3 a_position;" + "varying vec2 v_texcoord;" + "void main() {" + " v_texcoord = vec2(a_position);" + " gl_Position = u_mvpMatrix * vec4(a_position, 1.0);" + "}"; fShaderCode = "uniform float u_coefficients[" + numPoints + "];" + "uniform int u_xpow[" + numPoints + "];" + "uniform int u_ypow[" + numPoints + "];" + "varying vec2 v_texcoord;" + "void main() {" + " float value = 1.0;" + " for (int i = 0; i < " + numPoints + "; i++) {" + " float product = u_coefficients[i];" + " for (int j = 0; j < u_xpow[i]; j++) {" + " product *= v_texcoord.x;" + " }" + " for (int j = 0; j < u_ypow[i]; j++) {" + " product *= v_texcoord.y;" + " }" + // " product *= pow(v_texcoord.x, float(u_xpow[i]));" + // " product *= pow(v_texcoord.y, float(u_ypow[i]));" + " value += product;" + " }" + " float intensity = atan(value) * 0.6366;" + // " float intensity = 1.0 - abs(atan(value)) * 0.6366;" + // " if (intensity < 0.333) {" + // " gl_FragColor = mix(vec4(0.0, 0.0, 0.0, 1.0), vec4(0.45, 0.0, 0.5, 1.0), intensity * 3.0);" + // " } else if (intensity < 0.666) {" + // " gl_FragColor = mix(vec4(0.45, 0.0, 0.5, 1.0), vec4(0.8, 0.2, 0.0, 1.0), (intensity - 0.333) * 3.0);" + // " } else {" + // " gl_FragColor = mix(vec4(0.8, 0.2, 0.0, 1.0), vec4(1.0, 0.9, 0.0, 1.0), (intensity - 0.666) * 3.0);" + // " }" + // " float red = exp(-value*value/0.1);" + // " intensity = abs(intensity);" + " float red = 0.0;" + " if (intensity > 0.0) {" + " red = intensity;" + " }" + " float blue = 0.0;" + " if (intensity < 0.0) {" + " blue = -intensity;" + " }" + " gl_FragColor = vec4(red, 0.0, blue, 1.0);" + "}"; program = gl.glCreateProgram( ); checkGLError( gl ); int vShader = loadShader( gl , GL3.GL_VERTEX_SHADER , vShaderCode ); checkGLError( gl ); int fShader = loadShader( gl , GL3.GL_FRAGMENT_SHADER , fShaderCode ); checkGLError( gl ); gl.glAttachShader( program , vShader ); checkGLError( gl ); gl.glAttachShader( program , fShader ); checkGLError( gl ); gl.glLinkProgram( program ); checkGLError( gl ); int[ ] temp = new int[ 2 ]; gl.glGenVertexArrays( 1 , temp , 0 ); checkGLError( gl ); vao = temp[ 0 ]; gl.glBindVertexArray( vao ); checkGLError( gl ); gl.glGenBuffers( 2 , temp , 0 ); checkGLError( gl ); vbo = temp[ 0 ]; ebo = temp[ 1 ]; int vertexCount = 4; int bytesPerVertex = 4 * 3; int vertexBytes = vertexCount * bytesPerVertex; verts = ByteBuffer.allocate( vertexBytes ); verts.order( ByteOrder.nativeOrder( ) ); verts.putFloat( -100 ).putFloat( -100 ).putFloat( 0 ); verts.putFloat( 100 ).putFloat( -100 ).putFloat( 0 ); verts.putFloat( 100 ).putFloat( 100 ).putFloat( 0 ); verts.putFloat( -100 ).putFloat( 100 ).putFloat( 0 ); verts.position( 0 ); gl.glBindBuffer( GL3.GL_ARRAY_BUFFER , vbo ); checkGLError( gl ); gl.glBufferData( GL3.GL_ARRAY_BUFFER , verts.capacity( ) , verts , GL3.GL_STATIC_DRAW ); checkGLError( gl ); int positionLoc = gl.glGetAttribLocation( program , "a_position" ); checkGLError( gl ); gl.glEnableVertexAttribArray( positionLoc ); checkGLError( gl ); gl.glVertexAttribPointer( positionLoc , 3 , GL3.GL_FLOAT , false , bytesPerVertex , 0 ); checkGLError( gl ); int indexCount = 6; int indexBytes = 2 * indexCount; indices = ByteBuffer.allocate( indexBytes ); indices.order( ByteOrder.nativeOrder( ) ); indices.putChar( ( char ) 0 ).putChar( ( char ) 1 ).putChar( ( char ) 2 ); indices.putChar( ( char ) 2 ).putChar( ( char ) 3 ).putChar( ( char ) 0 ); indices.position( 0 ); gl.glBindBuffer( GL3.GL_ELEMENT_ARRAY_BUFFER , ebo ); checkGLError( gl ); gl.glBufferData( GL3.GL_ELEMENT_ARRAY_BUFFER , indices.capacity( ) , indices , GL3.GL_STATIC_DRAW ); checkGLError( gl ); gl.glBindVertexArray( 0 ); checkGLError( gl ); gl.glBindBuffer( GL3.GL_ELEMENT_ARRAY_BUFFER , 0 ); checkGLError( gl ); gl.glBindBuffer( GL3.GL_ARRAY_BUFFER , 0 ); checkGLError( gl ); } public void draw( GL3 gl , float[ ] mvpMatrix ) { gl.glUseProgram( program ); checkGLError( gl ); int mvpMatrixLoc = gl.glGetUniformLocation( program , "u_mvpMatrix" ); checkGLError( gl ); gl.glUniformMatrix4fv( mvpMatrixLoc , 1 , false , mvpMatrix , 0 ); checkGLError( gl ); int coefLoc = gl.glGetUniformLocation( program , "u_coefficients" ); checkGLError( gl ); gl.glUniform1fv( coefLoc , numPoints , floatCoefficients , 0 ); checkGLError( gl ); int xpowLoc = gl.glGetUniformLocation( program , "u_xpow" ); checkGLError( gl ); gl.glUniform1iv( xpowLoc , numPoints , xpow , 0 ); checkGLError( gl ); int ypowLoc = gl.glGetUniformLocation( program , "u_ypow" ); checkGLError( gl ); gl.glUniform1iv( ypowLoc , numPoints , ypow , 0 ); checkGLError( gl ); gl.glBindVertexArray( vao ); checkGLError( gl ); gl.glDrawElements( GL3.GL_TRIANGLES , 6 , GL3.GL_UNSIGNED_SHORT , 0 ); checkGLError( gl ); gl.glBindVertexArray( 0 ); checkGLError( gl ); } public void printCoefficients( ) { System.out.println( ArrayUtils.prettyPrint( coefficients , coefficients.length , 0 , coefficients.length , 0 , "%12.2f" ) ); } }