This repository has been archived by the owner on Oct 9, 2019. It is now read-only.
forked from johnpmayer/elm-webgl
-
Notifications
You must be signed in to change notification settings - Fork 22
/
crate.elm
150 lines (112 loc) · 3.18 KB
/
crate.elm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import Math.Vector2 exposing (Vec2)
import Math.Vector3 exposing (..)
import Math.Matrix4 exposing (..)
import Task
import Time exposing (Time)
import WebGL exposing (..)
import Html exposing (Html)
import Html.App as Html
import AnimationFrame
import Html.Attributes exposing (width, height)
type alias Model =
{ texture : Maybe Texture
, theta : Float
}
type Action
= TextureError Error
| TextureLoaded Texture
| Animate Time
update : Action -> Model -> (Model, Cmd Action)
update action model =
case action of
TextureError err ->
(model, Cmd.none)
TextureLoaded texture ->
({model | texture = Just texture}, Cmd.none)
Animate dt ->
({model | theta = model.theta + dt / 10000}, Cmd.none)
init : (Model, Cmd Action)
init =
( {texture = Nothing, theta = 0}
, loadTexture "texture/woodCrate.jpg"
|> Task.perform TextureError TextureLoaded
)
main : Program Never
main =
Html.program
{ init = init
, view = view
, subscriptions = (\model -> AnimationFrame.diffs Animate)
, update = update
}
-- MESHES
crate : Drawable { pos:Vec3, coord:Vec3 }
crate =
Triangle <|
List.concatMap rotatedFace [ (0,0), (90,0), (180,0), (270,0), (0,90), (0,-90) ]
rotatedFace : (Float,Float) -> List ({ pos:Vec3, coord:Vec3 }, { pos:Vec3, coord:Vec3 }, { pos:Vec3, coord:Vec3 })
rotatedFace (angleX,angleY) =
let
x = makeRotate (degrees angleX) (vec3 1 0 0)
y = makeRotate (degrees angleY) (vec3 0 1 0)
t = x `mul` y `mul` makeTranslate (vec3 0 0 1)
each f (a,b,c) =
(f a, f b, f c)
in
List.map (each (\x -> {x | pos = transform t x.pos })) face
face : List ({ pos:Vec3, coord:Vec3 }, { pos:Vec3, coord:Vec3 }, { pos:Vec3, coord:Vec3 })
face =
let
topLeft = { pos = vec3 -1 1 0, coord = vec3 0 1 0 }
topRight = { pos = vec3 1 1 0, coord = vec3 1 1 0 }
bottomLeft = { pos = vec3 -1 -1 0, coord = vec3 0 0 0 }
bottomRight = { pos = vec3 1 -1 0, coord = vec3 1 0 0 }
in
[ (topLeft,topRight,bottomLeft)
, (bottomLeft,topRight,bottomRight)
]
-- VIEW
perspective : Float -> Mat4
perspective angle =
List.foldr mul Math.Matrix4.identity
[ perspectiveMatrix
, camera
, makeRotate (3*angle) (vec3 0 1 0)
, makeRotate (2*angle) (vec3 1 0 0)
]
perspectiveMatrix : Mat4
perspectiveMatrix =
makePerspective 45 1 0.01 100
camera : Mat4
camera =
makeLookAt (vec3 0 0 5) (vec3 0 0 0) (vec3 0 1 0)
view : Model -> Html Action
view {texture, theta} =
(case texture of
Nothing ->
[]
Just tex ->
[render vertexShader fragmentShader crate { crate = tex, perspective = perspective theta }]
)
|> WebGL.toHtml [width 400, height 400]
-- SHADERS
vertexShader : Shader { pos:Vec3, coord:Vec3 } { u | perspective:Mat4 } { vcoord:Vec2 }
vertexShader = [glsl|
attribute vec3 pos;
attribute vec3 coord;
uniform mat4 perspective;
varying vec2 vcoord;
void main () {
gl_Position = perspective * vec4(pos, 1.0);
vcoord = coord.xy;
}
|]
fragmentShader : Shader {} { u | crate:Texture } { vcoord:Vec2 }
fragmentShader = [glsl|
precision mediump float;
uniform sampler2D crate;
varying vec2 vcoord;
void main () {
gl_FragColor = texture2D(crate, vcoord);
}
|]