## Optimization All feel good from the architecture point of vue. More precisely, the separation between rendering and world behavior is clear. But this is extremely slow now. Because we compute the mandelbulb for each frame now. Before we had Constant Function -> Constant List of Triangles -> Display Now we have World -> Function -> List of Objects -> Atoms -> Display And the World state could change. Then it is no more straightforward for the compiler to understand when not to recompute the entire list of atoms. Then to optimize we will have to make things a little less separate. We must control the flow of atom generation. Mostly the program is the same as before, but instead of providing a function, we will provide the list of atoms directly.
> data World = World { > angle :: Point3D > , scale :: Scalar > , position :: Point3D > , box :: Box3D > , told :: Time > -- We replace shape by cache > , cache :: [YObject] > } > instance DisplayableWorld World where > winTitle _ = "The YGL Mandelbulb" > camera w = Camera { > camPos = position w, > camDir = angle w, > camZoom = scale w } > -- We update our objects instanciation > objects = cache Our initial world state is slightly changed: > -- We initialize the world state > -- then angle, position and zoom of the camera > -- And the shape function > initialWorld :: World > initialWorld = World { > angle = makePoint3D (30,30,0) > , position = makePoint3D (0,0,0) > , scale = 1.0 > , box = Box3D { minPoint = makePoint3D (-2,-2,-2) > , maxPoint = makePoint3D (2,2,2) > , resolution = 0.02 } > , told = 0 > -- We declare cache directly this time > , cache = objectFunctionFromWorld initialWorld > } We use the `YGL.getObject3DFromShapeFunction` function directly. This way instead of providing `XYFunc`, we provide directly a list of Atoms. > objectFunctionFromWorld :: World -> [YObject] > objectFunctionFromWorld w = [Atoms atomList] > where atomListPositive = > getObject3DFromShapeFunction (shapeFunc (resolution (box w))) (box w) > atomList = atomListPositive ++ > map negativeTriangle atomListPositive > negativeTriangle (ColoredTriangle (p1,p2,p3,c)) = > ColoredTriangle (negz p1,negz p2,negz p3,c) > where negz (P (x,y,z)) = P (x,y,-z) We know that resize is the only world change that necessitate to recompute the list of atoms (triangles). Then we update our world state accordingly. > resize :: Scalar -> World -> World > resize r world = > tmpWorld { cache = objectFunctionFromWorld tmpWorld } > where > tmpWorld = world { box = (box world) { > resolution = sqrt ((resolution (box world))**2 * r) }} All the rest is exactly the same. - [`YGL.hs`](code/06_Mandelbulb/YGL.hs), the 3D rendering framework - [`Mandel`](code/06_Mandelbulb/Mandel.hs), the mandel function - [`ExtComplex`](code/06_Mandelbulb/ExtComplex.hs), the extended complexes