packages feed

geomancy-0.4.0.0: src/Geomancy/Swizzle.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

{- |
GLSL-style swizzles for every vector family.

Unlike the single-element fields, the swizzle instances are orphans.
Import this module to bring them all into scope:

> import Geomancy.Swizzle ()
>
> flip3 :: Vec3 -> Vec3
> flip3 v = v.zyx

Each family and kind of swizzle also has a module of its own,
@Geomancy.Swizzle.\<Family\>.\<Kind\>@, for when you need only some of them.
The families are @Vec@, @DVec@, @IVec@, @UVec@, @I64Vec@ and @U64Vec@, and the kinds are:

[@Shuffle@] keeps the size: @v.zyx@, @v.xxyy@, and the identity @v.xyz@.

[@Down@] narrows: @v.xy@ of a @Vec4@.

[@Up@] widens: @v.xyxy@ of a @Vec2@.

[@Extend@] widens with constant lanes, keeping the source in order: @v.xy0@, @v.xy01@, @v.xyz1@.

Swizzles chain, and the chains compile to plain lane reads:
@v.wzyx.zyx.yx.y@ is a single read of @v.y@.

While mask-swizzles aren't provided, you can chain an extend with a shuffle for this:

> white.xyz0.wyz      -- (0, y, z)
> v.yzw.xyz0.wxyz     -- (0, y, z, w) of a Vec4
> v.yz.xy01.zxyw      -- (0, y, z, 1) of a Vec3

The same swizzles work as labels with '(.@)' and @OverloadedLabels@: @v .\@ #zyx@.
-}
module Geomancy.Swizzle
  ( swizzle
  , (.@)
  ) where

import GHC.OverloadedLabels (IsLabel(..))
import GHC.Records (HasField(..))

import Geomancy.Swizzle.DVec.Down ()
import Geomancy.Swizzle.DVec.Extend ()
import Geomancy.Swizzle.DVec.Shuffle ()
import Geomancy.Swizzle.DVec.Up ()
import Geomancy.Swizzle.I64Vec.Down ()
import Geomancy.Swizzle.I64Vec.Extend ()
import Geomancy.Swizzle.I64Vec.Shuffle ()
import Geomancy.Swizzle.I64Vec.Up ()
import Geomancy.Swizzle.IVec.Down ()
import Geomancy.Swizzle.IVec.Extend ()
import Geomancy.Swizzle.IVec.Shuffle ()
import Geomancy.Swizzle.IVec.Up ()
import Geomancy.Swizzle.U64Vec.Down ()
import Geomancy.Swizzle.U64Vec.Extend ()
import Geomancy.Swizzle.U64Vec.Shuffle ()
import Geomancy.Swizzle.U64Vec.Up ()
import Geomancy.Swizzle.UVec.Down ()
import Geomancy.Swizzle.UVec.Extend ()
import Geomancy.Swizzle.UVec.Shuffle ()
import Geomancy.Swizzle.UVec.Up ()
import Geomancy.Swizzle.Vec.Down ()
import Geomancy.Swizzle.Vec.Extend ()
import Geomancy.Swizzle.Vec.Shuffle ()
import Geomancy.Swizzle.Vec.Up ()

newtype Swizzle to fro = Swizzle { swizzle :: fro -> to }

{-# INLINE (.@) #-}
(.@) :: forall to fro . fro -> Swizzle to fro -> to
v .@ Swizzle f = f v

instance HasField s fro to => IsLabel s (Swizzle to fro) where
  {-# INLINE fromLabel #-}
  fromLabel = Swizzle (getField @s)