{-# LANGUAGE BangPatterns #-}

{-
  Copyright 2020 The CodeWorld Authors. All rights reserved.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-}
module CodeWorld.DrawState where

import CodeWorld.Color

data DrawState
  = -- | A 'Color', if already chosen.
    DrawState
      !AffineTransformation
      !(Maybe Color)

-- | @(AffineTransformation a b c d e f)@ represents an affine transformation matrix
--
-- > a c e
-- > b d f
-- > 0 0 1
--
-- References:
-- https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/transform
-- https://en.wikipedia.org/wiki/Transformation_matrix#Affine_transformations
data AffineTransformation
  = AffineTransformation !Double !Double !Double !Double !Double !Double

initialAffineTransformation :: AffineTransformation
initialAffineTransformation :: AffineTransformation
initialAffineTransformation = Double
-> Double
-> Double
-> Double
-> Double
-> Double
-> AffineTransformation
AffineTransformation Double
1 Double
0 Double
0 Double
1 Double
0 Double
0

mapDSAT :: (AffineTransformation -> AffineTransformation) -> DrawState -> DrawState
mapDSAT :: (AffineTransformation -> AffineTransformation)
-> DrawState -> DrawState
mapDSAT AffineTransformation -> AffineTransformation
f (DrawState AffineTransformation
at Maybe Color
mc) = AffineTransformation -> Maybe Color -> DrawState
DrawState (AffineTransformation -> AffineTransformation
f AffineTransformation
at) Maybe Color
mc

mapDSColor :: (Maybe Color -> Maybe Color) -> DrawState -> DrawState
mapDSColor :: (Maybe Color -> Maybe Color) -> DrawState -> DrawState
mapDSColor Maybe Color -> Maybe Color
f (DrawState AffineTransformation
at Maybe Color
mc) = AffineTransformation -> Maybe Color -> DrawState
DrawState AffineTransformation
at (Maybe Color -> Maybe Color
f Maybe Color
mc)

initialDS :: DrawState
initialDS :: DrawState
initialDS = AffineTransformation -> Maybe Color -> DrawState
DrawState AffineTransformation
initialAffineTransformation forall a. Maybe a
Nothing

translateDS :: Double -> Double -> DrawState -> DrawState
translateDS :: Double -> Double -> DrawState -> DrawState
translateDS Double
x Double
y = (AffineTransformation -> AffineTransformation)
-> DrawState -> DrawState
mapDSAT forall a b. (a -> b) -> a -> b
$ \(AffineTransformation Double
a Double
b Double
c Double
d Double
e Double
f) ->
  Double
-> Double
-> Double
-> Double
-> Double
-> Double
-> AffineTransformation
AffineTransformation
    Double
a
    Double
b
    Double
c
    Double
d
    (Double
a forall a. Num a => a -> a -> a
* Double
x forall a. Num a => a -> a -> a
+ Double
c forall a. Num a => a -> a -> a
* Double
y forall a. Num a => a -> a -> a
+ Double
e)
    (Double
b forall a. Num a => a -> a -> a
* Double
x forall a. Num a => a -> a -> a
+ Double
d forall a. Num a => a -> a -> a
* Double
y forall a. Num a => a -> a -> a
+ Double
f)

scaleDS :: Double -> Double -> DrawState -> DrawState
scaleDS :: Double -> Double -> DrawState -> DrawState
scaleDS Double
x Double
y = (AffineTransformation -> AffineTransformation)
-> DrawState -> DrawState
mapDSAT forall a b. (a -> b) -> a -> b
$ \(AffineTransformation Double
a Double
b Double
c Double
d Double
e Double
f) ->
  Double
-> Double
-> Double
-> Double
-> Double
-> Double
-> AffineTransformation
AffineTransformation (Double
x forall a. Num a => a -> a -> a
* Double
a) (Double
x forall a. Num a => a -> a -> a
* Double
b) (Double
y forall a. Num a => a -> a -> a
* Double
c) (Double
y forall a. Num a => a -> a -> a
* Double
d) Double
e Double
f

rotateDS :: Double -> DrawState -> DrawState
rotateDS :: Double -> DrawState -> DrawState
rotateDS Double
r = (AffineTransformation -> AffineTransformation)
-> DrawState -> DrawState
mapDSAT forall a b. (a -> b) -> a -> b
$ \(AffineTransformation Double
a Double
b Double
c Double
d Double
e Double
f) ->
  Double
-> Double
-> Double
-> Double
-> Double
-> Double
-> AffineTransformation
AffineTransformation
    (Double
a forall a. Num a => a -> a -> a
* forall a. Floating a => a -> a
cos Double
r forall a. Num a => a -> a -> a
+ Double
c forall a. Num a => a -> a -> a
* forall a. Floating a => a -> a
sin Double
r)
    (Double
b forall a. Num a => a -> a -> a
* forall a. Floating a => a -> a
cos Double
r forall a. Num a => a -> a -> a
+ Double
d forall a. Num a => a -> a -> a
* forall a. Floating a => a -> a
sin Double
r)
    (Double
c forall a. Num a => a -> a -> a
* forall a. Floating a => a -> a
cos Double
r forall a. Num a => a -> a -> a
- Double
a forall a. Num a => a -> a -> a
* forall a. Floating a => a -> a
sin Double
r)
    (Double
d forall a. Num a => a -> a -> a
* forall a. Floating a => a -> a
cos Double
r forall a. Num a => a -> a -> a
- Double
b forall a. Num a => a -> a -> a
* forall a. Floating a => a -> a
sin Double
r)
    Double
e
    Double
f

reflectDS :: Double -> DrawState -> DrawState
reflectDS :: Double -> DrawState -> DrawState
reflectDS Double
th = (AffineTransformation -> AffineTransformation)
-> DrawState -> DrawState
mapDSAT forall a b. (a -> b) -> a -> b
$ \(AffineTransformation Double
a Double
b Double
c Double
d Double
e Double
f) ->
  Double
-> Double
-> Double
-> Double
-> Double
-> Double
-> AffineTransformation
AffineTransformation
    (Double
a forall a. Num a => a -> a -> a
* forall a. Floating a => a -> a
cos Double
r forall a. Num a => a -> a -> a
+ Double
c forall a. Num a => a -> a -> a
* forall a. Floating a => a -> a
sin Double
r)
    (Double
b forall a. Num a => a -> a -> a
* forall a. Floating a => a -> a
cos Double
r forall a. Num a => a -> a -> a
+ Double
d forall a. Num a => a -> a -> a
* forall a. Floating a => a -> a
sin Double
r)
    (Double
a forall a. Num a => a -> a -> a
* forall a. Floating a => a -> a
sin Double
r forall a. Num a => a -> a -> a
- Double
c forall a. Num a => a -> a -> a
* forall a. Floating a => a -> a
cos Double
r)
    (Double
b forall a. Num a => a -> a -> a
* forall a. Floating a => a -> a
sin Double
r forall a. Num a => a -> a -> a
- Double
d forall a. Num a => a -> a -> a
* forall a. Floating a => a -> a
cos Double
r)
    Double
e
    Double
f
  where
    r :: Double
r = Double
2 forall a. Num a => a -> a -> a
* Double
th

setColorDS :: Color -> DrawState -> DrawState
setColorDS :: Color -> DrawState -> DrawState
setColorDS Color
col = (Maybe Color -> Maybe Color) -> DrawState -> DrawState
mapDSColor forall a b. (a -> b) -> a -> b
$ \Maybe Color
mcol ->
  case (Color
col, Maybe Color
mcol) of
    (Color
_, Maybe Color
Nothing) -> forall a. a -> Maybe a
Just Color
col
    (RGBA Double
_ Double
_ Double
_ Double
0, Just Color
_) -> forall a. a -> Maybe a
Just Color
col
    (RGBA Double
_ Double
_ Double
_ Double
a1, Just (RGBA Double
r0 Double
g0 Double
b0 Double
a0)) -> forall a. a -> Maybe a
Just (Double -> Double -> Double -> Double -> Color
RGBA Double
r0 Double
g0 Double
b0 (Double
a0 forall a. Num a => a -> a -> a
* Double
a1))

opaqueDS :: DrawState -> DrawState
opaqueDS :: DrawState -> DrawState
opaqueDS = (Maybe Color -> Maybe Color) -> DrawState -> DrawState
mapDSColor forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (a -> b) -> a -> b
$ \(RGBA Double
r Double
g Double
b Double
_) -> Double -> Double -> Double -> Double -> Color
RGBA Double
r Double
g Double
b Double
1

getColorDS :: DrawState -> Maybe Color
getColorDS :: DrawState -> Maybe Color
getColorDS (DrawState AffineTransformation
_ Maybe Color
col) = Maybe Color
col