packages feed

SVGFonts-0.3: src/Test/Fonts.hs

module Main where

import Graphics.Rendering.OpenGL
import Graphics.UI.GLUT as GLUT-- (getArgsAndInitialize, initialDisplayMode, createWindow, windowSize, keyboardMouseCallback, idleCallback, displayCallback, reshapeCallback, mainLoop, swapBuffers, DisplayMode(..))
import Data.IORef
import System.IO.Unsafe (unsafePerformIO)
import Test.PointOfView
import Graphics.SVGFonts.ReadFont(displayString, AObj(..), Prop(..), Mode(..), Spacing(..), CharProp(..), makeMaps)
import Data.Tuple.Select
import Paths_SVGFonts(getDataFileName)

main= do
  (progName,_) <- getArgsAndInitialize
  initialDisplayMode $= [WithDepthBuffer, DoubleBuffered, RGBAMode, WithAlphaComponent, WithAccumBuffer]
  createWindow progName
  windowSize $= Size 800 600
  myInit

  gawFile <- getDataFileName "src/Test/GirlsareWeird.svg"
  linFile <- getDataFileName "src/Test/LinLibertine.svg"

  let resolution = (400, 400)
   -- mode: INSIDE_V1_V2_V3: the string is inside v1 v2 v3 boundaries (height/length-relation not kept)
   -- mode: INSIDE_V1: stay inside v1 boundary, size of v2 adjusted to height/length-relation
   -- mode: INSIDE_V2: stay inside v2 boundary, size of v1 adjusted to height/length-relation
      mode = INSIDE_V2
   -- spacing: MONO: use mono spacing between glyphs
   --          HADV: every glyph has a unique constant horiz. advance
   --          KERN: same as 1 but sometimes overridden by kerning: i.e. the horizontal advance in "VV" is bigger than in "VA"
      spacing = HADV
      gaw = makeMaps gawFile resolution
      lin = makeMaps linFile resolution
      o = (0,0,0) -- origin
      v1 = (5,0,0) -- direction of char-advance
      v2 = (0,0,-1) -- height direction
      v3 = (0,0.2,0) -- extrusion
      f :: [Char] -> [(Char,[CharProp])]
      f (a:(b:(c:d))) = addStrProp ( [(a,[Textured, ObjColor 255 0 0 255]), -- no color yet
                                      (b,[Outline v3]),
                                      (c,[Textured, ObjColor 0 0 255 255])] ++ (f d) ) [Font gaw]
      f _ = [] -- data CharProp = Outline V | Textured | ObjColor Int Int Int Int | Font (FontData, OutlineMap, TexMap)
      addStrProp xs prop = map (\(a,bs) -> (a, bs ++ prop)) xs
      onlyTextures (Annotate vs (TexObj (texobjs,str))) = Annotate vs (Textur (Just texobjs))
                                              -- str is the filename of the texture (for collada-output)
      onlyTextures (Annotate vs rest) = Annotate vs rest

      str = displayString "abcdef" resolution mode spacing (0,0,1.1) v1 v2 f

  g <- return ( G (map onlyTextures str) )

  putStrLn "Font read"
  l <- defineNewList Compile $ do display_g ( g )

  pPos <- newIORef (0::GLdouble,1::GLdouble,0::GLdouble, 0::GLdouble,0::GLdouble,0::GLdouble,
                    0::GLdouble,0::GLdouble,-1::GLdouble)
  -- 0,1,0 : point of location in x,y,z then 0,0,0: where to look at
  -- 0,0,-1: up direction
  keystate <- newIORef []
  keyboardMouseCallback $= Just (keyboard keystate)
  idleCallback$= Just (idle pPos)
  displayCallback $= display keystate pPos l
  reshapeCallback $= Just reshape
  mainLoop

-- Initialize lighting and other values.
myInit :: IO ()
myInit = do
   materialAmbient Front $= Color4 1 0.5 1 1
   materialSpecular Front $= Color4 0.2 1 0.8 1
   materialShininess Front $= 50
   
   position (Light 0) $= Vertex4 5 5 10 0
   lightModelAmbient $= Color4 0.2 0.2 0.2 1

   -- cullFace $= Just Back
   lighting $= Enabled
   light (Light 0) $= Enabled
   depthFunc $= Just Less
   shadeModel $= Flat
   normalize $= Enabled
   rowAlignment Unpack $= 1

   clearColor $= Color4 0.2 0 0 0
   clearAccum $= Color4 0 0 0 0

   blendFunc $= (SrcAlpha, OneMinusSrcAlpha)
   textureFunction $= Replace
   texture Texture2D $= Enabled

display keystate pPos l = do
  loadIdentity
  setPointOfView keystate pPos
  clear [ColorBuffer,DepthBuffer]
  callList l
  --deleteLists [l]
  swapBuffers

data Obj = G  [ AObj ]  | -- extruded objects in coords (G for Geometry)
              Nil

blue  = RedGreenBlue (0,0,1)

-- ========================================================
-- conversion into G [AObj]  (mainly with eval3d)
-- meaning of G [AObj] by example:
-- G [Annotate [1] pr, Annotate [2] pr, Annotate [3] pr, Annotate [4] pr] = four single points (0d)
-- G [Annotate [1,2] pr, Annotate [2,3] pr, Annotate [3,4] pr, Annotate [4,1] pr] = four lines (1d)
-- G [Annotate [1,2,3,4] pr]  a rectangle (2d)
-- G [Annotate [1,2,3,4] pr, Annotate [3,4,5,6] pr, Annotate [1,2,7,8] pr] = a 3d object, consisting of several rectangles
-- ========================================================

redG (G obj) = obj

add (x0,y0,z0) (x1,y1,z1) = (x0+x1, y0+y1, z0+z1)
sub (x0,y0,z0) (x1,y1,z1) = (x0-x1, y0-y1, z0-z1)

skalar (x,y,z) (a,b,c) = x*a + y*b + z*c

-- ====================================================================
-- displaying   (this is slow immediate mode, but it is just for testing)
-- ====================================================================
loc = preservingMatrix

display_g :: Obj -> IO()
display_g (G []) = return ()
display_g Nil = return()

display_g (G (p:ps)) = disp p >> display_g (G ps)

map3 = map (\(x,y,z) -> (realToFrac x, realToFrac y, realToFrac z))

disp :: AObj -> IO()
disp (Annotate ps ( Triangul tris )) = do diplay_primitive (generate_from_index (map3 ps) tris) blue Triangles
disp (Annotate ps pr) | (length ps) == 1 = do diplay_primitive (map3 ps) pr Points
                      | (length ps) == 2 = do diplay_primitive (map3 ps) pr Lines
                      | otherwise        = do diplay_primitive (map3 ps) pr Polygon

generate_from_index :: [(GLfloat,GLfloat,GLfloat)] -> [(Int,Int,Int)] -> [(GLfloat,GLfloat,GLfloat)]
generate_from_index ps [] = []
generate_from_index ps (t:tris) = [tp0, tp1, tp2] ++ (generate_from_index ps tris)
  where tp0 = head(drop (sel1 t) ps)
        tp1 = head(drop (sel2 t) ps)
        tp2 = head(drop (sel3 t) ps)

norm points = (set_len (kreuz (v0 `sub` v1) (v2 `sub` v1) ) 1)
  where v0 = head points
        v1 = head (drop 1 points)
        v2 = head (drop 2 points)

diplay_primitive p (RedGreenBlue(r,g,b)) primitiveShape
   | (length p) >=3 = do
                        materialAmbientAndDiffuse Front $= Color4 (realToFrac r) (realToFrac g) (realToFrac b) 1
                        currentNormal $= Normal3 (sel1(norm p)) (sel2(norm p)) (sel3(norm p))
                        displayPoints p primitiveShape
   | otherwise = do
                        materialAmbientAndDiffuse Front $= Color4 (realToFrac r) (realToFrac g) (realToFrac b) 1
                        displayPoints p primitiveShape

diplay_primitive points (Textur image) primitiveShape = do
               textureBinding Texture2D $= image
               let verts = makeV points
               let texs = [(TexCoord2 0 1), (TexCoord2 0 0), (TexCoord2 1 0), (TexCoord2 1 1)]
               renderPrimitive Polygon $ do mapVertices texs verts
               flush

displayPoints points primitiveShape = do
   renderPrimitive primitiveShape$makeVertices points
   flush

makeVertices = mapM_ ( \(x,y,z) -> vertex$Vertex3 x y z )
makeV = map ( \(x,y,z) -> (Vertex3 x y z) )

setVertex :: (TexCoord2 GLfloat, Vertex3 GLfloat) -> IO ()
setVertex (texCoordinates, vertexCoordinates) = do texCoord texCoordinates; vertex vertexCoordinates;

-- A routine used to draw a list of coordinates.
mapVertices :: [(TexCoord2 GLfloat)] -> [(Vertex3 GLfloat)] -> IO ()
mapVertices texs verts = mapM_ setVertex (zip texs verts)