{- ORMOLU_DISABLE -}
-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
-- Copyright (C) 2016 Julia Longtin (julial@turinglace.com)
-- Released under the GNU AGPLV3+, see LICENSE

-- FIXME: describe why we need this.
{-# LANGUAGE OverloadedStrings #-}

module Graphics.Implicit.Export.NormedTriangleMeshFormats (obj) where

import Prelude(($), fmap, (+), (.), (*), length, (-), pure, (<>))

import Graphics.Implicit.Definitions (NormedTriangle(NormedTriangle), NormedTriangleMesh(getNormedTriangles), ℝ3)
import Graphics.Implicit.Export.TextBuilderUtils (Text, Builder, toLazyText, bf, buildInt)

import Data.Foldable (fold, foldMap)
import Linear (V3(V3))

-- | Generate a .obj format file from a NormedTriangleMesh
--   see: https://en.wikipedia.org/wiki/Wavefront_.obj_file
obj :: NormedTriangleMesh -> Text
obj :: NormedTriangleMesh -> Text
obj NormedTriangleMesh
mesh = Builder -> Text
toLazyText (Builder -> Text) -> Builder -> Text
forall a b. (a -> b) -> a -> b
$ Builder
vertcode Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
normcode Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
trianglecode
    where
        -- A vertex line; v (0.0, 0.0, 1.0) = "v 0.0 0.0 1.0\n"
        v :: ℝ3 -> Builder
        v :: ℝ3 -> Builder
v (V3 x y z) = Builder
"v "  Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> ℝ -> Builder
bf x Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
" " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> ℝ -> Builder
bf y Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
" " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> ℝ -> Builder
bf z Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"\n"
        -- A normal line; n (0.0, 0.0, 1.0) = "vn 0.0 0.0 1.0\n"
        n :: ℝ3 -> Builder
        n :: ℝ3 -> Builder
n (V3 x y z) = Builder
"vn " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> ℝ -> Builder
bf x Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
" " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> ℝ -> Builder
bf y Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
" " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> ℝ -> Builder
bf z Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"\n"
        verts :: [ℝ3]
verts = do
            --  Extract the vertices for each triangle.
            --  recall that a normed triangle is of the form ((vert, norm), ...)
            NormedTriangle ((ℝ3
a,ℝ3
_),(ℝ3
b,ℝ3
_),(ℝ3
c,ℝ3
_)) <- [NormedTriangle]
normedTriangles
            -- The vertices from each triangle take up 3 positions in the resulting list
            [ℝ3
a,ℝ3
b,ℝ3
c]
        norms :: [ℝ3]
norms = do
            -- extract the normals for each triangle
            NormedTriangle ((ℝ3
_,ℝ3
a),(ℝ3
_,ℝ3
b),(ℝ3
_,ℝ3
c)) <- [NormedTriangle]
normedTriangles
            -- The normals from each triangle take up 3 positions in the resulting list
            [ℝ3
a,ℝ3
b,ℝ3
c]
        vertcode :: Builder
vertcode = (ℝ3 -> Builder) -> [ℝ3] -> Builder
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap ℝ3 -> Builder
v [ℝ3]
verts
        normcode :: Builder
normcode = (ℝ3 -> Builder) -> [ℝ3] -> Builder
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap ℝ3 -> Builder
n [ℝ3]
norms
        trianglecode :: Builder
        trianglecode :: Builder
trianglecode = [Builder] -> Builder
forall (t :: * -> *) m. (Foldable t, Monoid m) => t m -> m
fold ([Builder] -> Builder) -> [Builder] -> Builder
forall a b. (a -> b) -> a -> b
$ do
            Int
n' <- (Int -> Int) -> [Int] -> [Int]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Int -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)(Int -> Int) -> (Int -> Int) -> Int -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Int -> Int -> Int
forall a. Num a => a -> a -> a
*Int
3)) [Int
0,Int
1 .. [NormedTriangle] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [NormedTriangle]
normedTriangles Int -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1]
            let
                vta :: Builder
vta = Int -> Builder
buildInt  Int
n'
                vtb :: Builder
vtb = Int -> Builder
buildInt (Int
n'Int -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)
                vtc :: Builder
vtc = Int -> Builder
buildInt (Int
n'Int -> Int -> Int
forall a. Num a => a -> a -> a
+Int
2)
            Builder -> [Builder]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Builder -> [Builder]) -> Builder -> [Builder]
forall a b. (a -> b) -> a -> b
$ Builder
"f " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
vta Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
" " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
vtb Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
" " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
vtc Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
" " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"\n"
        normedTriangles :: [NormedTriangle]
normedTriangles = NormedTriangleMesh -> [NormedTriangle]
getNormedTriangles NormedTriangleMesh
mesh