コード例 #1
0
        public static void DuplicateSelection(EditorItemSelection selection, out bool errorFlag, out string errorMsg)
        {
            if (selection.ItemCount < 0)
            {
                errorFlag = true; errorMsg = "Negative selection count... what did you do?!?"; return;
            }

            List <Item> newItems     = new List <Item>();
            List <Item> currentItems = selection.GetSelection();

            // duplicate goes here
            for (int i = 0; i < selection.ItemCount; i++)
            {
                if (currentItems[i] is MissionSETItem)
                {
                    MissionSETItem originalItem = (MissionSETItem)currentItems[i];
                    MissionSETItem newItem      = new MissionSETItem(originalItem.GetBytes(), 0, originalItem.GetPRMBytes(), 0, selection);

                    MissionSETItems[Character].Add(newItem);
                    newItems.Add(newItem);
                }
                else if (currentItems[i] is SETItem)
                {
                    SETItem originalItem = (SETItem)currentItems[i];
                    SETItem newItem      = new SETItem(originalItem.GetBytes(), 0, selection);

                    //SETItems[Character].Add(newItem);
                    AddSETItem(Character, newItem);
                    newItems.Add(newItem);
                }
                else if (currentItems[i] is LevelItem)
                {
                    LevelItem originalItem = (LevelItem)currentItems[0];
                    LevelItem newItem      = new LevelItem(originalItem.CollisionData.Model.Attach, originalItem.Position, originalItem.Rotation, levelItems.Count, selection);

                    newItem.CollisionData.SurfaceFlags = originalItem.CollisionData.SurfaceFlags;
                    newItems.Add(newItem);
                }
                else if (currentItems[i] is CAMItem)
                {
                    CAMItem originalItem = (CAMItem)currentItems[i];
                    CAMItem newItem      = new CAMItem(originalItem.GetBytes(), 0, selection);

                    CAMItems[Character].Add(newItem);
                    newItems.Add(newItem);
                }
            }

            selection.Clear();
            selection.Add(newItems);

            changes.Push("Duplicate Item");

            InvalidateRenderState();

            errorFlag = false;
            errorMsg  = "";
        }
コード例 #2
0
ファイル: LevelData.cs プロジェクト: Radfordhound/sa_tools
        public static void DuplicateSelection(Device d3ddevice, EditorItemSelection selection, out bool errorFlag, out string errorMsg)
        {
            if (selection.ItemCount < 0) { errorFlag = true; errorMsg = "Negative selection count... what did you do?!?"; return; }

            List<Item> newItems = new List<Item>();
            List<Item> currentItems = selection.GetSelection();

            // duplicate goes here
            for (int i = 0; i < selection.ItemCount; i++)
            {
                if (currentItems[i] is SETItem)
                {
                    SETItem originalItem = (SETItem)currentItems[i];
                    SETItem newItem = new SETItem(originalItem.GetBytes(), 0, selection);

                    SETItems[Character].Add(newItem);
                    newItems.Add(newItem);
                }
                else if (currentItems[i] is LevelItem)
                {
                    LevelItem originalItem = (LevelItem)currentItems[0];
                    LevelItem newItem = new LevelItem(d3ddevice, originalItem.CollisionData.Model.Attach, originalItem.Position, originalItem.Rotation, LevelItems.Count, selection);

                    newItem.CollisionData.SurfaceFlags = originalItem.CollisionData.SurfaceFlags;
                    newItems.Add(newItem);
                }
                else if (currentItems[i] is CAMItem)
                {
                    CAMItem originalItem = (CAMItem)currentItems[i];
                    CAMItem newItem = new CAMItem(originalItem.GetBytes(), 0, selection);

                    CAMItems[Character].Add(newItem);
                    newItems.Add(newItem);
                }
            }

            selection.Clear();
            selection.Add(newItems);

            InvalidateRenderState();

            errorFlag = false;
            errorMsg = "";
        }
コード例 #3
0
ファイル: MainForm.cs プロジェクト: Radfordhound/sa_tools
 private void cameraToolStripMenuItem_Click(object sender, EventArgs e)
 {
     Vector3 pos = cam.Position + (-20 * cam.Look);
     CAMItem item = new CAMItem(new Vertex(pos.X, pos.Y, pos.Z), selectedItems);
     LevelData.CAMItems[LevelData.Character].Add(item);
     selectedItems.Clear();
     selectedItems.Add(item);
     LevelData_StateChanged();
 }
コード例 #4
0
ファイル: MainForm.cs プロジェクト: Radfordhound/sa_tools
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            #if !DEBUG
            try
            {
            #endif
                int steps = 10;
                if (d3ddevice == null)
                    ++steps;

                toolStrip1.Enabled = false;

                // HACK: Fixes Twinkle Circuit's geometry lingering if loaded before Sky Chase.
                // I'm sure the real problem is somewhere below, but this is sort of an all around cleanup.
                if (isStageLoaded)
                    LevelData.Clear();

                isStageLoaded = false;

                using (ProgressDialog progress = new ProgressDialog("Loading stage: " + levelName, steps))
                {
                    IniLevelData level = ini.Levels[levelID];

                    string syspath = Path.Combine(Environment.CurrentDirectory, ini.SystemPath);
                    string modpath = ini.ModPath;

                    SA1LevelAct levelact = new SA1LevelAct(level.LevelID);
                    LevelData.leveltexs = null;
                    cam = new EditorCamera(EditorOptions.RenderDrawDistance);

                    Invoke((Action<IWin32Window>)progress.Show, this);

                    if (d3ddevice == null)
                    {
                        progress.SetTask("Initializing Direct3D...");
                        Invoke((Action)InitializeDirect3D);
                        progress.StepProgress();
                    }

                    progress.SetTaskAndStep("Loading level data:", "Geometry");

                    if (string.IsNullOrEmpty(level.LevelGeometry))
                        LevelData.geo = null;
                    else
                    {
                        LevelData.geo = LandTable.LoadFromFile(level.LevelGeometry);
                        LevelData.LevelItems = new List<LevelItem>();
                        for (int i = 0; i < LevelData.geo.COL.Count; i++)
                            LevelData.LevelItems.Add(new LevelItem(LevelData.geo.COL[i], d3ddevice, i, selectedItems));
                    }

                    progress.StepProgress();
                    progress.SetStep("Textures");

                    LevelData.TextureBitmaps = new Dictionary<string, BMPInfo[]>();
                    LevelData.Textures = new Dictionary<string, Texture[]>();
                    if (LevelData.geo != null && !string.IsNullOrEmpty(LevelData.geo.TextureFileName))
                    {
                        BMPInfo[] TexBmps =
                            TextureArchive.GetTextures(Path.Combine(syspath, LevelData.geo.TextureFileName) + ".PVM");
                        Texture[] texs = new Texture[TexBmps.Length];
                        for (int j = 0; j < TexBmps.Length; j++)
                            texs[j] = new Texture(d3ddevice, TexBmps[j].Image, Usage.None, Pool.Managed);
                        if (!LevelData.TextureBitmaps.ContainsKey(LevelData.geo.TextureFileName))
                            LevelData.TextureBitmaps.Add(LevelData.geo.TextureFileName, TexBmps);
                        if (!LevelData.Textures.ContainsKey(LevelData.geo.TextureFileName))
                            LevelData.Textures.Add(LevelData.geo.TextureFileName, texs);
                        LevelData.leveltexs = LevelData.geo.TextureFileName;
                    }

                    progress.StepProgress();

                    #region Start Positions

                    progress.SetTaskAndStep("Setting up start positions...");

                    LevelData.StartPositions = new StartPosItem[LevelData.Characters.Length];
                    for (int i = 0; i < LevelData.StartPositions.Length; i++)
                    {
                        progress.SetStep(string.Format("{0}/{1}", (i + 1), LevelData.StartPositions.Length));

                        IniCharInfo character;
                        if (i == 0 && levelact.Level == SA1LevelIDs.PerfectChaos)
                            character = ini.Characters["SuperSonic"];
                        else
                            character = ini.Characters[LevelData.Characters[i]];

                        Dictionary<SA1LevelAct, SA1StartPosInfo> posini =
                            SA1StartPosList.Load(character.StartPositions);

                        Vertex pos = new Vertex();
                        int rot = 0;

                        if (posini.ContainsKey(levelact))
                        {
                            pos = posini[levelact].Position;
                            rot = posini[levelact].YRotation;
                        }
                        LevelData.StartPositions[i] = new StartPosItem(new ModelFile(character.Model).Model,
                            character.Textures, character.Height, pos, rot, d3ddevice, selectedItems);

                        LoadTextureList(character.TextureList, syspath);
                    }

                    progress.StepProgress();

                    #endregion

                    #region Death Zones

                    progress.SetTaskAndStep("Death Zones:", "Initializing...");

                    if (string.IsNullOrEmpty(level.DeathZones))
                        LevelData.DeathZones = null;
                    else
                    {
                        LevelData.DeathZones = new List<DeathZoneItem>();
                        DeathZoneFlags[] dzini = DeathZoneFlagsList.Load(level.DeathZones);
                        string path = Path.GetDirectoryName(level.DeathZones);
                        for (int i = 0; i < dzini.Length; i++)
                        {
                            progress.SetStep(String.Format("Loading model {0}/{1}", (i + 1), dzini.Length));

                            LevelData.DeathZones.Add(new DeathZoneItem(
                                new ModelFile(Path.Combine(path, i.ToString(System.Globalization.NumberFormatInfo.InvariantInfo) + ".sa1mdl"))
                                    .Model,
                                dzini[i].Flags, d3ddevice, selectedItems));
                        }
                    }

                    progress.StepProgress();

                    #endregion

                    #region Textures and Texture Lists

                    progress.SetTaskAndStep("Loading textures for:");

                    progress.SetStep("Common objects");
                    // Loads common object textures (e.g OBJ_REGULAR)
                    LoadTextureList(ini.ObjectTextureList, syspath);

                    progress.SetTaskAndStep("Loading stage texture lists...");

                    // Loads the textures in the texture list for this stage (e.g BEACH01)
                    foreach (string file in Directory.GetFiles(ini.LevelTextureLists))
                    {
                        LevelTextureList texini = LevelTextureList.Load(file);
                        if (texini.Level != levelact)
                            continue;

                        LoadTextureList(texini.TextureList, syspath);
                    }

                    progress.SetTaskAndStep("Loading textures for:", "Objects");
                    // Object texture list(s)
                    LoadTextureList(level.ObjectTextureList, syspath);

                    progress.SetStep("Stage");
                    // The stage textures... again? "Extra"?
                    if (level.Textures != null && level.Textures.Length > 0)
                        foreach (string tex in level.Textures)
                        {
                            LoadPVM(tex, syspath);

                            if (string.IsNullOrEmpty(LevelData.leveltexs))
                                LevelData.leveltexs = tex;
                        }

                    progress.StepProgress();

                    #endregion

                    #region Object Definitions / SET Layout

                    progress.SetTaskAndStep("Loading Object Definitions:", "Parsing...");

                    LevelData.ObjDefs = new List<ObjectDefinition>();
                    Dictionary<string, ObjectData> objdefini =
                        IniSerializer.Deserialize<Dictionary<string, ObjectData>>(ini.ObjectDefinitions);

                    if (!string.IsNullOrEmpty(level.ObjectList) && File.Exists(level.ObjectList))
                    {
                        List<ObjectData> objectErrors = new List<ObjectData>();
                        ObjectListEntry[] objlstini = ObjectList.Load(level.ObjectList, false);
                        Directory.CreateDirectory("dllcache").Attributes |= FileAttributes.Hidden;

                        for (int ID = 0; ID < objlstini.Length; ID++)
                        {
                            string codeaddr = objlstini[ID].CodeString;

                            if (!objdefini.ContainsKey(codeaddr))
                                codeaddr = "0";

                            ObjectData defgroup = objdefini[codeaddr];
                            ObjectDefinition def;

                            if (!string.IsNullOrEmpty(defgroup.CodeFile))
                            {
                                progress.SetStep("Compiling: " + defgroup.CodeFile);

                                // TODO: Split this out to a function
                                #region Compile object code files

                                string ty = defgroup.CodeType;
                                string dllfile = Path.Combine("dllcache", ty + ".dll");
                                DateTime modDate = DateTime.MinValue;
                                if (File.Exists(dllfile))
                                    modDate = File.GetLastWriteTime(dllfile);
                                string fp = defgroup.CodeFile.Replace('/', Path.DirectorySeparatorChar);
                                if (modDate >= File.GetLastWriteTime(fp) && modDate > File.GetLastWriteTime(Application.ExecutablePath))
                                    def =
                                        (ObjectDefinition)
                                            Activator.CreateInstance(
                                                Assembly.LoadFile(Path.Combine(Environment.CurrentDirectory, dllfile))
                                                    .GetType(ty));
                                else
                                {
                                    string ext = Path.GetExtension(fp);
                                    CodeDomProvider pr = null;
                                    switch (ext.ToLowerInvariant())
                                    {
                                        case ".cs":
                                            pr = new Microsoft.CSharp.CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } });
                                            break;
                                        case ".vb":
                                            pr = new Microsoft.VisualBasic.VBCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } });
                                            break;
                                    }
                                    if (pr != null)
                                    {
                                        CompilerParameters para =
                                            new CompilerParameters(new string[]
                                            {
                                                "System.dll", "System.Core.dll", "System.Drawing.dll", Assembly.GetAssembly(typeof (Vector3)).Location,
                                                Assembly.GetAssembly(typeof (Texture)).Location, Assembly.GetAssembly(typeof (D3DX)).Location,
                                                Assembly.GetExecutingAssembly().Location, Assembly.GetAssembly(typeof (LandTable)).Location,
                                                Assembly.GetAssembly(typeof (EditorCamera)).Location, Assembly.GetAssembly(typeof (SA1LevelAct)).Location,
                                                Assembly.GetAssembly(typeof (ObjectDefinition)).Location
                                            })
                                            {
                                                GenerateExecutable = false,
                                                GenerateInMemory = false,
                                                IncludeDebugInformation = true,
                                                OutputAssembly = Path.Combine(Environment.CurrentDirectory, dllfile)
                                            };
                                        CompilerResults res = pr.CompileAssemblyFromFile(para, fp);
                                        if (res.Errors.HasErrors)
                                        {
                                            // TODO: Merge with existing object error handler. I add too many ToDos.
                                            string errors = null;
                                            foreach (CompilerError item in res.Errors)
                                                errors += String.Format("\n\n{0}, {1}: {2}", item.Line, item.Column, item.ErrorText);

                                            MessageBox.Show("Failed to compile object code file:\n" + defgroup.CodeFile + errors,
                                                "Object compilation failure", MessageBoxButtons.OK, MessageBoxIcon.Error);

                                            def = new DefaultObjectDefinition();
                                        }
                                        else
                                        {
                                            def = (ObjectDefinition)Activator.CreateInstance(res.CompiledAssembly.GetType(ty));
                                        }
                                    }
                                    else
                                        def = new DefaultObjectDefinition();
                                }

                                #endregion
                            }
                            else
                            {
                                def = new DefaultObjectDefinition();
                            }

                            LevelData.ObjDefs.Add(def);

                            // The only reason .Model is checked for null is for objects that don't yet have any
                            // models defined for them. It would be annoying seeing that error all the time!
                            if (string.IsNullOrEmpty(defgroup.CodeFile) && !string.IsNullOrEmpty(defgroup.Model))
                            {
                                progress.SetStep("Loading: " + defgroup.Model);
                                // Otherwise, if the model file doesn't exist and/or no texture file is defined,
                                // load the "default object" instead ("?").
                                if (!File.Exists(defgroup.Model) || string.IsNullOrEmpty(defgroup.Texture) ||
                                    !LevelData.Textures.ContainsKey(defgroup.Texture))
                                {
                                    ObjectData error = new ObjectData { Name = defgroup.Name, Model = defgroup.Model, Texture = defgroup.Texture };
                                    objectErrors.Add(error);
                                    defgroup.Model = null;
                                }
                            }

                            def.Init(defgroup, objlstini[ID].Name, d3ddevice);
                            def.SetInternalName(objlstini[ID].Name);
                        }

                        // Loading SET Layout
                        progress.SetTaskAndStep("Loading SET items", "Initializing...");

                        if (LevelData.ObjDefs.Count > 0)
                        {
                            LevelData.SETName = level.SETName ?? level.LevelID;
                            string setstr = Path.Combine(syspath, "SET" + LevelData.SETName + "{0}.bin");
                            LevelData.SETItems = new List<SETItem>[LevelData.SETChars.Length];
                            for (int i = 0; i < LevelData.SETChars.Length; i++)
                            {
                                List<SETItem> list = new List<SETItem>();
                                byte[] setfile = null;

                                string formatted = string.Format(setstr, LevelData.SETChars[i]);

                                if (modpath != null && File.Exists(Path.Combine(modpath, formatted)))
                                    setfile = File.ReadAllBytes(Path.Combine(modpath, formatted));
                                else if (File.Exists(formatted))
                                    setfile = File.ReadAllBytes(formatted);

                                if (setfile != null)
                                {
                                    progress.SetTask("SET: " + formatted.Replace(Environment.CurrentDirectory, ""));

                                    int count = BitConverter.ToInt32(setfile, 0);
                                    int address = 0x20;
                                    for (int j = 0; j < count; j++)
                                    {
                                        progress.SetStep(string.Format("{0}/{1}", (j + 1), count));

                                        SETItem ent = new SETItem(setfile, address, selectedItems);
                                        list.Add(ent);
                                        address += 0x20;
                                    }
                                }
                                LevelData.SETItems[i] = list;
                            }
                        }
                        else
                        {
                            LevelData.SETItems = null;
                        }

                        // Checks if there have been any errors added to the error list and does its thing
                        // This thing is a mess. If anyone can think of a cleaner way to do this, be my guest.
                        if (objectErrors.Count > 0)
                        {
                            int count = objectErrors.Count;
                            List<string> errorStrings = new List<string> { "The following objects failed to load:" };

                            foreach (ObjectData o in objectErrors)
                            {
                                bool texEmpty = string.IsNullOrEmpty(o.Texture);
                                bool texExists = (!string.IsNullOrEmpty(o.Texture) && LevelData.Textures.ContainsKey(o.Texture));
                                errorStrings.Add("");
                                errorStrings.Add("Object:\t\t" + o.Name);
                                errorStrings.Add("\tModel:");
                                errorStrings.Add("\t\tName:\t" + o.Model);
                                errorStrings.Add("\t\tExists:\t" + File.Exists(o.Model));
                                errorStrings.Add("\tTexture:");
                                errorStrings.Add("\t\tName:\t" + ((texEmpty) ? "(N/A)" : o.Texture));
                                errorStrings.Add("\t\tExists:\t" + texExists);
                            }

                            // TODO: Proper logging. Who knows where this file may end up
                            File.WriteAllLines("SADXLVL2.log", errorStrings.ToArray());

                            MessageBox.Show(count + ((count == 1) ? " object" : " objects") + " failed to load their model(s).\n"
                                            +
                                            "\nThe level will still display, but the objects in question will not display their proper models." +
                                            "\n\nPlease check the log for details.",
                                "Error loading models", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        }
                    }
                    else
                    {
                        LevelData.SETItems = null;
                    }

                    progress.StepProgress();

                    #endregion

                    #region CAM Layout

                    progress.SetTaskAndStep("Loading CAM items", "Initializing...");

                    string camstr = Path.Combine(syspath, "CAM" + LevelData.SETName + "{0}.bin");

                    LevelData.CAMItems = new List<CAMItem>[LevelData.SETChars.Length];
                    for (int i = 0; i < LevelData.SETChars.Length; i++)
                    {
                        List<CAMItem> list = new List<CAMItem>();
                        byte[] camfile = null;

                        string formatted = string.Format(camstr, LevelData.SETChars[i]);

                        if (modpath != null && File.Exists(Path.Combine(modpath, formatted)))
                            camfile = File.ReadAllBytes(Path.Combine(modpath, formatted));
                        else if (File.Exists(formatted))
                            camfile = File.ReadAllBytes(formatted);

                        if (camfile != null)
                        {
                            progress.SetTask("CAM: " + formatted.Replace(Environment.CurrentDirectory, ""));

                            int count = BitConverter.ToInt32(camfile, 0);
                            int address = 0x40;
                            for (int j = 0; j < count; j++)
                            {
                                progress.SetStep(string.Format("{0}/{1}", (j + 1), count));

                                CAMItem ent = new CAMItem(camfile, address, selectedItems);
                                list.Add(ent);
                                address += 0x40;
                            }
                        }

                        LevelData.CAMItems[i] = list;
                    }

                    CAMItem.Init(d3ddevice);

                    progress.StepProgress();

                    #endregion

                    #region Loading Level Effects

                    LevelData.leveleff = null;
                    if (!string.IsNullOrEmpty(level.Effects))
                    {
                        progress.SetTaskAndStep("Loading Level Effects...");

                        LevelDefinition def = null;
                        string ty = "SADXObjectDefinitions.Level_Effects." + Path.GetFileNameWithoutExtension(level.Effects);
                        string dllfile = Path.Combine("dllcache", ty + ".dll");
                        DateTime modDate = DateTime.MinValue;

                        if (File.Exists(dllfile))
                            modDate = File.GetLastWriteTime(dllfile);

                        string fp = level.Effects.Replace('/', Path.DirectorySeparatorChar);
                        if (modDate >= File.GetLastWriteTime(fp) && modDate > File.GetLastWriteTime(Application.ExecutablePath))
                        {
                            def =
                                (LevelDefinition)
                                    Activator.CreateInstance(
                                        Assembly.LoadFile(Path.Combine(Environment.CurrentDirectory, dllfile)).GetType(ty));
                        }
                        else
                        {
                            string ext = Path.GetExtension(fp);
                            CodeDomProvider pr = null;
                            switch (ext.ToLowerInvariant())
                            {
                                case ".cs":
                                    pr = new Microsoft.CSharp.CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } });
                                    break;
                                case ".vb":
                                    pr = new Microsoft.VisualBasic.VBCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } });
                                    break;
                            }
                            if (pr != null)
                            {
                                CompilerParameters para =
                                    new CompilerParameters(new string[]
                                {
                                    "System.dll", "System.Core.dll", "System.Drawing.dll", Assembly.GetAssembly(typeof (Vector3)).Location,
                                    Assembly.GetAssembly(typeof (Texture)).Location, Assembly.GetAssembly(typeof (D3DX)).Location,
                                    Assembly.GetExecutingAssembly().Location, Assembly.GetAssembly(typeof (LandTable)).Location,
                                    Assembly.GetAssembly(typeof (EditorCamera)).Location, Assembly.GetAssembly(typeof (SA1LevelAct)).Location,
                                    Assembly.GetAssembly(typeof (Item)).Location
                                })
                                    {
                                        GenerateExecutable = false,
                                        GenerateInMemory = false,
                                        IncludeDebugInformation = true,
                                        OutputAssembly = Path.Combine(Environment.CurrentDirectory, dllfile)
                                    };
                                CompilerResults res = pr.CompileAssemblyFromFile(para, fp);
                                if (!res.Errors.HasErrors)
                                    def = (LevelDefinition)Activator.CreateInstance(res.CompiledAssembly.GetType(ty));
                            }
                        }

                        if (def != null)
                            def.Init(level, levelact.Act, d3ddevice);

                        LevelData.leveleff = def;
                    }

                    progress.StepProgress();

                    #endregion

                    #region Loading Splines

                    LevelData.LevelSplines = new List<SplineData>();
                    SplineData.Init();

                    if (!string.IsNullOrEmpty(ini.Paths))
                    {
                        progress.SetTaskAndStep("Reticulating splines...");

                        String splineDirectory = Path.Combine(Path.Combine(Environment.CurrentDirectory, ini.Paths),
                            levelact.ToString());

                        if (Directory.Exists(splineDirectory))
                        {
                            List<string> pathFiles = new List<string>();

                            for (int i = 0; i < int.MaxValue; i++)
                            {
                                string path = string.Concat(splineDirectory, string.Format("/{0}.ini", i));
                                if (File.Exists(path))
                                {
                                    pathFiles.Add(path);
                                }
                                else
                                    break;
                            }

                            foreach (string pathFile in pathFiles) // looping through path files
                            {
                                SplineData newSpline = new SplineData(PathData.Load(pathFile), selectedItems);

                                newSpline.RebuildMesh(d3ddevice);

                                LevelData.LevelSplines.Add(newSpline);
                            }
                        }
                    }

                    progress.StepProgress();

                    #endregion

                    #region Stage Lights
                    progress.SetTaskAndStep("Loading lights...");

                    if ((stageLightList != null) && (stageLightList.Count > 0))
                    {
                        List<SA1StageLightData> lightList = new List<SA1StageLightData>();

                        foreach (SA1StageLightData lightData in stageLightList)
                        {
                            if ((lightData.Level == levelact.Level) && (lightData.Act == levelact.Act))
                                lightList.Add(lightData);
                        }

                        if (lightList.Count > 0)
                        {
                            for (int i = 0; i < d3ddevice.Lights.Count; i++) // clear all default lights
                            {
                                d3ddevice.Lights[i].Enabled = false;
                            }

                            for (int i = 0; i < lightList.Count; i++)
                            {
                                SA1StageLightData lightData = lightList[i];

                                d3ddevice.Lights[i].Enabled = true;
                                d3ddevice.Lights[i].Type = (lightData.UseDirection) ? LightType.Directional : LightType.Point;
                                d3ddevice.Lights[i].Diffuse = lightData.RGB.ToColor();
                                d3ddevice.Lights[i].DiffuseColor = new ColorValue(lightData.RGB.X, lightData.RGB.Y, lightData.RGB.Z, 1.0f);
                                d3ddevice.Lights[i].Ambient = lightData.AmbientRGB.ToColor();
                                d3ddevice.Lights[i].Specular = Color.Black;
                                d3ddevice.Lights[i].Direction = lightData.Direction.ToVector3();
                                d3ddevice.Lights[i].Range = lightData.Dif; // guessing here
                            }
                        }
                        else
                        {
                            MessageBox.Show("No lights were found for this stage. Using default lights instead.", "No lights found",
                                MessageBoxButtons.OK, MessageBoxIcon.Warning);
                        }
                    }

                    progress.StepProgress();
                    #endregion

                    transformGizmo = new TransformGizmo();

                    Invoke((Action)progress.Close);
                }
            #if !DEBUG
            }
            catch (Exception ex)
            {
                MessageBox.Show(
                    ex.GetType().Name + ": " + ex.Message + "\nLog file has been saved to " + Path.Combine(Environment.CurrentDirectory, "SADXLVL2.log") + ".\nSend this to MainMemory on the Sonic Retro forums.",
                    "SADXLVL2 Fatal Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                File.WriteAllText("SADXLVL2.log", ex.ToString());
                initerror = true;
            }
            #endif
        }