language

heron:std:0.1

;

module

heron:geometry.mesh:0.1

{

import

heron:std.array:0.1

;

import

heron:geometry.vector:0.1

;

(Array<Float3> -> Mesh) function mesh ( vertexBuffer ) = mesh ( vertexBuffer , vertexBuffer . indices )

;

('a 'b -> 'c) function mesh ( vertexBuffer , indexBuffer ) = mesh ( vertexBuffer )

;

(Array<Float3> Array<Int> -> Mesh) function mesh ( vertexBuffer , indexBuffer ) = mesh ( vertexBuffer , indexBuffer , origin . repeat ( 0 ) )

;

(Array<Float3> Array<Int> Array<Float3> -> Mesh) function mesh ( vertexBuffer , indexBuffer , uvBuffer ) = mesh ( vertexBuffer , indexBuffer , uvBuffer , origin . repeat ( 0 ) )

;

(Array<Float3> Array<Int> Array<Float3> Array<Float3> -> Mesh) function mesh ( vertexBuffer , indexBuffer , uvBuffer , colorBuffer ) = mesh ( vertexBuffer , indexBuffer , uvBuffer , colorBuffer , origin . repeat ( 0 ) ) . computeVertexNormals ()

;

(Mesh Array<Float3> -> Mesh) function setVertices ( m , points ) = mesh ( points , m . indexBuffer , m . uvBuffer , m . colorBuffer , m . normalBuffer )

;

(Mesh Array<Float3> -> Mesh) function setVertexColors ( m , colors ) = mesh ( m . vertexBuffer , m . indexBuffer , m . uvBuffer , colors , m . normalBuffer )

;

(Mesh Array<Float3> -> Mesh) function setVertexUVs ( m , uvs ) = mesh ( m . vertexBuffer , m . indexBuffer , uvs , m . colorBuffer , m . normalBuffer )

;

(Mesh Array<Float3> -> Mesh) function setVertexNormals ( m , normals ) = mesh ( m . vertexBuffer , m . indexBuffer , m . uvBuffer , m . colorBuffer , normals )

;

var tetrahedron = mesh ( [ 1 , 1 , 1 , - 1 , - 1 , 1 , - 1 , 1 , - 1 , 1 , - 1 , - 1 ] . toVectors , [ 2 , 1 , 0 , 0 , 3 , 2 , 1 , 3 , 0 , 2 , 3 , 1 ] )

;

var cube = mesh ( [ - 1.0 , - 1.0 , 1.0 , 1.0 , - 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , - 1.0 , 1.0 , 1.0 , - 1.0 , - 1.0 , - 1.0 , 1.0 , - 1.0 , - 1.0 , 1.0 , 1.0 , - 1.0 , - 1.0 , 1.0 , - 1.0 ] . toVectors , [ 0 , 1 , 2 , 2 , 3 , 0 , 1 , 5 , 6 , 6 , 2 , 1 , 7 , 6 , 5 , 5 , 4 , 7 , 4 , 0 , 3 , 3 , 7 , 4 , 4 , 5 , 1 , 1 , 0 , 4 , 3 , 2 , 6 , 6 , 7 , 3 ] )

;

var octahedron = mesh ( [ 1 , 0 , 0 , - 1 , 0 , 0 , 0 , 1 , 0 , 0 , - 1 , 0 , 0 , 0 , 1 , 0 , 0 , - 1 ] . toVectors , [ 0 , 2 , 4 , 0 , 4 , 3 , 0 , 3 , 5 , 0 , 5 , 2 , 1 , 2 , 5 , 1 , 5 , 3 , 1 , 3 , 4 , 1 , 4 , 2 ] )

;

var dodecahedron = var t = ( 1 + sqrt ( 5 ) ) / 2 in var r = 1 / t in mesh ( [ - 1 , - 1 , - 1 , - 1 , - 1 , 1 , - 1 , 1 , - 1 , - 1 , 1 , 1 , 1 , - 1 , - 1 , 1 , - 1 , 1 , 1 , 1 , - 1 , 1 , 1 , 1 , 0 , - r , - t , 0 , - r , t , 0 , r , - t , 0 , r , t , - r , - t , 0 , - r , t , 0 , r , - t , 0 , r , t , 0 , - t , 0 , - r , t , 0 , - r , - t , 0 , r , t , 0 , r ] . toVectors , [ 3 , 11 , 7 , 3 , 7 , 15 , 3 , 15 , 13 , 7 , 19 , 17 , 7 , 17 , 6 , 7 , 6 , 15 , 17 , 4 , 8 , 17 , 8 , 10 , 17 , 10 , 6 , 8 , 0 , 16 , 8 , 16 , 2 , 8 , 2 , 10 , 0 , 12 , 1 , 0 , 1 , 18 , 0 , 18 , 16 , 6 , 10 , 2 , 6 , 2 , 13 , 6 , 13 , 15 , 2 , 16 , 18 , 2 , 18 , 3 , 2 , 3 , 13 , 18 , 1 , 9 , 18 , 9 , 11 , 18 , 11 , 3 , 4 , 14 , 12 , 4 , 12 , 0 , 4 , 0 , 8 , 11 , 9 , 5 , 11 , 5 , 19 , 11 , 19 , 7 , 19 , 5 , 14 , 19 , 14 , 4 , 19 , 4 , 17 , 1 , 12 , 14 , 1 , 14 , 5 , 1 , 5 , 9 ] )

;

var icosahedron = var t = ( 1 + sqrt ( 5 ) ) / 2 in mesh ( [ - 1 , t , 0 , 1 , t , 0 , - 1 , - t , 0 , 1 , - t , 0 , 0 , - 1 , t , 0 , 1 , t , 0 , - 1 , - t , 0 , 1 , - t , t , 0 , - 1 , t , 0 , 1 , - t , 0 , - 1 , - t , 0 , 1 ] . toVectors , [ 0 , 11 , 5 , 0 , 5 , 1 , 0 , 1 , 7 , 0 , 7 , 10 , 0 , 10 , 11 , 1 , 5 , 9 , 5 , 11 , 4 , 11 , 10 , 2 , 10 , 7 , 6 , 7 , 1 , 8 , 3 , 9 , 4 , 3 , 4 , 2 , 3 , 2 , 6 , 3 , 6 , 8 , 3 , 8 , 9 , 4 , 9 , 5 , 2 , 4 , 11 , 6 , 2 , 10 , 8 , 6 , 7 , 9 , 8 , 1 ] )

;

(Array<'a> Int Bool Bool -> Array<Int>) function quadStripToMeshIndices ( vertices , rows , connectRows , connectCols ) { var cols = vertices . count / rows ; var nr = connectRows ? rows : rows - 1 ; var nc = connectCols ? cols : cols - 1 ; var indices = [] . mutable ; for ( var row in 0 .. nr ) { for ( var col in 0 .. nc ) { var a = col + row * cols ; var b = ( col + 1 ) % ( cols ) + row * cols ; var c = ( col + 1 ) % ( cols ) + ( row + 1 ) % ( rows ) * cols ; var d = col + ( row + 1 ) % ( rows ) * cols ; indices = indices . pushMany ( [ a , b , d ] ) ; indices = indices . pushMany ( [ b , c , d ] ) ; } } return indices . immutable ; }

(Float2 -> Float3) function vector ( uv : Float2 ) = float3 ( - uv . x . cos * uv . y . sin , uv . x . cos , uv . x . sin * uv . y . sin )

;

('a 'a 'a -> 'a) function rescale ( v , from , length ) = from + ( v * length )

;

((Float Float -> Float3) Int Int Float Float Float Float Bool Bool -> Mesh) function meshFromUV ( f , uCount , vCount , uStart , vStart , uLength , vLength , uJoin , vJoin ) { var uMax = uJoin ? uCount . float : ( uCount - 1 ) . float ; var vMax = vJoin ? vCount . float : ( vCount - 1 ) . float ; var uvs = cartesianProduct ( 0 .. uCount , 0 .. vCount , ( u , v ) => vector ( u / uMax * uLength + uStart , v / vMax * vLength + vStart , 0 ) ) ; var points = uvs . map ( uvw => f ( uvw . x , uvw . y ) ) ; var normals = uvs . map ( uvw => normalFromUV ( uvw . x , uvw . y , f ) ) ; var indices = quadStripToMeshIndices ( points , vCount , uJoin , vJoin ) ; return mesh ( points , indices , uvs , origin . repeat ( 0 ) , normals ) ; }

((Float Float -> Float3) Int -> Mesh) function meshFromUV ( f , segments ) = meshFromUV ( f , segments , true )

;

((Float Float -> Float3) Int Bool -> Mesh) function meshFromUV ( f , segments , join ) = meshFromUV ( f , segments , segments , 0.0 , 0.0 , 1.0 , 1.0 , join , join )

;

(Float Float -> Float3) function spherePoint ( u , v ) = vector ( - cos ( u * 2.0 * pi ) * sin ( v * 2.0 * pi ) , cos ( v * 2.0 * pi ) , sin ( u * 2.0 * pi ) * sin ( v * 2.0 * pi ) )

;

(Int -> Mesh) function sphere ( segments ) = meshFromUV ( spherePoint , segments )

;

( -> Mesh) function sphere () = sphere ( 32 )

;

(Float Int -> Float3) function cylinderPoint ( u , v ) = vector ( sin ( u * 2.0 * pi ) , v * 2 , cos ( u * 2.0 * pi ) )

;

(Int -> Mesh) function cylinder ( segments ) = meshFromUV ( cylinderPoint , segments )

;

( -> Mesh) function cylinder () = cylinder ( 16 )

;

(Float Float Int -> Mesh) function torus ( r1 , r2 , segments ) = meshFromUV ( ( u , v ) => torusPoint ( u , v , r1 , r2 ) , segments )

;

(Float Float Float Float -> Float3) function torusPoint ( u , v , r1 , r2 ) = vector ( ( r1 + r2 * cos ( v * 2.0 * pi ) ) * cos ( u * 2.0 * pi ) , ( r1 + r2 * cos ( v * 2.0 * pi ) ) * sin ( u * 2.0 * pi ) , r2 * sin ( v * 2.0 * pi ) )

;

(Float 'a (Float 'a -> Float3) Float3 Float -> Float3) function tangentFromUV ( u , v , f , p : Float3 , eps : Float ) = u - eps >= 0 ? p - f ( u - eps , v ) : f ( u + eps , v ) - p

;

('a Float ('a Float -> Float3) Float3 Float -> Float3) function cotangentFromUV ( u , v , f , p : Float3 , eps : Float ) = v - eps >= 0 ? p - f ( u , v - eps ) : f ( u , v + eps ) - p

;

(Float Float (Float Float -> Float3) -> Float3) function normalFromUV ( u , v , f ) = var eps = 0.0001 in var p = f ( u , v ) in cross ( tangentFromUV ( u , v , f , p , eps ) , cotangentFromUV ( u , v , f , p , eps ) ) . normal

;

( -> Mesh) function torus () = torus ( 2 , 0.5 , 32 )

;

(Mesh -> Int) function vertexCount ( mesh ) = mesh . vertexBuffer . count

;

(Mesh -> Int) function faceCount ( mesh ) = mesh . indexBuffer . count / 3

;

(Array<Float> -> Array<Float3>) function toVectors ( xs ) = ( 0 .. xs . count / 3 ) . map ( i => vector ( xs [ i * 3 ] , xs [ i * 3 + 1 ] , xs [ i * 3 + 2 ] ) )

;

(Mesh (Float3 -> Float3) -> Mesh) function transform ( m , f ) = m . setVertices ( m . vertexBuffer . map ( f ) )

;

(Mesh Float3 -> Mesh) function translate ( m , amount ) = m . transform ( v => v + amount )

;

(Mesh Array<Float3> -> Mesh) function translate ( m , vectors ) = m . setVertices ( m . vertexBuffer . zip ( vectors , ( p , v ) => p + v ) )

;

(Mesh Float3 -> Mesh) function scale ( m , amount ) = m . transform ( v => v * amount )

;

(Float Float -> Float3) function kleinPoint ( a , b ) { var u = a * pi * 2.0 ; var v = b * pi * 2.0 ; var x = 0.0 , y = 0.0 , z = 0.0 ; if ( u < pi ) { x = 3.0 * u . cos * ( 1.0 + u . sin ) + ( 2.0 * ( 1.0 - u . cos / 2.0 ) ) * u . cos * v . cos ; z = - 8.0 * u . sin - 2.0 * ( 1.0 - u . cos / 2.0 ) * u . sin * v . cos ; } else { x = 3.0 * u . cos * ( 1.0 + u . sin ) + ( 2.0 * ( 1.0 - u . cos / 2.0 ) ) * cos ( v + pi ) ; z = - 8.0 * u . sin ; } y = - 2.0 * ( 1.0 - u . cos / 2.0 ) * v . sin ; return vector ( x / 4.0 , y / 4.0 , z / 4.0 ) ; }

( -> Mesh) function klein () = meshFromUV ( kleinPoint , 32 , false )

;

(Float Float -> Float3) function planeXYPoint ( u , v ) = vector ( u , v , 0 )

;

(Float Float -> Float3) function planeXZPoint ( u , v ) = vector ( u , 0 , v )

;

(Float Float -> Float3) function planeYZPoint ( u , v ) = vector ( 0 , u , v )

;

(Float Float -> Float3) function planeYXPoint ( u , v ) = vector ( v , u , 0 )

;

(Float Float -> Float3) function planeZXPoint ( u , v ) = vector ( v , 0 , u )

;

(Float Float -> Float3) function planeZYPoint ( u , v ) = vector ( 0 , v , u )

;

( -> Mesh) function plane () = meshFromUV ( planeXYPoint , 16 , false )

;

(Float Float -> Float3) function mobiusPoint ( a , b ) { var u = a - 0.5 ; var v = b * 2.0 * pi ; return vector ( v . cos * ( 2 + u * cos ( v / 2 ) ) , v . sin * ( 2 + u * cos ( v / 2 ) ) , u * sin ( v / 2 ) ) ; }

( -> Mesh) function mobius () = meshFromUV ( mobiusPoint , 20 , false )

;

(Mesh Int Int -> Float3) function facePoint ( mesh , f , i ) = mesh . vertexBuffer [ mesh . indexBuffer [ f * 3 + i ] ]

;

(Mesh Int -> Float3) function faceNormal ( mesh , f ) = cross ( mesh . faceSide1 ( f ) , mesh . faceSide2 ( f ) ) . normal

;

(Mesh Int -> Float3) function faceSide1 ( mesh , f ) = mesh . facePoint ( f , 1 ) - mesh . facePoint ( f , 0 )

;

(Mesh Int -> Float3) function faceSide2 ( mesh , f ) = mesh . facePoint ( f , 2 ) - mesh . facePoint ( f , 0 )

;

(Mesh -> Array<Float3>) function faceNormals ( mesh ) = ( 0 .. mesh . faceCount ) . map ( i => mesh . faceNormal ( i ) )

;

(Mesh -> Mesh) function computeVertexNormals ( mesh ) { var sums = origin . repeat ( mesh . vertexCount ) . mutable ; var counts = repeat ( 0 , mesh . vertexCount ) . mutable ; for ( var f in 0 .. mesh . faceCount ) { var normal = mesh . faceNormal ( f ) ; for ( var i in 0 .. 3 ) { var index = mesh . indexBuffer [ f * 3 + i ] ; sums [ index ] += normal ; counts [ index ] += 1 ; } } return mesh . setVertexNormals ( zip ( sums , counts , ( a , b ) => ( a / b . float . vector ) . normal ) ) ; }

(Float3 Float3 Float3 -> Float3) function applyRotation ( pos , rotXYZ , rotW ) = pos + 2.0 . vector * cross ( rotXYZ , cross ( rotXYZ , pos ) + rotW * pos )

;

(Float3 Float3 Float3 Float3 Float3 -> Float3) function applyTRS ( pos , trans , rotXYZ , rotW , scale ) = applyRotation ( pos * scale , rotXYZ , rotW ) + trans

;

}