Introduction

I found myself creating TV Singleton objects over and over again, and decided to find a more streamlined solution.

Instead of reffering to a global object with the singletons, or have creation code spread all over the app, i created a root class that virtually every class in my projects inherits from. This means that the creation/destruction of TV resources are written in ONLY ONE PLACE. I guess the idea could be extended further, please post a reply if you do!

A note on the usage: Each instance should be terminated with a call to Dispose(). If not, an error will be generated.

C# Code (not thread safe)

using System;
using MTV3D65;
 
public class RootClass : IDisposable
{
    private class TVSingletons
    {
        #region Instance data
        public static TVEngine tvEngine;
        public static TVDeviceInfo tvInfo;
        public static TVInputEngine tvInput;
        public static TVScene tvScene;
        public static TVLightEngine tvLightEngine;
        public static TVCameraFactory tvCamFactory;
        public static TVMathLibrary tvMath;
        public static TVGlobals tvGlobals;
        public static TVMaterialFactory tvMaterial;
        public static TVTextureFactory tvTexture;
        public static TVScreen2DImmediate tv2dImmediate;
        public static TVScreen2DText tv2dText;
        public static TVAtmosphere tvAtmos;
        public static TVGraphicEffect tvGraphicFX;
        public static TVGameControllers tvGameCtl;
        public static TVPhysics tvPhysics;
        public static TVInternalObjects tvInternals;
        private static bool initated = false;
        #endregion
 
        public static bool Initiated { get { return initated; } }
 
        public static void Init()
        {
            if (!initated)
            {
                tvEngine = new TVEngine();
                tvInfo = new TVDeviceInfo();
                tvInput = new TVInputEngine();
                tvScene = new TVScene();
                tvLightEngine = new TVLightEngine();
                tvCamFactory = new TVCameraFactory();
                tvMath = new TVMathLibrary();
                tvGlobals = new TVGlobals();
                tvMaterial = new TVMaterialFactory();
                tvTexture = new TVTextureFactory();
                tv2dImmediate = new TVScreen2DImmediate();
                tv2dText = new TVScreen2DText();
                tvAtmos = new TVAtmosphere();
                tvGraphicFX = new TVGraphicEffect();
                tvGameCtl = new TVGameControllers();
                tvPhysics = new TVPhysics();
                tvInternals = new TVInternalObjects();
                initated = true;
            }
        }
    }
 
    #region Instance data
    protected TVEngine tvEngine;
    protected TVDeviceInfo tvInfo;
    protected TVInputEngine tvInput;
    protected TVScene tvScene;
    protected TVLightEngine tvLightEngine;
    protected TVCameraFactory tvCamFactory;
    protected TVMathLibrary tvMath;
    protected TVGlobals tvGlobals;
    protected TVMaterialFactory tvMaterial;
    protected TVTextureFactory tvTexture;
    protected TVScreen2DImmediate tv2dImmediate;
    protected TVScreen2DText tv2dText; 
    protected TVAtmosphere tvAtmos;
    protected TVGraphicEffect tvGraphicFX;
    #endregion
 
    public RootClass()
    {
	    if(! TVSingletons.Initiated) 
		    TVSingletons.Init();
 
	    tvEngine = TVSingletons.tvEngine;
	    tvScene = TVSingletons.tvScene;
	    tvLightEngine = TVSingletons.tvLightEngine;
	    tvCamFactory =  TVSingletons.tvCamFactory;
	    tvMath = TVSingletons.tvMath;
	    tvMaterial = TVSingletons.tvMaterial;
	    tvTexture = TVSingletons.tvTexture;
	    tvGlobals = TVSingletons.tvGlobals;
	    tvInput = TVSingletons.tvInput;
	    tv2dImmediate = TVSingletons.tv2dImmediate;
	    tv2dText = TVSingletons.tv2dText; 
	    tvAtmos = TVSingletons.tvAtmos;
	    tvInfo = TVSingletons.tvInfo;
	    tvGraphicFX = TVSingletons.tvGraphicFX;
    }
 
    ~RootClass()
    {
        System.Diagnostics.Debug.WriteLine(this, ">>> ERROR: Dispose never explicitly called for this instance " + this.ToString() + " <<<");
	    if(Engine.windowed)
		    System.Diagnostics.Debug.Assert(false, ">>>> ERROR: Dispose never explicitly called for this instance: " + this.ToString() + " <<<");
    }
 
    public virtual void Dispose()
    {
	    tvEngine = null;
	    tvScene = null;
	    tvLightEngine = null;
	    tvMath = null;
	    tvMaterial = null;
	    tvTexture = null;
	    tvGlobals = null;
	    tvInput = null;
	    tv2dImmediate = null;
	    tv2dText = null;
	    tvAtmos = null;
	    tvInfo = null;
	    GC.SuppressFinalize(this);
    }
 
}

C# Code (Thread Safe)

using System;
using MTV3D65;
 
public class RootClass : IDisposable
{
    private class TVSingletons
    {
        #region Instance data
        public static TVEngine tvEngine;
        public static TVDeviceInfo tvInfo;
        public static TVInputEngine tvInput;
        public static TVScene tvScene;
        public static TVLightEngine tvLightEngine;
        public static TVCameraFactory tvCamFactory;
        public static TVMathLibrary tvMath;
        public static TVGlobals tvGlobals;
        public static TVMaterialFactory tvMaterial;
        public static TVTextureFactory tvTexture;
        public static TVScreen2DImmediate tv2dImmediate;
        public static TVScreen2DText tv2dText;
        public static TVAtmosphere tvAtmos;
        public static TVGraphicEffect tvGraphicFX;
        public static TVGameControllers tvGameCtl;
        public static TVPhysics tvPhysics;
        public static TVInternalObjects tvInternals;
        private static bool initated = false;
        private static object syncRoot = new object();
        #endregion
 
        public static bool Initiated { get { return initated; } }
 
        public static void Init()
        {
            if (!initated)
            {
                // Lock the root object to ensure thread safety
                lock (syncRoot)
                {
                    tvEngine = new TVEngine();
                    tvInfo = new TVDeviceInfo();
                    tvInput = new TVInputEngine();
                    tvScene = new TVScene();
                    tvLightEngine = new TVLightEngine();
                    tvCamFactory = new TVCameraFactory();
                    tvMath = new TVMathLibrary();
                    tvGlobals = new TVGlobals();
                    tvMaterial = new TVMaterialFactory();
                    tvTexture = new TVTextureFactory();
                    tv2dImmediate = new TVScreen2DImmediate();
                    tv2dText = new TVScreen2DText();
                    tvAtmos = new TVAtmosphere();
                    tvGraphicFX = new TVGraphicEffect();
                    tvGameCtl = new TVGameControllers();
                    tvPhysics = new TVPhysics();
                    tvInternals = new TVInternalObjects();
                    initated = true;
                }
            }
        }
    }
 
    #region Instance data
    protected TVEngine tvEngine;
    protected TVDeviceInfo tvInfo;
    protected TVInputEngine tvInput;
    protected TVScene tvScene;
    protected TVLightEngine tvLightEngine;
    protected TVCameraFactory tvCamFactory;
    protected TVMathLibrary tvMath;
    protected TVGlobals tvGlobals;
    protected TVMaterialFactory tvMaterial;
    protected TVTextureFactory tvTexture;
    protected TVScreen2DImmediate tv2dImmediate;
    protected TVScreen2DText tv2dText; 
    protected TVAtmosphere tvAtmos;
    protected TVGraphicEffect tvGraphicFX;
    #endregion
 
    public RootClass()
    {
	    if(! TVSingletons.Initiated) 
		    TVSingletons.Init();
 
	    tvEngine = TVSingletons.tvEngine;
	    tvScene = TVSingletons.tvScene;
	    tvLightEngine = TVSingletons.tvLightEngine;
	    tvCamFactory =  TVSingletons.tvCamFactory;
	    tvMath = TVSingletons.tvMath;
	    tvMaterial = TVSingletons.tvMaterial;
	    tvTexture = TVSingletons.tvTexture;
	    tvGlobals = TVSingletons.tvGlobals;
	    tvInput = TVSingletons.tvInput;
	    tv2dImmediate = TVSingletons.tv2dImmediate;
	    tv2dText = TVSingletons.tv2dText; 
	    tvAtmos = TVSingletons.tvAtmos;
	    tvInfo = TVSingletons.tvInfo;
	    tvGraphicFX = TVSingletons.tvGraphicFX;
    }
 
    ~RootClass()
    {
        System.Diagnostics.Debug.WriteLine(this, ">>> ERROR: Dispose never explicitly called for this instance " + this.ToString() + " <<<");
	    if(Engine.windowed)
		    System.Diagnostics.Debug.Assert(false, ">>>> ERROR: Dispose never explicitly called for this instance: " + this.ToString() + " <<<");
    }
 
    public virtual void Dispose()
    {
	    tvEngine = null;
	    tvScene = null;
	    tvLightEngine = null;
	    tvMath = null;
	    tvMaterial = null;
	    tvTexture = null;
	    tvGlobals = null;
	    tvInput = null;
	    tv2dImmediate = null;
	    tv2dText = null;
	    tvAtmos = null;
	    tvInfo = null;
	    GC.SuppressFinalize(this);
    }
 
}

Usage

Let all classes that uses TV objects inherit from the RootClass. Note that you should allways call Dispose to explicilty free the resources. This is particular important if you repeat construction/destruction of objects. Do not rely on the garbage collector in C#.

using System;
using MTV3D65;
 
 
public class MyMesh : RootClass
{
	private TVMesh mesh;
 
	public MyMesh()
	{
		mesh = tvScene.CreateMeshBuilder("mesh.tvm");
		mesh.LoadTVM("mesh.tvm", true, true);
	}
 
	public override void Render()
	{
		mesh.Render();
	}
 
	public override void Dispose()
	{
		mesh.Destroy();
		mesh = null;
		base.Dispose();
	}
}
 
tutorialsarticlesandexamples/using_tv3d_objects_as_singletons_-_revisited.txt · Last modified: 2013/11/22 13:32