on master help sign in
Merge pull request #548 from johnpmayer/webgl
be3daf7Evan Czaplicki
.gitignore+2
@@ -10,4 +10,6 @@ cabal-dev
10data
10data
11*/ElmFiles/*
11*/ElmFiles/*
12.DS_Store
12.DS_Store
13+build
14+cache
13*~
15*~
Elm.cabal+4
@@ -106,6 +106,7 @@ Library
106 filepath,
106 filepath,
107 indents,
107 indents,
108 language-ecmascript >=0.15 && < 1.0,
108 language-ecmascript >=0.15 && < 1.0,
109+ language-glsl,
109 mtl >= 2,
110 mtl >= 2,
110 pandoc >= 1.10,
111 pandoc >= 1.10,
111 parsec >= 3.1.1,
112 parsec >= 3.1.1,
@@ -188,6 +189,7 @@ Executable elm
188 filepath,
189 filepath,
189 indents,
190 indents,
190 language-ecmascript >=0.15 && < 1.0,
191 language-ecmascript >=0.15 && < 1.0,
192+ language-glsl,
191 mtl >= 2,
193 mtl >= 2,
192 pandoc >= 1.10,
194 pandoc >= 1.10,
193 parsec >= 3.1.1,
195 parsec >= 3.1.1,
@@ -229,6 +231,7 @@ Executable elm-doc
229 directory,
231 directory,
230 filepath,
232 filepath,
231 indents,
233 indents,
234+ language-glsl,
232 mtl >= 2,
235 mtl >= 2,
233 pandoc >= 1.10,
236 pandoc >= 1.10,
234 parsec >= 3.1.1,
237 parsec >= 3.1.1,
@@ -268,6 +271,7 @@ Test-Suite test-elm
268 filepath,
271 filepath,
269 indents,
272 indents,
270 language-ecmascript >=0.15 && < 1.0,
273 language-ecmascript >=0.15 && < 1.0,
274+ language-glsl,
271 mtl >= 2,
275 mtl >= 2,
272 pandoc >= 1.10,
276 pandoc >= 1.10,
273 parsec >= 3.1.1,
277 parsec >= 3.1.1,
compiler/Generate/JavaScript.hs+3
@@ -179,6 +179,9 @@ expression (A region expr) =
179 pad = "<div style=\"height:0;width:0;\">&nbsp;</div>"
179 pad = "<div style=\"height:0;width:0;\">&nbsp;</div>"
180 md = pad ++ MD.toHtml doc ++ pad
180 md = pad ++ MD.toHtml doc ++ pad
181
181
182+ GLShader _uid src _tipe ->
183+ return $ ObjectLit () [(PropString () "src", literal (Str src))]
184+
182 PortIn name tipe ->
185 PortIn name tipe ->
183 return $ obj "Native.Ports.portIn" `call` [ string name, Port.incoming tipe ]
186 return $ obj "Native.Ports.portIn" `call` [ string name, Port.incoming tipe ]
184
187
compiler/Parse/Expression.hs+7−1
@@ -44,7 +44,7 @@ negative = do
44-------- Complex Terms --------
44-------- Complex Terms --------
45
45
46listTerm :: IParser ParseExpr'
46listTerm :: IParser ParseExpr'
47−listTerm = markdown' <|> braces (try range <|> ExplicitList <$> commaSep expr)
47+listTerm = markdown' <|> glShader' <|> braces (try range <|> ExplicitList <$> commaSep expr)
48 where
48 where
49 range = do
49 range = do
50 lo <- expr
50 lo <- expr
@@ -57,6 +57,12 @@ listTerm = markdown' <|> braces (try range <|> ExplicitList <$> commaSep expr)
57 (rawText, exprs) <- markdown (interpolation uid)
57 (rawText, exprs) <- markdown (interpolation uid)
58 return (Markdown uid (filter (/='\r') rawText) exprs)
58 return (Markdown uid (filter (/='\r') rawText) exprs)
59
59
60+ glShader' = do
61+ pos <- getPosition
62+ let uid = show (sourceLine pos) ++ ":" ++ show (sourceColumn pos)
63+ (rawSrc, tipe) <- glShader
64+ return $ GLShader uid (filter (/='\r') rawSrc) tipe
65+
60 span uid index =
66 span uid index =
61 "<span id=\"md-" ++ uid ++ "-" ++ show index ++ "\">{{ markdown interpolation is in the pipeline, but still needs more testing }}</span>"
67 "<span id=\"md-" ++ uid ++ "-" ++ show index ++ "\">{{ markdown interpolation is in the pipeline, but still needs more testing }}</span>"
62
68
compiler/Parse/Helpers.hs+48
@@ -8,6 +8,8 @@ import Control.Monad.State
8import Data.Char (isUpper)
8import Data.Char (isUpper)
9import qualified Data.Set as Set
9import qualified Data.Set as Set
10import qualified Data.Map as Map
10import qualified Data.Map as Map
11+import qualified Language.GLSL.Parser as GLP
12+import Language.GLSL.Syntax as GLS
11import Text.Parsec hiding (newline,spaces,State)
13import Text.Parsec hiding (newline,spaces,State)
12import Text.Parsec.Indent
14import Text.Parsec.Indent
13import qualified Text.Parsec.Token as T
15import qualified Text.Parsec.Token as T
@@ -16,6 +18,7 @@ import SourceSyntax.Annotation as Annotation
16import SourceSyntax.Declaration (Assoc)
18import SourceSyntax.Declaration (Assoc)
17import SourceSyntax.Expression
19import SourceSyntax.Expression
18import SourceSyntax.Helpers as Help
20import SourceSyntax.Helpers as Help
21+import SourceSyntax.Literal as Literal
19import SourceSyntax.PrettyPrint
22import SourceSyntax.PrettyPrint
20import SourceSyntax.Variable as Variable
23import SourceSyntax.Variable as Variable
21
24
@@ -318,6 +321,51 @@ markdown interpolation = try (string "[markdown|") >> closeMarkdown (++ "") []
318 closeMarkdown (md . ([c]++)) stuff
321 closeMarkdown (md . ([c]++)) stuff
319 ]
322 ]
320
323
324+glShader :: IParser (String, Literal.GLShaderTipe)
325+glShader = do
326+ do
327+ rawSrc <- try (string "[glShader|") >> closeShader ""
328+ case glSource rawSrc of
329+ Left err -> parserFail . show $ err
330+ Right tipe -> return (rawSrc, tipe)
331+ where
332+ closeShader src = choice
333+ [ do
334+ try (string "|]")
335+ return src
336+ , do
337+ c <- anyChar
338+ closeShader (src ++ [c])
339+ ]
340+
341+glSource :: String -> Either ParseError Literal.GLShaderTipe
342+glSource src =
343+ case GLP.parse src of
344+ Right (TranslationUnit decls) ->
345+ Right . foldr addGLinput emptyDecls . join . map extractGLinputs $ decls
346+ Left e -> Left e
347+ where
348+ emptyDecls = Literal.GLShaderTipe Map.empty Map.empty Map.empty
349+ addGLinput (qual,tipe,name) glDecls = case qual of
350+ Attribute -> glDecls { attribute = Map.insert name tipe $ attribute glDecls }
351+ Uniform -> glDecls { uniform = Map.insert name tipe $ uniform glDecls }
352+ Varying -> glDecls { varying = Map.insert name tipe $ varying glDecls }
353+ _ -> error "Should never happen due to below filter"
354+ extractGLinputs decl = case decl of
355+ Declaration (InitDeclaration (TypeDeclarator (FullType (Just (TypeQualSto qual)) (TypeSpec _prec (TypeSpecNoPrecision tipe _mexpr1)))) [InitDecl name _mexpr2 _mexpr3]) ->
356+ if elem qual [Attribute, Varying, Uniform]
357+ then case tipe of
358+ GLS.Int -> return (qual,Literal.Int,name)
359+ GLS.Float -> return (qual,Literal.Float,name)
360+ GLS.Vec2 -> return (qual,V2,name)
361+ GLS.Vec3 -> return (qual,V3,name)
362+ GLS.Vec4 -> return (qual,V4,name)
363+ GLS.Mat4 -> return (qual,M4,name)
364+ GLS.Sampler2D -> return (qual,Texture,name)
365+ _ -> []
366+ else []
367+ _ -> []
368+
321--str :: IParser String
369--str :: IParser String
322str = expecting "String" $ do
370str = expecting "String" $ do
323 s <- choice [ multiStr, singleStr ]
371 s <- choice [ multiStr, singleStr ]
compiler/SourceSyntax/Expression.hs+3
@@ -58,6 +58,7 @@ data GeneralExpr' ann def var
58 -- for type checking and code gen only
58 -- for type checking and code gen only
59 | PortIn String SrcType.Type
59 | PortIn String SrcType.Type
60 | PortOut String SrcType.Type (GeneralExpr ann def var)
60 | PortOut String SrcType.Type (GeneralExpr ann def var)
61+ | GLShader String String Literal.GLShaderTipe
61 deriving (Show)
62 deriving (Show)
62
63
63
64
@@ -178,6 +179,8 @@ instance (Pretty def, Pretty var) => Pretty (GeneralExpr' ann def var) where
178
179
179 Markdown _ _ _ -> P.text "[markdown| ... |]"
180 Markdown _ _ _ -> P.text "[markdown| ... |]"
180
181
182+ GLShader _ _ _ -> P.text "[glShader| ... |]"
183+
181 PortIn name _ -> P.text $ "<port:" ++ name ++ ">"
184 PortIn name _ -> P.text $ "<port:" ++ name ++ ">"
182
185
183 PortOut _ _ signal -> pretty signal
186 PortOut _ _ signal -> pretty signal
compiler/SourceSyntax/Literal.hs+20
@@ -1,6 +1,7 @@
1{-# OPTIONS_GHC -Wall #-}
1{-# OPTIONS_GHC -Wall #-}
2module SourceSyntax.Literal where
2module SourceSyntax.Literal where
3
3
4+import Data.Map (Map)
4import SourceSyntax.PrettyPrint
5import SourceSyntax.PrettyPrint
5import qualified Text.PrettyPrint as PP
6import qualified Text.PrettyPrint as PP
6
7
@@ -19,3 +20,22 @@ instance Pretty Literal where
19 Chr c -> PP.text . show $ c
20 Chr c -> PP.text . show $ c
20 Str s -> PP.text . show $ s
21 Str s -> PP.text . show $ s
21 Boolean bool -> PP.text (show bool)
22 Boolean bool -> PP.text (show bool)
23+
24+data GLTipe = Int | Float | V2 | V3 | V4 | M4 | Texture
25+ deriving (Show)
26+
27+glTipeName :: GLTipe -> String
28+glTipeName Int = "Int"
29+glTipeName Float = "Float"
30+glTipeName V2 = "MJS.V2"
31+glTipeName V3 = "MJS.V3"
32+glTipeName V4 = "MJS.V4"
33+glTipeName M4 = "MJS.M4x4"
34+glTipeName Texture = "Graphics.WebGL.Texture"
35+
36+data GLShaderTipe = GLShaderTipe
37+ { attribute :: Map String GLTipe
38+ , uniform :: Map String GLTipe
39+ , varying :: Map String GLTipe
40+ } deriving (Show)
41+
compiler/Transform/Canonicalize.hs+1
@@ -178,6 +178,7 @@ rename env (A ann expr) =
178
178
179 PortOut name st signal -> PortOut name <$> renameType' env st <*> rnm signal
179 PortOut name st signal -> PortOut name <$> renameType' env st <*> rnm signal
180
180
181+ GLShader _ _ _ -> return expr
181
182
182renamePattern :: Env -> P.Pattern -> Either String P.Pattern
183renamePattern :: Env -> P.Pattern -> Either String P.Pattern
183renamePattern env pattern =
184renamePattern env pattern =
compiler/Transform/Expression.hs+1
@@ -49,6 +49,7 @@ crawl portInCheck portOutCheck defsTransform = go
49 Record fields -> Record <$> mapM (\(k,v) -> (,) k <$> go v) fields
49 Record fields -> Record <$> mapM (\(k,v) -> (,) k <$> go v) fields
50 Markdown uid md es -> Markdown uid md <$> mapM go es
50 Markdown uid md es -> Markdown uid md <$> mapM go es
51 Let defs body -> Let <$> defsTransform defs <*> go body
51 Let defs body -> Let <$> defsTransform defs <*> go body
52+ GLShader uid src gltipe -> return $ GLShader uid src gltipe
52 PortIn name st ->
53 PortIn name st ->
53 do portInCheck name st
54 do portInCheck name st
54 return $ PortIn name st
55 return $ PortIn name st
compiler/Transform/SafeNames.hs+1
@@ -54,6 +54,7 @@ expression (A ann expr) =
54 Modify r fs -> Modify (f r) (map (var *** f) fs)
54 Modify r fs -> Modify (f r) (map (var *** f) fs)
55 Record fs -> Record (map (var *** f) fs)
55 Record fs -> Record (map (var *** f) fs)
56 Markdown uid md es -> Markdown uid md (map f es)
56 Markdown uid md es -> Markdown uid md (map f es)
57+ GLShader _ _ _ -> expr
57 PortIn name st -> PortIn name st
58 PortIn name st -> PortIn name st
58 PortOut name st signal -> PortOut name st (f signal)
59 PortOut name st signal -> PortOut name st (f signal)
59
60
compiler/Transform/SortDefinitions.hs+2
@@ -84,6 +84,8 @@ reorder (A ann expr) =
84
84
85 Markdown uid md es -> Markdown uid md <$> mapM reorder es
85 Markdown uid md es -> Markdown uid md <$> mapM reorder es
86
86
87+ GLShader _ _ _ -> return expr
88+
87 PortOut name st signal -> PortOut name st <$> reorder signal
89 PortOut name st signal -> PortOut name st <$> reorder signal
88
90
89 PortIn name st -> return $ PortIn name st
91 PortIn name st -> return $ PortIn name st
compiler/Transform/Substitute.hs+1
@@ -40,5 +40,6 @@ subst old new expr =
40 Record fs -> Record (map (second f) fs)
40 Record fs -> Record (map (second f) fs)
41 Literal _ -> expr
41 Literal _ -> expr
42 Markdown uid md es -> Markdown uid md (map f es)
42 Markdown uid md es -> Markdown uid md (map f es)
43+ GLShader _ _ _ -> expr
43 PortIn name st -> PortIn name st
44 PortIn name st -> PortIn name st
44 PortOut name st signal -> PortOut name st (f signal)
45 PortOut name st signal -> PortOut name st (f signal)
compiler/Type/Constrain/Expression.hs+17
@@ -8,6 +8,7 @@ import qualified Data.List as List
8import qualified Data.Map as Map
8import qualified Data.Map as Map
9import qualified Text.PrettyPrint as PP
9import qualified Text.PrettyPrint as PP
10
10
11+import SourceSyntax.Literal as Lit
11import SourceSyntax.Annotation as Ann
12import SourceSyntax.Annotation as Ann
12import SourceSyntax.Expression
13import SourceSyntax.Expression
13import qualified SourceSyntax.Pattern as P
14import qualified SourceSyntax.Pattern as P
@@ -31,6 +32,22 @@ constrain env (A region expr) tipe =
31 case expr of
32 case expr of
32 Literal lit -> liftIO $ Literal.constrain env region lit tipe
33 Literal lit -> liftIO $ Literal.constrain env region lit tipe
33
34
35+ GLShader _uid _src gltipe ->
36+ exists $ \attr ->
37+ exists $ \unif ->
38+ let
39+ shaderTipe a u v = Env.get env Env.types "Graphics.WebGL.Shader" <| a <| u <| v
40+ glTipe = Env.get env Env.types . Lit.glTipeName
41+ makeRec accessor baseRec =
42+ let decls = accessor gltipe
43+ in if Map.size decls == 0
44+ then baseRec
45+ else record (Map.map (\t -> [glTipe t]) decls) baseRec
46+ attribute = makeRec Lit.attribute attr
47+ uniform = makeRec Lit.uniform unif
48+ varying = makeRec Lit.varying (TermN EmptyRecord1)
49+ in return . A region $ CEqual tipe (shaderTipe attribute uniform varying)
50+
34 Var (V.Raw name)
51 Var (V.Raw name)
35 | name == saveEnvName -> return (A region CSaveEnv)
52 | name == saveEnvName -> return (A region CSaveEnv)
36 | otherwise -> return (name <? tipe)
53 | otherwise -> return (name <? tipe)
libraries/Graphics/WebGL.elmnew file+56
@@ -0,0 +1,56 @@
1+module Graphics.WebGL (mapTriangle, zipTriangle, loadTex, model, webgl) where
2+
3+{-| The WebGL API is for high performance drawing.
4+
5+# Triangle Convenience Functions
6+@docs Triangle, mapTriangle, zipTriangle
7+
8+# Shaders
9+Shaders are created using glsl blocks.
10+
11+vertex : Shader { a | pos : V3 } {} {}
12+vertex = [glsl|
13+
14+attribute vec3 pos;
15+
16+void main () {
17+ gl_Position = vec4(pos,1.0);
18+}
19+
20+|]
21+
22+# WebGL Element
23+@docs webgl
24+
25+-}
26+
27+import Graphics.Element (Element)
28+import Http (Response)
29+import Native.Graphics.WebGL
30+import Signal (Signal)
31+
32+unsafeCoerceGLSL : String -> Shader attr unif vary
33+unsafeCoerceGLSL = Native.Graphics.WebGL.unsafeCoerceGLSL
34+
35+type Triangle a = (a,a,a)
36+
37+mapTriangle : (a -> b) -> Triangle a -> Triangle b
38+mapTriangle f (x,y,z) = (f x, f y, f z)
39+
40+zipTriangle : (a -> b -> c) -> Triangle a -> Triangle b -> Triangle c
41+zipTriangle f (x,y,z) (x',y',z') = (f x x', f y y', f z z')
42+
43+data Shader attr unif vary = Shader
44+
45+data Texture = Texture
46+
47+loadTex : String -> Signal (Response Texture)
48+loadTex = Native.Graphics.WebGL.loadTex
49+
50+data Model = Model
51+
52+model : Shader attr unif vary -> Shader {} unif vary -> [Triangle attr] -> unif -> Model
53+model = Native.Graphics.WebGL.model
54+
55+webgl : (Int,Int) -> [Model] -> Element
56+webgl = Native.Graphics.WebGL.webgl
libraries/MJS.elmnew file+129
@@ -0,0 +1,129 @@
1+module MJS where
2+
3+{-| MJS
4+
5+A high performance linear algebra library using
6+native JS arrays. Geared towards 3D graphics
7+and use with Graphics.WebGL.
8+
9+Both vectors and matrices are immutable.
10+
11+-}
12+
13+import Native.MJS
14+
15+data V2 = V2
16+data V3 = V3
17+data V4 = V4
18+data M4x4 = M4x4
19+
20+v3 : Float -> Float -> Float -> V3
21+v3 = Native.MJS.v3
22+
23+toTuple3 : V3 -> (Float,Float,Float)
24+toTuple3 = Native.MJS.toTuple3
25+
26+add : V3 -> V3 -> V3
27+add = Native.MJS.v3add
28+
29+sub : V3 -> V3 -> V3
30+sub = Native.MJS.v3sub
31+
32+neg : V3 -> V3
33+neg = Native.MJS.v3neg
34+
35+{- The normalized direction from v1 to v2 -}
36+direction : V3 -> V3 -> V3
37+direction = Native.MJS.v3direction
38+
39+length : V3 -> Float
40+length = Native.MJS.v3length
41+
42+lengthSquared : V3 -> Float
43+lengthSquared = Native.MJS.v3lengthSquared
44+
45+normalize : V3 -> V3
46+normalize = Native.MJS.v3normalize
47+
48+scale : V3 -> Float -> V3
49+scale = Native.MJS.v3scale
50+
51+dot : V3 -> V3 -> Float
52+dot = Native.MJS.v3dot
53+
54+cross : V3 -> V3 -> V3
55+cross = Native.MJS.v3cross
56+
57+mul4x4 : M4x4 -> V3 -> V3
58+mul4x4 = Native.MJS.v3mul4x4
59+
60+--m4x4 : V3[16] -> M4x4 ?
61+
62+identity : M4x4
63+identity = Native.MJS.m4x4identity
64+
65+--topLeft3x3 : M4x4 -> M3x3 ?
66+
67+{- Assumes that m is orthonormal -}
68+inverseOrthonormal : M4x4 -> M4x4
69+inverseOrthonormal = Native.MJS.m4x4inverseOrthonormal
70+
71+--inverseTo3x3 : M4x4 -> M3x3 ?
72+
73+makeFrustrum : Float -> Float -> Float -> Float -> Float -> Float -> Float -> M4x4
74+makeFrustrum = Native.MJS.m4x4makeFrustrum
75+
76+makePerspective : Float -> Float -> Float -> Float -> M4x4
77+makePerspective = Native.MJS.m4x4makePerspective
78+
79+makeOrtho : Float -> Float -> Float -> Float -> Float -> Float -> Float -> M4x4
80+makeOrtho = Native.MJS.m4x4makeOrtho
81+
82+makeOrtho2D : Float -> Float -> Float -> Float -> M4x4
83+makeOrtho2D = Native.MJS.m4x4makeOrtho2D
84+
85+mul : M4x4 -> M4x4 -> M4x4
86+mul = Native.MJS.m4x4mul
87+
88+mulAffine : M4x4 -> M4x4 -> M4x4
89+mulAffine = Native.MJS.m4x4mulAffine
90+
91+makeRotate : Float -> V3 -> M4x4
92+makeRotate = Native.MJS.m4x4makeRotate
93+
94+rotate : Float -> V3 -> M4x4 -> M4x4
95+rotate = Native.MJS.m4x4rotate
96+
97+makeScale3 : Float -> Float -> Float -> M4x4
98+makeScale3 = Native.MJS.m4x4makeScale3
99+
100+makeScale : V3 -> M4x4
101+makeScale = Native.MJS.m4x4makeScale
102+
103+scaleM3 : Float -> Float -> Float -> M4x4 -> M4x4
104+scaleM3 = Native.MJS.m4x4scale3
105+
106+scaleM : V3 -> M4x4 -> M4x4
107+scaleM = Native.MJS.m4x4scale
108+
109+makeTranslate3 : Float -> Float -> Float -> M4x4
110+makeTranslate3 = Native.MJS.m4x4makeTranslate3
111+
112+makeTranslate : V3 -> M4x4
113+makeTranslate = Native.MJS.m4x4makeTranslate
114+
115+translate3 : Float -> Float -> Float -> M4x4 -> M4x4
116+translate3 = Native.MJS.m4x4translate3
117+
118+translate : V3 -> M4x4 -> M4x4
119+translate = Native.MJS.m4x4translate
120+
121+makeLookAt : V3 -> V3 -> V3 -> M4x4
122+makeLookAt = Native.MJS.m4x4makeLookAt
123+
124+transpose : M4x4 -> M4x4
125+transpose = Native.MJS.m4x4transpose
126+
127+{- Custom constructor for supplying arbitrary x,y,z axis -}
128+makeBasis : V3 -> V3 -> V3 -> M4x4
129+makeBasis = Native.MJS.m4x4makeBasis
libraries/Native/Graphics/WebGL.jsnew file+366
@@ -0,0 +1,366 @@
1+Elm.Native.Graphics.WebGL = {};
2+Elm.Native.Graphics.WebGL.make = function(elm) {
3+
4+ // LOG LEVEL
5+
6+ elm.Native = elm.Native || {};
7+ elm.Native.Graphics = elm.Native.Graphics || {};
8+ elm.Native.Graphics.WebGL = elm.Native.Graphics.WebGL || {};
9+ if (elm.Native.Graphics.WebGL.values) return elm.Native.Graphics.WebGL.values;
10+
11+ var newNode = ElmRuntime.use(ElmRuntime.Render.Utils).newElement;
12+ var newElement = Elm.Graphics.Element.make(elm).newElement;
13+
14+ var List = Elm.Native.List.make(elm);
15+ var MJS = Elm.Native.MJS.make(elm);
16+ var Utils = Elm.Native.Utils.make(elm);
17+ var Signal = Elm.Signal.make(elm);
18+ var Tuple2 = Utils.Tuple2;
19+
20+ function unsafeCoerceGLSL(src) {
21+ return { src : src };
22+ }
23+
24+ function loadTex(source) {
25+
26+ var response = Signal.constant(elm.Http.values.Waiting);
27+
28+ var img = new Image();
29+
30+ img.onload = function() {
31+ var success = elm.Http.values.Success({img:img});
32+ elm.notify(response.id, success);
33+ }
34+
35+ img.onerror = function(e) {
36+ var failure = A2(elm.Http.values.Failure,0,"Failed");
37+ elm.notify(response.id, failure);
38+ }
39+
40+ img.src = source;
41+
42+ return response;
43+
44+ }
45+
46+ function model(vert, frag, buffer, uniforms) {
47+
48+ return model = {
49+ vert: vert,
50+ frag: frag,
51+ buffer: buffer,
52+ uniforms: uniforms
53+ };
54+
55+ }
56+
57+ function do_texture (gl, img) {
58+
59+ var tex = gl.createTexture();
60+ console.log("Created texture");
61+ gl.bindTexture(gl.TEXTURE_2D, tex);
62+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
63+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
64+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
65+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
66+ gl.generateMipmap(gl.TEXTURE_2D);
67+ //gl.bindTexture(gl.TEXTURE0, null);
68+ return tex;
69+
70+ }
71+
72+ function do_compile (gl, src, tipe) {
73+
74+ var shader = gl.createShader(tipe);
75+ console.log("Created shader");
76+
77+ gl.shaderSource(shader, src);
78+ gl.compileShader(shader);
79+ var compile = gl.COMPILE_STATUS;
80+ if (!gl.getShaderParameter(shader,compile)) {
81+ throw gl.getShaderInfoLog(shader);
82+ }
83+
84+ return shader;
85+
86+ }
87+
88+ function do_link (gl, vshader, fshader) {
89+
90+ var program = gl.createProgram();
91+ console.log("Created program");
92+
93+ gl.attachShader(program, vshader);
94+ gl.attachShader(program, fshader);
95+ gl.linkProgram(program);
96+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
97+ throw gl.getProgramInfoLog(program);
98+ }
99+
100+ return program;
101+
102+ }
103+
104+ function do_bind (gl, program, bufferElems) {
105+
106+ var buffers = {};
107+
108+ var attributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
109+ for (var i = 0; i < attributes; i += 1) {
110+ var attribute = gl.getActiveAttrib(program, i);
111+ switch (attribute.type) {
112+ case gl.FLOAT_VEC3:
113+
114+ // Might want to invert the loop
115+ // to build the array buffer first
116+ // and then bind each one-at-a-time
117+ var data = [];
118+ List.each(function(elem){
119+ data.push(elem._0[attribute.name][0]);
120+ data.push(elem._0[attribute.name][1]);
121+ data.push(elem._0[attribute.name][2]);
122+ data.push(elem._1[attribute.name][0]);
123+ data.push(elem._1[attribute.name][1]);
124+ data.push(elem._1[attribute.name][2]);
125+ data.push(elem._2[attribute.name][0]);
126+ data.push(elem._2[attribute.name][1]);
127+ data.push(elem._2[attribute.name][2]);
128+ }, bufferElems);
129+ var array = new Float32Array(data);
130+
131+ var buffer = gl.createBuffer();
132+ console.log("Created attribute buffer " + attribute.name);
133+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
134+ gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW);
135+
136+ buffers[attribute.name] = buffer;
137+
138+ break;
139+
140+ default:
141+ console.log("Bad buffer type");
142+ break;
143+ }
144+
145+ }
146+
147+ var numIndices = 3 * List.length(bufferElems);
148+ var indices = List.toArray(List.range(0, numIndices - 1));
149+ console.log("Created index buffer");
150+ var indexBuffer = gl.createBuffer();
151+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
152+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
153+
154+ var bufferObject = {
155+ numIndices: numIndices,
156+ indexBuffer: indexBuffer,
157+ buffers: buffers
158+ };
159+
160+ return bufferObject;
161+
162+ }
163+
164+ function drawGL(model) {
165+
166+ var gl = model.cache.gl;
167+
168+ gl.viewport(0, 0, model.w, model.h);
169+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
170+ console.log("Drawing");
171+
172+ function drawModel(m) {
173+
174+ var program;
175+ if (m.vert.id && m.frag.id) {
176+ var progid = m.vert.id + '#' + m.frag.id;
177+ program = model.cache.programs[progid];
178+ }
179+
180+ if (!program) {
181+
182+ var vshader = undefined;
183+ if (m.vert.id) {
184+ vshader = model.cache.shaders[m.vert.id];
185+ } else {
186+ m.vert.id = Utils.guid();
187+ }
188+
189+ if (!vshader) {
190+ vshader = do_compile(gl, m.vert.src, gl.VERTEX_SHADER);
191+ model.cache.shaders[m.vert.id] = vshader;
192+ }
193+
194+ var fshader = undefined;
195+ if (m.frag.id) {
196+ fshader = model.cache.shaders[m.frag.id];
197+ } else {
198+ m.frag.id = Utils.guid();
199+ }
200+
201+ if (!fshader) {
202+ fshader = do_compile(gl, m.frag.src, gl.FRAGMENT_SHADER);
203+ model.cache.shaders[m.frag.id] = fshader;
204+ }
205+
206+ program = do_link(gl, vshader, fshader);
207+ var progid = m.vert.id + '#' + m.frag.id;
208+ model.cache.programs[progid] = program;
209+
210+ }
211+
212+ gl.useProgram(program);
213+
214+ var numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
215+ var textureCounter = 0;
216+ for (var i = 0; i < numUniforms; i += 1) {
217+ var uniform = gl.getActiveUniform(program, i);
218+ var uniformLocation = gl.getUniformLocation(program, uniform.name);
219+ switch (uniform.type) {
220+ case gl.INT:
221+ gl.uniform1i(uniformLocation, m.uniforms[uniform.name]);
222+ break;
223+ case gl.FLOAT:
224+ gl.uniform1f(uniformLocation, m.uniforms[uniform.name]);
225+ break;
226+ case gl.FLOAT_VEC3:
227+ gl.uniform3fv(uniformLocation, m.uniforms[uniform.name]);
228+ break;
229+ case gl.FLOAT_MAT4:
230+ gl.uniformMatrix4fv(uniformLocation, false, m.uniforms[uniform.name]);
231+ break;
232+ case gl.SAMPLER_2D:
233+ var texture = m.uniforms[uniform.name];
234+ var tex = undefined;
235+ if (texture.id) {
236+ tex = model.cache.textures[texture.id];
237+ } else {
238+ texture.id = Utils.guid();
239+ }
240+ if (!tex) {
241+ tex = do_texture(gl, texture.img);
242+ model.cache.textures[texture.id] = tex;
243+ }
244+ var activeName = 'TEXTURE' + textureCounter;
245+ gl.activeTexture(gl[activeName]);
246+ gl.bindTexture(gl.TEXTURE_2D,tex);
247+ gl.uniform1i(uniformLocation, textureCounter);
248+ textureCounter += 1;
249+ break;
250+ default:
251+ console.log("Unsupported uniform type: " + uniform.type);
252+ break;
253+ }
254+ }
255+
256+ var buffer = model.cache.buffers[m.buffer.guid];
257+ if (!buffer) {
258+ buffer = do_bind(gl, program, m.buffer);
259+ model.cache.buffers[m.buffer.guid] = buffer;
260+ }
261+
262+ var numIndices = buffer.numIndices;
263+ var indexBuffer = buffer.indexBuffer;
264+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
265+
266+ var numAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
267+ for (var i = 0; i < numAttributes; i += 1) {
268+ var attribute = gl.getActiveAttrib(program, i);
269+ var attribLocation = gl.getAttribLocation(program, attribute.name);
270+ gl.enableVertexAttribArray(attribLocation);
271+ var attributeBuffer = buffer.buffers[attribute.name];
272+
273+ switch (attribute.type) {
274+ case gl.FLOAT_VEC3:
275+ gl.bindBuffer(gl.ARRAY_BUFFER, attributeBuffer);
276+ gl.vertexAttribPointer(attribLocation, 3, gl.FLOAT, false, 0, 0);
277+ break;
278+ default:
279+ console.log("Unsupported attribute type: " + attribute.type);
280+ break;
281+ }
282+ }
283+
284+ gl.drawElements(gl.TRIANGLES, numIndices, gl.UNSIGNED_SHORT, 0);
285+
286+ }
287+
288+ List.each(drawModel, model.models);
289+
290+ }
291+
292+ function webgl(dimensions, models) {
293+
294+ if (!window.WebGLRenderingContext) {
295+ throw new Error("It appears your browser does not support WebGL! http://get.webgl.org/troubleshooting");
296+ return;
297+ }
298+
299+ var w = dimensions._0;
300+ var h = dimensions._1;
301+
302+ function render(model) {
303+
304+ var div = newNode('div');
305+ div.style.overflow = 'hidden';
306+ var canvas = newNode('canvas');
307+ var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
308+ gl.enable(gl.DEPTH_TEST);
309+
310+ model.cache.gl = gl;
311+ model.cache.canvas = canvas;
312+ model.cache.shaders = [];
313+ model.cache.programs = {};
314+ model.cache.buffers = [];
315+ model.cache.textures = [];
316+
317+ update(div, model, model);
318+
319+ return div;
320+
321+ }
322+
323+ function update(div, oldModel, newModel) {
324+
325+ newModel.cache = oldModel.cache;
326+
327+ var canvas = newModel.cache.canvas;
328+
329+ canvas.style.width = oldModel.w + 'px';
330+ canvas.style.height = oldModel.h + 'px';
331+ canvas.style.display = "block";
332+ canvas.style.position = "absolute";
333+ canvas.width = oldModel.w;
334+ canvas.height = oldModel.h;
335+
336+ drawGL(newModel);
337+
338+ div.appendChild(canvas);
339+
340+ }
341+
342+ var elem = {
343+ ctor: 'Custom',
344+ type: 'WebGL',
345+ render: render,
346+ update: update,
347+ model: {
348+ models: models,
349+ cache: {},
350+ w: w,
351+ h: h,
352+ }
353+ };
354+
355+ return A3(newElement, w, h, elem);
356+
357+ }
358+
359+ return elm.Native.Graphics.WebGL.values = {
360+ unsafeCoerceGLSL:unsafeCoerceGLSL,
361+ loadTex:loadTex,
362+ model:F4(model),
363+ webgl:F2(webgl)
364+ };
365+
366+};
libraries/Native/List.js+13−1
@@ -289,6 +289,16 @@ Elm.Native.List.make = function(elm) {
289 return fromArray(out);
289 return fromArray(out);
290 }
290 }
291
291
292+ /*
293+ * Only to be used internally; do some side effects for each elem
294+ */
295+ function each(action, xs) {
296+ while(xs.ctor !== '[]') {
297+ action(xs._0);
298+ xs = xs._1;
299+ }
300+ }
301+
292 Elm.Native.List.values = {
302 Elm.Native.List.values = {
293 Nil:Nil,
303 Nil:Nil,
294 Cons:Cons,
304 Cons:Cons,
@@ -328,7 +338,9 @@ Elm.Native.List.make = function(elm) {
328 drop:F2(drop),
338 drop:F2(drop),
329 repeat:F2(repeat),
339 repeat:F2(repeat),
330
340
331− join:F2(join)
341+ join:F2(join),
342+
343+ each:each
332 };
344 };
333 return elm.Native.List.values = Elm.Native.List.values;
345 return elm.Native.List.values = Elm.Native.List.values;
334
346
libraries/Native/MJS.jsnew file+1783
@@ -0,0 +1,1783 @@
1+
2+/*
3+ * Copyright (c) 2010 Mozilla Corporation
4+ * Copyright (c) 2010 Vladimir Vukicevic
5+ * Copyright (c) 2013 John Mayer
6+ *
7+ * Permission is hereby granted, free of charge, to any person
8+ * obtaining a copy of this software and associated documentation
9+ * files (the "Software"), to deal in the Software without
10+ * restriction, including without limitation the rights to use,
11+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
12+ * copies of the Software, and to permit persons to whom the
13+ * Software is furnished to do so, subject to the following
14+ * conditions:
15+ *
16+ * The above copyright notice and this permission notice shall be
17+ * included in all copies or substantial portions of the Software.
18+ *
19+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26+ * OTHER DEALINGS IN THE SOFTWARE.
27+ */
28+
29+/*
30+ * File: mjs
31+ *
32+ * Vector and Matrix math utilities for JavaScript, optimized for WebGL.
33+ * Edited to work with Elm Programming Language
34+ */
35+
36+Elm.Native.MJS = {};
37+Elm.Native.MJS.make = function(elm) {
38+
39+ elm.Native = elm.Native || {};
40+ elm.Native.MJS = elm.Native.MJS || {};
41+ if (elm.Native.MJS.values) return elm.Native.MJS.values;
42+
43+ /*
44+ * Constant: MJS_VERSION
45+ *
46+ * mjs version number aa.bb.cc, encoded as an integer of the form:
47+ * 0xaabbcc.
48+ */
49+ var MJS_VERSION = 0x000000;
50+
51+ /*
52+ * Constant: MJS_DO_ASSERT
53+ *
54+ * Enables or disables runtime assertions.
55+ *
56+ * For potentially more performance, the assert methods can be
57+ * commented out in each place where they are called.
58+ */
59+ //var MJS_DO_ASSERT = true;
60+
61+ /*
62+ * Constant: MJS_FLOAT_ARRAY_TYPE
63+ *
64+ * The base float array type. By default, WebGLFloatArray.
65+ *
66+ * mjs can work with any array-like elements, but if an array
67+ * creation is requested, it will create an array of the type
68+ * MJS_FLOAT_ARRAY_TYPE. Also, the builtin constants such as (M4x4.I)
69+ * will be of this type.
70+ */
71+ //MJS_FLOAT_ARRAY_TYPE = WebGLFloatArray;
72+ var MJS_FLOAT_ARRAY_TYPE = Float32Array;
73+ //MJS_FLOAT_ARRAY_TYPE = Float64Array;
74+ //MJS_FLOAT_ARRAY_TYPE = Array;
75+
76+ //if (MJS_DO_ASSERT) {
77+ //function MathUtils_assert(cond, msg) {
78+ //if (!cond)
79+ //throw "Assertion failed: " + msg;
80+ //}
81+ //} else {
82+ function MathUtils_assert() { }
83+ //}
84+
85+ /*
86+ * Class: V3
87+ *
88+ * Methods for working with 3-element vectors. A vector is represented by a 3-element array.
89+ * Any valid JavaScript array type may be used, but if new
90+ * vectors are created they are created using the configured MJS_FLOAT_ARRAY_TYPE.
91+ */
92+
93+ var V3 = { };
94+
95+ V3._temp1 = new MJS_FLOAT_ARRAY_TYPE(3);
96+ V3._temp2 = new MJS_FLOAT_ARRAY_TYPE(3);
97+ V3._temp3 = new MJS_FLOAT_ARRAY_TYPE(3);
98+
99+ if (MJS_FLOAT_ARRAY_TYPE == Array) {
100+ V3.x = [1.0, 0.0, 0.0];
101+ V3.y = [0.0, 1.0, 0.0];
102+ V3.z = [0.0, 0.0, 1.0];
103+
104+ V3.$ = function V3_$(x, y, z) {
105+ return [x, y, z];
106+ };
107+
108+ V3.clone = function V3_clone(a) {
109+ //MathUtils_assert(a.length == 3, "a.length == 3");
110+ return [a[0], a[1], a[2]];
111+ };
112+ } else {
113+ V3.x = new MJS_FLOAT_ARRAY_TYPE([1.0, 0.0, 0.0]);
114+ V3.y = new MJS_FLOAT_ARRAY_TYPE([0.0, 1.0, 0.0]);
115+ V3.z = new MJS_FLOAT_ARRAY_TYPE([0.0, 0.0, 1.0]);
116+
117+ /*
118+ * Function: V3.$
119+ *
120+ * Creates a new 3-element vector with the given values.
121+ *
122+ * Parameters:
123+ *
124+ * x,y,z - the 3 elements of the new vector.
125+ *
126+ * Returns:
127+ *
128+ * A new vector containing with the given argument values.
129+ */
130+
131+ V3.$ = function V3_$(x, y, z) {
132+ return new MJS_FLOAT_ARRAY_TYPE([x, y, z]);
133+ };
134+
135+ /*
136+ * Function: V3.clone
137+ *
138+ * Clone the given 3-element vector.
139+ *
140+ * Parameters:
141+ *
142+ * a - the 3-element vector to clone
143+ *
144+ * Returns:
145+ *
146+ * A new vector with the same values as the passed-in one.
147+ */
148+
149+ V3.clone = function V3_clone(a) {
150+ //MathUtils_assert(a.length == 3, "a.length == 3");
151+ return new MJS_FLOAT_ARRAY_TYPE(a);
152+ };
153+ }
154+
155+ V3.u = V3.x;
156+ V3.v = V3.y;
157+
158+ /* Function: V3.toTuple3
159+ *
160+ * Turn into an Elm Tuple
161+ */
162+ V3.toTuple3 = function V3_toTuple3(a) {
163+ return v = {
164+ ctor:"_Tuple3",
165+ _0:a[0],
166+ _1:a[1],
167+ _2:a[2]
168+ };
169+ };
170+
171+ /*
172+ * Function: V3.add
173+ *
174+ * Perform r = a + b.
175+ *
176+ * Parameters:
177+ *
178+ * a - the first vector operand
179+ * b - the second vector operand
180+ * r - optional vector to store the result in
181+ *
182+ * Returns:
183+ *
184+ * If r is specified, returns r after performing the operation.
185+ * Otherwise, returns a new 3-element vector with the result.
186+ */
187+ V3.add = function V3_add(a, b, r) {
188+ //MathUtils_assert(a.length == 3, "a.length == 3");
189+ //MathUtils_assert(b.length == 3, "b.length == 3");
190+ //MathUtils_assert(r == undefined || r.length == 3, "r == undefined || r.length == 3");
191+
192+ if (r == undefined)
193+ r = new MJS_FLOAT_ARRAY_TYPE(3);
194+ r[0] = a[0] + b[0];
195+ r[1] = a[1] + b[1];
196+ r[2] = a[2] + b[2];
197+ return r;
198+ };
199+
200+ /*
201+ * Function: V3.sub
202+ *
203+ * Perform
204+ * r = a - b.
205+ *
206+ * Parameters:
207+ *
208+ * a - the first vector operand
209+ * b - the second vector operand
210+ * r - optional vector to store the result in
211+ *
212+ * Returns:
213+ *
214+ * If r is specified, returns r after performing the operation.
215+ * Otherwise, returns a new 3-element vector with the result.
216+ */
217+ V3.sub = function V3_sub(a, b, r) {
218+ //MathUtils_assert(a.length == 3, "a.length == 3");
219+ //MathUtils_assert(b.length == 3, "b.length == 3");
220+ //MathUtils_assert(r == undefined || r.length == 3, "r == undefined || r.length == 3");
221+
222+ if (r == undefined)
223+ r = new MJS_FLOAT_ARRAY_TYPE(3);
224+ r[0] = a[0] - b[0];
225+ r[1] = a[1] - b[1];
226+ r[2] = a[2] - b[2];
227+ return r;
228+ };
229+
230+ /*
231+ * Function: V3.neg
232+ *
233+ * Perform
234+ * r = - a.
235+ *
236+ * Parameters:
237+ *
238+ * a - the vector operand
239+ * r - optional vector to store the result in
240+ *
241+ * Returns:
242+ *
243+ * If r is specified, returns r after performing the operation.
244+ * Otherwise, returns a new 3-element vector with the result.
245+ */
246+ V3.neg = function V3_neg(a, r) {
247+ //MathUtils_assert(a.length == 3, "a.length == 3");
248+ //MathUtils_assert(r == undefined || r.length == 3, "r == undefined || r.length == 3");
249+
250+ if (r == undefined)
251+ r = new MJS_FLOAT_ARRAY_TYPE(3);
252+ r[0] = - a[0];
253+ r[1] = - a[1];
254+ r[2] = - a[2];
255+ return r;
256+ };
257+
258+ /*
259+ * Function: V3.direction
260+ *
261+ * Perform
262+ * r = (a - b) / |a - b|. The result is the normalized
263+ * direction from a to b.
264+ *
265+ * Parameters:
266+ *
267+ * a - the first vector operand
268+ * b - the second vector operand
269+ * r - optional vector to store the result in
270+ *
271+ * Returns:
272+ *
273+ * If r is specified, returns r after performing the operation.
274+ * Otherwise, returns a new 3-element vector with the result.
275+ */
276+ V3.direction = function V3_direction(a, b, r) {
277+ //MathUtils_assert(a.length == 3, "a.length == 3");
278+ //MathUtils_assert(b.length == 3, "b.length == 3");
279+ //MathUtils_assert(r == undefined || r.length == 3, "r == undefined || r.length == 3");
280+
281+ if (r == undefined)
282+ r = new MJS_FLOAT_ARRAY_TYPE(3);
283+ return V3.normalize(V3.sub(a, b, r), r);
284+ };
285+
286+ /*
287+ * Function: V3.length
288+ *
289+ * Perform r = |a|.
290+ *
291+ * Parameters:
292+ *
293+ * a - the vector operand
294+ *
295+ * Returns:
296+ *
297+ * The length of the given vector.
298+ */
299+ V3.length = function V3_length(a) {
300+ //MathUtils_assert(a.length == 3, "a.length == 3");
301+
302+ return Math.sqrt(a[0]*a[0] + a[1]*a[1] + a[2]*a[2]);
303+ };
304+
305+ /*
306+ * Function: V3.lengthSquard
307+ *
308+ * Perform r = |a|*|a|.
309+ *
310+ * Parameters:
311+ *
312+ * a - the vector operand
313+ *
314+ * Returns:
315+ *
316+ * The square of the length of the given vector.
317+ */
318+ V3.lengthSquared = function V3_lengthSquared(a) {
319+ //MathUtils_assert(a.length == 3, "a.length == 3");
320+
321+ return a[0]*a[0] + a[1]*a[1] + a[2]*a[2];
322+ };
323+
324+ /*
325+ * Function: V3.normalize
326+ *
327+ * Perform r = a / |a|.
328+ *
329+ * Parameters:
330+ *
331+ * a - the vector operand
332+ * r - optional vector to store the result in
333+ *
334+ * Returns:
335+ *
336+ * If r is specified, returns r after performing the operation.
337+ * Otherwise, returns a new 3-element vector with the result.
338+ */
339+ V3.normalize = function V3_normalize(a, r) {
340+ //MathUtils_assert(a.length == 3, "a.length == 3");
341+ //MathUtils_assert(r == undefined || r.length == 3, "r == undefined || r.length == 3");
342+
343+ if (r == undefined)
344+ r = new MJS_FLOAT_ARRAY_TYPE(3);
345+ var im = 1.0 / V3.length(a);
346+ r[0] = a[0] * im;
347+ r[1] = a[1] * im;
348+ r[2] = a[2] * im;
349+ return r;
350+ };
351+
352+ /*
353+ * Function: V3.scale
354+ *
355+ * Perform r = a * k.
356+ *
357+ * Parameters:
358+ *
359+ * a - the vector operand
360+ * k - a scalar value
361+ * r - optional vector to store the result in
362+ *
363+ * Returns:
364+ *
365+ * If r is specified, returns r after performing the operation.
366+ * Otherwise, returns a new 3-element vector with the result.
367+ */
368+ V3.scale = function V3_scale(a, k, r) {
369+ //MathUtils_assert(a.length == 3, "a.length == 3");
370+ //MathUtils_assert(r == undefined || r.length == 3, "r == undefined || r.length == 3");
371+
372+ if (r == undefined)
373+ r = new MJS_FLOAT_ARRAY_TYPE(3);
374+ r[0] = a[0] * k;
375+ r[1] = a[1] * k;
376+ r[2] = a[2] * k;
377+ return r;
378+ };
379+
380+ /*
381+ * Function: V3.dot
382+ *
383+ * Perform
384+ * r = dot(a, b).
385+ *
386+ * Parameters:
387+ *
388+ * a - the first vector operand
389+ * b - the second vector operand
390+ *
391+ * Returns:
392+ *
393+ * The dot product of a and b.
394+ */
395+ V3.dot = function V3_dot(a, b) {
396+ //MathUtils_assert(a.length == 3, "a.length == 3");
397+ //MathUtils_assert(b.length == 3, "b.length == 3");
398+
399+ return a[0] * b[0] +
400+ a[1] * b[1] +
401+ a[2] * b[2];
402+ };
403+
404+ /*
405+ * Function: V3.cross
406+ *
407+ * Perform r = a x b.
408+ *
409+ * Parameters:
410+ *
411+ * a - the first vector operand
412+ * b - the second vector operand
413+ * r - optional vector to store the result in
414+ *
415+ * Returns:
416+ *
417+ * If r is specified, returns r after performing the operation.
418+ * Otherwise, returns a new 3-element vector with the result.
419+ */
420+ V3.cross = function V3_cross(a, b, r) {
421+ //MathUtils_assert(a.length == 3, "a.length == 3");
422+ //MathUtils_assert(b.length == 3, "b.length == 3");
423+ //MathUtils_assert(r == undefined || r.length == 3, "r == undefined || r.length == 3");
424+
425+ if (r == undefined)
426+ r = new MJS_FLOAT_ARRAY_TYPE(3);
427+ r[0] = a[1]*b[2] - a[2]*b[1];
428+ r[1] = a[2]*b[0] - a[0]*b[2];
429+ r[2] = a[0]*b[1] - a[1]*b[0];
430+ return r;
431+ };
432+
433+ /*
434+ * Function: V3.mul4x4
435+ *
436+ * Perform
437+ * r = m * v.
438+ *
439+ * Parameters:
440+ *
441+ * m - the 4x4 matrix operand
442+ * v - the 3-element vector operand
443+ * r - optional vector to store the result in
444+ *
445+ * Returns:
446+ *
447+ * If r is specified, returns r after performing the operation.
448+ * Otherwise, returns a new 3-element vector with the result.
449+ * The 4-element result vector is divided by the w component
450+ * and returned as a 3-element vector.
451+ */
452+ V3.mul4x4 = function V3_mul4x4(m, v, r) {
453+ //MathUtils_assert(m.length == 16, "m.length == 16");
454+ //MathUtils_assert(v.length == 3, "v.length == 3");
455+ //MathUtils_assert(r == undefined || r.length == 3, "r == undefined || r.length == 3");
456+
457+ var w;
458+ var tmp = V3._temp1;
459+ if (r == undefined)
460+ r = new MJS_FLOAT_ARRAY_TYPE(3);
461+ tmp[0] = m[ 3];
462+ tmp[1] = m[ 7];
463+ tmp[2] = m[11];
464+ w = V3.dot(v, tmp) + m[15];
465+ tmp[0] = m[ 0];
466+ tmp[1] = m[ 4];
467+ tmp[2] = m[ 8];
468+ r[0] = (V3.dot(v, tmp) + m[12])/w;
469+ tmp[0] = m[ 1];
470+ tmp[1] = m[ 5];
471+ tmp[2] = m[ 9];
472+ r[1] = (V3.dot(v, tmp) + m[13])/w;
473+ tmp[0] = m[ 2];
474+ tmp[1] = m[ 6];
475+ tmp[2] = m[10];
476+ r[2] = (V3.dot(v, tmp) + m[14])/w;
477+ return r;
478+ };
479+
480+ /*
481+ * Class: M4x4
482+ *
483+ * Methods for working with 4x4 matrices. A matrix is represented by a 16-element array
484+ * in column-major order. Any valid JavaScript array type may be used, but if new
485+ * matrices are created they are created using the configured MJS_FLOAT_ARRAY_TYPE.
486+ */
487+
488+ var M4x4 = { };
489+
490+ M4x4._temp1 = new MJS_FLOAT_ARRAY_TYPE(16);
491+ M4x4._temp2 = new MJS_FLOAT_ARRAY_TYPE(16);
492+
493+ if (MJS_FLOAT_ARRAY_TYPE == Array) {
494+ M4x4.I = [1.0, 0.0, 0.0, 0.0,
495+ 0.0, 1.0, 0.0, 0.0,
496+ 0.0, 0.0, 1.0, 0.0,
497+ 0.0, 0.0, 0.0, 1.0];
498+
499+ M4x4.$ = function M4x4_$(m00, m01, m02, m03,
500+ m04, m05, m06, m07,
501+ m08, m09, m10, m11,
502+ m12, m13, m14, m15)
503+ {
504+ return [m00, m01, m02, m03,
505+ m04, m05, m06, m07,
506+ m08, m09, m10, m11,
507+ m12, m13, m14, m15];
508+ };
509+
510+ M4x4.clone = function M4x4_clone(m) {
511+ //MathUtils_assert(m.length == 16, "m.length == 16");
512+ return new [m[0], m[1], m[2], m[3],
513+ m[4], m[5], m[6], m[7],
514+ m[8], m[9], m[10], m[11],
515+ m[12], m[13], m[14], m[15]];
516+ };
517+ } else {
518+ M4x4.I = new MJS_FLOAT_ARRAY_TYPE([1.0, 0.0, 0.0, 0.0,
519+ 0.0, 1.0, 0.0, 0.0,
520+ 0.0, 0.0, 1.0, 0.0,
521+ 0.0, 0.0, 0.0, 1.0]);
522+
523+ /*
524+ * Function: M4x4.$
525+ *
526+ * Creates a new 4x4 matrix with the given values.
527+ *
528+ * Parameters:
529+ *
530+ * m00..m15 - the 16 elements of the new matrix.
531+ *
532+ * Returns:
533+ *
534+ * A new matrix filled with the given argument values.
535+ */
536+ M4x4.$ = function M4x4_$(m00, m01, m02, m03,
537+ m04, m05, m06, m07,
538+ m08, m09, m10, m11,
539+ m12, m13, m14, m15)
540+ {
541+ return new MJS_FLOAT_ARRAY_TYPE([m00, m01, m02, m03,
542+ m04, m05, m06, m07,
543+ m08, m09, m10, m11,
544+ m12, m13, m14, m15]);
545+ };
546+
547+ /*
548+ * Function: M4x4.clone
549+ *
550+ * Clone the given 4x4 matrix.
551+ *
552+ * Parameters:
553+ *
554+ * m - the 4x4 matrix to clone
555+ *
556+ * Returns:
557+ *
558+ * A new matrix with the same values as the passed-in one.
559+ */
560+ M4x4.clone = function M4x4_clone(m) {
561+ //MathUtils_assert(m.length == 16, "m.length == 16");
562+ return new MJS_FLOAT_ARRAY_TYPE(m);
563+ };
564+ }
565+
566+ M4x4.identity = M4x4.I;
567+
568+ /*
569+ * Function: M4x4.topLeft3x3
570+ *
571+ * Return the top left 3x3 matrix from the given 4x4 matrix m.
572+ *
573+ * Parameters:
574+ *
575+ * m - the matrix
576+ * r - optional 3x3 matrix to store the result in
577+ *
578+ * Returns:
579+ *
580+ * If r is specified, returns r after performing the operation.
581+ * Otherwise, returns a new 3x3 matrix with the result.
582+ */
583+ M4x4.topLeft3x3 = function M4x4_topLeft3x3(m, r) {
584+ //MathUtils_assert(m.length == 16, "m.length == 16");
585+ //MathUtils_assert(r == undefined || r.length == 9, "r == undefined || r.length == 9");
586+
587+ if (r == undefined)
588+ r = new MJS_FLOAT_ARRAY_TYPE(9);
589+ r[0] = m[0]; r[1] = m[1]; r[2] = m[2];
590+ r[3] = m[4]; r[4] = m[5]; r[5] = m[6];
591+ r[6] = m[8]; r[7] = m[9]; r[8] = m[10];
592+ return r;
593+ };
594+
595+ /*
596+ * Function: M4x4.inverseOrthonormal
597+ *
598+ * Computes the inverse of the given matrix m, assuming that
599+ * the matrix is orthonormal.
600+ *
601+ * Parameters:
602+ *
603+ * m - the matrix
604+ * r - optional 4x4 matrix to store the result in
605+ *
606+ * Returns:
607+ *
608+ * If r is specified, returns r after performing the operation.
609+ * Otherwise, returns a new 4x4 matrix with the result.
610+ */
611+ M4x4.inverseOrthonormal = function M4x4_inverseOrthonormal(m, r) {
612+ //MathUtils_assert(m.length == 16, "m.length == 16");
613+ //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16");
614+ //MathUtils_assert(m != r, "m != r");
615+
616+ if (r == undefined)
617+ r = new MJS_FLOAT_ARRAY_TYPE(16);
618+ M4x4.transpose(m, r);
619+ var t = [m[12], m[13], m[14]];
620+ r[3] = r[7] = r[11] = 0;
621+ r[12] = -V3.dot([r[0], r[4], r[8]], t);
622+ r[13] = -V3.dot([r[1], r[5], r[9]], t);
623+ r[14] = -V3.dot([r[2], r[6], r[10]], t);
624+ return r;
625+ };
626+
627+ /*
628+ * Function: M4x4.inverseTo3x3
629+ *
630+ * Computes the inverse of the given matrix m, but calculates
631+ * only the top left 3x3 values of the result.
632+ *
633+ * Parameters:
634+ *
635+ * m - the matrix
636+ * r - optional 3x3 matrix to store the result in
637+ *
638+ * Returns:
639+ *
640+ * If r is specified, returns r after performing the operation.
641+ * Otherwise, returns a new 3x3 matrix with the result.
642+ */
643+ M4x4.inverseTo3x3 = function M4x4_inverseTo3x3(m, r) {
644+ //MathUtils_assert(m.length == 16, "m.length == 16");
645+ //MathUtils_assert(r == undefined || r.length == 9, "r == undefined || r.length == 9");
646+
647+ if (r == undefined)
648+ r = new MJS_FLOAT_ARRAY_TYPE(9);
649+
650+ var a11 = m[10]*m[5]-m[6]*m[9],
651+ a21 = -m[10]*m[1]+m[2]*m[9],
652+ a31 = m[6]*m[1]-m[2]*m[5],
653+ a12 = -m[10]*m[4]+m[6]*m[8],
654+ a22 = m[10]*m[0]-m[2]*m[8],
655+ a32 = -m[6]*m[0]+m[2]*m[4],
656+ a13 = m[9]*m[4]-m[5]*m[8],
657+ a23 = -m[9]*m[0]+m[1]*m[8],
658+ a33 = m[5]*m[0]-m[1]*m[4];
659+ var det = m[0]*(a11) + m[1]*(a12) + m[2]*(a13);
660+ if (det == 0) // no inverse
661+ throw "matrix not invertible";
662+ var idet = 1.0 / det;
663+
664+ r[0] = idet*a11;
665+ r[1] = idet*a21;
666+ r[2] = idet*a31;
667+ r[3] = idet*a12;
668+ r[4] = idet*a22;
669+ r[5] = idet*a32;
670+ r[6] = idet*a13;
671+ r[7] = idet*a23;
672+ r[8] = idet*a33;
673+
674+ return r;
675+ };
676+
677+ /*
678+ * Function: M4x4.makeFrustum
679+ *
680+ * Creates a matrix for a projection frustum with the given parameters.
681+ *
682+ * Parameters:
683+ *
684+ * left - the left coordinate of the frustum
685+ * right- the right coordinate of the frustum
686+ * bottom - the bottom coordinate of the frustum
687+ * top - the top coordinate of the frustum
688+ * znear - the near z distance of the frustum
689+ * zfar - the far z distance of the frustum
690+ * r - optional 4x4 matrix to store the result in
691+ *
692+ * Returns:
693+ *
694+ * If r is specified, returns r after creating the projection matrix.
695+ * Otherwise, returns a new 4x4 matrix.
696+ */
697+ M4x4.makeFrustum = function M4x4_makeFrustum(left, right, bottom, top, znear, zfar, r) {
698+ //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16");
699+
700+ if (r == undefined)
701+ r = new MJS_FLOAT_ARRAY_TYPE(16);
702+
703+ var X = 2*znear/(right-left);
704+ var Y = 2*znear/(top-bottom);
705+ var A = (right+left)/(right-left);
706+ var B = (top+bottom)/(top-bottom);
707+ var C = -(zfar+znear)/(zfar-znear);
708+ var D = -2*zfar*znear/(zfar-znear);
709+
710+ r[0] = 2*znear/(right-left);
711+ r[1] = 0;
712+ r[2] = 0;
713+ r[3] = 0;
714+ r[4] = 0;
715+ r[5] = 2*znear/(top-bottom);
716+ r[6] = 0;
717+ r[7] = 0;
718+ r[8] = (right+left)/(right-left);
719+ r[9] = (top+bottom)/(top-bottom);
720+ r[10] = -(zfar+znear)/(zfar-znear);
721+ r[11] = -1;
722+ r[12] = 0;
723+ r[13] = 0;
724+ r[14] = -2*zfar*znear/(zfar-znear);
725+ r[15] = 0;
726+
727+ return r;
728+ };
729+
730+ /*
731+ * Function: M4x4.makePerspective
732+ *
733+ * Creates a matrix for a perspective projection with the given parameters.
734+ *
735+ * Parameters:
736+ *
737+ * fovy - field of view in the y axis, in degrees
738+ * aspect - aspect ratio
739+ * znear - the near z distance of the projection
740+ * zfar - the far z distance of the projection
741+ * r - optional 4x4 matrix to store the result in
742+ *
743+ * Returns:
744+ *
745+ * If r is specified, returns r after creating the projection matrix.
746+ * Otherwise, returns a new 4x4 matrix.
747+ */
748+ M4x4.makePerspective = function M4x4_makePerspective (fovy, aspect, znear, zfar, r) {
749+ //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16");
750+
751+ var ymax = znear * Math.tan(fovy * Math.PI / 360.0);
752+ var ymin = -ymax;
753+ var xmin = ymin * aspect;
754+ var xmax = ymax * aspect;
755+
756+ return M4x4.makeFrustum(xmin, xmax, ymin, ymax, znear, zfar, r);
757+ };
758+
759+ /*
760+ * Function: M4x4.makeOrtho
761+ *
762+ * Creates a matrix for an orthogonal frustum projection with the given parameters.
763+ *
764+ * Parameters:
765+ *
766+ * left - the left coordinate of the frustum
767+ * right- the right coordinate of the frustum
768+ * bottom - the bottom coordinate of the frustum
769+ * top - the top coordinate of the frustum
770+ * znear - the near z distance of the frustum
771+ * zfar - the far z distance of the frustum
772+ * r - optional 4x4 matrix to store the result in
773+ *
774+ * Returns:
775+ *
776+ * If r is specified, returns r after creating the projection matrix.
777+ * Otherwise, returns a new 4x4 matrix.
778+ */
779+ M4x4.makeOrtho = function M4x4_makeOrtho (left, right, bottom, top, znear, zfar, r) {
780+ //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16");
781+
782+ if (r == undefined)
783+ r = new MJS_FLOAT_ARRAY_TYPE(16);
784+
785+ var tX = -(right+left)/(right-left);
786+ var tY = -(top+bottom)/(top-bottom);
787+ var tZ = -(zfar+znear)/(zfar-znear);
788+ var X = 2 / (right-left);
789+ var Y = 2 / (top-bottom);
790+ var Z = -2 / (zfar-znear);
791+
792+ r[0] = 2 / (right-left);
793+ r[1] = 0;
794+ r[2] = 0;
795+ r[3] = 0;
796+ r[4] = 0;
797+ r[5] = 2 / (top-bottom);
798+ r[6] = 0;
799+ r[7] = 0;
800+ r[8] = 0;
801+ r[9] = 0;
802+ r[10] = -2 / (zfar-znear);
803+ r[11] = 0;
804+ r[12] = -(right+left)/(right-left);
805+ r[13] = -(top+bottom)/(top-bottom);
806+ r[14] = -(zfar+znear)/(zfar-znear);
807+ r[15] = 1;
808+
809+ return r;
810+ };
811+
812+ /*
813+ * Function: M4x4.makeOrtho2D
814+ *
815+ * Creates a matrix for a 2D orthogonal frustum projection with the given parameters.
816+ * znear and zfar are assumed to be -1 and 1, respectively.
817+ *
818+ * Parameters:
819+ *
820+ * left - the left coordinate of the frustum
821+ * right- the right coordinate of the frustum
822+ * bottom - the bottom coordinate of the frustum
823+ * top - the top coordinate of the frustum
824+ * r - optional 4x4 matrix to store the result in
825+ *
826+ * Returns:
827+ *
828+ * If r is specified, returns r after creating the projection matrix.
829+ * Otherwise, returns a new 4x4 matrix.
830+ */
831+ M4x4.makeOrtho2D = function M4x4_makeOrtho2D (left, right, bottom, top, r) {
832+ //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16");
833+
834+ return M4x4.makeOrtho(left, right, bottom, top, -1, 1, r);
835+ };
836+
837+ /*
838+ * Function: M4x4.mul
839+ *
840+ * Performs r = a * b.
841+ *
842+ * Parameters:
843+ *
844+ * a - the first matrix operand
845+ * b - the second matrix operand
846+ * r - optional 4x4 matrix to store the result in
847+ *
848+ * Returns:
849+ *
850+ * If r is specified, returns r after performing the operation.
851+ * Otherwise, returns a new 4x4 matrix with the result.
852+ */
853+ M4x4.mul = function M4x4_mul(a, b, r) {
854+ //MathUtils_assert(a.length == 16, "a.length == 16");
855+ //MathUtils_assert(b.length == 16, "b.length == 16");
856+ //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16");
857+ //MathUtils_assert(a != r && b != r, "a != r && b != r");
858+
859+ if (r == undefined)
860+ r = new MJS_FLOAT_ARRAY_TYPE(16);
861+
862+ var a11 = a[0];
863+ var a21 = a[1];
864+ var a31 = a[2];
865+ var a41 = a[3];
866+ var a12 = a[4];
867+ var a22 = a[5];
868+ var a32 = a[6];
869+ var a42 = a[7];
870+ var a13 = a[8];
871+ var a23 = a[9];
872+ var a33 = a[10];
873+ var a43 = a[11];
874+ var a14 = a[12];
875+ var a24 = a[13];
876+ var a34 = a[14];
877+ var a44 = a[15];
878+
879+ var b11 = b[0];
880+ var b21 = b[1];
881+ var b31 = b[2];
882+ var b41 = b[3];
883+ var b12 = b[4];
884+ var b22 = b[5];
885+ var b32 = b[6];
886+ var b42 = b[7];
887+ var b13 = b[8];
888+ var b23 = b[9];
889+ var b33 = b[10];
890+ var b43 = b[11];
891+ var b14 = b[12];
892+ var b24 = b[13];
893+ var b34 = b[14];
894+ var b44 = b[15];
895+
896+ r[0] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
897+ r[1] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
898+ r[2] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
899+ r[3] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
900+ r[4] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
901+ r[5] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
902+ r[6] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
903+ r[7] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
904+ r[8] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
905+ r[9] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
906+ r[10] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
907+ r[11] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
908+ r[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
909+ r[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
910+ r[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
911+ r[15] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
912+
913+ return r;
914+ };
915+
916+ /*
917+ * Function: M4x4.mulAffine
918+ *
919+ * Performs r = a * b, assuming a and b are affine (elements 3,7,11,15 = 0,0,0,1)
920+ *
921+ * Parameters:
922+ *
923+ * a - the first matrix operand
924+ * b - the second matrix operand
925+ * r - optional 4x4 matrix to store the result in
926+ *
927+ * Returns:
928+ *
929+ * If r is specified, returns r after performing the operation.
930+ * Otherwise, returns a new 4x4 matrix with the result.
931+ */
932+ M4x4.mulAffine = function M4x4_mulAffine(a, b, r) {
933+ //MathUtils_assert(a.length == 16, "a.length == 16");
934+ //MathUtils_assert(b.length == 16, "b.length == 16");
935+ //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16");
936+ //MathUtils_assert(a != r && b != r, "a != r && b != r");
937+
938+ if (r == undefined)
939+ r = new MJS_FLOAT_ARRAY_TYPE(16);
940+ var a11 = a[0];
941+ var a21 = a[1];
942+ var a31 = a[2];
943+ var a12 = a[4];
944+ var a22 = a[5];
945+ var a32 = a[6];
946+ var a13 = a[8];
947+ var a23 = a[9];
948+ var a33 = a[10];
949+ var a14 = a[12];
950+ var a24 = a[13];
951+ var a34 = a[14];
952+
953+ var b11 = b[0];
954+ var b21 = b[1];
955+ var b31 = b[2];
956+ var b12 = b[4];
957+ var b22 = b[5];
958+ var b32 = b[6];
959+ var b13 = b[8];
960+ var b23 = b[9];
961+ var b33 = b[10];
962+ var b14 = b[12];
963+ var b24 = b[13];
964+ var b34 = b[14];
965+
966+ r[0] = a11 * b11 + a12 * b21 + a13 * b31;
967+ r[1] = a21 * b11 + a22 * b21 + a23 * b31;
968+ r[2] = a31 * b11 + a32 * b21 + a33 * b31;
969+ r[3] = 0;
970+ r[4] = a11 * b12 + a12 * b22 + a13 * b32;
971+ r[5] = a21 * b12 + a22 * b22 + a23 * b32;
972+ r[6] = a31 * b12 + a32 * b22 + a33 * b32;
973+ r[7] = 0;
974+ r[8] = a11 * b13 + a12 * b23 + a13 * b33;
975+ r[9] = a21 * b13 + a22 * b23 + a23 * b33;
976+ r[10] = a31 * b13 + a32 * b23 + a33 * b33;
977+ r[11] = 0;
978+ r[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14;
979+ r[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24;
980+ r[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34;
981+ r[15] = 1;
982+
983+ return r;
984+ };
985+
986+ /*
987+ * Function: M4x4.makeRotate
988+ *
989+ * Creates a transformation matrix for rotation by angle radians about the 3-element vector axis.
990+ *
991+ * Parameters:
992+ *
993+ * angle - the angle of rotation, in radians
994+ * axis - the axis around which the rotation is performed, a 3-element vector
995+ * r - optional 4x4 matrix to store the result in
996+ *
997+ * Returns:
998+ *
999+ * If r is specified, returns r after creating the matrix.
1000+ * Otherwise, returns a new 4x4 matrix with the result.
1001+ */
1002+ M4x4.makeRotate = function M4x4_makeRotate(angle, axis, r) {
1003+ //MathUtils_assert(angle.length == 3, "angle.length == 3");
1004+ //MathUtils_assert(axis.length == 3, "axis.length == 3");
1005+ //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16");
1006+
1007+ if (r == undefined)
1008+ r = new MJS_FLOAT_ARRAY_TYPE(16);
1009+
1010+ axis = V3.normalize(axis, V3._temp1);
1011+ var x = axis[0], y = axis[1], z = axis[2];
1012+ var c = Math.cos(angle);
1013+ var c1 = 1-c;
1014+ var s = Math.sin(angle);
1015+
1016+ r[0] = x*x*c1+c;
1017+ r[1] = y*x*c1+z*s;
1018+ r[2] = z*x*c1-y*s;
1019+ r[3] = 0;
1020+ r[4] = x*y*c1-z*s;
1021+ r[5] = y*y*c1+c;
1022+ r[6] = y*z*c1+x*s;
1023+ r[7] = 0;
1024+ r[8] = x*z*c1+y*s;
1025+ r[9] = y*z*c1-x*s;
1026+ r[10] = z*z*c1+c;
1027+ r[11] = 0;
1028+ r[12] = 0;
1029+ r[13] = 0;
1030+ r[14] = 0;
1031+ r[15] = 1;
1032+
1033+ return r;
1034+ };
1035+
1036+ /*
1037+ * Function: M4x4.rotate
1038+ *
1039+ * Concatenates a rotation of angle radians about the axis to the give matrix m.
1040+ *
1041+ * Parameters:
1042+ *
1043+ * angle - the angle of rotation, in radians
1044+ * axis - the axis around which the rotation is performed, a 3-element vector
1045+ * m - the matrix to concatenate the rotation to
1046+ * r - optional 4x4 matrix to store the result in
1047+ *
1048+ * Returns:
1049+ *
1050+ * If r is specified, returns r after performing the operation.
1051+ * Otherwise, returns a new 4x4 matrix with the result.
1052+ */
1053+ M4x4.rotate = function M4x4_rotate(angle, axis, m, r) {
1054+ //MathUtils_assert(angle.length == 3, "angle.length == 3");
1055+ //MathUtils_assert(axis.length == 3, "axis.length == 3");
1056+ //MathUtils_assert(m.length == 16, "m.length == 16");
1057+ //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16");
1058+
1059+ if (r == undefined)
1060+ r = new MJS_FLOAT_ARRAY_TYPE(16);
1061+ var a0=axis [0], a1=axis [1], a2=axis [2];
1062+ var l = Math.sqrt(a0*a0 + a1*a1 + a2*a2);
1063+ var x = a0, y = a1, z = a2;
1064+ if (l != 1.0) {
1065+ var im = 1.0 / l;
1066+ x *= im;
1067+ y *= im;
1068+ z *= im;
1069+ }
1070+ var c = Math.cos(angle);
1071+ var c1 = 1-c;
1072+ var s = Math.sin(angle);
1073+ var xs = x*s;
1074+ var ys = y*s;
1075+ var zs = z*s;
1076+ var xyc1 = x * y * c1;
1077+ var xzc1 = x * z * c1;
1078+ var yzc1 = y * z * c1;
1079+
1080+ var m11 = m[0];
1081+ var m21 = m[1];
1082+ var m31 = m[2];
1083+ var m41 = m[3];
1084+ var m12 = m[4];
1085+ var m22 = m[5];
1086+ var m32 = m[6];
1087+ var m42 = m[7];
1088+ var m13 = m[8];
1089+ var m23 = m[9];
1090+ var m33 = m[10];
1091+ var m43 = m[11];
1092+
1093+ var t11 = x * x * c1 + c;
1094+ var t21 = xyc1 + zs;
1095+ var t31 = xzc1 - ys;
1096+ var t12 = xyc1 - zs;
1097+ var t22 = y * y * c1 + c;
1098+ var t32 = yzc1 + xs;
1099+ var t13 = xzc1 + ys;
1100+ var t23 = yzc1 - xs;
1101+ var t33 = z * z * c1 + c;
1102+
1103+ r[0] = m11 * t11 + m12 * t21 + m13 * t31;
1104+ r[1] = m21 * t11 + m22 * t21 + m23 * t31;
1105+ r[2] = m31 * t11 + m32 * t21 + m33 * t31;
1106+ r[3] = m41 * t11 + m42 * t21 + m43 * t31;
1107+ r[4] = m11 * t12 + m12 * t22 + m13 * t32;
1108+ r[5] = m21 * t12 + m22 * t22 + m23 * t32;
1109+ r[6] = m31 * t12 + m32 * t22 + m33 * t32;
1110+ r[7] = m41 * t12 + m42 * t22 + m43 * t32;
1111+ r[8] = m11 * t13 + m12 * t23 + m13 * t33;
1112+ r[9] = m21 * t13 + m22 * t23 + m23 * t33;
1113+ r[10] = m31 * t13 + m32 * t23 + m33 * t33;
1114+ r[11] = m41 * t13 + m42 * t23 + m43 * t33;
1115+ if (r != m) {
1116+ r[12] = m[12];
1117+ r[13] = m[13];
1118+ r[14] = m[14];
1119+ r[15] = m[15];
1120+ }
1121+ return r;
1122+ };
1123+
1124+ /*
1125+ * Function: M4x4.makeScale3
1126+ *
1127+ * Creates a transformation matrix for scaling by 3 scalar values, one for
1128+ * each of the x, y, and z directions.
1129+ *
1130+ * Parameters:
1131+ *
1132+ * x - the scale for the x axis
1133+ * y - the scale for the y axis
1134+ * z - the scale for the z axis
1135+ * r - optional 4x4 matrix to store the result in
1136+ *
1137+ * Returns:
1138+ *
1139+ * If r is specified, returns r after creating the matrix.
1140+ * Otherwise, returns a new 4x4 matrix with the result.
1141+ */
1142+ M4x4.makeScale3 = function M4x4_makeScale3(x, y, z, r) {
1143+ //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16");
1144+
1145+ if (r == undefined)
1146+ r = new MJS_FLOAT_ARRAY_TYPE(16);
1147+
1148+ r[0] = x;
1149+ r[1] = 0;
1150+ r[2] = 0;
1151+ r[3] = 0;
1152+ r[4] = 0;
1153+ r[5] = y;
1154+ r[6] = 0;
1155+ r[7] = 0;
1156+ r[8] = 0;
1157+ r[9] = 0;
1158+ r[10] = z;
1159+ r[11] = 0;
1160+ r[12] = 0;
1161+ r[13] = 0;
1162+ r[14] = 0;
1163+ r[15] = 1;
1164+
1165+ return r;
1166+ };
1167+
1168+ /*
1169+ * Function: M4x4.makeScale1
1170+ *
1171+ * Creates a transformation matrix for a uniform scale by a single scalar value.
1172+ *
1173+ * Parameters:
1174+ *
1175+ * k - the scale factor
1176+ * r - optional 4x4 matrix to store the result in
1177+ *
1178+ * Returns:
1179+ *
1180+ * If r is specified, returns r after creating the matrix.
1181+ * Otherwise, returns a new 4x4 matrix with the result.
1182+ */
1183+ M4x4.makeScale1 = function M4x4_makeScale1(k, r) {
1184+ //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16");
1185+
1186+ return M4x4.makeScale3(k, k, k, r);
1187+ };
1188+
1189+ /*
1190+ * Function: M4x4.makeScale
1191+ *
1192+ * Creates a transformation matrix for scaling each of the x, y, and z axes by the amount
1193+ * given in the corresponding element of the 3-element vector.
1194+ *
1195+ * Parameters:
1196+ *
1197+ * v - the 3-element vector containing the scale factors
1198+ * r - optional 4x4 matrix to store the result in
1199+ *
1200+ * Returns:
1201+ *
1202+ * If r is specified, returns r after creating the matrix.
1203+ * Otherwise, returns a new 4x4 matrix with the result.
1204+ */
1205+ M4x4.makeScale = function M4x4_makeScale(v, r) {
1206+ //MathUtils_assert(v.length == 3, "v.length == 3");
1207+ //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16");
1208+
1209+ return M4x4.makeScale3(v[0], v[1], v[2], r);
1210+ };
1211+
1212+ /*
1213+ * Function: M4x4.scale3
1214+ */
1215+ M4x4.scale3 = function M4x4_scale3(x, y, z, m, r) {
1216+ //MathUtils_assert(m.length == 16, "m.length == 16");
1217+ //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16");
1218+
1219+ if (r == m) {
1220+ m[0] *= x;
1221+ m[1] *= x;
1222+ m[2] *= x;
1223+ m[3] *= x;
1224+ m[4] *= y;
1225+ m[5] *= y;
1226+ m[6] *= y;
1227+ m[7] *= y;
1228+ m[8] *= z;
1229+ m[9] *= z;
1230+ m[10] *= z;
1231+ m[11] *= z;
1232+ return m;
1233+ }
1234+
1235+ if (r == undefined)
1236+ r = new MJS_FLOAT_ARRAY_TYPE(16);
1237+
1238+ r[0] = m[0] * x;
1239+ r[1] = m[1] * x;
1240+ r[2] = m[2] * x;
1241+ r[3] = m[3] * x;
1242+ r[4] = m[4] * y;
1243+ r[5] = m[5] * y;
1244+ r[6] = m[6] * y;
1245+ r[7] = m[7] * y;
1246+ r[8] = m[8] * z;
1247+ r[9] = m[9] * z;
1248+ r[10] = m[10] * z;
1249+ r[11] = m[11] * z;
1250+ r[12] = m[12];
1251+ r[13] = m[13];
1252+ r[14] = m[14];
1253+ r[15] = m[15];
1254+
1255+ return r;
1256+ };
1257+
1258+ /*
1259+ * Function: M4x4.scale1
1260+ */
1261+ M4x4.scale1 = function M4x4_scale1(k, m, r) {
1262+ //MathUtils_assert(m.length == 16, "m.length == 16");
1263+ //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16");
1264+ if (r == m) {
1265+ m[0] *= k;
1266+ m[1] *= k;
1267+ m[2] *= k;
1268+ m[3] *= k;
1269+ m[4] *= k;
1270+ m[5] *= k;
1271+ m[6] *= k;
1272+ m[7] *= k;
1273+ m[8] *= k;
1274+ m[9] *= k;
1275+ m[10] *= k;
1276+ m[11] *= k;
1277+ return m;
1278+ }
1279+
1280+
1281+ if (r == undefined)
1282+ r = new MJS_FLOAT_ARRAY_TYPE(16);
1283+
1284+ r[0] = m[0] * k;
1285+ r[1] = m[1] * k;
1286+ r[2] = m[2] * k;
1287+ r[3] = m[3] * k;
1288+ r[4] = m[4] * k;
1289+ r[5] = m[5] * k;
1290+ r[6] = m[6] * k;
1291+ r[7] = m[7] * k;
1292+ r[8] = m[8] * k;
1293+ r[9] = m[9] * k;
1294+ r[10] = m[10] * k;
1295+ r[11] = m[11] * k;
1296+ r[12] = m[12];
1297+ r[13] = m[13];
1298+ r[14] = m[14];
1299+ r[15] = m[15];
1300+
1301+ return r;
1302+ };
1303+
1304+ /*
1305+ * Function: M4x4.scale1
1306+ */
1307+ M4x4.scale = function M4x4_scale(v, m, r) {
1308+ //MathUtils_assert(v.length == 3, "v.length == 3");
1309+ //MathUtils_assert(m.length == 16, "m.length == 16");
1310+ //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16");
1311+ var x = v[0], y = v[1], z = v[2];
1312+
1313+ if (r == m) {
1314+ m[0] *= x;
1315+ m[1] *= x;
1316+ m[2] *= x;
1317+ m[3] *= x;
1318+ m[4] *= y;
1319+ m[5] *= y;
1320+ m[6] *= y;
1321+ m[7] *= y;
1322+ m[8] *= z;
1323+ m[9] *= z;
1324+ m[10] *= z;
1325+ m[11] *= z;
1326+ return m;
1327+ }
1328+
1329+ if (r == undefined)
1330+ r = new MJS_FLOAT_ARRAY_TYPE(16);
1331+
1332+
1333+ r[0] = m[0] * x;
1334+ r[1] = m[1] * x;
1335+ r[2] = m[2] * x;
1336+ r[3] = m[3] * x;
1337+ r[4] = m[4] * y;
1338+ r[5] = m[5] * y;
1339+ r[6] = m[6] * y;
1340+ r[7] = m[7] * y;
1341+ r[8] = m[8] * z;
1342+ r[9] = m[9] * z;
1343+ r[10] = m[10] * z;
1344+ r[11] = m[11] * z;
1345+ r[12] = m[12];
1346+ r[13] = m[13];
1347+ r[14] = m[14];
1348+ r[15] = m[15];
1349+
1350+ return r;
1351+ };
1352+
1353+ /*
1354+ * Function: M4x4.makeTranslate3
1355+ */
1356+ M4x4.makeTranslate3 = function M4x4_makeTranslate3(x, y, z, r) {
1357+ //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16");
1358+
1359+ if (r == undefined)
1360+ r = new MJS_FLOAT_ARRAY_TYPE(16);
1361+
1362+ r[0] = 1;
1363+ r[1] = 0;
1364+ r[2] = 0;
1365+ r[3] = 0;
1366+ r[4] = 0;
1367+ r[5] = 1;
1368+ r[6] = 0;
1369+ r[7] = 0;
1370+ r[8] = 0;
1371+ r[9] = 0;
1372+ r[10] = 1;
1373+ r[11] = 0;
1374+ r[12] = x;
1375+ r[13] = y;
1376+ r[14] = z;
1377+ r[15] = 1;
1378+
1379+ return r;
1380+ };
1381+
1382+ /*
1383+ * Function: M4x4.makeTranslate1
1384+ */
1385+ M4x4.makeTranslate1 = function M4x4_makeTranslate1 (k, r) {
1386+ //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16");
1387+
1388+ return M4x4.makeTranslate3(k, k, k, r);
1389+ };
1390+
1391+ /*
1392+ * Function: M4x4.makeTranslate
1393+ */
1394+ M4x4.makeTranslate = function M4x4_makeTranslate (v, r) {
1395+ //MathUtils_assert(v.length == 3, "v.length == 3");
1396+ //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16");
1397+
1398+ return M4x4.makeTranslate3(v[0], v[1], v[2], r);
1399+ };
1400+
1401+ /*
1402+ * Function: M4x4.translate3Self
1403+ */
1404+ M4x4.translate3Self = function M4x4_translate3Self (x, y, z, m) {
1405+ //MathUtils_assert(m.length == 16, "m.length == 16");
1406+ //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16");
1407+ m[12] += m[0] * x + m[4] * y + m[8] * z;
1408+ m[13] += m[1] * x + m[5] * y + m[9] * z;
1409+ m[14] += m[2] * x + m[6] * y + m[10] * z;
1410+ m[15] += m[3] * x + m[7] * y + m[11] * z;
1411+ return m;
1412+ };
1413+
1414+ /*
1415+ * Function: M4x4.translate3
1416+ */
1417+ M4x4.translate3 = function M4x4_translate3 (x, y, z, m, r) {
1418+ //MathUtils_assert(m.length == 16, "m.length == 16");
1419+ //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16");
1420+
1421+ if (r == m) {
1422+ m[12] += m[0] * x + m[4] * y + m[8] * z;
1423+ m[13] += m[1] * x + m[5] * y + m[9] * z;
1424+ m[14] += m[2] * x + m[6] * y + m[10] * z;
1425+ m[15] += m[3] * x + m[7] * y + m[11] * z;
1426+ return m;
1427+ }
1428+
1429+ if (r == undefined)
1430+ r = new MJS_FLOAT_ARRAY_TYPE(16);
1431+
1432+ var m11 = m[0];
1433+ var m21 = m[1];
1434+ var m31 = m[2];
1435+ var m41 = m[3];
1436+ var m12 = m[4];
1437+ var m22 = m[5];
1438+ var m32 = m[6];
1439+ var m42 = m[7];
1440+ var m13 = m[8];
1441+ var m23 = m[9];
1442+ var m33 = m[10];
1443+ var m43 = m[11];
1444+
1445+
1446+ r[0] = m11;
1447+ r[1] = m21;
1448+ r[2] = m31;
1449+ r[3] = m41;
1450+ r[4] = m12;
1451+ r[5] = m22;
1452+ r[6] = m32;
1453+ r[7] = m42;
1454+ r[8] = m13;
1455+ r[9] = m23;
1456+ r[10] = m33;
1457+ r[11] = m43;
1458+ r[12] = m11 * x + m12 * y + m13 * z + m[12];
1459+ r[13] = m21 * x + m22 * y + m23 * z + m[13];
1460+ r[14] = m31 * x + m32 * y + m33 * z + m[14];
1461+ r[15] = m41 * x + m42 * y + m43 * z + m[15];
1462+
1463+ return r;
1464+ };
1465+
1466+ /*
1467+ * Function: M4x4.translate1
1468+ */
1469+ M4x4.translate1 = function M4x4_translate1 (k, m, r) {
1470+ //MathUtils_assert(m.length == 16, "m.length == 16");
1471+ //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16");
1472+
1473+ return M4x4.translate3(k, k, k, m, r);
1474+ };
1475+ /*
1476+ * Function: M4x4.translateSelf
1477+ */
1478+ M4x4.translateSelf = function M4x4_translateSelf (v, m) {
1479+ //MathUtils_assert(v.length == 3, "v.length == 3");
1480+ //MathUtils_assert(m.length == 16, "m.length == 16");
1481+ var x=v[0], y=v[1], z=v[2];
1482+ m[12] += m[0] * x + m[4] * y + m[8] * z;
1483+ m[13] += m[1] * x + m[5] * y + m[9] * z;
1484+ m[14] += m[2] * x + m[6] * y + m[10] * z;
1485+ m[15] += m[3] * x + m[7] * y + m[11] * z;
1486+ return m;
1487+ };
1488+ /*
1489+ * Function: M4x4.translate
1490+ */
1491+ M4x4.translate = function M4x4_translate (v, m, r) {
1492+ //MathUtils_assert(v.length == 3, "v.length == 3");
1493+ //MathUtils_assert(m.length == 16, "m.length == 16");
1494+ //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16");
1495+ var x=v[0], y=v[1], z=v[2];
1496+ if (r == m) {
1497+ m[12] += m[0] * x + m[4] * y + m[8] * z;
1498+ m[13] += m[1] * x + m[5] * y + m[9] * z;
1499+ m[14] += m[2] * x + m[6] * y + m[10] * z;
1500+ m[15] += m[3] * x + m[7] * y + m[11] * z;
1501+ return m;
1502+ }
1503+
1504+ if (r == undefined)
1505+ r = new MJS_FLOAT_ARRAY_TYPE(16);
1506+
1507+ var m11 = m[0];
1508+ var m21 = m[1];
1509+ var m31 = m[2];
1510+ var m41 = m[3];
1511+ var m12 = m[4];
1512+ var m22 = m[5];
1513+ var m32 = m[6];
1514+ var m42 = m[7];
1515+ var m13 = m[8];
1516+ var m23 = m[9];
1517+ var m33 = m[10];
1518+ var m43 = m[11];
1519+
1520+ r[0] = m11;
1521+ r[1] = m21;
1522+ r[2] = m31;
1523+ r[3] = m41;
1524+ r[4] = m12;
1525+ r[5] = m22;
1526+ r[6] = m32;
1527+ r[7] = m42;
1528+ r[8] = m13;
1529+ r[9] = m23;
1530+ r[10] = m33;
1531+ r[11] = m43;
1532+ r[12] = m11 * x + m12 * y + m13 * z + m[12];
1533+ r[13] = m21 * x + m22 * y + m23 * z + m[13];
1534+ r[14] = m31 * x + m32 * y + m33 * z + m[14];
1535+ r[15] = m41 * x + m42 * y + m43 * z + m[15];
1536+
1537+ return r;
1538+ };
1539+
1540+ /*
1541+ * Function: M4x4.makeLookAt
1542+ */
1543+ M4x4.makeLookAt = function M4x4_makeLookAt (eye, center, up, r) {
1544+ //MathUtils_assert(eye.length == 3, "eye.length == 3");
1545+ //MathUtils_assert(center.length == 3, "center.length == 3");
1546+ //MathUtils_assert(up.length == 3, "up.length == 3");
1547+ //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16");
1548+
1549+ var z = V3.direction(eye, center, V3._temp1);
1550+ var x = V3.normalize(V3.cross(up, z, V3._temp2), V3._temp2);
1551+ var y = V3.normalize(V3.cross(z, x, V3._temp3), V3._temp3);
1552+
1553+ var tm1 = M4x4._temp1;
1554+ var tm2 = M4x4._temp2;
1555+
1556+ tm1[0] = x[0];
1557+ tm1[1] = y[0];
1558+ tm1[2] = z[0];
1559+ tm1[3] = 0;
1560+ tm1[4] = x[1];
1561+ tm1[5] = y[1];
1562+ tm1[6] = z[1];
1563+ tm1[7] = 0;
1564+ tm1[8] = x[2];
1565+ tm1[9] = y[2];
1566+ tm1[10] = z[2];
1567+ tm1[11] = 0;
1568+ tm1[12] = 0;
1569+ tm1[13] = 0;
1570+ tm1[14] = 0;
1571+ tm1[15] = 1;
1572+
1573+ tm2[0] = 1; tm2[1] = 0; tm2[2] = 0; tm2[3] = 0;
1574+ tm2[4] = 0; tm2[5] = 1; tm2[6] = 0; tm2[7] = 0;
1575+ tm2[8] = 0; tm2[9] = 0; tm2[10] = 1; tm2[11] = 0;
1576+ tm2[12] = -eye[0]; tm2[13] = -eye[1]; tm2[14] = -eye[2]; tm2[15] = 1;
1577+
1578+ if (r == undefined)
1579+ r = new MJS_FLOAT_ARRAY_TYPE(16);
1580+ return M4x4.mul(tm1, tm2, r);
1581+ };
1582+
1583+ /*
1584+ * Function: M4x4.transposeSelf
1585+ */
1586+ M4x4.transposeSelf = function M4x4_transposeSelf (m) {
1587+ //MathUtils_assert(m.length == 16, "m.length == 16");
1588+ var tmp = m[1]; m[1] = m[4]; m[4] = tmp;
1589+ tmp = m[2]; m[2] = m[8]; m[8] = tmp;
1590+ tmp = m[3]; m[3] = m[12]; m[12] = tmp;
1591+ tmp = m[6]; m[6] = m[9]; m[9] = tmp;
1592+ tmp = m[7]; m[7] = m[13]; m[13] = tmp;
1593+ tmp = m[11]; m[11] = m[14]; m[14] = tmp;
1594+ return m;
1595+ };
1596+ /*
1597+ * Function: M4x4.transpose
1598+ */
1599+ M4x4.transpose = function M4x4_transpose (m, r) {
1600+ //MathUtils_assert(m.length == 16, "m.length == 16");
1601+ //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16");
1602+
1603+ if (m == r) {
1604+ var tmp = 0.0;
1605+ tmp = m[1]; m[1] = m[4]; m[4] = tmp;
1606+ tmp = m[2]; m[2] = m[8]; m[8] = tmp;
1607+ tmp = m[3]; m[3] = m[12]; m[12] = tmp;
1608+ tmp = m[6]; m[6] = m[9]; m[9] = tmp;
1609+ tmp = m[7]; m[7] = m[13]; m[13] = tmp;
1610+ tmp = m[11]; m[11] = m[14]; m[14] = tmp;
1611+ return m;
1612+ }
1613+
1614+ if (r == undefined)
1615+ r = new MJS_FLOAT_ARRAY_TYPE(16);
1616+
1617+ r[0] = m[0]; r[1] = m[4]; r[2] = m[8]; r[3] = m[12];
1618+ r[4] = m[1]; r[5] = m[5]; r[6] = m[9]; r[7] = m[13];
1619+ r[8] = m[2]; r[9] = m[6]; r[10] = m[10]; r[11] = m[14];
1620+ r[12] = m[3]; r[13] = m[7]; r[14] = m[11]; r[15] = m[15];
1621+
1622+ return r;
1623+ };
1624+
1625+
1626+ /*
1627+ * Function: M4x4.transformPoint
1628+ */
1629+ M4x4.transformPoint = function M4x4_transformPoint (m, v, r) {
1630+ //MathUtils_assert(m.length == 16, "m.length == 16");
1631+ //MathUtils_assert(v.length == 3, "v.length == 3");
1632+ //MathUtils_assert(r == undefined || r.length == 3, "r == undefined || r.length == 3");
1633+ if (r == undefined)
1634+ r = new MJS_FLOAT_ARRAY_TYPE(3);
1635+
1636+ var v0 = v[0], v1 = v[1], v2 = v[2];
1637+
1638+ r[0] = m[0] * v0 + m[4] * v1 + m[8] * v2 + m[12];
1639+ r[1] = m[1] * v0 + m[5] * v1 + m[9] * v2 + m[13];
1640+ r[2] = m[2] * v0 + m[6] * v1 + m[10] * v2 + m[14];
1641+ var w = m[3] * v0 + m[7] * v1 + m[11] * v2 + m[15];
1642+
1643+ if (w != 1.0) {
1644+ r[0] /= w;
1645+ r[1] /= w;
1646+ r[2] /= w;
1647+ }
1648+
1649+ return r;
1650+ };
1651+
1652+ /*
1653+ * Function: M4x4.transformLine
1654+ */
1655+ M4x4.transformLine = function M4x4_transformLine(m, v, r) {
1656+ //MathUtils_assert(m.length == 16, "m.length == 16");
1657+ //MathUtils_assert(v.length == 3, "v.length == 3");
1658+ //MathUtils_assert(r == undefined || r.length == 3, "r == undefined || r.length == 3");
1659+ if (r == undefined)
1660+ r = new MJS_FLOAT_ARRAY_TYPE(3);
1661+
1662+ var v0 = v[0], v1 = v[1], v2 = v[2];
1663+ r[0] = m[0] * v0 + m[4] * v1 + m[8] * v2;
1664+ r[1] = m[1] * v0 + m[5] * v1 + m[9] * v2;
1665+ r[2] = m[2] * v0 + m[6] * v1 + m[10] * v2;
1666+ var w = m[3] * v0 + m[7] * v1 + m[11] * v2;
1667+
1668+ if (w != 1.0) {
1669+ r[0] /= w;
1670+ r[1] /= w;
1671+ r[2] /= w;
1672+ }
1673+
1674+ return r;
1675+ };
1676+
1677+
1678+ /*
1679+ * Function: M4x4.transformPointAffine
1680+ */
1681+ M4x4.transformPointAffine = function M4x4_transformPointAffine (m, v, r) {
1682+ //MathUtils_assert(m.length == 16, "m.length == 16");
1683+ //MathUtils_assert(v.length == 3, "v.length == 3");
1684+ //MathUtils_assert(r == undefined || r.length == 3, "r == undefined || r.length == 3");
1685+ if (r == undefined)
1686+ r = new MJS_FLOAT_ARRAY_TYPE(3);
1687+
1688+ var v0 = v[0], v1 = v[1], v2 = v[2];
1689+
1690+ r[0] = m[0] * v0 + m[4] * v1 + m[8] * v2 + m[12];
1691+ r[1] = m[1] * v0 + m[5] * v1 + m[9] * v2 + m[13];
1692+ r[2] = m[2] * v0 + m[6] * v1 + m[10] * v2 + m[14];
1693+
1694+ return r;
1695+ };
1696+
1697+ /*
1698+ * Function: M4x4.transformLineAffine
1699+ */
1700+ M4x4.transformLineAffine = function M4x4_transformLineAffine(m, v, r) {
1701+ //MathUtils_assert(m.length == 16, "m.length == 16");
1702+ //MathUtils_assert(v.length == 3, "v.length == 3");
1703+ //MathUtils_assert(r == undefined || r.length == 3, "r == undefined || r.length == 3");
1704+ if (r == undefined)
1705+ r = new MJS_FLOAT_ARRAY_TYPE(3);
1706+
1707+ var v0 = v[0], v1 = v[1], v2 = v[2];
1708+ r[0] = m[0] * v0 + m[4] * v1 + m[8] * v2;
1709+ r[1] = m[1] * v0 + m[5] * v1 + m[9] * v2;
1710+ r[2] = m[2] * v0 + m[6] * v1 + m[10] * v2;
1711+
1712+ return r;
1713+ };
1714+
1715+ M4x4.makeBasis = function M4x4_makeBasis(vx,vy,vz) {
1716+
1717+ var r = new MJS_FLOAT_ARRAY_TYPE(16);
1718+
1719+ r[0] = vx[0];
1720+ r[1] = vx[1];
1721+ r[2] = vx[2];
1722+ r[3] = 0;
1723+ r[4] = vy[0];
1724+ r[5] = vy[1];
1725+ r[6] = vy[2];
1726+ r[7] = 0;
1727+ r[8] = vz[0];
1728+ r[9] = vz[1];
1729+ r[10] = vz[2];
1730+ r[11] = 0;
1731+ r[12] = 0;
1732+ r[13] = 0;
1733+ r[14] = 0;
1734+ r[15] = 1;
1735+
1736+ return r;
1737+
1738+ };
1739+
1740+ return {
1741+ V3: V3,
1742+ v3: F3(V3.$),
1743+ toTuple3: V3.toTuple3,
1744+ v3add: F2(V3.add),
1745+ v3sub: F2(V3.sub),
1746+ v3neg: V3.neg,
1747+ v3direction: F2(V3.direction),
1748+ v3length: V3.length,
1749+ v3lengthSquared: V3.lengthSquared,
1750+ v3normalize: V3.normalize,
1751+ v3scale: F2(V3.scale),
1752+ v3dot: F2(V3.dot),
1753+ v3cross: F2(V3.cross),
1754+ v3mul4x4: F2(V3.mul4x4),
1755+ M4x4:M4x4,
1756+ m4x4identity: M4x4.identity,
1757+ m4x4topLeft3x3: M4x4.topLeft3x3,
1758+ m4x4inverseOrthonormal: M4x4.inverseOrthonormal,
1759+ m4x4inverseTo3x3: M4x4.inverseTo3x3,
1760+ m4x4makeFrustum: F6(M4x4.makeFrustum),
1761+ m4x4makePerspective: F4(M4x4.makePerspective),
1762+ m4x4makeOrtho: F6(M4x4.makeOrtho),
1763+ m4x4makeOrtho2D: F4(M4x4.makeOrtho2D),
1764+ m4x4mul: F2(M4x4.mul),
1765+ m4x4Affine: F2(M4x4.mulAffine),
1766+ m4x4makeRotate: F2(M4x4.makeRotate),
1767+ m4x4rotate: F3(M4x4.rotate),
1768+ m4x4makeScale3: F3(M4x4.makeScale3),
1769+ m4x4makeScale1: M4x4.makeScale1,
1770+ m4x4makeScale: M4x4.makeScale,
1771+ m4x4scale3: F4(M4x4.scale3),
1772+ m4x4scale: F2(M4x4.scale),
1773+ m4x4makeTranslate3: F3(M4x4.makeTranslate3),
1774+ m4x4makeTranslate: M4x4.makeTranslate,
1775+ m4x4translate3: F4(M4x4.translate3),
1776+ m4x4translate: F2(M4x4.translate),
1777+ m4x4makeLookAt: F3(M4x4.makeLookAt),
1778+ m4x4transpose: M4x4.transpose,
1779+ m4x4transformPoint: F2(M4x4.transformPoint),
1780+ m4x4makeBasis: F3(M4x4.makeBasis),
1781+ };
1782+
1783+}
libraries/elm_dependencies.json+2
@@ -17,6 +17,7 @@
17 , "Graphics.Element"
17 , "Graphics.Element"
18 , "Graphics.Collage"
18 , "Graphics.Collage"
19 , "Graphics.Input"
19 , "Graphics.Input"
20+ , "Graphics.WebGL"
20 , "Graphics.Input.Field"
21 , "Graphics.Input.Field"
21 , "Http"
22 , "Http"
22 , "JavaScript.Experimental"
23 , "JavaScript.Experimental"
@@ -24,6 +25,7 @@
24 , "Keyboard"
25 , "Keyboard"
25 , "List"
26 , "List"
26 , "Maybe"
27 , "Maybe"
28+ , "MJS"
27 , "Mouse"
29 , "Mouse"
28 , "Random"
30 , "Random"
29 , "Regex"
31 , "Regex"
server/elm-server.cabal+2−2
@@ -1,5 +1,5 @@
1Name: elm-server
1Name: elm-server
2−Version: 0.11
2+Version: 0.12
3Synopsis: Server for developing Elm projects
3Synopsis: Server for developing Elm projects
4Description: Provides a standalone Snap server that serves static files.
4Description: Provides a standalone Snap server that serves static files.
5 For Elm files, it recompiles them and serves them as HTML,
5 For Elm files, it recompiles them and serves them as HTML,
@@ -33,7 +33,7 @@ Executable elm-server
33 containers >= 0.3,
33 containers >= 0.3,
34 directory,
34 directory,
35 filepath,
35 filepath,
36− Elm >= 0.11,
36+ Elm >= 0.12,
37 snap-core,
37 snap-core,
38 snap-server,
38 snap-server,
39 mtl,
39 mtl,
tests/test-files/good/Box.elmnew file+82
@@ -0,0 +1,82 @@
1+
2+module Box where
3+
4+import MJS (V3,M4x4,v3,makeRotate,makePerspective,makeLookAt,mul)
5+import Graphics.WebGL (Triangle, zipTriangle, Shader, Model, model, webgl)
6+import Window(dimensions)
7+
8+-- Define what our geometry looks like
9+
10+p0 = v3 1 1 1
11+p1 = v3 -1 1 1
12+p2 = v3 -1 -1 1
13+p3 = v3 1 -1 1
14+p4 = v3 1 -1 -1
15+p5 = v3 1 1 -1
16+p6 = v3 -1 1 -1
17+p7 = v3 -1 -1 -1
18+
19+front = [(p0,p1,p2),(p2,p3,p0)]
20+back = [(p5,p6,p7),(p7,p4,p5)]
21+right = [(p0,p3,p4),(p4,p5,p0)]
22+left = [(p1,p2,p7),(p7,p6,p1)]
23+top = [(p0,p5,p6),(p6,p1,p0)]
24+bottom = [(p3,p4,p7),(p7,p2,p3)]
25+
26+positions = front ++ back ++ right ++ left ++ top ++ bottom
27+
28+gray = v3 0.7 0.7 0.7
29+red = v3 1 0 0
30+green = v3 0 1 0
31+blue = v3 0 0 1
32+yellow = v3 1 1 0
33+purple = v3 0 1 1
34+
35+repeat n elem = map (\_ -> elem) [0..n-1]
36+
37+colors = concat . map (\c -> repeat 2 (c,c,c)) <| [gray,red,green,blue,yellow,purple]
38+
39+mesh : [Triangle {pos : V3, color : V3}]
40+mesh = zipWith (zipTriangle (\pos color -> { pos = pos, color = color })) positions colors
41+
42+vert : Shader {a | pos : V3, color : V3} {b | rot : M4x4, per : M4x4, cam : M4x4} {vcolor : V3}
43+vert = [glShader|
44+attribute vec3 pos;
45+attribute vec3 color;
46+uniform mat4 per;
47+uniform mat4 cam;
48+uniform mat4 rot;
49+varying vec3 vcolor;
50+void main () {
51+ gl_Position = per * cam * rot * vec4(pos, 1.0);
52+ vcolor = color;
53+}
54+|]
55+
56+frag : Shader {} {b | shade : Float} {vcolor : V3}
57+frag = [glShader|
58+precision mediump float;
59+uniform float shade;
60+varying vec3 vcolor;
61+void main () {
62+ gl_FragColor = shade * vec4(vcolor, 1.0);
63+}
64+|]
65+
66+per : M4x4
67+per = makePerspective 45 1 0.01 100
68+
69+cam : M4x4
70+cam = makeLookAt (v3 0 0 5) (v3 0 0 0) (v3 0 1 0)
71+
72+angle : Signal Float
73+angle = foldp (\_ n -> n + 0.02) 0 (fps 25)
74+
75+rot : Signal { rot : M4x4, per : M4x4, cam : M4x4, shade : Float }
76+rot = (\t -> { rot = mul (makeRotate (3*t) (v3 0 1 0)) (makeRotate (2*t) (v3 1 0 0)), per = per, cam = cam, shade = 0.8 }) <~ angle
77+
78+draw : Signal [Model]
79+draw = combine [ (\rot -> (model vert frag mesh rot)) <~ rot ]
80+
81+main = webgl <~ dimensions ~ draw
82+
tests/test-files/good/Crate.elmnew file+84
@@ -0,0 +1,84 @@
1+
2+module Crate where
3+
4+import Http (..)
5+import MJS (..)
6+import Graphics.WebGL (..)
7+
8+pul = {pos=v3 -1 1 0, coord=v3 0 1 0}
9+pur = {pos=v3 1 1 0, coord=v3 1 1 0}
10+pbl = {pos=v3 -1 -1 0, coord=v3 0 0 0}
11+pbr = {pos=v3 1 -1 0, coord=v3 1 0 0}
12+
13+face : [Triangle { pos : V3, coord : V3 }]
14+face = [(pul,pur,pbl),(pbl,pur,pbr)]
15+
16+rotFace : Float -> Float -> [Triangle { pos : V3, coord : V3 }]
17+rotFace turnH turnV =
18+ let x = makeRotate (turnV * pi / 2) (v3 1 0 0)
19+ y = makeRotate (turnH * pi / 2) (v3 0 1 0)
20+ s = makeTranslate (v3 0 0 1)
21+ t = mul (mul x y) s
22+ in map (mapTriangle (\x -> {x | pos <- mul4x4 t x.pos })) face
23+
24+mesh : [Triangle { pos : V3, coord : V3 }]
25+mesh = concat . map (uncurry rotFace) <|
26+ [ (0,0)
27+ , (1,0)
28+ , (2,0)
29+ , (3,0)
30+ , (0,1)
31+ , (0,-1)
32+ ]
33+
34+vert : Shader { pos : V3, coord : V3 } { u | view : M4x4 } { vcoord : V2 }
35+vert = [glShader|
36+attribute vec3 pos;
37+attribute vec3 coord;
38+uniform mat4 view;
39+varying vec2 vcoord;
40+void main () {
41+ gl_Position = view * vec4(pos, 1.0);
42+ vcoord = coord.xy;
43+}
44+|]
45+
46+frag : Shader {} { u | crate : Texture } { vcoord : V2 }
47+frag = [glShader|
48+precision mediump float;
49+uniform sampler2D crate;
50+varying vec2 vcoord;
51+void main () {
52+ gl_FragColor = texture2D(crate, vcoord);
53+}
54+|]
55+
56+crateTex : Signal (Response Texture)
57+crateTex = loadTex "woodCrate.JPG"
58+
59+per : M4x4
60+per = makePerspective 45 1 0.01 100
61+
62+cam : M4x4
63+cam = makeLookAt (v3 0 0 5) (v3 0 0 0) (v3 0 1 0)
64+
65+angle : Signal Float
66+angle = foldp (\_ n -> n + 0.02) 0 (fps 25)
67+
68+view : Float -> M4x4
69+view t =
70+ let x = makeRotate (2*t) (v3 1 0 0)
71+ y = makeRotate (3*t) (v3 0 1 0)
72+ in foldr mul identity [per,cam,y,x]
73+
74+content : Response Texture -> M4x4 -> [Model]
75+content response view = case response of
76+ Waiting -> []
77+ Failure i s -> []
78+ Success tex -> [model vert frag mesh { crate = tex, view = view }]
79+
80+main = webgl (400,400) <~ (content <~ crateTex ~ (view <~ angle))
81+
82+--main = asText (List.length mesh)
83+
84+
tests/test-files/good/woodCrate.JPGnew file

Binary file not shown.