Skip to content

Instantly share code, notes, and snippets.

@dptole
Last active August 24, 2020 09:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dptole/251a1fa4706442a2ca170f1772a1260c to your computer and use it in GitHub Desktop.
Save dptole/251a1fa4706442a2ca170f1772a1260c to your computer and use it in GitHub Desktop.
WebGL standalone example: Traceable cartesian plane (elm) https://ellie-app.com/7CqCLBYQCYHa1
-- https://ellie-app.com/7CqCLBYQCYHa1
-- https://webglfundamentals.org/
-- elm install elm-explorations/linear-algebra
-- elm install elm-explorations/webgl
-- elm install elm/json
module Main exposing (..)
import Browser
import Json.Decode
import Html
import Html.Attributes
import Html.Events
import Math.Vector3
import WebGL
-- MAIN
main =
Browser.element
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
-- MODEL
type alias Coords =
{ x : Int
, y : Int
}
type alias Model =
{ x : Int
, y : Int
, v : List Vertex
, canvas_width : Int
, canvas_height : Int
}
init : () -> ( Model, Cmd Msg )
init () =
( Model 0 0 [] 300 300, Cmd.none )
-- UPDATE
type Msg
= CartesianPlaneCoords Coords
| RemoveLastVertex
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
RemoveLastVertex ->
( { model
| v = List.take ( List.length model.v - 1 ) model.v
}
, Cmd.none
)
CartesianPlaneCoords {x, y} ->
let
vertex_x =
toFloat x / toFloat model.canvas_width
|> (*) 2
|> firstMinusSecond 1.0
|> (*) 10
|> round
|> toFloat
|> firstDivideSecond 10.0
vertex_y =
toFloat y / toFloat model.canvas_height
|> (*) 2
|> (-) 1
|> (*) 10
|> round
|> toFloat
|> firstDivideSecond 10.0
v =
List.append
model.v
[ Vertex ( Math.Vector3.vec3 vertex_x vertex_y 0 ) ( Math.Vector3.vec3 1 0 0 ) ]
in
( { model
| x = x
, y = y
, v = v
}
, Cmd.none
)
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.none
-- VIEW
view : Model -> Html.Html Msg
view model =
Html.div
[]
[ WebGL.toHtml
[ Html.Attributes.width model.canvas_width
, Html.Attributes.height model.canvas_height
, Html.Attributes.style "display" "block"
, Html.Events.on "click"
(Json.Decode.map2 Coords
(Json.Decode.field "offsetX" Json.Decode.int)
(Json.Decode.field "offsetY" Json.Decode.int)
|> Json.Decode.map CartesianPlaneCoords
)
]
[ WebGL.entity vertexShader fragmentShader ( mesh model.v ) Uniforms ]
, Html.div
[]
[ Html.input
[ Html.Attributes.type_ "button"
, Html.Attributes.value "Remove last vertex"
, Html.Events.onClick RemoveLastVertex
]
[]
]
, Html.pre
[ Html.Attributes.style "white-space" "pre-wrap" ]
[ Html.text <| Debug.toString model ]
]
-- MISC
firstMinusSecond : number -> number -> number
firstMinusSecond a b =
b - a
firstDivideSecond : Float -> Float -> Float
firstDivideSecond a b =
b / a
-- MESH
type alias Vertex =
{ position : Math.Vector3.Vec3
, color : Math.Vector3.Vec3
}
mesh : List Vertex -> WebGL.Mesh Vertex
mesh vertexes =
let
pairedVertexes : List a -> List (a, a)
pairedVertexes p =
case p of
p1 :: p2 :: rest ->
( p1, p2 ) :: pairedVertexes ( p2 :: rest )
_ ->
[]
vertex_points =
pairedVertexes vertexes
in
-- In WebGL clipspace goes from -1 to 1
-- https://webglfundamentals.org/webgl/lessons/webgl-fundamentals.html
List.range -10 10
|> List.map (\i -> ( toFloat i ) / 10.0)
|> List.concatMap
(\i ->
let
position_horizontal_line_coord_1 =
Math.Vector3.vec3 -1 i 0
position_horizontal_line_coord_2 =
Math.Vector3.vec3 1 i 0
position_vertical_line_coord_1 =
Math.Vector3.vec3 i 1 0
position_vertical_line_coord_2 =
Math.Vector3.vec3 i -1 0
vcolor =
if i == 0 then -- Axis
Math.Vector3.vec3 0.3 0.3 0.3
else
Math.Vector3.vec3 0.6 0.6 0.6
in
[ ( Vertex position_horizontal_line_coord_1 vcolor
, Vertex position_horizontal_line_coord_2 vcolor
)
, ( Vertex position_vertical_line_coord_1 vcolor
, Vertex position_vertical_line_coord_2 vcolor
)
]
)
|> List.append vertex_points
|> WebGL.lines
-- SHADERS
type alias Uniforms =
{}
vertexShader : WebGL.Shader Vertex Uniforms { vcolor : Math.Vector3.Vec3 }
vertexShader =
[glsl|
attribute vec3 position;
attribute vec3 color;
varying vec3 vcolor;
void main () {
gl_Position = vec4(position, 1.0);
vcolor = color;
}
|]
fragmentShader : WebGL.Shader {} Uniforms { vcolor : Math.Vector3.Vec3 }
fragmentShader =
[glsl|
precision mediump float;
varying vec3 vcolor;
void main () {
gl_FragColor = vec4(vcolor, 1.0);
}
|]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment