let display_singleton = (object(self)
        inherit display_singleton_type
        val mutable renderer = null_renderer
        val event_dispatcher = new event_dispatcher

        val mutable gl_initialized = false
        val mutable next_tick = 0

        val mutable antialiasing_passes = 1

        method set_antialiasing passes =
                assert (passes > 0) ;
                antialiasing_passes <- passes

        method set_renderer new_renderer = renderer <- new_renderer
        
        
        (** Sets the video mode. *)

        method set_video_mode ~width ~height =
                Init.init_sdl_once () ;
                let _ = Sdlvideo.set_video_mode ~w:width ~h:height [`OPENGLin
                if not gl_initialized then begin
                        self#init_gl ;
                        gl_initialized <- true
                end else () ;
                renderer#set_viewport ~x:0 ~y:0 ~width ~height

        method event_dispatcher = event_dispatcher

        method render =
                GlClear.clear [`color ; `depth ] ;
                
                (*let antialias_passes = 1 in*)
                Antialias.accumulate renderer#render antialiasing_passes;
                
                (* Sort of like an Apply button on the OpenGL " :-) *)
                Sdlgl.swap_buffers () ;
                ()

                
        
        
        (** Blocks forever, processing events from SDL. Events can be detected (and simulated) using Application.display_singleton.event_dispatcher. Raises Exit when the user wishes to exit (for example, by closing the window). Event listeners may also raise Exit with the same effect. *)

        method event_loop =
                let rec loop () =
            (* This function evaluates all pending events.
               Raises Done when the program should terminate. *)

                    let rec handle_events evt_opt =
                        match evt_opt with
                          Some evt ->
                                   begin match evt with
                              (Sdlevent.KEYDOWN key_evt) ->
                                event_dispatcher#key#pressed key_evt
                                        | (Sdlevent.KEYUP key_evt) ->
                                                event_dispatcher#key#released key_evt
                                          | (Sdlevent.MOUSEBUTTONDOWN e) ->
                                event_dispatcher#mouse#pressed e
                                   | (Sdlevent.MOUSEBUTTONUP e) ->
                                       event_dispatcher#mouse#released e
                            | (Sdlevent.MOUSEMOTION e) ->
                                       if e.Sdlevent.mme_state = [] then
                                           event_dispatcher#mouse#moved e
                                else
                                           event_dispatcher#mouse#dragged e
                                   |  Sdlevent.QUIT ->
                                raise Exit
                            | _ -> ignore ()
                                   end ;
                            handle_events (Sdlevent.poll ())
                        | None -> ()
                    in
                    let donenow = try
                handle_events (Sdlevent.poll ()) ; false
                    with Done -> true
            in
            match donenow with
                  false ->
                        begin let now = Sdltimer.get_ticks () in
                       match now >= next_tick with
                          true ->
                                next_tick <- now + 30 ;
                                event_dispatcher#ticker#do_tick
                | false -> ()
                end ;
                       Sdltimer.delay 1 ;
                loop ()
                | true ->
                       print_endline "exiting main loop."
        
        in loop ()
        
                (* interesting: when listeners are added to affectors 
                   (using affector#affect listener) they are appended
                   to the front of the list of listeners.  This means
                   the first listener added is the last listener executed.
                   Since the first listener we add to event_dispatcher#tick 
                   is this render function.
                   Result: Any other tick_listeners we add to the event 
                   dispatcher will be evalutated /before/ the render step. *)

                method render_synchronously =
                        let sync_renderer = object 
                                method do_tick = self#render
                        end 
                        in event_dispatcher#ticker#affect sync_renderer
                
        method private init_gl =
            let blending = true in
            print_string "OpenGL Version: " ;
            print_endline (GlMisc.get_string `version) ;
            (*print_string " ;
                   print_endline (GlMisc.get_string `extensions) ;*)

            (*print_string " ;
            print_endline (GlMisc.get_string `renderer) ;
            print_string " ;
            print_endline (GlMisc.get_string `vendor) ;*)

            GlDraw.shade_model `smooth ;
            GlClear.color (0.0, 0.0, 0.0) ;
            GlClear.depth 1.0 ;

            GlMisc.hint `perspective_correction `nicest ;
        
                
            if false then begin
                GlLight.light 0 (`ambient (0.5,0.5,0.5,1.0)) ;
                GlLight.light 0 (`diffuse (0.5,0.5,0.5,1.0)) ;
                GlLight.light 0 (`position (2.0, 0.0, 2.0, 1.0)) ;
                Gl.enable(`lighting) ;
                Gl.enable(`light0)
            end else () ;
                
                
            Gl.enable `depth_test ;
            GlFunc.depth_func `lequal ;

            ()

end :> display_singleton_type)