packages feed

gloss-1.2.0.0: Graphics/Gloss/Internals/Render/Circle.hs

{-# LANGUAGE BangPatterns, MagicHash, PatternGuards #-}
{-# OPTIONS_HADDOCK hide #-}

-- | Fast(ish) rendering of circles.
module Graphics.Gloss.Internals.Render.Circle  where

import 	Graphics.Gloss.Internals.Render.Common
import	qualified Graphics.Rendering.OpenGL.GL		as GL
import	GHC.Exts

-- | Render a circle with the given thickness
renderCircle :: Float -> Float -> Float -> Float -> Float -> IO ()
renderCircle posX posY scaleFactor radius thickness
 	| radScreen	<- scaleFactor * radius
	, steps		<- circleSteps (2 * radScreen)
	= if thickness == 0 
		then renderCircleLine posX posY steps radius
		else renderCircleStrip posX posY steps radius thickness


-- | Decide how many line segments to use to render the circle
circleSteps :: Float -> Int
circleSteps sDiam
	| sDiam < 1	= 1
	| sDiam < 2	= 4
	| sDiam < 10	= 8
	| sDiam < 20	= 16
	| sDiam < 30	= 32
	| otherwise	= 40


renderCircleLine_step :: Float# -> Float# -> Float# -> Float# -> Float# -> Float# -> IO ()
renderCircleLine_step posX posY tStep tStop rad tt
	| tt `geFloat#` tStop
	= return ()
	
	| otherwise
	= do	GL.vertex 
		 $ GL.Vertex2 
			(gf $ F# (posX `plusFloat#` (rad `timesFloat#` (cosFloat# tt))))
			(gf $ F# (posY `plusFloat#` (rad `timesFloat#` (sinFloat# tt))))

		renderCircleLine_step posX posY tStep tStop rad (tt `plusFloat#` tStep)

-- | Render a circle as a line.
renderCircleLine :: Float -> Float -> Int -> Float -> IO ()
renderCircleLine (F# posX) (F# posY) steps (F# rad)
 = let 	n		= fromIntegral steps
	!(F# tStep)	= (2 * pi) / n
	!(F# tStop)	= (2 * pi)

   in	GL.renderPrimitive GL.LineLoop
   		$ renderCircleLine_step posX posY tStep tStop rad 0.0#


-- | Render a circle with a given thickness as a triangle strip
renderCircleStrip :: Float -> Float -> Int -> Float -> Float -> IO ()
renderCircleStrip (F# posX) (F# posY) steps r width
 = let	n		= fromIntegral steps
	!(F# tStep)	= (2 * pi) / n
	!(F# tStop)	= (2 * pi) + (F# tStep) / 2
	!(F# r1)	= r - width / 2
	!(F# r2)	= r + width / 2

   in	GL.renderPrimitive GL.TriangleStrip
   		$ renderCircleStrip_step posX posY tStep tStop r1 0.0# r2 
			(tStep `divideFloat#` 2.0#)
   
renderCircleStrip_step 
	:: Float# -> Float# 
	-> Float# -> Float# 
	-> Float# -> Float# -> Float# -> Float# -> IO ()

renderCircleStrip_step posX posY tStep tStop r1 t1 r2 t2
	| t1 `geFloat#` tStop
	= return ()
	
	| otherwise
	= do	GL.vertex 
	 	 $ GL.Vertex2 
			(gf $ F# (posX `plusFloat#` (r1 `timesFloat#` (cosFloat# t1)))) 
			(gf $ F# (posY `plusFloat#` (r1 `timesFloat#` (sinFloat# t1))))

		GL.vertex 
		 $ GL.Vertex2 
			(gf $ F# (posX `plusFloat#` (r2 `timesFloat#` (cosFloat# t2))))
			(gf $ F# (posY `plusFloat#` (r2 `timesFloat#` (sinFloat# t2))))
		
		renderCircleStrip_step posX posY tStep tStop r1 
			(t1 `plusFloat#` tStep) r2 (t2 `plusFloat#` tStep)