Importing code from previous merged project
This commit is contained in:
		
						commit
						33a452ad83
					
				
							
								
								
									
										16
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| /assg3-distrib/ | ||||
| *.pdf | ||||
| *.log | ||||
| *.swp | ||||
| *.suo | ||||
| *.html | ||||
| presentation/ | ||||
| final/ | ||||
| .idea/ | ||||
| *.zip | ||||
| elm-stuff/** | ||||
| !elm-stuff/packages/ | ||||
| !elm-stuff/packages/Zinggi/ | ||||
| !elm-stuff/packages/Zinggi/elm-obj-loader/ | ||||
| !elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/ | ||||
| !elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/** | ||||
							
								
								
									
										39
									
								
								README.org
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								README.org
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | ||||
| ### FPS Scene | ||||
| 
 | ||||
| You can walk around the scene with simple FPS controls. | ||||
| Open `scene.html` with an http server, you can use the following; | ||||
| 
 | ||||
| ```python3 -m http.server 8000``` | ||||
| 
 | ||||
| Unfortunately, elm-reactor has issues with loading obj files so that's why the | ||||
| python server is needed. | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| 
 | ||||
| ##### Controls | ||||
| 
 | ||||
| Mouse - Look Rotation | ||||
| 
 | ||||
| WASD - Player movement | ||||
| 
 | ||||
| ◀ ▼ ▲ ▶ - Move the Robot | ||||
| 
 | ||||
| N and M - Rotate robot left and right | ||||
| 
 | ||||
| Y and H - Rotate robot arm up and down | ||||
| 
 | ||||
| U and J - Rotate robot hand up and down | ||||
| 
 | ||||
| 
 | ||||
| ### PQTorusknot | ||||
| 
 | ||||
| Either open up `torus.html`, or use the command `elm-reactor`, if you want to be able to modify the source file and compile; | ||||
| 
 | ||||
| https://guide.elm-lang.org/install.html | ||||
| 
 | ||||
| Alternatively, here's the Ellie link | ||||
| 
 | ||||
| https://ellie-app.com/vVTgpBj77ra1 | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										379
									
								
								Scene.elm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										379
									
								
								Scene.elm
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,379 @@ | ||||
| module Scene exposing (..) | ||||
| 
 | ||||
| import Html exposing (Html) | ||||
| import Html.Attributes exposing (width, height, style) | ||||
| import AnimationFrame | ||||
| import Time exposing (Time) | ||||
| import Dict exposing (..) | ||||
| import Math.Matrix4 as Mat4 exposing (Mat4) | ||||
| import Math.Vector2 as Vec2 exposing (vec2, Vec2) | ||||
| import Math.Vector3 as Vec3 exposing (vec3, Vec3) | ||||
| import WebGL exposing (Mesh, Shader) | ||||
| import Mouse | ||||
| import Keyboard exposing (..) | ||||
| import Task | ||||
| import WebGL.Texture as Texture exposing (..) | ||||
| import Color exposing (..) | ||||
| import Window | ||||
| import OBJ | ||||
| import OBJ.Types | ||||
| import Shaders exposing (..) | ||||
| 
 | ||||
| type alias ObjVert = OBJ.Types.Vertex | ||||
| type alias ObjMesh = OBJ.Types.MeshWith ObjVert | ||||
| 
 | ||||
| main : Program Never Model Msg | ||||
| main = Html.program | ||||
|     { init = init | ||||
|     , view = view | ||||
|     , update = update | ||||
|     , subscriptions = subscriptions } | ||||
| 
 | ||||
| 
 | ||||
| type alias Model = | ||||
|     { texDict : Dict String Texture | ||||
|     , objDict : Dict String ObjMesh | ||||
|     , rot : Float | ||||
|     , winSize : Window.Size | ||||
|     , keys : Keys | ||||
|     , pos : Vec3 | ||||
|     , pitchAndYaw : ( Float , Float ) | ||||
|     , lookDir : Vec3 | ||||
|     , lastMousePos : Mouse.Position | ||||
|     , robot : Robot } | ||||
| 
 | ||||
| type alias Robot = { pos : Vec3 , rot : Float , armRot : Float , handRot : Float } | ||||
| 
 | ||||
| type alias Keys = | ||||
|     { left : Bool , down : Bool , up : Bool , right : Bool | ||||
|     , w : Bool , a : Bool , s : Bool , d : Bool | ||||
|     , y : Bool , h : Bool , u : Bool , j : Bool | ||||
|     , n : Bool , m : Bool } | ||||
| 
 | ||||
| type Msg | ||||
|     = TextureLoaded (Result Texture.Error (String , Texture)) | ||||
|     | ObjLoaded (Result String (String , ObjMesh)) | ||||
|     | Animate Time | ||||
|     | WindowResized Window.Size | ||||
|     | MouseMove Mouse.Position | ||||
|     | KeyChange Bool Keyboard.KeyCode | ||||
| 
 | ||||
| init: ( Model , Cmd Msg ) | ||||
| init = | ||||
|     ( Model | ||||
|         Dict.empty | ||||
|         Dict.empty | ||||
|         0 | ||||
|         (Window.Size 1 1) | ||||
|         -- God this is horrendous | ||||
|         (Keys False False False False False False False False False False False False False False) | ||||
|         (vec3 0 0 -10) | ||||
|         (0 , -90) | ||||
|         (vec3 0 0 1) | ||||
|         { x = 0 , y = 0 } | ||||
|         { pos = vec3 0 -0.5 -3 , rot = 45 , armRot = 0 , handRot = 0 } | ||||
|     , Cmd.batch | ||||
|         [ loadTex "Thwomp" "textures/thwomp-face.jpg" | ||||
|         , loadTex "UV" "textures/uv_big.png" | ||||
|         , loadTex "Tetra" "textures/tetra.png" | ||||
|         , loadObj "Teapot" "models/suz.obj" | ||||
|         , Task.perform WindowResized Window.size] ) | ||||
| 
 | ||||
| loadTex: String -> String -> Cmd Msg | ||||
| loadTex id path = | ||||
|     Task.attempt TextureLoaded (Texture.load path |> Task.map (\t -> (id , t) ) ) | ||||
| 
 | ||||
| loadObj: String -> String -> Cmd Msg | ||||
| loadObj id path = | ||||
|     OBJ.loadMeshWithoutTexture path (\ r -> Result.map (\ o -> (id , o)) r ) |> Cmd.map ObjLoaded | ||||
| 
 | ||||
| subscriptions: Model -> Sub Msg | ||||
| subscriptions _ = | ||||
|     Sub.batch | ||||
|         [ AnimationFrame.diffs Animate | ||||
|         , Window.resizes WindowResized | ||||
|         , Mouse.moves MouseMove | ||||
|         , Keyboard.downs (KeyChange True) | ||||
|         , Keyboard.ups (KeyChange False) ] | ||||
| 
 | ||||
| 
 | ||||
| update: Msg -> Model -> (Model , Cmd Msg) | ||||
| update msg model = | ||||
|     let m = case msg of | ||||
|             KeyChange b k -> { model | keys = getKeys b k model.keys } | ||||
|             Animate dt -> | ||||
|                 { model | ||||
|                 | pos = movePos | ||||
|                     (model.keys.a , model.keys.s , model.keys.w , model.keys.d) | ||||
|                     model.lookDir | ||||
|                     model.pos | ||||
|                     0.2 | ||||
|                 , robot = updateRobot model dt | ||||
|                 , rot = model.rot + 0.001 * dt} | ||||
|             WindowResized size -> { model | winSize = size } | ||||
|             TextureLoaded result -> | ||||
|                 case result of | ||||
|                     Ok (id , tex) -> { model | texDict = Dict.insert id tex model.texDict } | ||||
|                     Err e -> model | ||||
|             ObjLoaded result -> | ||||
|                 case result of | ||||
|                     Ok (id , obj) -> { model | objDict = Dict.insert id obj model.objDict } | ||||
|                     Err e -> model |> Debug.log e | ||||
|             MouseMove mp -> | ||||
|                 let (ld , py) = getLookPos model.lastMousePos mp model.pitchAndYaw | ||||
|                 in { model | lookDir = ld , lastMousePos = mp , pitchAndYaw = py } | ||||
|     in ( m , Cmd.none ) | ||||
| 
 | ||||
| updateRobot: Model -> Time -> Robot | ||||
| updateRobot { robot , keys } dt = | ||||
|     let rr part = part + dt * 0.005 | ||||
|         rl part = part - dt * 0.005 | ||||
|         rot = radians robot.rot | ||||
|     in { pos = | ||||
|            movePos | ||||
|                (keys.left, keys.down, keys.up, keys.right) | ||||
|                (vec3 (sin rot) (sin rot) (cos rot)) | ||||
|                robot.pos | ||||
|                0.1 | ||||
|     , rot = if keys.n then rr robot.rot else if keys.m then rl robot.rot else robot.rot | ||||
|     , armRot = | ||||
|         let angle = if keys.y then rr robot.armRot else if keys.h then rl robot.armRot else robot.armRot | ||||
|         in clamp -0.5 2.5 angle | ||||
|     , handRot = | ||||
|         let angle = if keys.u then rr robot.handRot else if keys.j then rl robot.handRot else robot.handRot | ||||
|         in clamp -1 1 angle} | ||||
| 
 | ||||
| view: Model -> Html Msg | ||||
| view model = | ||||
|     WebGL.toHtml | ||||
|         [ width model.winSize.width , height model.winSize.height , style [ ( "display" , "block") ] ] | ||||
|         ([ getEntity model wall texturedPlane "Thwomp" | ||||
|         , getEntity model tetraB tetraBasic "UV" | ||||
|         , getEntity model tetra tetraF "Tetra" | ||||
|         , getRobot model | ||||
|         , getModel model (Mat4.makeRotate model.rot Vec3.j) "Teapot" | ||||
|         , getEntity model floor texturedPlane "UV" ] |> List.concat) | ||||
| 
 | ||||
| getRobot: Model -> List WebGL.Entity | ||||
| getRobot model = | ||||
|     let body = Mat4.makeTranslate model.robot.pos | ||||
|             |> Mat4.rotate model.robot.rot Vec3.j | ||||
|         arm  = Mat4.makeTranslate3 0 0 -0.35 | ||||
|             |> Mat4.rotate model.robot.armRot Vec3.i | ||||
|             |> Mat4.inverse |> Maybe.withDefault Mat4.identity | ||||
|             |> Mat4.mul (Mat4.makeTranslate3 0 0.5 0.5) | ||||
|             |> Mat4.mul body | ||||
|         hand = Mat4.makeTranslate3 0 0 -0.25 | ||||
|             |> Mat4.rotate model.robot.handRot Vec3.i | ||||
|             |> Mat4.inverse |> Maybe.withDefault Mat4.identity | ||||
|             |> Mat4.mul (Mat4.makeTranslate3 0 0 0.6) | ||||
|             |> Mat4.mul arm | ||||
|     in [ getEntity3 model (body |> Mat4.scale3 0.5 0.5 0.5) cube Color.blue | ||||
|        , getEntity3 model (arm |> Mat4.scale3 0.2 0.2 0.5) cube Color.green | ||||
|        , getEntity3 model (hand |> Mat4.scale3 0.15 0.15 0.45) cube Color.red | ||||
|        ] |> List.concat | ||||
| 
 | ||||
| getModel: Model -> Mat4 -> String -> List WebGL.Entity | ||||
| getModel model local id = | ||||
|     case Dict.get id model.objDict of | ||||
|         Just mesh -> | ||||
|             case Dict.get "UV" model.texDict of | ||||
|                 Just t -> [ WebGL.entity | ||||
|                     diffuseVS | ||||
|                     diffuseFS | ||||
|                     (WebGL.indexedTriangles mesh.vertices mesh.indices) | ||||
|                     (DiffuseColor | ||||
|                         (projectionMatrix model) | ||||
|                         (viewMatrix model) | ||||
|                         local | ||||
|                         (colorToVec3 Color.blue) | ||||
|                         (vec3 1 1 0) | ||||
|                         (vec3 1 0 1) | ||||
|                         (vec3 0 0 1) | ||||
|                         1.0) ] | ||||
|                 Nothing -> [] | ||||
|         Nothing -> [] | ||||
| 
 | ||||
| getEntity: Model -> Mat4 -> Mesh UTVertex -> String -> List WebGL.Entity | ||||
| getEntity model local mesh texId = | ||||
|     case Dict.get texId model.texDict of | ||||
|         Just t -> | ||||
|             [ WebGL.entity | ||||
|                 unlitTexturedVS | ||||
|                 unlitTexturedFS | ||||
|                 mesh | ||||
|                 (UnlitTextured (projectionMatrix model) (viewMatrix model ) local t) ] | ||||
|         Nothing -> [] | ||||
| 
 | ||||
| getEntity2: Model -> Mat4 -> Mesh ObjVert -> Color -> List WebGL.Entity | ||||
| getEntity2 model local mesh color = | ||||
|     [ WebGL.entity | ||||
|         unlitColorVS | ||||
|         unlitColorFS | ||||
|         mesh | ||||
|         (UnlitColor (projectionMatrix model) (viewMatrix model ) local (colorToVec3 color) ) ] | ||||
| 
 | ||||
| getEntity3: Model -> Mat4 -> Mesh ObjVert -> Color -> List WebGL.Entity | ||||
| getEntity3 model local mesh color = | ||||
|     [ WebGL.entity | ||||
|         diffuseVS | ||||
|         diffuseFS | ||||
|         mesh | ||||
|         (DiffuseColor | ||||
|             (projectionMatrix model) | ||||
|             (viewMatrix model) | ||||
|             local | ||||
|             (colorToVec3 color) | ||||
|             (vec3 1 1 0) | ||||
|             (vec3 1 0 1) | ||||
|             (vec3 0 0 1) | ||||
|             1.0 ) ] | ||||
| 
 | ||||
| projectionMatrix: Model -> Mat4 | ||||
| projectionMatrix model = | ||||
|     Mat4.makePerspective 50 (toFloat model.winSize.width / toFloat model.winSize.height) 0.01 1000 | ||||
| 
 | ||||
| viewMatrix: Model -> Mat4 | ||||
| viewMatrix model = | ||||
|     Mat4.makeLookAt model.pos (Vec3.add model.pos model.lookDir) Vec3.j | ||||
| 
 | ||||
| getLookPos: Mouse.Position -> Mouse.Position -> ( Float , Float ) -> ( Vec3 , (Float , Float) ) | ||||
| getLookPos lmp mp ( lastPitch , lastYaw ) = | ||||
|     let sensitivity = 0.0039 | ||||
|         rangeY = 89 | ||||
|         ox = mp.x - lmp.x |> toFloat | ||||
|         oy = lmp.y - mp.y |> toFloat | ||||
|         yaw = ox * sensitivity + lastYaw |> radians | ||||
|         pitch = -oy * sensitivity + lastPitch |> radians | ||||
|         pitch_ = if pitch > rangeY then rangeY else if pitch < -rangeY then -rangeY else pitch | ||||
|         lookDir = vec3 (cos yaw * cos pitch_) (sin pitch_) (sin yaw * cos pitch_) | ||||
|     in (Vec3.normalize lookDir , ( pitch_ , yaw ) ) | ||||
| 
 | ||||
| colorToVec3: Color -> Vec3 | ||||
| colorToVec3 color = | ||||
|     let to01 x = toFloat x / 255 | ||||
|         c = Color.toRgb color | ||||
|     in vec3 (to01 c.red) (to01 c.green) (to01 c.blue) | ||||
| 
 | ||||
| movePos: (Bool, Bool, Bool, Bool) -> Vec3 -> Vec3 -> Float -> Vec3 | ||||
| movePos ( left , down , up , right ) lookDir pos speed = | ||||
|     let lookDir_ = Vec3.setY 0 lookDir | ||||
|         forward = if up then 1 else if down then -1 else 0 | ||||
|         strafe = if right then 1 else if left then -1 else 0 | ||||
|         cross = Vec3.cross lookDir_ Vec3.j | ||||
|         dir = Vec3.add (Vec3.scale strafe cross) (Vec3.scale forward lookDir_) | ||||
|         dir_ = if Vec3.length dir <= 0 then dir else Vec3.normalize dir | ||||
|     in Vec3.add pos <| Vec3.scale speed dir_ | ||||
| 
 | ||||
| getKeys: Bool -> KeyCode -> Keys -> Keys | ||||
| getKeys isOn code keys = | ||||
|     case code of | ||||
|         -- ◀ ▼ ▲ ▶ | ||||
|         37 -> { keys | left = isOn } | ||||
|         40 -> { keys | down = isOn } | ||||
|         38 -> { keys | up = isOn } | ||||
|         39 -> { keys | right = isOn } | ||||
|         -- WASD | ||||
|         87 -> { keys | w = isOn } | ||||
|         65 -> { keys | a = isOn } | ||||
|         83 -> { keys | s = isOn } | ||||
|         68 -> { keys | d = isOn } | ||||
|         -- YHUJNM | ||||
|         89 -> { keys | y = isOn } | ||||
|         72 -> { keys | h = isOn } | ||||
|         85 -> { keys | u = isOn } | ||||
|         74 -> { keys | j = isOn } | ||||
|         78 -> { keys | n = isOn } | ||||
|         77 -> { keys | m = isOn } | ||||
|         _ -> keys | ||||
| 
 | ||||
| 
 | ||||
| ------------- | ||||
| -- Geometry | ||||
| ------------- | ||||
| 
 | ||||
| wall = Mat4.makeTranslate3 0 0 3 | ||||
| floor = Mat4.makeTranslate3 0 -1 0 | ||||
|         |> Mat4.rotate (pi / -2) ( vec3 1 0 0) | ||||
|         |> Mat4.rotate pi ( vec3 0 0 1) | ||||
|         |> Mat4.scale3 15 15 0 | ||||
| tetraB = Mat4.makeTranslate3 -5 1.5 5 | ||||
|         |> Mat4.scale3 2 2 2 | ||||
| tetra = Mat4.makeTranslate3 5 0 5 | ||||
| 
 | ||||
| -- right/left front/back top/bottom | ||||
| cube: Mesh ObjVert | ||||
| cube = | ||||
|     let rtf = vec3 1 1 1 | ||||
|         ltf = vec3 -1 1 1 | ||||
|         ltb = vec3 -1 1 -1 | ||||
|         rtb = vec3 1 1 -1 | ||||
|         rbb = vec3 1 -1 -1 | ||||
|         rbf = vec3 1 -1 1 | ||||
|         lbf = vec3 -1 -1 1 | ||||
|         lbb = vec3 -1 -1 -1 | ||||
|         front = Vec3.k | ||||
|         back = Vec3.scale -1 front | ||||
|         top = Vec3.j | ||||
|         bottom = Vec3.scale -1 top | ||||
|         right = Vec3.i | ||||
|         left = Vec3.scale -1 right | ||||
|     in | ||||
|         [ face right rtf rbf rbb rtb | ||||
|         , face left ltf lbf lbb ltb | ||||
|         , face front rtf rbf lbf ltf | ||||
|         , face back rtb rbb lbb ltb | ||||
|         , face top rtf ltf ltb rtb | ||||
|         , face bottom rbf lbf lbb rbb | ||||
|         ] |> List.concat | ||||
|           |> WebGL.triangles | ||||
| 
 | ||||
| face: Vec3 -> Vec3 -> Vec3 -> Vec3 -> Vec3 -> List (ObjVert , ObjVert , ObjVert) | ||||
| face norm a b c d = | ||||
|     let v pos = OBJ.Types.Vertex pos norm | ||||
|     in [ ( v a , v b , v c ) , ( v c , v d , v a ) ] | ||||
| 
 | ||||
| tetraBasic: Mesh UTVertex | ||||
| tetraBasic = | ||||
|     let peak = UTVertex (vec3 0 1 0) (vec2 1 1) | ||||
|         bottomLeft = UTVertex (vec3 -1 -1 -1) (vec2 0 0) | ||||
|         bottomRight = UTVertex (vec3 -1 -1 1) (vec2 1 0) | ||||
|         topLeft = UTVertex (vec3 1 -1 1) (vec2 0 0) | ||||
|         topRight = UTVertex (vec3 1 -1 -1) (vec2 0 1) | ||||
|     in [ ( peak , bottomLeft , bottomRight ) | ||||
|        , ( peak , bottomLeft , topRight ) | ||||
|        , ( peak , bottomRight , topLeft ) | ||||
|        , ( peak , topRight , topLeft ) | ||||
|        , ( bottomLeft , bottomRight , topRight) | ||||
|        , ( bottomRight, topLeft , topRight ) ] | ||||
|        |> WebGL.triangles | ||||
| 
 | ||||
| tetraF: Mesh UTVertex | ||||
| tetraF = | ||||
|     let f0a = UTVertex (vec3 -1 -1 1) (vec2 0 0.5) | ||||
|         f0b = UTVertex (vec3 1 -1 1) (vec2 0.5 0.5) | ||||
|         f0c = UTVertex (vec3 0 1 0) (vec2 0.25 1) | ||||
| 
 | ||||
|         f1a = UTVertex (vec3 -1 -1 -1) (vec2 0.5 0.5) | ||||
|         f1b = UTVertex (vec3 -1 -1 1) (vec2 1 0.5) | ||||
|         f1c = UTVertex (vec3 0 1 0) (vec2 0.75 1) | ||||
| 
 | ||||
|         f2a = UTVertex (vec3 1 -1 -1) (vec2 0 0) | ||||
|         f2b = UTVertex (vec3 -1 -1 -1) (vec2 0.5 0) | ||||
|         f2c = UTVertex (vec3 0 1 0) (vec2 0.25 0.5) | ||||
| 
 | ||||
|         f3a = UTVertex (vec3 1 -1 1) (vec2 0.5 0) | ||||
|         f3b = UTVertex (vec3 1 -1 -1) (vec2 1 0) | ||||
|         f3c = UTVertex (vec3 0 1 0) (vec2 0.75 0.5) | ||||
|     in [ ( f0a , f0b , f0c ) , ( f1a , f1b , f1c ) , ( f2a , f2b , f2c ) , ( f3a , f3b , f3c ) ] | ||||
|        |> WebGL.triangles | ||||
| 
 | ||||
| texturedPlane: Mesh UTVertex | ||||
| texturedPlane = | ||||
|     let topLeft = UTVertex (vec3 -1 1 1) (vec2 0 1) | ||||
|         topRight = UTVertex (vec3 1 1 1) (vec2 1 1) | ||||
|         bottomLeft = UTVertex (vec3 -1 -1 1) (vec2 0 0) | ||||
|         bottomRight = UTVertex (vec3 1 -1 1) (vec2 1 0) | ||||
|     in [ ( topLeft, topRight, bottomLeft ) , ( bottomLeft, topRight, bottomRight ) ] | ||||
|        |> WebGL.triangles | ||||
| 
 | ||||
							
								
								
									
										130
									
								
								Shaders.elm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								Shaders.elm
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,130 @@ | ||||
| module Shaders exposing (..) | ||||
| 
 | ||||
| import Math.Matrix4 as Mat4 exposing (Mat4) | ||||
| import Math.Vector2 as Vec2 exposing (vec2, Vec2) | ||||
| import Math.Vector3 as Vec3 exposing (vec3, Vec3) | ||||
| import WebGL exposing (Mesh, Shader) | ||||
| import WebGL.Texture as Texture exposing (..) | ||||
| import OBJ | ||||
| import OBJ.Types | ||||
| 
 | ||||
| type alias UTVertex = { position : Vec3 , coord : Vec2 } | ||||
| type alias ColorVertex = { position : Vec3 , normal : Vec3 , color : Vec3 } | ||||
| 
 | ||||
| type alias UnlitColor = { projection : Mat4 , view : Mat4 , model : Mat4 , color : Vec3 } | ||||
| type alias UnlitTextured = { projection : Mat4 , view : Mat4 , model : Mat4 , texture : Texture } | ||||
| type alias DiffuseColor = | ||||
|     { projection : Mat4 | ||||
|     , view : Mat4 | ||||
|     , model : Mat4 | ||||
|     , color : Vec3 | ||||
|     , ambient : Vec3 | ||||
|     , diffuse : Vec3 | ||||
|     , specular : Vec3 | ||||
|     , shininess : Float } | ||||
| 
 | ||||
| 
 | ||||
| diffuseVS: Shader { position : Vec3 , normal : Vec3 } DiffuseColor { vlightWeight : Vec3 } | ||||
| diffuseVS = | ||||
|     [glsl| | ||||
|         attribute vec3 position; | ||||
|         attribute vec3 normal; | ||||
|         uniform mat4 projection; | ||||
|         uniform mat4 view; | ||||
|         uniform mat4 model; | ||||
|         uniform vec3 ambient; | ||||
|         uniform vec3 diffuse; | ||||
|         uniform vec3 specular; | ||||
|         uniform float shininess; | ||||
|         varying vec3 vlightWeight; | ||||
| 
 | ||||
|         void main() | ||||
|         { | ||||
|             gl_Position = projection * view * model * vec4(position, 1.0); | ||||
| 
 | ||||
|             vec3 lightDir = normalize(vec3(0.0, -0.0, -1.0)); | ||||
|             vec4 norm =  model * vec4(normal, 0.0); | ||||
|             vec3 n = norm.xyz; | ||||
|             float dir = max(dot(n, lightDir), 0.0); | ||||
|             float v = 0.5; | ||||
|             vlightWeight = diffuse * dir + vec3(v, v, v); | ||||
|         } | ||||
|     |] | ||||
| 
 | ||||
| diffuseFS: Shader {} DiffuseColor { vlightWeight : Vec3 } | ||||
| diffuseFS = | ||||
|     [glsl| | ||||
| 
 | ||||
|         precision mediump float; | ||||
|         uniform vec3 color; | ||||
|         varying vec3 vlightWeight; | ||||
| 
 | ||||
|         void main() | ||||
|         { | ||||
|             gl_FragColor = vec4(color * vlightWeight, 1.0); | ||||
|         } | ||||
|     |] | ||||
| 
 | ||||
| 
 | ||||
| unlitColorVS: Shader OBJ.Types.Vertex UnlitColor { vcolor : Vec3 } | ||||
| unlitColorVS = | ||||
|     [glsl| | ||||
|         attribute vec3 position; | ||||
|         attribute vec3 normal; | ||||
|         uniform mat4 projection; | ||||
|         uniform mat4 view; | ||||
|         uniform mat4 model; | ||||
|         uniform vec3 color; | ||||
|         varying vec3 vcolor; | ||||
| 
 | ||||
|         void main() | ||||
|         { | ||||
|             gl_Position = projection * view * model * vec4(position, 1.0); | ||||
|             vcolor = color; | ||||
|         } | ||||
|     |] | ||||
| 
 | ||||
| unlitColorFS: Shader {} UnlitColor { vcolor : Vec3 } | ||||
| unlitColorFS = | ||||
|     [glsl| | ||||
| 
 | ||||
|         precision mediump float; | ||||
|         varying vec3 vcolor; | ||||
| 
 | ||||
|         void main() | ||||
|         { | ||||
|             gl_FragColor = vec4(vcolor, 1.0); | ||||
|         } | ||||
|     |] | ||||
| 
 | ||||
| 
 | ||||
| unlitTexturedVS: Shader { position : Vec3 , coord : Vec2 } UnlitTextured { vcoord : Vec2 } | ||||
| unlitTexturedVS = | ||||
|     [glsl| | ||||
|         attribute vec3 position; | ||||
|         attribute vec2 coord; | ||||
|         uniform mat4 projection; | ||||
|         uniform mat4 view; | ||||
|         uniform mat4 model; | ||||
|         varying vec2 vcoord; | ||||
| 
 | ||||
|         void main() | ||||
|         { | ||||
|             gl_Position = projection * view * model * vec4(position, 1.0); | ||||
|             vcoord = coord; | ||||
|         } | ||||
|     |] | ||||
| 
 | ||||
| unlitTexturedFS: Shader {} UnlitTextured { vcoord : Vec2 } | ||||
| unlitTexturedFS = | ||||
|     [glsl| | ||||
| 
 | ||||
|         precision mediump float; | ||||
|         uniform sampler2D texture; | ||||
|         varying vec2 vcoord; | ||||
| 
 | ||||
|         void main() | ||||
|         { | ||||
|             gl_FragColor = texture2D(texture, vcoord); | ||||
|         } | ||||
|     |] | ||||
							
								
								
									
										22
									
								
								elm-package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								elm-package.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| { | ||||
|     "version": "1.0.0", | ||||
|     "summary": "helpful summary of your project, less than 80 characters", | ||||
|     "repository": "https://github.com/user/project.git", | ||||
|     "license": "BSD3", | ||||
|     "source-directories": [ | ||||
|         "." | ||||
|     ], | ||||
|     "exposed-modules": [], | ||||
|     "dependencies": { | ||||
|         "Zinggi/elm-obj-loader": "1.0.3 <= v < 2.0.0", | ||||
|         "elm-community/linear-algebra": "3.1.2 <= v < 4.0.0", | ||||
|         "elm-community/webgl": "2.0.5 <= v < 3.0.0", | ||||
|         "elm-lang/animation-frame": "1.0.1 <= v < 2.0.0", | ||||
|         "elm-lang/core": "5.1.1 <= v < 6.0.0", | ||||
|         "elm-lang/html": "2.0.0 <= v < 3.0.0", | ||||
|         "elm-lang/keyboard": "1.0.1 <= v < 2.0.0", | ||||
|         "elm-lang/mouse": "1.0.1 <= v < 2.0.0", | ||||
|         "elm-lang/window": "1.0.1 <= v < 2.0.0" | ||||
|     }, | ||||
|     "elm-version": "0.18.0 <= v < 0.19.0" | ||||
| } | ||||
							
								
								
									
										6
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| elm-stuff/ | ||||
| index.html | ||||
| src/Main.elm | ||||
| documentation.json | ||||
| # this is only for debugging | ||||
| src/Native/ | ||||
							
								
								
									
										21
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/LICENSE
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/LICENSE
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| MIT License | ||||
| 
 | ||||
| Copyright (c) 2016 Florian Zinggeler | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | ||||
| in the Software without restriction, including without limitation the rights | ||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
| copies of the Software, and to permit persons to whom the Software is | ||||
| furnished to do so, subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| SOFTWARE. | ||||
							
								
								
									
										34
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/README.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/README.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| # elm-obj-loader | ||||
| 
 | ||||
| This is a small library for importing [wavefront .obj][objSpecs] files into your WebGL application. | ||||
| 
 | ||||
| # Demo/Examples | ||||
|  * [Model viewer][modelViewer] | ||||
|  * [Suzanne from Blender][suzanne] | ||||
| 
 | ||||
| [Src](/examples) | ||||
| 
 | ||||
| # Limitations | ||||
| Only a small subset of the .obj file specification is supported. | ||||
| 
 | ||||
| The easiest is to export/convert your model from Blender or another 3D content creation tool as an .obj file. | ||||
| 
 | ||||
| The default export options from blender work fine. Make sure you keep 'Write Normals' selected. | ||||
| 
 | ||||
| Completely supported face types are those with vertex position, normals and optionally vertex texture coordinates. (`v`, `vn`, `vt`) | ||||
| 
 | ||||
| Smooth groups are ignored (`s n`).   | ||||
| Your model needs vertex normals (`vn`).   | ||||
| 
 | ||||
| Only tris and quads are supported. (Tris might load slightly faster)     | ||||
| No free-form curves/surfaces.     | ||||
| No material library (mtllib) support.    | ||||
| No negative indexing.    | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| [suzanne]: https://zinggi.github.io/randomDemos/webgl/objLoader_simple.html | ||||
| [modelViewer]: https://zinggi.github.io/randomDemos/webgl/objLoader_modelViewer.html | ||||
| [objSpecs]: http://www.martinreddy.net/gfx/3d/OBJ.spec | ||||
							
								
								
									
										22
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/elm-package.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/elm-package.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| { | ||||
|     "version": "1.0.3", | ||||
|     "summary": "Load wavefront .obj files in your WebGL scene.", | ||||
|     "repository": "https://github.com/Zinggi/elm-obj-loader.git", | ||||
|     "license": "MIT", | ||||
|     "source-directories": [ | ||||
|         "src" | ||||
|     ], | ||||
|     "exposed-modules": [ | ||||
|         "OBJ", | ||||
|         "OBJ.Types" | ||||
|     ], | ||||
|     "dependencies": { | ||||
|         "Bogdanp/elm-combine": "3.1.1 <= v < 4.0.0", | ||||
|         "Skinney/elm-array-exploration": "2.0.1 <= v < 3.0.0", | ||||
|         "elm-community/linear-algebra": "3.1.0 <= v < 4.0.0", | ||||
|         "elm-community/webgl": "2.0.0 <= v < 3.0.0", | ||||
|         "elm-lang/core": "5.0.0 <= v < 6.0.0", | ||||
|         "elm-lang/http": "1.0.0 <= v < 2.0.0" | ||||
|     }, | ||||
|     "elm-version": "0.18.0 <= v < 0.19.0" | ||||
| } | ||||
							
								
								
									
										3
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/examples/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/examples/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| elm-stuff/ | ||||
| index.html | ||||
| testObjs/ | ||||
							
								
								
									
										299
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/examples/ElmLogo.elm
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										299
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/examples/ElmLogo.elm
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,299 @@ | ||||
| module ElmLogo exposing (..) | ||||
| 
 | ||||
| import AnimationFrame | ||||
| import Dict exposing (Dict) | ||||
| import Html exposing (Html, div, text) | ||||
| import Html.Attributes as Attr | ||||
| import Html.Events exposing (on, onInput, onCheck) | ||||
| import Json.Decode as JD | ||||
| import Math.Matrix4 as M4 exposing (Mat4) | ||||
| import Math.Vector3 as V3 exposing (Vec3, vec3) | ||||
| import Task | ||||
| import WebGL as GL | ||||
| import WebGL.Texture | ||||
| import WebGL.Settings exposing (cullFace, front) | ||||
| import WebGL.Settings.DepthTest as DepthTest | ||||
| import Mouse | ||||
| import Window | ||||
| 
 | ||||
| 
 | ||||
| -- | ||||
| 
 | ||||
| import Shaders | ||||
| import OBJ | ||||
| import OBJ.Types exposing (ObjFile, Mesh(..)) | ||||
| 
 | ||||
| 
 | ||||
| main : Program Never Model Msg | ||||
| main = | ||||
|     Html.program | ||||
|         { init = ( initModel, initCmd ) | ||||
|         , view = view | ||||
|         , subscriptions = subscriptions | ||||
|         , update = update | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| -- MODEL | ||||
| 
 | ||||
| 
 | ||||
| type alias Model = | ||||
|     { time : Float | ||||
|     , mesh : Result String ObjFile | ||||
|     , currentModel : String | ||||
|     , zoom : Float | ||||
|     , diffText : Result String GL.Texture | ||||
|     , normText : Result String GL.Texture | ||||
|     , isDown : Bool | ||||
|     , lastMousePos : Mouse.Position | ||||
|     , mouseDelta : MouseDelta | ||||
|     , windowSize : Window.Size | ||||
|     , withTangent : Bool | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| type alias MouseDelta = | ||||
|     { x : Float, y : Float } | ||||
| 
 | ||||
| 
 | ||||
| initModel : Model | ||||
| initModel = | ||||
|     { mesh = Err "loading ..." | ||||
|     , currentModel = "meshes/elmLogo.obj" | ||||
|     , time = 0 | ||||
|     , zoom = 5 | ||||
|     , diffText = Err "Loading texture..." | ||||
|     , normText = Err "Loading texture..." | ||||
|     , isDown = False | ||||
|     , lastMousePos = Mouse.Position 0 0 | ||||
|     , mouseDelta = MouseDelta 0 (pi / 2) | ||||
|     , windowSize = Window.Size 800 600 | ||||
|     , withTangent = True | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| models : List String | ||||
| models = | ||||
|     [ "meshes/elmLogo.obj" | ||||
|     , "meshes/suzanneNoUV.obj" | ||||
|     ] | ||||
| 
 | ||||
| 
 | ||||
| initCmd : Cmd Msg | ||||
| initCmd = | ||||
|     Cmd.batch | ||||
|         [ loadModel True "meshes/elmLogo.obj" | ||||
|         , loadTexture "textures/elmLogoDiffuse.png" DiffTextureLoaded | ||||
|         , loadTexture "textures/elmLogoNorm.png" NormTextureLoaded | ||||
|         , Task.perform ResizeWindow Window.size | ||||
|         ] | ||||
| 
 | ||||
| 
 | ||||
| loadModel : Bool -> String -> Cmd Msg | ||||
| loadModel withTangents url = | ||||
|     OBJ.loadObjFileWith { withTangents = withTangents } url (LoadObj url) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| -- UPDATE | ||||
| 
 | ||||
| 
 | ||||
| type Msg | ||||
|     = Tick Float | ||||
|     | LoadObj String (Result String (Dict String (Dict String Mesh))) | ||||
|     | Zoom Float | ||||
|     | MouseMove Mouse.Position | ||||
|     | MouseDown Mouse.Position | ||||
|     | MouseUp | ||||
|     | DiffTextureLoaded (Result String GL.Texture) | ||||
|     | NormTextureLoaded (Result String GL.Texture) | ||||
|     | ResizeWindow Window.Size | ||||
|     | SelectMesh String | ||||
|     | SetUseTangent Bool | ||||
| 
 | ||||
| 
 | ||||
| update : Msg -> Model -> ( Model, Cmd Msg ) | ||||
| update msg model = | ||||
|     case msg of | ||||
|         Tick dt -> | ||||
|             ( { model | time = model.time + dt / 1000 }, Cmd.none ) | ||||
| 
 | ||||
|         Zoom dy -> | ||||
|             ( { model | zoom = max 0.01 (model.zoom + dy / 100) }, Cmd.none ) | ||||
| 
 | ||||
|         SelectMesh url -> | ||||
|             ( model, loadModel model.withTangent url ) | ||||
| 
 | ||||
|         SetUseTangent t -> | ||||
|             ( { model | withTangent = t }, loadModel t model.currentModel ) | ||||
| 
 | ||||
|         LoadObj url mesh -> | ||||
|             ( { model | mesh = mesh, currentModel = url }, Cmd.none ) | ||||
| 
 | ||||
|         DiffTextureLoaded t -> | ||||
|             ( { model | diffText = t }, Cmd.none ) | ||||
| 
 | ||||
|         NormTextureLoaded t -> | ||||
|             ( { model | normText = t }, Cmd.none ) | ||||
| 
 | ||||
|         MouseDown p -> | ||||
|             ( { model | isDown = True, lastMousePos = p }, Cmd.none ) | ||||
| 
 | ||||
|         MouseUp -> | ||||
|             ( { model | isDown = False }, Cmd.none ) | ||||
| 
 | ||||
|         MouseMove p -> | ||||
|             ( { model | mouseDelta = getDelta p model.lastMousePos model.mouseDelta, lastMousePos = p }, Cmd.none ) | ||||
| 
 | ||||
|         ResizeWindow w -> | ||||
|             ( { model | windowSize = w }, Cmd.none ) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| -- VIEW / RENDER | ||||
| 
 | ||||
| 
 | ||||
| renderModel : Model -> GL.Texture -> GL.Texture -> Mesh -> GL.Entity | ||||
| renderModel model textureDiff textureNorm mesh = | ||||
|     let | ||||
|         ( camera, view, viewProjection, cameraPos ) = | ||||
|             getCamera model | ||||
| 
 | ||||
|         modelM = | ||||
|             M4.makeTranslate (vec3 -1 0 0) | ||||
| 
 | ||||
|         lightPos = | ||||
|             vec3 (0.5 * cos (2 * model.time)) (1 + 0.5 * sin (2 * model.time)) 0.5 | ||||
| 
 | ||||
|         uniforms = | ||||
|             { camera = camera | ||||
|             , mvMat = M4.mul view modelM | ||||
|             , modelViewProjectionMatrix = M4.mul viewProjection modelM | ||||
|             , modelMatrix = modelM | ||||
|             , viewPosition = cameraPos | ||||
|             , textureDiff = textureDiff | ||||
|             , textureNorm = textureNorm | ||||
|             , lightPosition = lightPos | ||||
|             } | ||||
|     in | ||||
|         case mesh of | ||||
|             WithoutTexture { vertices, indices } -> | ||||
|                 renderCullFace Shaders.simpleVert Shaders.simpleFrag (GL.indexedTriangles vertices indices) uniforms | ||||
| 
 | ||||
|             WithTexture { vertices, indices } -> | ||||
|                 renderCullFace Shaders.noNormalVert Shaders.noNormalFrag (GL.indexedTriangles vertices indices) uniforms | ||||
| 
 | ||||
|             WithTextureAndTangent { vertices, indices } -> | ||||
|                 renderCullFace Shaders.normalVert Shaders.normalFrag (GL.indexedTriangles vertices indices) uniforms | ||||
| 
 | ||||
| 
 | ||||
| getCamera : Model -> ( Mat4, Mat4, Mat4, Vec3 ) | ||||
| getCamera { mouseDelta, zoom, windowSize } = | ||||
|     let | ||||
|         ( mx, my ) = | ||||
|             ( mouseDelta.x, mouseDelta.y ) | ||||
| 
 | ||||
|         aspect = | ||||
|             toFloat windowSize.width / toFloat windowSize.height | ||||
| 
 | ||||
|         proj = | ||||
|             M4.makePerspective 45 aspect 0.01 10000 | ||||
| 
 | ||||
|         position = | ||||
|             vec3 (zoom * sin -mx * sin my) (-zoom * cos my + 1) (zoom * cos -mx * sin my) | ||||
| 
 | ||||
|         view = | ||||
|             M4.makeLookAt (position) (vec3 0 1 0) (vec3 0 1 0) | ||||
|     in | ||||
|         ( proj, view, M4.mul proj view, position ) | ||||
| 
 | ||||
| 
 | ||||
| view : Model -> Html.Html Msg | ||||
| view model = | ||||
|     div [] | ||||
|         [ selectModel model | ||||
|         , case ( model.mesh, model.diffText, model.normText ) of | ||||
|             ( Ok m, Ok td, Ok tn ) -> | ||||
|                 GL.toHtmlWith [ GL.antialias, GL.depth 1 ] | ||||
|                     [ onZoom | ||||
|                     , Attr.width (model.windowSize.width) | ||||
|                     , Attr.height (model.windowSize.height) | ||||
|                     , Attr.style [ ( "position", "absolute" ) ] | ||||
|                     ] | ||||
|                     (Dict.values m | ||||
|                         |> List.concatMap Dict.values | ||||
|                         |> List.map (renderModel model td tn) | ||||
|                     ) | ||||
| 
 | ||||
|             err -> | ||||
|                 Html.div [] [ Html.text (toString err) ] | ||||
|         ] | ||||
| 
 | ||||
| 
 | ||||
| selectModel : Model -> Html Msg | ||||
| selectModel model = | ||||
|     div [ Attr.style [ ( "position", "absolute" ), ( "z-index", "2" ), ( "backgroundColor", "white" ) ] ] | ||||
|         ([ Html.select [ onInput SelectMesh, Attr.value model.currentModel ] | ||||
|             (List.map (\t -> Html.option [ Attr.value t ] [ text t ]) models) | ||||
|          ] | ||||
|             ++ if String.startsWith "meshes/elmLogo" model.currentModel then | ||||
|                 [ text "\twith normal map: " | ||||
|                 , Html.input [ Attr.type_ "checkbox", onCheck SetUseTangent, Attr.checked model.withTangent ] [] | ||||
|                 ] | ||||
|                else | ||||
|                 [] | ||||
|         ) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| -- SUBS | ||||
| 
 | ||||
| 
 | ||||
| subscriptions : Model -> Sub Msg | ||||
| subscriptions model = | ||||
|     Sub.batch | ||||
|         ((if model.isDown then | ||||
|             [ Mouse.moves MouseMove ] | ||||
|           else | ||||
|             [] | ||||
|          ) | ||||
|             ++ [ AnimationFrame.diffs Tick | ||||
|                , Mouse.downs MouseDown | ||||
|                , Mouse.ups (\_ -> MouseUp) | ||||
|                , Window.resizes ResizeWindow | ||||
|                ] | ||||
|         ) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| -- HELPERS | ||||
| 
 | ||||
| 
 | ||||
| onZoom : Html.Attribute Msg | ||||
| onZoom = | ||||
|     on "wheel" (JD.map Zoom (JD.field "deltaY" JD.float)) | ||||
| 
 | ||||
| 
 | ||||
| getDelta : Mouse.Position -> Mouse.Position -> MouseDelta -> MouseDelta | ||||
| getDelta curr lastP delta = | ||||
|     MouseDelta (toFloat (curr.x - lastP.x) / 100 + delta.x) (clamp 0.01 pi (toFloat (curr.y - lastP.y) / 100 + delta.y)) | ||||
| 
 | ||||
| 
 | ||||
| loadTexture : String -> (Result String GL.Texture -> msg) -> Cmd msg | ||||
| loadTexture url msg = | ||||
|     WebGL.Texture.load url | ||||
|         |> Task.attempt | ||||
|             (\r -> | ||||
|                 case r of | ||||
|                     Ok t -> | ||||
|                         msg (Ok t) | ||||
| 
 | ||||
|                     Err e -> | ||||
|                         msg (Err ("Failed to load texture: " ++ toString e)) | ||||
|             ) | ||||
| 
 | ||||
| 
 | ||||
| renderCullFace : GL.Shader a u v -> GL.Shader {} u v -> GL.Mesh a -> u -> GL.Entity | ||||
| renderCullFace = | ||||
|     GL.entityWith [ DepthTest.default, cullFace front ] | ||||
							
								
								
									
										9
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/examples/README.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/examples/README.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| # Running | ||||
| Due to [a bug in elm reactor](https://github.com/elm-lang/elm-reactor/issues/217), the obj file will be served as an html page instead of `plain/text`. This screws up the parsing. | ||||
| 
 | ||||
| Using another file server works, e.g. | ||||
| using [elm-live](https://github.com/tomekwi/elm-live) or `python -m http.server` | ||||
| 
 | ||||
| # Acknowledgements | ||||
| 
 | ||||
| Brick textures were taken from: http://www.textures.com/ | ||||
							
								
								
									
										301
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/examples/Shaders.elm
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										301
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/examples/Shaders.elm
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,301 @@ | ||||
| module Shaders exposing (..) | ||||
| 
 | ||||
| import WebGL | ||||
| 
 | ||||
| 
 | ||||
| {-| This shader uses Spherical Environment Mapping (SEM). | ||||
| Here are some relevant links: | ||||
| 
 | ||||
|   - [very cool demo](https://www.clicktorelease.com/code/spherical-normal-mapping/#) | ||||
|   - <https://www.clicktorelease.com/blog/creating-spherical-environment-mapping-shader> | ||||
|   - <http://www.ozone3d.net/tutorials/glsl_texturing_p04.php> | ||||
| 
 | ||||
| -} | ||||
| reflectionVert = | ||||
|     [glsl| | ||||
| 
 | ||||
| attribute vec3 position; | ||||
| attribute vec3 normal; | ||||
| uniform mat4 mvMat; | ||||
| uniform mat4 camera; | ||||
| varying vec3 vNormal; | ||||
| 
 | ||||
| void main() | ||||
| { | ||||
|     vec4 vertex4 = mvMat * vec4(position, 1.0); | ||||
|     vNormal = vec3(mvMat * vec4(normal, 0.0)); | ||||
|     vec3 nm_z = normalize(vec3(vertex4)); | ||||
|     vec3 nm_x = cross(nm_z, vec3(0.0, 1.0, 0.0)); | ||||
|     vec3 nm_y = cross(nm_x, nm_z); | ||||
|     vNormal = vec3(dot(vNormal, nm_x), dot(vNormal, nm_y), dot(vNormal, nm_z)); | ||||
|     gl_Position = camera * vertex4; | ||||
| } | ||||
| 
 | ||||
| |] | ||||
| 
 | ||||
| 
 | ||||
| reflectionFrag = | ||||
|     [glsl| | ||||
| precision mediump float; | ||||
| 
 | ||||
| uniform sampler2D texture; | ||||
| 
 | ||||
| varying vec3 vNormal; | ||||
| 
 | ||||
| void main() | ||||
| { | ||||
|     vec2 texCoord = vec2(0.5 * vNormal.x + 0.5, - 0.5 * vNormal.y - 0.5); | ||||
|     vec4 fragColor = texture2D(texture, texCoord); | ||||
|     fragColor.a = 1.0; | ||||
| 
 | ||||
|     gl_FragColor = fragColor; | ||||
| } | ||||
| 
 | ||||
| |] | ||||
| 
 | ||||
| 
 | ||||
| {-| normal mapping according to: | ||||
| <http://www.gamasutra.com/blogs/RobertBasler/20131122/205462/Three_Normal_Mapping_Techniques_Explained_For_the_Mathematically_Uninclined.php?print=1> | ||||
| -} | ||||
| normalVert = | ||||
|     [glsl| | ||||
| attribute vec3 position; | ||||
| attribute vec3 normal; | ||||
| attribute vec2 texCoord; | ||||
| attribute vec4 tangent; | ||||
| 
 | ||||
| varying vec2 vTexCoord; | ||||
| varying vec3 vLightDirection; | ||||
| varying vec3 vViewDirection; | ||||
| 
 | ||||
| 
 | ||||
| uniform mat4 modelViewProjectionMatrix; | ||||
| uniform mat4 modelMatrix; | ||||
| uniform vec3 lightPosition; | ||||
| uniform vec3 viewPosition; | ||||
| 
 | ||||
| mat3 transpose(mat3 m) { | ||||
|     return mat3(m[0][0], m[1][0], m[2][0], | ||||
|                 m[0][1], m[1][1], m[2][1], | ||||
|                 m[0][2], m[1][2], m[2][2]); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void main() | ||||
| { | ||||
|     vec4 pos = vec4(position, 1.0 ); | ||||
|     vec3 posWorld = (modelMatrix * pos).xyz; | ||||
| 
 | ||||
|     // Tangent, Bitangent, Normal space matrix TBN | ||||
|     // this isn't entirely correct, it should use the normal matrix | ||||
|     // In this special case it works out well, | ||||
|     // since my model matrix does not contain any rotation or translation. | ||||
|     // http://www.lighthouse3d.com/tutorials/glsl-12-tutorial/the-normal-matrix/ | ||||
|     vec3 n = normalize((modelMatrix * vec4(normal, 0.0)).xyz); | ||||
|     vec3 t = normalize((modelMatrix * vec4(tangent.xyz, 0.0)).xyz); | ||||
|     vec3 b = normalize((modelMatrix * vec4((cross(normal, tangent.xyz) * tangent.w), 0.0)).xyz); | ||||
|     mat3 tbn = transpose(mat3(t, b, n)); | ||||
|     vLightDirection = tbn*(lightPosition - posWorld); | ||||
|     vViewDirection = tbn*(viewPosition - posWorld); | ||||
|     vTexCoord = texCoord; | ||||
|     gl_Position = modelViewProjectionMatrix * pos; | ||||
| } | ||||
| |] | ||||
| 
 | ||||
| 
 | ||||
| normalFrag = | ||||
|     [glsl| | ||||
| precision mediump float; | ||||
| 
 | ||||
| uniform sampler2D textureDiff; | ||||
| uniform sampler2D textureNorm; | ||||
| 
 | ||||
| varying vec2 vTexCoord; | ||||
| varying vec3 vLightDirection; | ||||
| varying vec3 vViewDirection; | ||||
| 
 | ||||
| void main() { | ||||
| 
 | ||||
|     vec3 lightDir = normalize(vLightDirection); | ||||
| 
 | ||||
|     // Local normal, in tangent space | ||||
|     vec3 pixelNormal = normalize(texture2D(textureNorm, vTexCoord).rgb*2.0 - 1.0); | ||||
|     float lambert = max(dot(pixelNormal, lightDir), 0.0); | ||||
| 
 | ||||
| 
 | ||||
|     // diffuse + lambert | ||||
|     vec3 lightIntensities = vec3(1.5, 1.0, 1.0); | ||||
|     vec3 diffuseColor = texture2D(textureDiff, vTexCoord).rgb; | ||||
|     vec3 diffuse = lambert * diffuseColor * lightIntensities; | ||||
| 
 | ||||
|     // ambient | ||||
|     vec3 ambient = 0.3 * diffuseColor; | ||||
| 
 | ||||
|     // specular | ||||
|     float shininess = 32.0; | ||||
|     vec3 viewDir = normalize(vViewDirection); | ||||
|     vec3 reflectDir = reflect(-lightDir, pixelNormal); | ||||
|     vec3 halfwayDir = normalize(lightDir + viewDir); | ||||
|     float spec = pow(max(dot(pixelNormal, halfwayDir), 0.0), shininess); | ||||
|     vec3 specular = vec3(0.2) * spec * lightIntensities; | ||||
| 
 | ||||
|     // attenuation | ||||
|     float lightAttenuation = 0.3; | ||||
|     float attenuation = 1.0 / (1.0 + lightAttenuation * pow(length(vLightDirection), 2.0)); | ||||
| 
 | ||||
|     vec3 final_color = ambient + (diffuse + specular) * attenuation; | ||||
|     gl_FragColor = vec4(final_color, 1.0); | ||||
| } | ||||
| |] | ||||
| 
 | ||||
| 
 | ||||
| {-| same as the normal mapping shader, but without deforming normals. | ||||
| -} | ||||
| noNormalVert = | ||||
|     [glsl| | ||||
| attribute vec3 position; | ||||
| attribute vec3 normal; | ||||
| attribute vec2 texCoord; | ||||
| 
 | ||||
| varying vec2 vTexCoord; | ||||
| varying vec3 vLightDirection; | ||||
| varying vec3 vViewDirection; | ||||
| varying vec3 vNormal; | ||||
| 
 | ||||
| uniform mat4 modelViewProjectionMatrix; | ||||
| uniform mat4 modelMatrix; | ||||
| uniform vec3 lightPosition; | ||||
| uniform vec3 viewPosition; | ||||
| 
 | ||||
| void main() | ||||
| { | ||||
|     vec4 pos = vec4(position, 1.0 ); | ||||
|     vec3 posWorld = (modelMatrix * pos).xyz; | ||||
| 
 | ||||
|     vLightDirection = lightPosition - posWorld; | ||||
|     vViewDirection = viewPosition - posWorld; | ||||
|     vTexCoord = texCoord; | ||||
|     // this is incorrect, it should use the normal matrix | ||||
|     vNormal = mat3(modelMatrix) * normal; | ||||
|     gl_Position = modelViewProjectionMatrix * pos; | ||||
| } | ||||
| |] | ||||
| 
 | ||||
| 
 | ||||
| noNormalFrag = | ||||
|     [glsl| | ||||
| precision mediump float; | ||||
| 
 | ||||
| uniform sampler2D textureDiff; | ||||
| 
 | ||||
| varying vec2 vTexCoord; | ||||
| varying vec3 vLightDirection; | ||||
| varying vec3 vViewDirection; | ||||
| varying vec3 vNormal; | ||||
| 
 | ||||
| void main() | ||||
| { | ||||
|     vec3 lightDir = normalize(vLightDirection); | ||||
| 
 | ||||
|     // lambert | ||||
|     vec3 pixelNormal = normalize(vNormal); | ||||
|     float lambert = max(dot(pixelNormal, lightDir), 0.0); | ||||
| 
 | ||||
|     // diffuse + lambert | ||||
|     vec3 lightIntensities = vec3(1.5, 1.0, 1.0); | ||||
|     vec3 diffuseColor = texture2D(textureDiff, vTexCoord).rgb; | ||||
|     vec3 diffuse = lambert * diffuseColor * lightIntensities; | ||||
| 
 | ||||
|     // ambient | ||||
|     vec3 ambient = 0.3 * diffuseColor; | ||||
| 
 | ||||
|     // specular | ||||
|     float shininess = 32.0; | ||||
|     vec3 viewDir = normalize(vViewDirection); | ||||
|     vec3 reflectDir = reflect(-lightDir, pixelNormal); | ||||
|     vec3 halfwayDir = normalize(lightDir + viewDir); | ||||
|     float spec = pow(max(dot(pixelNormal, halfwayDir), 0.0), shininess); | ||||
|     vec3 specular = vec3(0.2) * spec * lightIntensities; | ||||
| 
 | ||||
|     // attenuation | ||||
|     float lightAttenuation = 0.3; | ||||
|     float attenuation = 1.0 / (1.0 + lightAttenuation * pow(length(vLightDirection), 2.0)); | ||||
| 
 | ||||
|     vec3 final_color = ambient + (diffuse + specular) * attenuation; | ||||
|     gl_FragColor = vec4(final_color, 1.0); | ||||
| } | ||||
| |] | ||||
| 
 | ||||
| 
 | ||||
| {-| same as above, but without any textures. | ||||
| -} | ||||
| simpleVert = | ||||
|     [glsl| | ||||
| attribute vec3 position; | ||||
| attribute vec3 normal; | ||||
| 
 | ||||
| varying vec3 vLightDirection; | ||||
| varying vec3 vViewDirection; | ||||
| varying vec3 vNormal; | ||||
| 
 | ||||
| uniform mat4 modelViewProjectionMatrix; | ||||
| uniform mat4 modelMatrix; | ||||
| uniform vec3 lightPosition; | ||||
| uniform vec3 viewPosition; | ||||
| 
 | ||||
| void main() | ||||
| { | ||||
|     vec4 pos = vec4(position, 1.0 ); | ||||
|     vec3 posWorld = (modelMatrix * pos).xyz; | ||||
| 
 | ||||
|     vLightDirection = lightPosition - posWorld; | ||||
|     vViewDirection = viewPosition - posWorld; | ||||
|     // this is incorrect, it should use the normal matrix, like this: | ||||
|     // vNormal = mat3(normalMatrix) * normal; | ||||
|     // it works in this case, since the modelMatrix is the identity matrix | ||||
|     vNormal = normal; | ||||
|     gl_Position = modelViewProjectionMatrix * pos; | ||||
| } | ||||
| |] | ||||
| 
 | ||||
| 
 | ||||
| simpleFrag = | ||||
|     [glsl| | ||||
| precision mediump float; | ||||
| 
 | ||||
| varying vec3 vLightDirection; | ||||
| varying vec3 vViewDirection; | ||||
| varying vec3 vNormal; | ||||
| 
 | ||||
| void main() | ||||
| { | ||||
|     vec3 lightDir = normalize(vLightDirection); | ||||
| 
 | ||||
|     // lambert | ||||
|     vec3 pixelNormal = normalize(vNormal); | ||||
|     float lambert = max(dot(pixelNormal, lightDir), 0.0); | ||||
| 
 | ||||
|     // diffuse + lambert | ||||
|     vec3 lightIntensities = vec3(1.5, 1.0, 1.0); | ||||
|     vec3 diffuseColor = vec3(0.3, 0.2, 0.95); | ||||
|     vec3 diffuse = lambert * diffuseColor * lightIntensities; | ||||
| 
 | ||||
|     // ambient | ||||
|     vec3 ambient = 0.2 * diffuseColor; | ||||
| 
 | ||||
|     // specular | ||||
|     float shininess = 32.0; | ||||
|     vec3 viewDir = normalize(vViewDirection); | ||||
|     vec3 reflectDir = reflect(-lightDir, pixelNormal); | ||||
|     vec3 halfwayDir = normalize(lightDir + viewDir); | ||||
|     float spec = pow(max(dot(pixelNormal, halfwayDir), 0.0), shininess); | ||||
|     vec3 specular = vec3(0.2) * spec * lightIntensities; | ||||
| 
 | ||||
|     // attenuation | ||||
|     float lightAttenuation = 0.3; | ||||
|     float attenuation = 1.0 / (1.0 + lightAttenuation * pow(length(vLightDirection), 2.0)); | ||||
| 
 | ||||
|     vec3 final_color = ambient + (diffuse + specular) * attenuation; | ||||
|     gl_FragColor = vec4(final_color, 1.0); | ||||
| } | ||||
| |] | ||||
							
								
								
									
										148
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/examples/Suzanne.elm
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/examples/Suzanne.elm
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,148 @@ | ||||
| module Suzanne exposing (..) | ||||
| 
 | ||||
| import AnimationFrame | ||||
| import Html | ||||
| import Html.Attributes as Attr | ||||
| import Html.Events exposing (on) | ||||
| import Json.Decode as JD | ||||
| import Math.Matrix4 as M4 exposing (Mat4) | ||||
| import Math.Vector3 as V3 exposing (Vec3, vec3) | ||||
| import Task | ||||
| import WebGL as GL | ||||
| import WebGL.Texture | ||||
| import WebGL.Settings exposing (cullFace, front) | ||||
| import WebGL.Settings.DepthTest as DepthTest | ||||
| 
 | ||||
| 
 | ||||
| -- | ||||
| 
 | ||||
| import OBJ | ||||
| import OBJ.Types exposing (MeshWith, VertexWithTexture) | ||||
| import Shaders exposing (reflectionVert, reflectionFrag) | ||||
| 
 | ||||
| 
 | ||||
| main : Program Never Model Msg | ||||
| main = | ||||
|     Html.program | ||||
|         { init = ( initModel, initCmd ) | ||||
|         , view = view | ||||
|         , subscriptions = (\model -> AnimationFrame.diffs Tick) | ||||
|         , update = update | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| -- MODEL | ||||
| 
 | ||||
| 
 | ||||
| type alias Model = | ||||
|     { time : Float | ||||
|     , mesh : Result String (MeshWith VertexWithTexture) | ||||
|     , zoom : Float | ||||
|     , reflectionTexture : Result String GL.Texture | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| initModel : Model | ||||
| initModel = | ||||
|     { mesh = Err "loading ...", time = 0, zoom = 10, reflectionTexture = Err "Loading texture..." } | ||||
| 
 | ||||
| 
 | ||||
| initCmd : Cmd Msg | ||||
| initCmd = | ||||
|     Cmd.batch | ||||
|         [ OBJ.loadMesh "meshes/suzanne.obj" LoadObj | ||||
|         , loadTexture "textures/chavant.jpg" TextureLoaded | ||||
|         ] | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| -- UPDATE | ||||
| 
 | ||||
| 
 | ||||
| type Msg | ||||
|     = Tick Float | ||||
|     | LoadObj (Result String (MeshWith VertexWithTexture)) | ||||
|     | Zoom Float | ||||
|     | TextureLoaded (Result String GL.Texture) | ||||
| 
 | ||||
| 
 | ||||
| update : Msg -> Model -> ( Model, Cmd Msg ) | ||||
| update msg model = | ||||
|     case msg of | ||||
|         Tick dt -> | ||||
|             ( { model | time = model.time + dt / 1000 }, Cmd.none ) | ||||
| 
 | ||||
|         Zoom dy -> | ||||
|             ( { model | zoom = model.zoom + dy / 100 }, Cmd.none ) | ||||
| 
 | ||||
|         LoadObj mesh -> | ||||
|             ( { model | mesh = mesh }, Cmd.none ) | ||||
| 
 | ||||
|         TextureLoaded t -> | ||||
|             ( { model | reflectionTexture = t }, Cmd.none ) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| -- VIEW / RENDER | ||||
| 
 | ||||
| 
 | ||||
| renderModel : Model -> GL.Texture -> MeshWith VertexWithTexture -> GL.Entity | ||||
| renderModel { zoom, time } texture { vertices, indices } = | ||||
|     let | ||||
|         ( camera, view ) = | ||||
|             getCamera zoom time | ||||
| 
 | ||||
|         model = | ||||
|             M4.makeRotate time (vec3 0 1 0) | ||||
| 
 | ||||
|         modelView = | ||||
|             M4.mul view model | ||||
|     in | ||||
|         GL.entityWith [ DepthTest.default, cullFace front ] | ||||
|             reflectionVert | ||||
|             reflectionFrag | ||||
|             (GL.indexedTriangles vertices indices) | ||||
|             { camera = camera, mvMat = modelView, texture = texture } | ||||
| 
 | ||||
| 
 | ||||
| getCamera : Float -> Float -> ( Mat4, Mat4 ) | ||||
| getCamera zoom t = | ||||
|     ( (M4.makePerspective 45 1 0.01 10000) | ||||
|     , (M4.makeLookAt (vec3 (zoom) (zoom / 2) (zoom)) (vec3 0 0 0) (vec3 0 1 0)) | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| view : Model -> Html.Html Msg | ||||
| view model = | ||||
|     case ( model.mesh, model.reflectionTexture ) of | ||||
|         ( Ok m, Ok t ) -> | ||||
|             GL.toHtmlWith [ GL.antialias, GL.depth 1 ] | ||||
|                 [ onZoom, Attr.width 400, Attr.height 400 ] | ||||
|                 [ renderModel model t m ] | ||||
| 
 | ||||
|         ( a, b ) -> | ||||
|             Html.div [] [ Html.text (toString a ++ "\n\n\n" ++ toString b) ] | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| -- HELPERS | ||||
| 
 | ||||
| 
 | ||||
| loadTexture : String -> (Result String GL.Texture -> msg) -> Cmd msg | ||||
| loadTexture url msg = | ||||
|     WebGL.Texture.load url | ||||
|         |> Task.attempt | ||||
|             (\r -> | ||||
|                 case r of | ||||
|                     Ok t -> | ||||
|                         msg (Ok t) | ||||
| 
 | ||||
|                     Err e -> | ||||
|                         msg (Err ("Failed to load texture: " ++ toString e)) | ||||
|             ) | ||||
| 
 | ||||
| 
 | ||||
| onZoom : Html.Attribute Msg | ||||
| onZoom = | ||||
|     on "wheel" (JD.map Zoom (JD.field "deltaY" JD.float)) | ||||
							
								
								
									
										24
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/examples/elm-package.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/examples/elm-package.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| { | ||||
|     "version": "1.0.0", | ||||
|     "summary": "helpful summary of your project, less than 80 characters", | ||||
|     "repository": "https://github.com/Zinggi/elm-obj-loader.git", | ||||
|     "license": "BSD3", | ||||
|     "source-directories": [ | ||||
|         ".", | ||||
|         "../src" | ||||
|     ], | ||||
|     "exposed-modules": [], | ||||
|     "dependencies": { | ||||
|         "Bogdanp/elm-combine": "3.1.1 <= v < 4.0.0", | ||||
|         "Skinney/elm-array-exploration": "2.0.1 <= v < 3.0.0", | ||||
|         "elm-community/linear-algebra": "1.0.0 <= v < 2.0.0", | ||||
|         "elm-community/webgl": "2.0.0 <= v < 3.0.0", | ||||
|         "elm-lang/animation-frame": "1.0.1 <= v < 2.0.0", | ||||
|         "elm-lang/core": "5.0.0 <= v < 6.0.0", | ||||
|         "elm-lang/html": "2.0.0 <= v < 3.0.0", | ||||
|         "elm-lang/http": "1.0.0 <= v < 2.0.0", | ||||
|         "elm-lang/mouse": "1.0.1 <= v < 2.0.0", | ||||
|         "elm-lang/window": "1.0.1 <= v < 2.0.0" | ||||
|     }, | ||||
|     "elm-version": "0.18.0 <= v < 0.19.0" | ||||
| } | ||||
							
								
								
									
										1576
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/examples/meshes/elmLogo.obj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1576
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/examples/meshes/elmLogo.obj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2580
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/examples/meshes/suzanne.obj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2580
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/examples/meshes/suzanne.obj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1518
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/examples/meshes/suzanneNoUV.obj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1518
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/examples/meshes/suzanneNoUV.obj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/examples/textures/chavant.jpg
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/examples/textures/chavant.jpg
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 19 KiB | 
							
								
								
									
										
											BIN
										
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/examples/textures/elmLogoDiffuse.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/examples/textures/elmLogoDiffuse.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 191 KiB | 
							
								
								
									
										
											BIN
										
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/examples/textures/elmLogoNorm.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/examples/textures/elmLogoNorm.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 408 KiB | 
							
								
								
									
										169
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/src/OBJ.elm
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/src/OBJ.elm
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,169 @@ | ||||
| module OBJ exposing (..) | ||||
| 
 | ||||
| {-| | ||||
| 
 | ||||
| 
 | ||||
| # .obj file loader | ||||
| 
 | ||||
| The returned models can be rendered using `indexedTriangles` from `WebGL`. | ||||
| 
 | ||||
|     WebGL.indexedTriangles mesh.vertices mesh.indices | ||||
| 
 | ||||
| 
 | ||||
| ## From URL | ||||
| 
 | ||||
| All these methods take an URL as the first parameter. | ||||
| 
 | ||||
| 
 | ||||
| ### Single model | ||||
| 
 | ||||
| Use the methods from here if you know whats in your file | ||||
| and if they only contain a single object with a single material. | ||||
| These are just provided for convenience. | ||||
| 
 | ||||
| @docs loadMeshWithoutTexture, loadMesh, loadMeshWithTangent | ||||
| 
 | ||||
| 
 | ||||
| ### General | ||||
| 
 | ||||
| Use these methods if you don't know what kind of files you'll get or | ||||
| if your files contain multiple groups or materials. | ||||
| 
 | ||||
| @docs loadObjFile, loadObjFileWith, Settings, defaultSettings | ||||
| 
 | ||||
| 
 | ||||
| ## From String | ||||
| 
 | ||||
| @docs parseObjStringWith | ||||
| 
 | ||||
| -} | ||||
| 
 | ||||
| import Dict exposing (Dict) | ||||
| import Http | ||||
| import OBJ.Assembler exposing (compile) | ||||
| import OBJ.Parser exposing (parse) | ||||
| import OBJ.Types exposing (Mesh, ObjFile) | ||||
| import Task | ||||
| 
 | ||||
| 
 | ||||
| -- | ||||
| 
 | ||||
| import OBJ.Assembler exposing (compile) | ||||
| import OBJ.Parser exposing (parse) | ||||
| import OBJ.Types exposing (..) | ||||
| 
 | ||||
| 
 | ||||
| {-| Load a model that doesn't have texture coordinates. | ||||
| -} | ||||
| loadMeshWithoutTexture : String -> (Result String (MeshWith Vertex) -> msg) -> Cmd msg | ||||
| loadMeshWithoutTexture url msg = | ||||
|     loadObjFile url | ||||
|         (\res -> | ||||
|             case res of | ||||
|                 Ok f -> | ||||
|                     case (Dict.values f |> List.map Dict.values) of | ||||
|                         [ [ WithoutTexture m ] ] -> | ||||
|                             msg (Ok m) | ||||
| 
 | ||||
|                         _ -> | ||||
|                             msg (Err "file loaded correctly, but there were more than one models.") | ||||
| 
 | ||||
|                 Err e -> | ||||
|                     msg (Err e) | ||||
|         ) | ||||
| 
 | ||||
| 
 | ||||
| {-| Load a model with texture coordinates. | ||||
| -} | ||||
| loadMesh : String -> (Result String (MeshWith VertexWithTexture) -> msg) -> Cmd msg | ||||
| loadMesh url msg = | ||||
|     loadObjFile url | ||||
|         (\res -> | ||||
|             case res of | ||||
|                 Ok f -> | ||||
|                     case (Dict.values f |> List.map Dict.values) of | ||||
|                         [ [ WithTexture m ] ] -> | ||||
|                             msg (Ok m) | ||||
| 
 | ||||
|                         _ -> | ||||
|                             msg (Err "file loaded correctly, but there were more than one models.") | ||||
| 
 | ||||
|                 Err e -> | ||||
|                     msg (Err e) | ||||
|         ) | ||||
| 
 | ||||
| 
 | ||||
| {-| Load a model with texture coordinate and calculate vertex tangents. | ||||
| This is needed if you want to do tangent space normal mapping. | ||||
| -} | ||||
| loadMeshWithTangent : String -> (Result String (MeshWith VertexWithTextureAndTangent) -> msg) -> Cmd msg | ||||
| loadMeshWithTangent url msg = | ||||
|     loadObjFileWith { withTangents = True } | ||||
|         url | ||||
|         (\res -> | ||||
|             case res of | ||||
|                 Ok f -> | ||||
|                     case (Dict.values f |> List.map Dict.values) of | ||||
|                         [ [ WithTextureAndTangent m ] ] -> | ||||
|                             msg (Ok m) | ||||
| 
 | ||||
|                         _ -> | ||||
|                             msg (Err "file loaded correctly, but there were more than one models.") | ||||
| 
 | ||||
|                 Err e -> | ||||
|                     msg (Err e) | ||||
|         ) | ||||
| 
 | ||||
| 
 | ||||
| {-| Load a .obj file from an URL | ||||
| 
 | ||||
|     loadObjFile url ObjFileLoaded | ||||
| 
 | ||||
| -} | ||||
| loadObjFile : String -> (Result String ObjFile -> msg) -> Cmd msg | ||||
| loadObjFile = | ||||
|     loadObjFileWith defaultSettings | ||||
| 
 | ||||
| 
 | ||||
| {-| withTangents : If true, vertex tangents will be calculated for meshes with texture coordinates. | ||||
| This is needed if you want to do tangent space normal mapping. | ||||
| -} | ||||
| type alias Settings = | ||||
|     { withTangents : Bool } | ||||
| 
 | ||||
| 
 | ||||
| {-| -} | ||||
| defaultSettings : Settings | ||||
| defaultSettings = | ||||
|     { withTangents = False } | ||||
| 
 | ||||
| 
 | ||||
| {-| -} | ||||
| loadObjFileWith : Settings -> String -> (Result String ObjFile -> msg) -> Cmd msg | ||||
| loadObjFileWith settings url msg = | ||||
|     Http.toTask (Http.getString url) | ||||
|         |> Task.andThen | ||||
|             (\s -> | ||||
|                 parseObjStringWith settings s |> Task.succeed | ||||
|             ) | ||||
|         |> Task.onError (\e -> Task.succeed (Err ("failed to load:\n" ++ toString e))) | ||||
|         |> Task.attempt | ||||
|             (\r -> | ||||
|                 case r of | ||||
|                     Ok (Ok m) -> | ||||
|                         msg (Ok m) | ||||
| 
 | ||||
|                     Ok (Err e) -> | ||||
|                         msg (Err e) | ||||
| 
 | ||||
|                     Err e -> | ||||
|                         msg (Err e) | ||||
|             ) | ||||
| 
 | ||||
| 
 | ||||
| {-| Same as `loadObjFile`, but works on a string. | ||||
| -} | ||||
| parseObjStringWith : Settings -> String -> Result String ObjFile | ||||
| parseObjStringWith config input = | ||||
|     parse input | ||||
|         |> Result.map (compile config) | ||||
							
								
								
									
										463
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/src/OBJ/Assembler.elm
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										463
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/src/OBJ/Assembler.elm
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,463 @@ | ||||
| module OBJ.Assembler exposing (..) | ||||
| 
 | ||||
| import Array.Hamt as Array exposing (Array) | ||||
| import Dict exposing (Dict) | ||||
| import Math.Vector2 as V2 exposing (Vec2) | ||||
| import Math.Vector3 as V3 exposing (Vec3, vec3) | ||||
| import Math.Vector4 as V4 exposing (Vec4, vec4) | ||||
| import OBJ.Types exposing (..) | ||||
| import OBJ.InternalTypes exposing (..) | ||||
| 
 | ||||
| 
 | ||||
| compile config lines = | ||||
|     compileHelper (emptyCompileState config) lines | ||||
|         |> addCurrentMesh | ||||
|         |> addCurrentGroup | ||||
|         |> .groups | ||||
| 
 | ||||
| 
 | ||||
| emptyCompileState config = | ||||
|     { -- this is a Dict (GroupName/String) Group | ||||
|       -- it's the final output of this algorithm | ||||
|       --  Group = Dict (MtlName/String) Mesh | ||||
|       groups = Dict.empty | ||||
|     , currentGroupName = "__default__" | ||||
|     , currentMaterialName = "__default__" | ||||
|     , currentMesh = Nothing | ||||
|     , currentGroup = Dict.empty | ||||
|     , vs = Array.empty | ||||
|     , vts = Array.empty | ||||
|     , vns = Array.empty | ||||
|     , currentIndex = 0 | ||||
|     , knownVertexTextures = Dict.empty | ||||
|     , knownVertexTexturesTangents = Dict.empty | ||||
|     , knownVertex = Dict.empty | ||||
|     , config = config | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| compileHelper state lines = | ||||
|     case lines of | ||||
|         [] -> | ||||
|             state | ||||
| 
 | ||||
|         l :: ls -> | ||||
|             compileHelper (insertLine l state) ls | ||||
| 
 | ||||
| 
 | ||||
| {-| | ||||
| this 'inserts' a line into the state. | ||||
| This means it manipulates the current state to reflect state changing commands | ||||
| and buils meshes on the fly. | ||||
| -} | ||||
| insertLine line state = | ||||
|     case line of | ||||
|         Object s -> | ||||
|             -- even though the specs doesn't give it any meaningful meaning, | ||||
|             -- I treat is exactely like a group statement. | ||||
|             -- This is because blender uses o instead of g per default. | ||||
|             addCurrentGroup state | ||||
|                 |> (\st -> { st | currentGroupName = s }) | ||||
| 
 | ||||
|         MtlLib s -> | ||||
|             -- MtlLib statements are ignored, | ||||
|             -- as I don't plan to support loading .mtl files | ||||
|             state | ||||
| 
 | ||||
|         Group s -> | ||||
|             addCurrentGroup state | ||||
|                 |> (\st -> { st | currentGroupName = s }) | ||||
| 
 | ||||
|         Smooth s -> | ||||
|             -- smooth groups are ignored. | ||||
|             -- I tried to calculate these, but failed, | ||||
|             -- since doing them correctly is more tricky than you might think: | ||||
|             -- http://www.bytehazard.com/articles/vertnorm.html | ||||
|             -- { state | activeSmoothGroup = s } | ||||
|             state | ||||
| 
 | ||||
|         UseMtl s -> | ||||
|             addCurrentMesh state | ||||
|                 |> (\st -> { st | currentMaterialName = s }) | ||||
| 
 | ||||
|         V v -> | ||||
|             { state | vs = Array.push v state.vs } | ||||
| 
 | ||||
|         Vt v -> | ||||
|             { state | vts = Array.push v state.vts } | ||||
| 
 | ||||
|         Vn v -> | ||||
|             { state | vns = Array.push v state.vns } | ||||
| 
 | ||||
|         F f -> | ||||
|             triangulateFace f | ||||
|                 |> List.foldr addFace state | ||||
| 
 | ||||
| 
 | ||||
| triangulateFace f = | ||||
|     case f of | ||||
|         FVertexTextureNormal a -> | ||||
|             triangulate a |> List.map FTVertexTextureNormal | ||||
| 
 | ||||
|         FVertexNormal a -> | ||||
|             triangulate a |> List.map FTVertexNormal | ||||
| 
 | ||||
| 
 | ||||
| addCurrentMesh state = | ||||
|     -- this adds the current mesh, to the current group. | ||||
|     -- We also normalize all values here that need normalizing | ||||
|     case state.currentMesh of | ||||
|         Just m -> | ||||
|             { state | ||||
|                 | currentGroup = Dict.insert state.currentMaterialName (finalizeMesh m) state.currentGroup | ||||
|                 , currentMesh = Nothing | ||||
|                 , knownVertexTextures = Dict.empty | ||||
|                 , knownVertexTexturesTangents = Dict.empty | ||||
|                 , knownVertex = Dict.empty | ||||
|             } | ||||
| 
 | ||||
|         _ -> | ||||
|             state | ||||
| 
 | ||||
| 
 | ||||
| finalizeMesh mesh = | ||||
|     case mesh of | ||||
|         WithTextureT m -> | ||||
|             WithTexture m | ||||
| 
 | ||||
|         WithoutTextureT m -> | ||||
|             WithoutTexture m | ||||
| 
 | ||||
|         WithTextureAndTangentT m -> | ||||
|             WithTextureAndTangent | ||||
|                 { m | ||||
|                     | vertices = | ||||
|                         Array.foldr | ||||
|                             (\({ position, texCoord, normal, sdir, tdir } as v) acc -> | ||||
|                                 let | ||||
|                                     -- handedness: | ||||
|                                     -- https://web.archive.org/web/20160409104130/http://www.terathon.com/code/tangent.html | ||||
|                                     w = | ||||
|                                         if V3.dot (V3.cross normal sdir) tdir < 0 then | ||||
|                                             -1 | ||||
|                                         else | ||||
|                                             1 | ||||
| 
 | ||||
|                                     ( x, y, z ) = | ||||
|                                         -- I have not seen this anywhere, but I added it because I sometimes got (0,0,0) | ||||
|                                         if V3.lengthSquared sdir /= 0 then | ||||
|                                             V3.toTuple <| V3.normalize (V3.sub sdir (V3.scale (V3.dot normal sdir) normal)) | ||||
|                                         else | ||||
|                                             V3.toTuple <| V3.cross (V3.normalize (V3.sub tdir (V3.scale (V3.dot normal tdir) normal))) normal | ||||
|                                 in | ||||
|                                     { position = position | ||||
|                                     , texCoord = texCoord | ||||
|                                     , normal = normal | ||||
|                                     , tangent = vec4 x y z w | ||||
|                                     } | ||||
|                                         :: acc | ||||
|                             ) | ||||
|                             [] | ||||
|                             m.vertices | ||||
|                 } | ||||
| 
 | ||||
| 
 | ||||
| addCurrentGroup state = | ||||
|     if Dict.isEmpty state.currentGroup then | ||||
|         state | ||||
|     else | ||||
|         { state | ||||
|             | groups = Dict.insert state.currentGroupName state.currentGroup state.groups | ||||
|             , currentGroup = Dict.empty | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
| addFace f state = | ||||
|     -- this function adds a single face to the currentMesh | ||||
|     -- for this it needs a dictionary containing the already known vertices, | ||||
|     -- indexed using the v/vn etc. | ||||
|     case state.currentMesh of | ||||
|         Nothing -> | ||||
|             -- we dont have a mesh yet, create one based on the type of the face | ||||
|             addFaceToMesh f (createMesh state.config.withTangents f) { state | currentIndex = 0 } | ||||
| 
 | ||||
|         Just m -> | ||||
|             addFaceToMesh f m state | ||||
| 
 | ||||
| 
 | ||||
| addFaceToMesh f mesh ({ vs, vts, vns, currentIndex } as state) = | ||||
|     -- add a face to the mesh | ||||
|     case ( f, mesh ) of | ||||
|         ( FTVertexTextureNormal ( v1, v2, v3 ), WithTextureT m ) -> | ||||
|             let | ||||
|                 ( newState, newVs, newIs ) = | ||||
|                     applyForFace getOrInsertVTN ( v1, v2, v3 ) state | ||||
| 
 | ||||
|                 newMesh = | ||||
|                     WithTextureT { m | indices = newIs :: m.indices, vertices = m.vertices ++ newVs } | ||||
|             in | ||||
|                 { newState | currentMesh = Just newMesh } | ||||
| 
 | ||||
|         ( FTVertexTextureNormal ( v1, v2, v3 ), WithTextureAndTangentT m ) -> | ||||
|             let | ||||
|                 tangents = | ||||
|                     getFaceTangent ( v1, v2, v3 ) state | ||||
| 
 | ||||
|                 ( newState, newVs, newIs ) = | ||||
|                     applyForFaceA (getOrInsertVTNT tangents) ( v1, v2, v3 ) state | ||||
| 
 | ||||
|                 newMesh = | ||||
|                     WithTextureAndTangentT { m | indices = newIs :: m.indices, vertices = Array.append m.vertices newVs } | ||||
|             in | ||||
|                 { newState | currentMesh = Just newMesh } | ||||
| 
 | ||||
|         ( FTVertexNormal ( v1, v2, v3 ), WithoutTextureT m ) -> | ||||
|             let | ||||
|                 ( newState, newVs, newIs ) = | ||||
|                     applyForFace getOrInsertVN ( v1, v2, v3 ) state | ||||
| 
 | ||||
|                 newMesh = | ||||
|                     WithoutTextureT { m | indices = newIs :: m.indices, vertices = m.vertices ++ newVs } | ||||
|             in | ||||
|                 { newState | currentMesh = Just newMesh } | ||||
| 
 | ||||
|         _ -> | ||||
|             -- TODO: lift this error into a Result type | ||||
|             Debug.crash "mixed face types in the model!" | ||||
| 
 | ||||
| 
 | ||||
| applyForFace f ( i1, i2, i3 ) s_0 = | ||||
|     let | ||||
|         ( s_1, vs_1, i_1 ) = | ||||
|             f i1 s_0 | ||||
| 
 | ||||
|         ( s_2, vs_2, i_2 ) = | ||||
|             f i2 s_1 | ||||
| 
 | ||||
|         ( s_3, vs_3, i_3 ) = | ||||
|             f i3 s_2 | ||||
|     in | ||||
|         ( s_3, vs_1 ++ vs_2 ++ vs_3, ( i_3, i_2, i_1 ) ) | ||||
| 
 | ||||
| 
 | ||||
| applyForFaceA f ( i1, i2, i3 ) s_0 = | ||||
|     let | ||||
|         ( s_1, vs_1, i_1 ) = | ||||
|             f i1 s_0 | ||||
| 
 | ||||
|         ( s_2, vs_2, i_2 ) = | ||||
|             f i2 s_1 | ||||
| 
 | ||||
|         ( s_3, vs_3, i_3 ) = | ||||
|             f i3 s_2 | ||||
|     in | ||||
|         ( s_3, Array.append (Array.append vs_1 vs_2) vs_3, ( i_3, i_2, i_1 ) ) | ||||
| 
 | ||||
| 
 | ||||
| getFaceTangent (( ( pi1, ti1, ni1 ), ( pi2, ti2, ni2 ), ( pi3, ti3, ni3 ) ) as index) { vs, vts, vns } = | ||||
|     -- This is from here: | ||||
|     -- https://web.archive.org/web/20160409104130/http://www.terathon.com/code/tangent.html | ||||
|     -- But since the reference doesn't mention what to do in case the denominator is 0, | ||||
|     -- This is probably not correct. | ||||
|     case ( get3 ( pi1, pi2, pi3 ) vs vs vs, get3 ( ti1, ti2, ti3 ) vts vts vts ) of | ||||
|         ( Just ( v1, v2, v3 ), Just ( w1, w2, w3 ) ) -> | ||||
|             let | ||||
|                 ( ( v1x, v1y, v1z ), ( v2x, v2y, v2z ), ( v3x, v3y, v3z ) ) = | ||||
|                     t3map V3.toTuple ( v1, v2, v3 ) | ||||
| 
 | ||||
|                 ( ( w1x, w1y ), ( w2x, w2y ), ( w3x, w3y ) ) = | ||||
|                     t3map V2.toTuple ( w1, w2, w3 ) | ||||
| 
 | ||||
|                 ( ( x1, x2 ), ( y1, y2 ), ( z1, z2 ) ) = | ||||
|                     ( ( v2x - v1x, v3x - v1x ) | ||||
|                     , ( v2y - v1y, v3y - v1y ) | ||||
|                     , ( v2z - v1z, v3z - v1z ) | ||||
|                     ) | ||||
| 
 | ||||
|                 ( ( s1, s2 ), ( t1, t2 ) ) = | ||||
|                     ( ( w2x - w1x, w3x - w1x ), ( w2y - w1y, w3y - w1y ) ) | ||||
| 
 | ||||
|                 denom = | ||||
|                     s1 * t2 - s2 * t1 | ||||
| 
 | ||||
|                 r = | ||||
|                     if abs denom <= 0.000001 then | ||||
|                         0.1 | ||||
|                     else | ||||
|                         1 / denom | ||||
| 
 | ||||
|                 sdir = | ||||
|                     vec3 ((t2 * x1 - t1 * x2) * r) ((t2 * y1 - t1 * y2) * r) ((t2 * z1 - t1 * z2) * r) | ||||
| 
 | ||||
|                 tdir = | ||||
|                     vec3 ((s1 * x2 - s2 * x1) * r) ((s1 * y2 - s2 * y1) * r) ((s1 * z2 - s2 * z1) * r) | ||||
|             in | ||||
|                 ( sdir, tdir ) | ||||
| 
 | ||||
|         _ -> | ||||
|             -- TODO: lift this error into a Result type | ||||
|             ( vec3 1 1 1, vec3 1 1 1 ) | ||||
|                 |> log ("index " ++ toString index ++ " out of bounds!\nThis should never happen with a well formed file") | ||||
| 
 | ||||
| 
 | ||||
| getOrInsertVTN index ({ vs, vts, vns, knownVertexTextures, currentIndex } as state) = | ||||
|     case Dict.get index knownVertexTextures of | ||||
|         Just i -> | ||||
|             ( state, [], i ) | ||||
| 
 | ||||
|         Nothing -> | ||||
|             case get3 index vs vts vns of | ||||
|                 Just ( p, t, n ) -> | ||||
|                     ( { state | ||||
|                         | knownVertexTextures = Dict.insert index currentIndex knownVertexTextures | ||||
|                         , currentIndex = currentIndex + 1 | ||||
|                       } | ||||
|                     , [ VertexWithTexture p t n ] | ||||
|                     , currentIndex | ||||
|                     ) | ||||
| 
 | ||||
|                 Nothing -> | ||||
|                     -- TODO: lift this error into a Result type | ||||
|                     ( state, [], -42 ) | ||||
|                         |> log ("index " ++ toString index ++ " out of bounds!\nThis should never happen with a well formed file") | ||||
| 
 | ||||
| 
 | ||||
| getOrInsertVTNT ( s_dir, t_dir ) index ({ vs, vts, vns, knownVertexTexturesTangents, currentIndex } as state) = | ||||
|     case Dict.get index knownVertexTexturesTangents of | ||||
|         Just i -> | ||||
|             case state.currentMesh of | ||||
|                 Just (WithTextureAndTangentT m) -> | ||||
|                     ( { state | ||||
|                         | currentMesh = | ||||
|                             Just | ||||
|                                 (WithTextureAndTangentT | ||||
|                                     { m | ||||
|                                         | vertices = | ||||
|                                             updateArray i | ||||
|                                                 (\({ sdir, tdir } as v) -> | ||||
|                                                     { v | sdir = V3.add sdir s_dir, tdir = V3.add tdir t_dir } | ||||
|                                                 ) | ||||
|                                                 m.vertices | ||||
|                                     } | ||||
|                                 ) | ||||
|                       } | ||||
|                     , Array.empty | ||||
|                     , i | ||||
|                     ) | ||||
| 
 | ||||
|                 _ -> | ||||
|                     -- should never happen | ||||
|                     ( state, Array.empty, i ) | ||||
| 
 | ||||
|         Nothing -> | ||||
|             case get3 index vs vts vns of | ||||
|                 Just ( p, t, n ) -> | ||||
|                     ( { state | ||||
|                         | knownVertexTexturesTangents = Dict.insert index currentIndex knownVertexTexturesTangents | ||||
|                         , currentIndex = currentIndex + 1 | ||||
|                       } | ||||
|                     , Array.fromList [ VertexWithTextureAndTangentT p t n s_dir t_dir ] | ||||
|                     , currentIndex | ||||
|                     ) | ||||
| 
 | ||||
|                 Nothing -> | ||||
|                     -- TODO: lift this error into a Result type | ||||
|                     ( state, Array.empty, -42 ) | ||||
|                         |> log ("index " ++ toString index ++ " out of bounds!\nThis should never happen with a well formed file") | ||||
| 
 | ||||
| 
 | ||||
| getOrInsertVN index ({ vs, vns, knownVertex, currentIndex } as state) = | ||||
|     case Dict.get index knownVertex of | ||||
|         Just i -> | ||||
|             ( state, [], i ) | ||||
| 
 | ||||
|         Nothing -> | ||||
|             case get2 index vs vns of | ||||
|                 Just ( p, n ) -> | ||||
|                     ( { state | ||||
|                         | knownVertex = Dict.insert index currentIndex knownVertex | ||||
|                         , currentIndex = currentIndex + 1 | ||||
|                       } | ||||
|                     , [ Vertex p n ] | ||||
|                     , currentIndex | ||||
|                     ) | ||||
| 
 | ||||
|                 Nothing -> | ||||
|                     -- TODO: lift this error into a Result type | ||||
|                     ( state, [], -42 ) | ||||
|                         |> log ("index " ++ toString index ++ " out of bounds!\nThis should never happen with a well formed file") | ||||
| 
 | ||||
| 
 | ||||
| fst2 ( a, b, c ) = | ||||
|     ( a, b ) | ||||
| 
 | ||||
| 
 | ||||
| arrayUpdate i f a = | ||||
|     case Array.get i a of | ||||
|         Just e -> | ||||
|             Array.set i (f e) a | ||||
| 
 | ||||
|         _ -> | ||||
|             a | ||||
| 
 | ||||
| 
 | ||||
| triangulate threeOrFour = | ||||
|     case threeOrFour of | ||||
|         Three t -> | ||||
|             [ t ] | ||||
| 
 | ||||
|         Four ( a, b, c, d ) -> | ||||
|             [ ( a, b, c ), ( d, a, c ) ] | ||||
| 
 | ||||
| 
 | ||||
| createMesh withTangents f = | ||||
|     let | ||||
|         emptyMesh = | ||||
|             { vertices = [], indices = [] } | ||||
|     in | ||||
|         case f of | ||||
|             FTVertexTextureNormal _ -> | ||||
|                 if withTangents then | ||||
|                     WithTextureAndTangentT { emptyMesh | vertices = Array.empty } | ||||
|                 else | ||||
|                     WithTextureT emptyMesh | ||||
| 
 | ||||
|             FTVertexNormal _ -> | ||||
|                 WithoutTextureT emptyMesh | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| -- | ||||
| -- Some helpers: | ||||
| -- | ||||
| 
 | ||||
| 
 | ||||
| t3map f ( a, b, c ) = | ||||
|     ( f a, f b, f c ) | ||||
| 
 | ||||
| 
 | ||||
| updateArray i f a = | ||||
|     case Array.get i a of | ||||
|         Just v -> | ||||
|             Array.set i (f v) a | ||||
| 
 | ||||
|         Nothing -> | ||||
|             a | ||||
| 
 | ||||
| 
 | ||||
| get3 ( a, b, c ) a1 a2 a3 = | ||||
|     case ( Array.get (a - 1) a1, Array.get (b - 1) a2, Array.get (c - 1) a3 ) of | ||||
|         ( Just a_, Just b_, Just c_ ) -> | ||||
|             Just ( a_, b_, c_ ) | ||||
| 
 | ||||
|         _ -> | ||||
|             Nothing | ||||
| 
 | ||||
| 
 | ||||
| get2 ( a, b ) a1 a2 = | ||||
|     case ( Array.get (a - 1) a1, Array.get (b - 1) a2 ) of | ||||
|         ( Just a_, Just b_ ) -> | ||||
|             Just ( a_, b_ ) | ||||
| 
 | ||||
|         _ -> | ||||
|             Nothing | ||||
							
								
								
									
										102
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/src/OBJ/InternalTypes.elm
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/src/OBJ/InternalTypes.elm
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,102 @@ | ||||
| module OBJ.InternalTypes exposing (..) | ||||
| 
 | ||||
| import Math.Vector3 exposing (Vec3) | ||||
| import Math.Vector2 exposing (Vec2) | ||||
| import Array.Hamt as Array exposing (Array) | ||||
| import OBJ.Types exposing (..) | ||||
| 
 | ||||
| 
 | ||||
| -- | ||||
| -- {- DEBUG -} | ||||
| -- | ||||
| -- import Native.Time | ||||
| -- | ||||
| -- | ||||
| -- debugNow : () -> Float | ||||
| -- debugNow = | ||||
| --     Native.Time.now | ||||
| -- | ||||
| -- | ||||
| -- time : String -> (() -> a) -> a | ||||
| -- time name f = | ||||
| --     let | ||||
| --         a = | ||||
| --             debugNow () | ||||
| --     in | ||||
| --         f () | ||||
| --             |> (\r -> log (name ++ ": " ++ toString (debugNow () - a) ++ " ms") r) | ||||
| 
 | ||||
| 
 | ||||
| log s a = | ||||
|     let | ||||
|         _ = | ||||
|             Debug.log s () | ||||
|     in | ||||
|         a | ||||
| 
 | ||||
| 
 | ||||
| type MeshT | ||||
|     = WithoutTextureT (MeshWith Vertex) | ||||
|     | WithTextureT (MeshWith VertexWithTexture) | ||||
|     | WithTextureAndTangentT (MeshWithT VertexWithTextureAndTangentT) | ||||
| 
 | ||||
| 
 | ||||
| type alias MeshWithT a = | ||||
|     { vertices : Array a | ||||
|     , indices : List Int3 | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| type alias VertexWithTextureAndTangentT = | ||||
|     { position : Vec3, texCoord : Vec2, normal : Vec3, sdir : Vec3, tdir : Vec3 } | ||||
| 
 | ||||
| 
 | ||||
| type | ||||
|     Line | ||||
|     -- v 1 3 4 | ||||
|     = V Vec3 | ||||
|       -- vt 2 4 | ||||
|     | Vt Vec2 | ||||
|       -- vn 3 3 1 | ||||
|     | Vn Vec3 | ||||
|       -- f 1 2 4 | ||||
|       -- f 1/3 2/3 1/7 | ||||
|       -- f 1/2/3 7/4/2 8/12/90 | ||||
|       -- f 4//8 4//1 6//2 | ||||
|     | F Face | ||||
|       -- steteful stuff | ||||
|     | Object String | ||||
|     | Group String | ||||
|     | Smooth String | ||||
|     | MtlLib String | ||||
|     | UseMtl String | ||||
| 
 | ||||
| 
 | ||||
| type Face | ||||
|     = FVertexTextureNormal (ThreeOrFour Int3) | ||||
|     | FVertexNormal (ThreeOrFour Int2) | ||||
| 
 | ||||
| 
 | ||||
| type FaceTriangle | ||||
|     = FTVertexTextureNormal ( Int3, Int3, Int3 ) | ||||
|     | FTVertexNormal ( Int2, Int2, Int2 ) | ||||
| 
 | ||||
| 
 | ||||
| type ThreeOrFour a | ||||
|     = Three ( a, a, a ) | ||||
|     | Four ( a, a, a, a ) | ||||
| 
 | ||||
| 
 | ||||
| type Group | ||||
|     = GV { faces : List Int3 } | ||||
|     | GVT { faces : List ( Int2, Int2, Int2 ) } | ||||
|     | GVTN { faces : List ( Int3, Int3, Int3 ) } | ||||
|     | GVN { faces : List ( Int2, Int2, Int2 ) } | ||||
| 
 | ||||
| 
 | ||||
| type alias Int2 = | ||||
|     ( Int, Int ) | ||||
| 
 | ||||
| 
 | ||||
| type alias Int3 = | ||||
|     ( Int, Int, Int ) | ||||
							
								
								
									
										258
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/src/OBJ/Parser.elm
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										258
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/src/OBJ/Parser.elm
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,258 @@ | ||||
| module OBJ.Parser exposing (..) | ||||
| 
 | ||||
| import Math.Vector3 as V3 exposing (Vec3, vec3) | ||||
| import Math.Vector2 as V2 exposing (Vec2, vec2) | ||||
| import Combine exposing (..) | ||||
| import Json.Decode as JD | ||||
| import Combine.Num exposing (..) | ||||
| import Combine.Char exposing (..) | ||||
| import OBJ.InternalTypes exposing (..) | ||||
| import Regex exposing (find, HowMany(..)) | ||||
| 
 | ||||
| 
 | ||||
| -- TODO: figure out how nice error messages work | ||||
| -- | ||||
| -- The obj specs: | ||||
| --  http://www.martinreddy.net/gfx/3d/OBJ.spec | ||||
| 
 | ||||
| 
 | ||||
| parse : String -> Result String (List Line) | ||||
| parse input = | ||||
|     String.split "\n" input | ||||
|         |> List.foldr parseLineAcc (Ok []) | ||||
| 
 | ||||
| 
 | ||||
| parseLineAcc : String -> Result String (List Line) -> Result String (List Line) | ||||
| parseLineAcc line acc = | ||||
|     case acc of | ||||
|         Ok lines -> | ||||
|             if canSkip line then | ||||
|                 Ok lines | ||||
|             else | ||||
|                 parseLine line | ||||
|                     |> Result.andThen | ||||
|                         (\l -> | ||||
|                             Ok (l :: lines) | ||||
|                         ) | ||||
| 
 | ||||
|         Err e -> | ||||
|             Err e | ||||
| 
 | ||||
| 
 | ||||
| canSkip line = | ||||
|     Regex.contains (Regex.regex "^((\\s*)|(\\s*#.*\\r?))$") line | ||||
| 
 | ||||
| 
 | ||||
| parseLine l = | ||||
|     case Combine.parse line l of | ||||
|         Ok ( _, stream, result ) -> | ||||
|             Ok result | ||||
| 
 | ||||
|         Err ( _, stream, errors ) -> | ||||
|             Err (formatError errors stream) | ||||
| 
 | ||||
| 
 | ||||
| file : Parser s (List Line) | ||||
| file = | ||||
|     (many ignoredLines) | ||||
|         *> sepBy (many1 ignoredLines) | ||||
|             line | ||||
|         <* (many ignoredLines) | ||||
|         <* end | ||||
| 
 | ||||
| 
 | ||||
| ignoredLines : Parser s () | ||||
| ignoredLines = | ||||
|     (skip eol) <|> (skip comment) | ||||
| 
 | ||||
| 
 | ||||
| objectName : Parser s String | ||||
| objectName = | ||||
|     regex "o[ \t]+" *> regex ".+" | ||||
| 
 | ||||
| 
 | ||||
| mtllib : Parser s String | ||||
| mtllib = | ||||
|     regex "mtllib[ \t]+" *> regex ".+" | ||||
| 
 | ||||
| 
 | ||||
| group : Parser s String | ||||
| group = | ||||
|     (regex "g[ \t]+" *> regex ".+") | ||||
|         <|> (char 'g' *> succeed "") | ||||
| 
 | ||||
| 
 | ||||
| smooth : Parser s String | ||||
| smooth = | ||||
|     regex "s[ \t]+" *> regex ".+" | ||||
| 
 | ||||
| 
 | ||||
| usemtl : Parser s String | ||||
| usemtl = | ||||
|     regex "usemtl[ \t]+" *> regex ".+" | ||||
| 
 | ||||
| 
 | ||||
| line : Parser s Line | ||||
| line = | ||||
|     choice | ||||
|         [ V <$> vertex | ||||
|         , Vt <$> vertexTexture | ||||
|         , Vn <$> vertexNormal | ||||
|         , F <$> face | ||||
|         , Object <$> objectName | ||||
|         , Group <$> group | ||||
|         , Smooth <$> smooth | ||||
|         , UseMtl <$> usemtl | ||||
|         , MtlLib <$> mtllib | ||||
|         ] | ||||
|         <* regex "[ \t]*" | ||||
| 
 | ||||
| 
 | ||||
| face : Parser s Face | ||||
| face = | ||||
|     regex "f[ \t]+" | ||||
|         *> choice | ||||
|             [ fVertexTextureNormal | ||||
|             , fVertexNormal | ||||
|             , fVertex | ||||
|             , fVertexTexture | ||||
|             ] | ||||
| 
 | ||||
| 
 | ||||
| fVertex : Parser s a | ||||
| fVertex = | ||||
|     threeOrFourValues int | ||||
|         *> fail "Models with no precalculated vertex normals are not supported!" | ||||
| 
 | ||||
| 
 | ||||
| fVertexTexture : Parser s a | ||||
| fVertexTexture = | ||||
|     threeOrFourValues int_int | ||||
|         *> fail "Models with no precalculated vertex normals are not supported!" | ||||
| 
 | ||||
| 
 | ||||
| fVertexTextureNormal : Parser s Face | ||||
| fVertexTextureNormal = | ||||
|     FVertexTextureNormal <$> threeOrFourValues int_int_int | ||||
| 
 | ||||
| 
 | ||||
| fVertexNormal : Parser s Face | ||||
| fVertexNormal = | ||||
|     FVertexNormal <$> threeOrFourValues int__int | ||||
| 
 | ||||
| 
 | ||||
| threeValues : (a -> a -> a -> b) -> Parser s a -> Parser s b | ||||
| threeValues tagger vtype = | ||||
|     tagger <$> (vtype) <*> (spaces *> vtype) <*> (spaces *> vtype) | ||||
| 
 | ||||
| 
 | ||||
| fourValues : (a -> a -> a -> a -> b) -> Parser s a -> Parser s b | ||||
| fourValues tagger vtype = | ||||
|     tagger <$> (vtype) <*> (spaces *> vtype) <*> (spaces *> vtype) <*> (spaces *> vtype) | ||||
| 
 | ||||
| 
 | ||||
| threeOrFourValues : Parser s a -> Parser s (ThreeOrFour a) | ||||
| threeOrFourValues elements = | ||||
|     (Four <$> (fourValues (,,,) elements)) | ||||
|         <|> (Three <$> (threeValues (,,) elements)) | ||||
| 
 | ||||
| 
 | ||||
| int_int : Parser s ( Int, Int ) | ||||
| int_int = | ||||
|     (,) <$> int <*> (string "/" *> int) | ||||
| 
 | ||||
| 
 | ||||
| int_int_int : Parser s ( Int, Int, Int ) | ||||
| int_int_int = | ||||
|     (,,) <$> int <*> (string "/" *> int) <*> (string "/" *> int) | ||||
| 
 | ||||
| 
 | ||||
| int__int : Parser s ( Int, Int ) | ||||
| int__int = | ||||
|     (,) <$> int <*> (string "//" *> int) | ||||
| 
 | ||||
| 
 | ||||
| vertexNormal : Parser s Vec3 | ||||
| vertexNormal = | ||||
|     regex "vn[ \t]+" *> (V3.normalize <$> vector3) | ||||
| 
 | ||||
| 
 | ||||
| vertexTexture : Parser s Vec2 | ||||
| vertexTexture = | ||||
|     regex "vt[ \t]+" *> ((ignoreZ <$> vector3) <|> vector2) | ||||
| 
 | ||||
| 
 | ||||
| vertex : Parser s Vec3 | ||||
| vertex = | ||||
|     regex "v[ \t]+" *> vector3 | ||||
| 
 | ||||
| 
 | ||||
| comment : Parser s String | ||||
| comment = | ||||
|     regex "#" *> regex ".*" | ||||
| 
 | ||||
| 
 | ||||
| vector3 : Parser s Vec3 | ||||
| vector3 = | ||||
|     threeValues vec3 betterFloat | ||||
| 
 | ||||
| 
 | ||||
| spaces : Parser s String | ||||
| spaces = | ||||
|     regex "[ \t]+" | ||||
| 
 | ||||
| 
 | ||||
| vector2 : Parser s Vec2 | ||||
| vector2 = | ||||
|     vec2 <$> betterFloat <*> (spaces *> betterFloat) | ||||
| 
 | ||||
| 
 | ||||
| betterFloat : Parser s Float | ||||
| betterFloat = | ||||
|     (\s -> Result.withDefault 0 (JD.decodeString JD.float s)) <$> regex "[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?" | ||||
| 
 | ||||
| 
 | ||||
| formatError : List String -> InputStream -> String | ||||
| formatError ms stream = | ||||
|     let | ||||
|         location = | ||||
|             currentLocation stream | ||||
| 
 | ||||
|         separator = | ||||
|             "| " | ||||
| 
 | ||||
|         expectationSeparator = | ||||
|             "\n  * " | ||||
| 
 | ||||
|         lineNumberOffset = | ||||
|             floor (logBase 10 (toFloat location.line)) + 1 | ||||
| 
 | ||||
|         separatorOffset = | ||||
|             String.length separator | ||||
| 
 | ||||
|         padding = | ||||
|             location.column + separatorOffset + 2 | ||||
|     in | ||||
|         "Parse error around line:\n\n" | ||||
|             ++ toString location.line | ||||
|             ++ separator | ||||
|             ++ location.source | ||||
|             ++ "\n" | ||||
|             ++ String.padLeft padding ' ' "^" | ||||
|             ++ "\nI expected one of the following:\n" | ||||
|             ++ expectationSeparator | ||||
|             ++ String.join expectationSeparator ms | ||||
| 
 | ||||
| 
 | ||||
| toInt : String -> Int | ||||
| toInt s = | ||||
|     String.toInt s |> Result.withDefault 0 | ||||
| 
 | ||||
| 
 | ||||
| ignoreZ : Vec3 -> Vec2 | ||||
| ignoreZ v = | ||||
|     let | ||||
|         ( x, y, _ ) = | ||||
|             V3.toTuple v | ||||
|     in | ||||
|         vec2 x y | ||||
							
								
								
									
										74
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/src/OBJ/Types.elm
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								elm-stuff/packages/Zinggi/elm-obj-loader/1.0.3/src/OBJ/Types.elm
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,74 @@ | ||||
| module OBJ.Types exposing (..) | ||||
| 
 | ||||
| {-| | ||||
| These are the types used by the obj loader. | ||||
| 
 | ||||
| @docs ObjFile, Mesh, MeshWith | ||||
| 
 | ||||
| -- | ||||
| @docs Vertex, VertexWithTexture, VertexWithTextureAndTangent | ||||
| 
 | ||||
| 
 | ||||
| -} | ||||
| 
 | ||||
| import Dict exposing (Dict) | ||||
| import Math.Vector2 exposing (Vec2) | ||||
| import Math.Vector3 exposing (Vec3) | ||||
| import Math.Vector4 exposing (Vec4) | ||||
| 
 | ||||
| 
 | ||||
| {-| A .obj file is optionally divided into different groups/objects. | ||||
| Each group/object is optionally made up of different meshes, each with it's own material. | ||||
| 
 | ||||
| So the keys of this dictionary are: | ||||
| 
 | ||||
|     Dict GroupNameOrObjectName (Dict MaterialName Mesh) | ||||
| 
 | ||||
| If no name is specified in the input file, "__default__" will be used instead. | ||||
| -} | ||||
| type alias ObjFile = | ||||
|     Dict String (Dict String Mesh) | ||||
| 
 | ||||
| 
 | ||||
| {-| | ||||
| A `Mesh` loaded by the obj loader is a record with a list of vertices and a list of indices. | ||||
| Depending on the mesh type and the loading options you get a different kind of mesh. | ||||
| They differ on what information a vertex contains. | ||||
| 
 | ||||
| These meshes are meant to be used with `WebGL.indexedTriangles mesh.vertices mesh.indices`. | ||||
| -} | ||||
| type Mesh | ||||
|     = WithoutTexture (MeshWith Vertex) | ||||
|     | WithTexture (MeshWith VertexWithTexture) | ||||
|     | WithTextureAndTangent (MeshWith VertexWithTextureAndTangent) | ||||
| 
 | ||||
| 
 | ||||
| {-| | ||||
| -} | ||||
| type alias MeshWith a = | ||||
|     { vertices : List a | ||||
|     , indices : List ( Int, Int, Int ) | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| {-| -} | ||||
| type alias Vertex = | ||||
|     { position : Vec3, normal : Vec3 } | ||||
| 
 | ||||
| 
 | ||||
| {-| -} | ||||
| type alias VertexWithTexture = | ||||
|     { position : Vec3, texCoord : Vec2, normal : Vec3 } | ||||
| 
 | ||||
| 
 | ||||
| {-| | ||||
| The `tangent` is a vector pointing tangential to the object surface, in the direction of the `u` texture coordinate. | ||||
| This is needed for doing tangent space normal mapping. | ||||
| The 4th component is either 1 or -1 and has to be used to get the bitangent in the glsl shader, | ||||
| e.g: `vec3 bitangent = cross(normal, tangent.xyz) * tangent.w` | ||||
| 
 | ||||
| more info here: | ||||
| https://web.archive.org/web/20160409104130/http://www.terathon.com/code/tangent.html | ||||
| -} | ||||
| type alias VertexWithTextureAndTangent = | ||||
|     { position : Vec3, texCoord : Vec2, normal : Vec3, tangent : Vec4 } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user