SVGFonts-0.2: src/Test/Fonts.hs
module Main where
import Graphics.Rendering.OpenGL
import Graphics.UI.GLUT as GLUT
import Data.IORef
import System.IO.Unsafe (unsafePerformIO)
import Test.PointOfView
import Graphics.SVGFonts.ReadFont(get_glyph_polygon, read_font, horiz_sum, cycle_neighbours, triang)
import Char
main= do
(progName,_) <- getArgsAndInitialize
initialDisplayMode $= [WithDepthBuffer, DoubleBuffered, RGBAMode, WithAlphaComponent, WithAccumBuffer]
createWindow progName
windowSize $= Size 800 600
myInit
-- display_string uses 4 vectors and a mode: origin, v1 (direction of char-advance), v2(height direction), v3(extrusion), mode
-- mode 0: the string is inside v1 v2 v3 boundaries (height/length-relation not kept)
-- mode 1: stay inside v1 boundary, size of v2 adjusted to height/length-relation
-- mode 2: stay inside v2 boundary, size of v1 adjusted to height/length-relation
g <- return ( G (display_string "Haskell will be mainstream"
--"abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 +-~{}[]()=*/%"
"../../../src/Test/GirlsareWeird.svg" -- "LinLibertineO.svg" "Scriptin.svg"
5 (0,0,0) (10,0,0) (0,0,-1) (0,0.2,0) 1) )
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 1 1 1
materialSpecular Front $= Color4 1 1 1 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
clearColor $= Color4 0 0 0 0
clearAccum $= Color4 0 0 0 0
-- spriteInit 800 600
display keystate pPos l = do
loadIdentity
setPointOfView keystate pPos
clear [ColorBuffer,DepthBuffer]
callList l
--deleteLists [l]
swapBuffers
type Rad = Val
type X = Val
type Y = Val
type Z = Val
type B = Bool
type T = Int -- times
type C = Float -- const
type O = V -- position vector
data Prop = RedGreenBlue (Float, Float, Float) | N | -- N = not visible
Textur (Maybe TextureObject) | --deriving (Show) -- from sprites.hs
Triangul [(Int,Int,Int)] -- list of triangles
data AObj = Annotate [V] Prop
type V = (Float,Float,Float) -- x,y,z
instance Show Prop where
show (RedGreenBlue (a,b,c)) = "RGB(" ++ show (floor a) ++ "," ++ show (floor b) ++ "," ++
show (floor c) ++ ")"
type Val = GLfloat -- size in meters
type Tup = (O, V, V, C, C)
type Svg_glyph = [(String, String, String, String)]
nul = ( (0,0,0), (0,0,0), (0,0,0), 1, 1)
data Obj = G [ AObj ] | -- extruded objects in coords (G for Geometry)
Nil
red = RedGreenBlue (1,0,0)
green = RedGreenBlue (0,1,0)
blue = RedGreenBlue (0,0,1)
white = RedGreenBlue (1,1,1)
grey = RedGreenBlue (0.7,0.7,0.7)
turk = RedGreenBlue (0,1,1)
-- extrude a 2d polygon to 3d, the same points are added again with extrusion direction v
add_points3d :: V -> Prop -> [AObj] -> [AObj]
add_points3d v pr [] = []
add_points3d v pr poly =
poly ++ -- bottom polygon
( map (add_points v pr) (map (\x -> Annotate x pr) (cycle_neighbours (de_ann(head poly)))) ) ++ --side polygons
[ Annotate (map (add v) (de_ann(head poly))) (property (head poly)) ] -- top polygon
property (Annotate ps pr) = pr
de_ann (Annotate ps pr) = ps
-- extrude a line to a construct a polygon
add_points :: V -> Prop -> AObj -> AObj
add_points v pr (Annotate p _) = Annotate (p ++ (map (add v) (reverse p))) pr
-- add_points v pr _ = Annotate [] pr
-- ========================================================
-- conversion into G [AObj] (mainly with eval3d)
-- meaning of G [AObj] by example:
-- G [Annotate pr [1], Annotate pr [2], Annotate pr [3], Annotate pr [4]] = four single points (0d)
-- G [Annotate pr [1,2], Annotate pr [2,3], Annotate pr [3,4], Annotate pr [4,1]] = four lines (1d)
-- G [Annotate pr [1,2,3,4]] a rectangle (2d)
-- G [Annotate pr [1,2,3,4], Annotate pr [3,4,5,6], Annotate pr [1,2,7,8]] = a 3d object, consisting of several rectangles
-- ========================================================
-- mode 0: the string is inside v1 v2 v3 boundaries (height/length-relation not kept)
-- mode 1: stay inside v1 boundary, size of v2 adjusted to height/length-relation
-- mode 2: stay inside v2 boundary, size of v1 adjusted to height/length-relation
display_string :: String -> FilePath -> Int -> O -> V -> V -> V -> Int -> [AObj]
display_string str file bez o v1 v2 v3 mode | mode == 0 = make_str str (fst glyph) h max_h bez o v1 v2 v3
| mode == 1 = make_str str (fst glyph) h max_h bez o v1 new_v2 v3
| mode == 2 = make_str str (fst glyph) h max_h bez o new_v1 v2 v3
where
glyph = read_font file
h = fromIntegral (horiz_sum str (fst glyph))
bbox = splitBy isSpace (snd glyph)
max_h = read (head (drop 3 bbox)) -- bbox) -- max height of glyph
new_v1 = set_len v1 ( (v_len v2) * (h/max_h) )
new_v2 = set_len v2 ( (v_len v1) * (max_h/h) )
splitBy :: (a -> Bool) -> [a] -> [[a]]
splitBy _ [] = []
splitBy f list = first : splitBy f (dropWhile f rest) where
(first, rest) = break f list
make_str :: String -> Svg_glyph -> Float -> Float -> Int -> O -> V -> V -> V -> [AObj]
make_str [] g h mh bez o v1 v2 v3 = []
make_str (ch:str) g h mh bez o v1 v2 v3 | (length outline) == 0 = (make_str str g h mh bez (o `add` v1_advance) v1 v2 v3)
| otherwise = glyph_faces ++ (make_str str g h mh bez (o `add` v1_advance) v1 v2 v3)
where
glyph_faces = glyph3d -- tail ( init glyph3d) -- with tail and init top and bottom polygon are deleted
glyph3d = concat ( map (\(o,t) -> add_points3d v3 blue [ Annotate (map resize o) t ] ) out_tri )
out_tri = zip outline triangles -- list of tuples of outline with its triangulation:
-- i.e. a character like "j" has two outlines (one for the point).
resize (x,y) = o `add` (v1 `mul` (x/h)) `add` (v2 `mul` (y/mh))
outline = sel3_1 glyph
triangles = map (\x -> Triangul x) (sel3_3 glyph)
v1_advance = v1 `mul` ((sel3_2 glyph) / h)
glyph = get_glyph_polygon ch g bez mh -- ([[F2]], X,[[ (Int,Int,Int) ]]) = (outline, ha, map triang outline)
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
sel3_1 (x,y,z) = x
sel3_2 (x,y,z) = y
sel3_3 (x,y,z) = z
-- ====================================================================
-- displaying
-- ====================================================================
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)
disp :: AObj -> IO()
disp (Annotate ps ( Triangul tris )) = do diplay_primitive (generate_from_index ps tris) blue Triangles
disp (Annotate ps pr) | (length ps) == 1 = do diplay_primitive ps pr Points
| (length ps) == 2 = do diplay_primitive ps pr Lines
| otherwise = do diplay_primitive ps pr Polygon
generate_from_index :: [(Float,Float,Float)] -> [(Int,Int,Int)] -> [(Float,Float,Float)]
generate_from_index ps [] = []
generate_from_index ps (t:tris) = [tp0, tp1, tp2] ++ (generate_from_index ps tris)
where tp0 = head(drop (sel3_1 t) ps)
tp1 = head(drop (sel3_2 t) ps)
tp2 = head(drop (sel3_3 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 r g b 1
currentNormal $= Normal3 (sel3_1(norm p)) (sel3_2(norm p)) (sel3_3(norm p))
displayPoints p primitiveShape
| otherwise = do
materialAmbientAndDiffuse Front $= Color4 r g 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)