Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/terrain improvements #322

Merged
merged 3 commits into from
Jan 2, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 62 additions & 70 deletions src/Page/Terrain.elm
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
module Page.Terrain exposing (Model, Msg, info, init, subscriptions, update, view)

import Basics.Extra exposing (curry)
import Browser.Events exposing (onAnimationFrameDelta)
import Color exposing (black, blue, toCssString)
import Color.Manipulate exposing (darken)
import Html exposing (Html, div, input, p, section, text)
import Html.Attributes as Attr exposing (name, size, type_, value)
import Html.Events exposing (onInput)
Expand Down Expand Up @@ -42,9 +43,13 @@ type alias Parameters =
, nbCurves : Int
, near : Float
, offsetFactor : Float
, xScale : Float
, yScale : Float
, depth : Int
, hurst : Float
, mountainProbability : Float
, shapeColor : Color.Color
, groundColor : Color.Color
}


Expand All @@ -67,7 +72,7 @@ init =
initialParameters

initialSeed =
Random.initialSeed 42
Random.initialSeed 40

curveGenerator =
generateFractal parameters.depth parameters.hurst (initialCurve parameters.mountainProbability)
Expand All @@ -93,9 +98,13 @@ initialParameters =
, nbCurves = 40
, near = 300
, offsetFactor = 20.0
, xScale = 3.5
, yScale = 1.5
, depth = 4
, hurst = 0.3
, hurst = 1.2
, mountainProbability = 0.1
, shapeColor = blue
, groundColor = darken 0.3 blue
}


Expand Down Expand Up @@ -234,20 +243,17 @@ view (Model { parameters, terrain }) =


type alias ViewTerrainParams a =
{ a | width : Int, height : Int, near : Float, offsetFactor : Float }
{ a | width : Int, height : Int, near : Float, offsetFactor : Float, xScale : Float, yScale : Float, shapeColor : Color.Color, groundColor : Color.Color }


viewTerrain : ViewTerrainParams a -> Terrain -> Svg Msg
viewTerrain { width, height, near, offsetFactor } terrain =
viewTerrain ({ width, height, near, offsetFactor, xScale, yScale } as params) terrain =
let
scaleFactor =
2

offsetYPct =
0.4
0.5

( offsetX, offsetY ) =
( toFloat width * (1 - scaleFactor) / 2, offsetYPct * toFloat height )
( toFloat width * (1 - xScale) / 2, offsetYPct * toFloat height )

terrains =
terrain
Expand All @@ -259,7 +265,7 @@ viewTerrain { width, height, near, offsetFactor } terrain =
offset * offsetFactor

( zoomX, zoomY ) =
( toFloat width / (toFloat <| List.length curve), 1 )
( toFloat width / (toFloat <| List.length curve), yScale )

perspectiveFactor =
near / (near + z)
Expand Down Expand Up @@ -288,7 +294,7 @@ viewTerrain { width, height, near, offsetFactor } terrain =
++ ")"
)
]
(viewCurve curve)
(viewCurve params curve)
)
in
Svg.svg
Expand All @@ -306,39 +312,45 @@ viewTerrain { width, height, near, offsetFactor } terrain =
, y "0"
, SvgAttr.width (fromInt width)
, SvgAttr.height (fromInt height)
, fill "black"
, fill <| toCssString black
, strokeWidth "0"
]
[]
]
, Svg.g
[ transform ("translate(" ++ fromFloat offsetX ++ "," ++ fromFloat (toFloat height + offsetY) ++ ") scale(" ++ fromFloat scaleFactor ++ ", -1)") ]
[ transform ("translate(" ++ fromFloat offsetX ++ "," ++ fromFloat (toFloat height + offsetY) ++ ") scale(" ++ fromFloat xScale ++ ", -1)") ]
[ Svg.g
[ Attr.id "terrain" ]
terrains
]
]


viewCurve : Curve -> List (Svg Msg)
viewCurve curve =
type alias ViewCurveParams a =
{ a | shapeColor : Color.Color, groundColor : Color.Color }


viewCurve : ViewCurveParams a -> Curve -> List (Svg Msg)
viewCurve { shapeColor, groundColor } curve =
let
pts =
curve
|> curvePoints
|> List.map (\p -> ( p |> Vec2.getX, p |> Vec2.getY ))
|> List.map (\( x, y ) -> String.fromFloat x ++ "," ++ String.fromFloat y)
|> List.map (\p -> String.fromFloat (Vec2.getX p) ++ "," ++ String.fromFloat (Vec2.getY p))

path =
"M 0,0 "
++ List.foldl (\p acc -> acc ++ " L " ++ p) "" pts
++ " V 0 Z"
"M 0,0 " ++ String.join " L " pts ++ " V 0 Z"

polyline =
join " " pts
String.join " " pts

groundPath =
"M 0,0 L " ++ String.fromInt (List.length curve) ++ ",0"
in
[ Svg.path [ d path, fill "black", stroke "none" ] []
, Svg.polyline [ points polyline, fill "none", stroke "blue", strokeWidth "0.5" ] []
, Svg.polyline [ points polyline, fill "none", stroke <| toCssString shapeColor, strokeWidth "0.5" ]
[]
, Svg.path [ d groundPath, fill "none", stroke <| toCssString groundColor, strokeWidth "2" ] []
]


Expand Down Expand Up @@ -424,75 +436,55 @@ terrainGenerator indexToOffset curveGenerator nbCurves =



-- MISCELLANEOUS
-- FBM


fBm : Int -> Float -> Random.Generator Curve -> Random.Generator Curve
fBm depth hurst baseGenerator =
List.foldl
(\_ gen -> fBmAtDepth depth hurst gen)
baseGenerator
(List.range 1 depth)


fBmAtDepth : Int -> Float -> Random.Generator Curve -> Random.Generator Curve
fBmAtDepth depth hurst curveGenerator =
if depth == 0 then
curveGenerator
fBm depth hurst genCurve =
if depth <= 0 then
genCurve

else
let
generateMidpoint : Random.Generator Float -> Random.Generator Float -> Random.Generator Float
generateMidpoint a b =
Random.map2 (curry (midpointDisplacementGenerator (2 * hurst * (depth |> toFloat)))) a b
|> Random.andThen identity

refine : List Float -> Random.Generator Curve
refine =
List.map Random.constant
>> insertBetween generateMidpoint
>> combineGenerators
in
curveGenerator
|> Random.andThen refine
genCurve
|> Random.andThen
(\points ->
subdivideAndCombine points (\( a, b ) -> midpointDisplacementGenerator hurst ( a, b ))
|> Random.andThen
(\refinedPoints ->
fBm (depth - 1) hurst (Random.constant refinedPoints)
)
)


midpointDisplacementGenerator : Float -> ( Float, Float ) -> Random.Generator Float
midpointDisplacementGenerator hurst ( a, b ) =
let
midpoint : Float
midpoint =
(a + b) / 2

delta : Float
delta =
abs (a - b) * 2 ^ -hurst
abs (a - b) * (2 ^ -hurst)

rg : Random.Generator Float
rg =
randomDisplacement =
Random.float -delta delta
in
rg |> Random.map (\r -> midpoint + r)
Random.map (\d -> midpoint + d) randomDisplacement


combineGenerators : List (Random.Generator a) -> Random.Generator (List a)
combineGenerators list =
case list of
subdivideAndCombine :
List Float
-> (( Float, Float ) -> Random.Generator Float)
-> Random.Generator Curve
subdivideAndCombine points combine =
case points of
[] ->
Random.constant []

gen :: gens ->
Random.map2 (::) gen (combineGenerators gens)


insertBetween : (a -> a -> a) -> List a -> List a
insertBetween f list =
case list of
[] ->
[]

[ x ] ->
[ x ]
Random.constant [ x ]

x :: y :: rest ->
x :: f x y :: insertBetween f (y :: rest)
Random.map2
(\mid newTail -> x :: mid :: newTail)
(combine ( x, y ))
(subdivideAndCombine (y :: rest) combine)
Loading