-- |
-- Module      :  HGE2D.Shapes
-- Copyright   :  (c) 2016 Martin Buck
-- License     :  see LICENSE
--
-- Containing basic shapes which can be used to define more complex ones through combination

module HGE2D.Shapes where

import HGE2D.Settings
import HGE2D.Types
import HGE2D.Datas
import HGE2D.GlFunctions

import qualified Graphics.Rendering.OpenGL as GL

--------------------------------------------------------------------------------

-- | A bordered rectangle define by width, height, thickness and two colors
borderedRectangle :: GlWidth -> GlHeight -> GlThickness -> GlColorRGB -> GlColorRGBA -> RenderInstruction
borderedRectangle w h t colorInner colorBorder = RenderMany
    [ RenderColorize colorInner
    , rectangle w h
    , RenderColorizeAlpha colorBorder
    , wireFrame w h t
    ]

-- | A line defined by its start and end points and a thickness
line :: GlPoint2 -> GlPoint2 -> GlThickness -> RenderInstruction
line start end w = RenderLineStrip [start, end] w

-- | A wireframe defined by width heigh and thickness (the borders of a box)
wireFrame :: GlWidth -> GlHeight -> GlThickness -> RenderInstruction
wireFrame w h t = RenderLineLoop [ll, lr, ur, ul] t
  where
    ll = point2 xMin yMin
    lr = point2 xMax yMin
    ur = point2 xMax yMax
    ul = point2 xMin yMax

    xMin = - (w/2)
    xMax =   (w/2)
    yMin = - (h/2)
    yMax =   (h/2)

-- | A rectangle defined by width and height
rectangle :: GlWidth -> GlHeight -> RenderInstruction
rectangle w h = RenderTriangle [ll, lr, ur, ur, ul, ll]
  where
    ll = point2 xMin yMin
    lr = point2 xMax yMin
    ur = point2 xMax yMax
    ul = point2 xMin yMax

    xMin = - (w/2)
    xMax =   (w/2)
    yMin = - (h/2)
    yMax =   (h/2)

-- | A ring defined by its radius and thickness
ring :: GlRadius -> GlThickness -> RenderInstruction
ring r w = RenderLineLoop (buildRing 0 []) w
  where
    buildRing :: Int -> GlShape -> GlShape
    buildRing nVertex prevShape
      | nVertex >= nFacesCircle = prevShape
      | otherwise = buildRing (nVertex+1) (prevShape ++ [vertex])
        where
          vertex = pointOnCircle nVertex

          pointOnCircle :: Int -> GlPoint2 ---TODO defined twice, move somewhere else
          pointOnCircle i = GL.Vertex2 x y
            where
              x = r * cos phi
              y = r * sin phi
              phi = 2.0 * pi * (fromIntegral i / fromIntegral nFacesCircle)

-- | A circle defined by its radius
circle :: GlRadius -> RenderInstruction
circle r = RenderTriangle (buildCircle 0 [])
  where
    buildCircle :: Int -> GlShape -> GlShape
    buildCircle nFace prevShape
      | nFace >= nFacesCircle = prevShape
      | otherwise = buildCircle (nFace+1) (prevShape ++ face)
        where
          face   = [(GL.Vertex2 0 0), first, second]
          first  = pointOnCircle nFace
          second = pointOnCircle (nFace+1)

          pointOnCircle :: Int -> GlPoint2
          pointOnCircle i = GL.Vertex2 x y
            where
              x = r * cos phi
              y = r * sin phi
              phi = 2.0 * pi * (fromIntegral i / fromIntegral nFacesCircle)