private void SliceEv(Slicer.eSliceEvent ev, int layer, int totallayers, SliceFile sf)
 {
     if (InvokeRequired)
     {
         BeginInvoke(new MethodInvoker(delegate() { SliceEv(ev, layer, totallayers,sf); }));
     }
     else
     {
         switch (ev)
         {
             case Slicer.eSliceEvent.eSliceStarted:
                 cmdSlice.Text = "Cancel";
                 prgSlice.Maximum = totallayers - 1;
                 break;
             case Slicer.eSliceEvent.eLayerSliced:
                 prgSlice.Maximum = totallayers - 1;
                 prgSlice.Value = layer;
                 lblMessage.Text = "Slicing Layer " + (layer + 1).ToString() + " of " + totallayers.ToString();
                 
                 break;
             case Slicer.eSliceEvent.eSliceCompleted:
                 lblMessage.Text = "Slicing Completed";
                 cmdSlice.Text = "Slice!";
                 Close();
                 break;
             case Slicer.eSliceEvent.eSliceCancelled:
                 cmdSlice.Text = "Slice!";
                 lblMessage.Text = "Slicing Cancelled";
                 prgSlice.Value = 0;
                 break;
         }
     }
 }
        /*
         GCode Process for building 3d DVP UV objects

         * <Build Start>
         * <Slicing Comments> comments containing the slicing and building parameters
         * <Header Code> start.gcode - commands from this
         * file are inserted, they contain whatever intiailization sequences are need to initialize the machine
         * at this point, the build tray is in position to start printing a layer
         * <Layer Start>
         * Display the correct image slice for the current layer
         * Delay for <Layertime> to expose the UV resin
         * <Layer End>

         Example:
         * G1 Z0.05 F10 (move to the layer position .05 mm distance)
         * (<Layer 0 >) (show the slice image layer)
         * (<Delay 1000 >) (pause to expose the layer, first layer time is longer)
         * (<Layer Blank >) (show the blank image layer now)
         * (pre- lift gcode goes here)
         * G1 Z5 F10    (Move up (or down) for the lift sequence)
         * G1 X20 F20   (Move the wiper)
         * G1 X-20 F20  (Move the wiper back)
         * G1 Z5 F10    (Move down (or up) for the lift sequence)
         * (post - lift gcode goes here)
         * (<Delay blanktime >) (the previous commands will all be run, this command will cause the build manager to delay before moving to the next layer)

         */
        /*
         This is the main function to generate gcode files for the
         * already sliced model
         */
        public static GCodeFile Generate(SliceFile sf, MachineConfig pi)
        {
            String gcode;
            StringBuilder sb = new StringBuilder();
            double zdist = 0.0;
            double feedrate = pi.ZMaxFeedrate; // 10mm/min
            double zdir = 1.0; // assume a bottom up machine
            int numbottom = sf.m_config.numfirstlayers;

            if (sf.m_config.direction == SliceBuildConfig.eBuildDirection.Top_Down)
            {
                zdir = -1.0;// top down machine, reverse the z direction
            }

            // append the build parameters as reference
            sb.Append(sf.m_config.ToString());

            // append the header
            sb.Append(sf.m_config.HeaderCode);

            String firstlayerdelay = "(<Delay> " + sf.m_config.firstlayertime_ms + " )\r\n";
            String layerdelay = "(<Delay> " + sf.m_config.layertime_ms + " )\r\n";
            String blankdelay = "(<Delay> " + sf.m_config.blanktime_ms + " )\r\n";
            String raisetime = "(<Delay> " + sf.m_config.raise_time_ms + " )\r\n";
            zdist = sf.m_config.ZThick;

            for (int c = 0; c < sf.m_slices.Count; c++ )
            {
                //move the z axis to the right layer position
              //  sb.Append("G1 Z" + String.Format("{0:0.00000}", (zdist * zdir)) + " F" + feedrate + "\r\n");
                // this is the marker the BuildManager uses to display the correct slice
                sb.Append( "(<Slice> " + c + " )\r\n");
                // add a pause for the UV resin to be set using this image
                if (c < numbottom)// check for the bottom layers
                {
                    sb.Append(firstlayerdelay);
                }
                else
                {
                    sb.Append(layerdelay);
                }
                sb.Append("(<Slice> Blank )\r\n"); // show the blank layer
                sb.Append(sf.m_config.PreLiftCode); // append the pre-lift codes
                //do the lift
                sb.Append("G1 Z" + String.Format("{0:0.00000}", (sf.m_config.liftdistance * zdir)) + " F" + feedrate + " (Lift) \r\n");
                sb.Append(sf.m_config.PostLiftCode); // append the post-lift codes
                // move back from the lift
                sb.Append("G1 Z" + String.Format("{0:0.00000}", (sf.m_config.liftdistance * zdir * -1)) + " F" + feedrate + " (End Lift) \r\n");
                // add a delay for the lift sequence and the pre/post lift codes to execute
                sb.Append(blankdelay);
                // this move is moved to the end, so the first layer doesn't try to move up
                sb.Append("G1 Z" + String.Format("{0:0.00000}", (zdist * zdir)) + " F" + feedrate + "\r\n");
                sb.Append(raisetime);
            }
            //append the footer
            sb.Append(sf.m_config.FooterCode);
            gcode = sb.ToString();
            GCodeFile gc = new GCodeFile(gcode);
            return gc;
        }
 private void SliceEv(Slicer.eSliceEvent ev, int layer, int totallayers, SliceFile sf)
 {
     try
     {
         if (InvokeRequired)
         {
             BeginInvoke(new MethodInvoker(delegate() { SliceEv(ev, layer, totallayers, sf); }));
         }
         else
         {
             switch (ev)
             {
                 case Slicer.eSliceEvent.eSliceStarted:
                     Text = "";
                     break;
                 case Slicer.eSliceEvent.eSliceCompleted:
                     //show the gcode
                     Text = UVDLPApp.Instance().m_gcode.RawGCode;
                     break;
             }
         }
     }
     catch (Exception ex)
     {
         DebugLogger.Instance().LogError(ex.Message);
     }
 }
 private void SliceEv(Slicer.eSliceEvent ev, int layer, int totallayers, SliceFile sf)
 {
     try
     {
         if (InvokeRequired)
         {
             BeginInvoke(new MethodInvoker(delegate() { SliceEv(ev, layer, totallayers, sf); }));
         }
         else
         {
             switch (ev)
             {
                 case Slicer.eSliceEvent.eSliceStarted:
                    
                     break;
                 case Slicer.eSliceEvent.eLayerSliced:
                     break;
                 case Slicer.eSliceEvent.eSliceCompleted:                            
                     SetNumLayers(totallayers);
                     break;
             }
         }
     }
     catch (Exception ex)
     {
         DebugLogger.Instance().LogError(ex.Message);
     }
 }
        /*
         This is the main function to generate gcode files for the
         * already sliced model
         */
        public static GCodeFile Generate(SliceFile sf, MachineConfig pi)
        {
            String gcode;
            StringBuilder sb = new StringBuilder();
            PreProcessor pp = PreparePreprocessor(sf, pi);
            double zdist = 0.0;
               // double feedrate = pi.ZMaxFeedrate; // 10mm/min
            double liftfeed = sf.m_config.liftfeedrate;
            double retractfeed = sf.m_config.liftretractrate;
            double zdir = 1.0; // assume a bottom up machine
            int numbottom = sf.m_config.numfirstlayers;

            if (sf.m_config.direction == SliceBuildConfig.eBuildDirection.Top_Down)
            {
                zdir = -1.0;// top down machine, reverse the z direction
            }
            pp.SetVar("$ZDir", zdir);

            // append the build parameters as reference
            sb.Append(sf.m_config.ToString());
            sb.Append(";Number of Slices        =  " + sf.NumSlices.ToString() + "\r\n");

            sb.Append(pi.ToString());//add the machine build parameters string

            // append the header
            sb.Append(pp.Process(sf.m_config.HeaderCode));

            zdist = sf.m_config.ZThick;

            String firstlayerdelay = ";<Delay> " + sf.m_config.firstlayertime_ms + " \r\n";
            String layerdelay = ";<Delay> " + sf.m_config.layertime_ms + " \r\n";
            String blankdelay = ";<Delay> " + sf.m_config.blanktime_ms + " \r\n";

            String preSliceGCode = pp.Process(sf.m_config.PreSliceCode);
            String LiftGCode = pp.Process(sf.m_config.LiftCode);

            for (int c = 0; c < sf.NumSlices; c++)
            {
                sb.Append(preSliceGCode);//add in the pre-slice code
                // this is the marker the BuildManager uses to display the correct slice
                sb.Append(";<Slice> " + c + " \r\n");
                // add a pause for the UV resin to be set using this image
                if (c < numbottom)// check for the bottom layers
                {
                    sb.Append(firstlayerdelay);
                }
                else
                {
                    sb.Append(layerdelay);
                }
                sb.Append(";<Slice> Blank \r\n"); // show the blank layer
                sb.Append(LiftGCode); // append the pre-lift codes
            }
            //append the footer
            sb.Append(pp.Process(sf.m_config.FooterCode));
            gcode = sb.ToString();
            GCodeFile gc = new GCodeFile(gcode);
            return gc;
        }
        /*
         GCode Process for building 3d DVP UV objects
         
         * <Build Start>
         * <Slicing Comments> comments containing the slicing and building parameters
         * <Header Code> start.gcode - commands from this 
         * file are inserted, they contain whatever intiailization sequences are need to initialize the machine
         * at this point, the build tray is in position to start printing a layer
         * <Layer Start>
         * Display the correct image slice for the current layer
         * Delay for <Layertime> to expose the UV resin
         * <Layer End>
         
         
        */

        // here we prepare the gcode preprocessor and fill all nessesary variables 
        protected static PreProcessor PreparePreprocessor(SliceFile sf, MachineConfig pi)
        {
            PreProcessor pp = new PreProcessor();
            pp.SetVar("$LayerThickness", sf.m_config.ZThick); // the thickenss of the layer in mm
            pp.SetVar("$ZLiftDist", sf.m_config.liftdistance); // how far we're lifting
            pp.SetVar("$ZLiftRate", sf.m_config.liftfeedrate); // the rate at which we're lifting
            pp.SetVar("$ZRetractRate", sf.m_config.liftretractrate); // how fast we'r retracting
            pp.SetVar("$SlideTiltVal", sf.m_config.slidetiltval); // any used slide / tilt value on the x axis
            pp.SetVar("$BlankTime", sf.m_config.blanktime_ms); // how long to show the blank in ms
            pp.SetVar("$LayerTime", sf.m_config.layertime_ms); // total delay for a layer for gcode commands to complete - not including expusre time
            pp.SetVar("$FirstLayerTime", sf.m_config.firstlayertime_ms); // time to expose the first layers in ms
            pp.SetVar("$NumFirstLayers", sf.m_config.numfirstlayers); // number of first layers
            return pp;
        }
        /// <summary>
        /// Loads a model, adds it to the 3d engine to be shown, and raises an app event
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        public bool LoadModel(String filename)
        {
            try
            {
                ModelLoader ml = new ModelLoader();
                List<Object3d> objs = ml.Load(filename);
                if (objs != null)
                {
                    foreach (Object3d obj in objs)
                    {
                        obj.CenterOnPlatform();
                        m_engine3d.AddObject(obj);
                        m_undoer.SaveAddition(obj);
                        SelectedObject = obj;
                    }
                    UVDLPApp.Instance().m_engine3d.UpdateLists();
                    m_slicefile = null; // the slice file is not longer current
                    RaiseAppEvent(eAppEvent.eModelAdded, "Model Loaded " + filename);
                    //now try to load the gcode file
                    String gcodefile = Path.GetFileNameWithoutExtension(filename) + ".gcode";
                    String gcodepath = SliceFile.GetSliceFilePath(filename);

                    String gpath = gcodepath + UVDLPApp.m_pathsep + gcodefile;
                    if (File.Exists(gpath))
                    {
                        LoadGCode(gpath);
                    }
                    else // read the gcode from the zip file
                    {
                        String zpath = gcodepath + ".zip";
                        if(File.Exists(zpath)) // make sure the file exists before we try to read it
                        {
                            Stream s = Utility.ReadFromZip(zpath, gcodefile);
                            if(s  != null)
                            {
                                s.Seek(0, 0); // go to the beginning of the stream
                                byte []array = Utility.ReadFully(s);
                                string gc = System.Text.Encoding.ASCII.GetString(array);
                                m_gcode = new GCodeFile(gc);
                                RaiseAppEvent(eAppEvent.eGCodeLoaded, "GCode Loaded " + gcodefile);
                            }
                            else
                            {
                                DebugLogger.Instance().LogError("Could not load GCode from Zip " + zpath);
                            }
                        }

                    }
                    if(m_gcode !=null)
                    {
                        int xres, yres, numslices;
                        xres = m_gcode.GetVar("Projector X Res");
                        yres = m_gcode.GetVar("Projector Y Res");
                        numslices = m_gcode.GetVar("Number of Slices");
                        m_slicefile = new SliceFile(xres,yres,numslices);
                        m_slicefile.modelname = SelectedObject.m_fullname;
                        m_slicefile.m_config = null; //this can be null if we're loading it...
                        RaiseAppEvent(eAppEvent.eSlicedLoaded, "SliceFile Created");
                    }
                }
                else
                {
                    RaiseAppEvent(eAppEvent.eModelNotLoaded, "Model " + filename + " Failed to load");
                }

                return (objs != null);
            }
            catch (Exception ex)
            {
                DebugLogger.Instance().LogRecord(ex.Message);
                return false;
            }
        }
        void SliceEv(Slicer.eSliceEvent ev, int layer, int totallayers,SliceFile sf)
        {
            String path = "";
            String fileName = "";
            switch (ev)
            {
                case Slicer.eSliceEvent.eSliceStarted:

                    break;
                case Slicer.eSliceEvent.eLayerSliced:

                    break;
                case Slicer.eSliceEvent.eSliceCompleted:
                    m_slicefile = sf;
                    //generate the GCode
                    m_gcode = GCodeGenerator.Generate(m_slicefile, m_printerinfo);

                    path = SliceFile.GetSliceFilePath(m_slicefile.modelname);
                    fileName = Path.GetFileNameWithoutExtension(m_slicefile.modelname) + ".gcode";
                    //see if we're exporting this to a zip file
                    if (sf.m_config.m_exportopt.Contains("ZIP"))
                    {
                        // open the existing zip file
                        //store the gcode
                        Stream stream = new MemoryStream(System.Text.Encoding.ASCII.GetBytes (m_gcode.RawGCode));
                        String zpath = path + ".zip";
                        if (!Utility.StoreInZip(zpath, fileName, stream))
                        {
                            DebugLogger.Instance().LogError("Could not store GCode in Zip " + zpath);
                        }
                    }
                    else  // or just to the disk
                    {
                        String sdn = path + UVDLPApp.m_pathsep + fileName;
                        SaveGCode(sdn);
                    }

                    //save the slicer object for later too
                    //save the slice file

                   // UVDLPApp.Instance().m_slicefile.Save(path + UVDLPApp.m_pathsep + fn + ".sliced");
                    break;
                case Slicer.eSliceEvent.eSliceCancelled:
                    DebugLogger.Instance().LogRecord("Slicing Cancelled");
                    break;

            }
        }
        /// <summary>
        /// Loads a model, adds it to the 3d engine to be shown, and raises an app event
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        public bool LoadModel(String filename)
        {
            try
            {
                Object3d obj = new Object3d();

                string ext = Path.GetExtension(filename);
                bool ret = false;
                ext = ext.ToLower();
                if (ext.Equals(".dxf"))
                {
                    ret = obj.LoadDXF(filename);
                }
                if (ext.Equals(".stl"))
                {
                    ret = obj.LoadSTL(filename);
                }
                if (ext.Equals(".obj"))
                {
                    ret = obj.LoadObjFile(filename);
                }
                if (ext.Equals(".3ds"))
                {
                    ret = obj.Load3ds(filename);
                }
                if (ret == true)
                {
                    m_engine3d.AddObject(obj);
                    m_selectedobject = obj;
                    m_slicefile = null; // the slice file is not longer current
                    RaiseAppEvent(eAppEvent.eModelAdded, "Model Loaded");

                }
                else
                {
                    RaiseAppEvent(eAppEvent.eModelNotLoaded, "Model " + filename + " Failed to load");
                }

                return ret;
            }
            catch (Exception ex)
            {
                DebugLogger.Instance().LogRecord(ex.Message);
                return false;
            }
        }
 // This function is called to start the print job
 public void StartPrint(SliceFile sf, GCodeFile gcode)
 {
     if (m_printing)  // already printing
         return;
     if (sf == null)
     {
         DebugLogger.Instance().LogRecord("No slice file, build cannot start");
         RaiseStatusEvent(ePrintStat.ePrintCancelled);
         return;
     }
     if (gcode == null)
     {
         DebugLogger.Instance().LogRecord("No gcode file, build cannot start");
         RaiseStatusEvent(ePrintStat.ePrintCancelled);
         return;
     }
     // we really need to map onto the events of the PrinterInterface to determine
     // important stuff like current z position, HBP temp, etc...
     m_printing = true;
     m_sf = sf; // set the slicefile for rendering
     m_gcode = gcode; // set the file
     m_state = STATE_START; // set the state machine as started
     m_runthread = new Thread(new ThreadStart(BuildThread));
     m_running = true;
     m_runthread.Start();
 }
        /// <summary>
        /// This is the adaptive support generation, it should automatically 
        /// detect overhangs and generate supports acordingly
        /// </summary>
        public void GenerateAdaptive2()
        {
            // iterate through all the layers starting from z=0
            // slice all layers
            // split each layer into non overlapping polygons
            // check each polygon to see if it is completely overhangs in the air, or partially
            //   supported by previous layers.
            // for complete overhangs always create supports
            // for partialy supported polygons, generate supports only if there is no other
            //   support in the vicinity
            try
            {

                SliceBuildConfig config = UVDLPApp.Instance().m_buildparms;
                config.UpdateFrom(UVDLPApp.Instance().m_printerinfo); // make sure we've got the correct display size and PixPerMM values   

                if (UVDLPApp.Instance().m_slicer.SliceFile == null)
                {
                    SliceFile sf = new SliceFile(config);
                    sf.m_mode = SliceFile.SFMode.eImmediate;
                    UVDLPApp.Instance().m_slicer.SliceFile = sf; // wasn't set
                }
                //create new list for new supports
                List<Object3d> lstsupports = new List<Object3d>(); // final list of supports
                List<SupportLocation> supLocs = new List<SupportLocation>(); // temporary list of support locations.

                int numslices = UVDLPApp.Instance().m_slicer.GetNumberOfSlices(config);
                float zlev = 0.0f;
                int hxres = config.xres / 2;
                int hyres = config.yres / 2;
                int npix = config.xres * config.yres;
                int[] lbm = new int[npix];  // current slice
                int[] lbmz = new int[npix]; // z buffer
                bool[] lbms = new bool[npix]; // support map
                int p;
                for (p = 0; p < npix; p++)
                {
                    lbmz[p] = 0;
                    lbms[p] = false;
                }

                Bitmap bm = new Bitmap(config.xres, config.yres, System.Drawing.Imaging.PixelFormat.Format32bppArgb); // working bitmap
                Color savecol = UVDLPApp.Instance().m_appconfig.m_foregroundcolor;
                m_supportgap = (int)(m_sc.mingap * config.dpmmX);

                m_asp.lbm = lbm;
                m_asp.lbms = lbms;
                m_asp.lbmz = lbmz;
                m_asp.searchmap = new int[npix];
                m_asp.xres = config.xres;
                m_asp.yres = config.yres;
                m_asp.mingap = m_supportgap;

                for (int c = 0; c < numslices; c++)
                {
                    //bool layerneedssupport = false;
                    if (m_cancel)
                    {
                        RaiseSupportEvent(UV_DLP_3D_Printer.SupportEvent.eCancel, "Support Generation Cancelled", null);
                        return;
                    }
                    RaiseSupportEvent(UV_DLP_3D_Printer.SupportEvent.eProgress, "" + c + "/" + numslices, null);

                    Slice sl = UVDLPApp.Instance().m_slicer.GetSliceImmediate(zlev);
                    zlev += (float)config.ZThick;

                    if ((sl == null) || (sl.m_segments == null) || (sl.m_segments.Count == 0))
                        continue;
                    sl.Optimize();// find loops
                    using (Graphics gfx = Graphics.FromImage(bm))
                        gfx.Clear(Color.Transparent);

                     //render current slice
                    UVDLPApp.Instance().m_appconfig.m_foregroundcolor = Color.FromArgb((0xFF << 24) | c);
                    sl.RenderSlice(config, ref bm);
                    BitmapData data = bm.LockBits(new Rectangle(0, 0, bm.Width, bm.Height),
                            ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
                    Marshal.Copy(data.Scan0, lbm, 0, lbm.Length);
                    for (p = 0; p < npix; p++)
                        lbm[p] &= 0xFFFFFF;
                    bm.UnlockBits(data);
                    if (c > 0)
                    {
                        if (m_sc.eSupType == SupportConfig.eAUTOSUPPORTTYPE.eADAPTIVE)
                            ProcessSlice(lbm, lbmz, lbms, config.xres, config.yres, supLocs);
                        else
                            ProcessSlice2(supLocs);
                    }

                    // add slice to zbuffer bitmap
                    for (p = 0; p < npix; p++)
                        if (lbm[p] != 0)
                            lbmz[p] = lbm[p];
                }
                UVDLPApp.Instance().m_appconfig.m_foregroundcolor = savecol;

                int scnt = 0;
                foreach (SupportLocation spl in supLocs)
                {
                    float px = (float)(spl.x - hxres) / (float)config.dpmmX;
                    float py = (float)(spl.y - hyres) / (float)config.dpmmY;
                    float pz = (float)(spl.ztop) * (float)config.ZThick;
                    AddNewSupport(px, py, pz, scnt++, GetSupportParrent(px,py,pz), lstsupports);

                }
                RaiseSupportEvent(UV_DLP_3D_Printer.SupportEvent.eCompleted, "Support Generation Completed", lstsupports);
                m_generating = false;

            }
            catch (Exception ex)
            {
                DebugLogger.Instance().LogError(ex);
            }
        }
        // This function is called to start the print job
        public void StartPrint(SliceFile sf, GCodeFile gcode, bool snippet = false)
        {
            //late init of callback handler
            if (callbackinited == false)
            {
                UVDLPApp.Instance().m_callbackhandler.RegisterCallback("DisplayDone", DisplayDone, null, "Indicates when the display device is done with the current slice");
                callbackinited = true;
            }
            m_runningsnippet = snippet;

            if (m_printing)  // already printing
                return;
            //make sure to reset these
            m_pause_request = false;
            //m_cancel_request = false;

            m_printing = true;
            m_buildstarttime = new DateTime();
            m_buildstarttime = DateTime.Now;
            estimatedbuildtime = EstimateBuildTime(gcode);
            StartBuildTimer();

            m_sf = sf; // set the slicefile for rendering
            m_gcode = gcode; // set the file
            m_state = STATE_START; // set the state machine as started
            m_runthread = new Thread(new ThreadStart(BuildThread));
            m_running = true;
            m_runthread.Start();
        }
        void SliceEv(Slicer.eSliceEvent ev, int layer, int totallayers,SliceFile sf)
        {
            //  String path = "";
               // String fileName = "";
            switch (ev)
            {
                case Slicer.eSliceEvent.eSliceStarted:

                    break;
                case Slicer.eSliceEvent.eLayerSliced:

                    break;
                case Slicer.eSliceEvent.eSliceCompleted: // this all needs to be changed....
                    m_slicefile = sf;
                    //generate the GCode
                    m_gcode = GCodeGenerator.Generate(m_slicefile, m_printerinfo);
                    //we only need the file name of the gcode if we're saving it somewhere...
                    //see if we're exporting this to a zip file
                    //if (sf.m_config.m_exportopt.Contains("ZIP") && sf.m_config.export)
                    if (sf.m_config.export)
                    {
                        // open the existing scene file
                        //store the gcode
                        MemoryStream stream = new MemoryStream(System.Text.Encoding.ASCII.GetBytes(m_gcode.RawGCode));
                        String gcn = Path.GetFileNameWithoutExtension(UVDLPApp.Instance().SceneFileName) + ".gcode";
                        //SceneFile.Instance().RemoveExistingGCode(UVDLPApp.Instance().SceneFileName);
                        SceneFile.Instance().RemoveResourcesFromFile(UVDLPApp.Instance().SceneFileName, "GCode", ".gcode");
                        SceneFile.Instance().AddGCodeToFile(UVDLPApp.Instance().SceneFileName, stream, gcn);
                    }
                    //save the slicer object for later too
                    //save the slice file

                   // UVDLPApp.Instance().m_slicefile.Save(path + UVDLPApp.m_pathsep + fn + ".sliced");
                    break;
                case Slicer.eSliceEvent.eSliceCancelled:
                    DebugLogger.Instance().LogRecord("Slicing Cancelled");
                    break;

            }
        }
 // this function takes the object, the slicing parameters,
 // and the output directory. it generates the object slices
 // and saves them in the directory
 public SliceFile Slice(SliceBuildConfig sp, Object3d obj, String outdir)
 {
     m_obj = obj;
         m_cancel = false;
         // create new slice file
         m_sf = new SliceFile(sp);
         m_slicethread = new Thread(new ThreadStart(slicefunc));
         m_slicethread.Start();
         isslicing = true;
         return m_sf;
 }
 // standard scene slicing
 // this function takes the object, the slicing parameters,
 // and the output directory. it generates the object slices
 // and saves them in the directory
 public SliceFile Slice(SliceBuildConfig sp)//, Object3d obj) 
 {
     // create new slice file
     m_sf = new SliceFile(sp);
     m_sf.m_modeltype = Slicing.SliceFile.ModelType.eScene;
     if (sp.export == false)
     {
         m_sf.m_mode = SliceFile.SFMode.eImmediate;
     }
     m_slicethread = new Thread(new ThreadStart(slicefunc));
     m_slicethread.Start();
     isslicing = true;
     return m_sf;
 }
        /*
         GCode Process for building 3d DVP UV objects

         * <Build Start>
         * <Slicing Comments> comments containing the slicing and building parameters
         * <Header Code> start.gcode - commands from this
         * file are inserted, they contain whatever intiailization sequences are need to initialize the machine
         * at this point, the build tray is in position to start printing a layer
         * <Layer Start>
         * Display the correct image slice for the current layer
         * Delay for <Layertime> to expose the UV resin
         * <Layer End>

        */
        /*
         This is the main function to generate gcode files for the
         * already sliced model
         */
        public static GCodeFile Generate(SliceFile sf, MachineConfig pi)
        {
            String gcode;
            StringBuilder sb = new StringBuilder();
            double zdist = 0.0;
               // double feedrate = pi.ZMaxFeedrate; // 10mm/min
            double liftfeed = sf.m_config.liftfeedrate;
            double retractfeed = sf.m_config.liftretractrate;
            double zdir = 1.0; // assume a bottom up machine
            int numbottom = sf.m_config.numfirstlayers;

            if (sf.m_config.direction == SliceBuildConfig.eBuildDirection.Top_Down)
            {
                zdir = -1.0;// top down machine, reverse the z direction
            }

            // append the build parameters as reference
            sb.Append(sf.m_config.ToString());
            sb.Append(";(Number of Slices        =  " + sf.NumSlices.ToString() + ")\r\n");

            sb.Append(pi.ToString());//add the machine build parameters string

            // append the header
            sb.Append(sf.m_config.HeaderCode);

            zdist = sf.m_config.ZThick;

            String firstlayerdelay = ";(<Delay> " + sf.m_config.firstlayertime_ms + " )\r\n";
            String layerdelay = ";(<Delay> " + sf.m_config.layertime_ms + " )\r\n";
            String blankdelay = ";(<Delay> " + sf.m_config.blanktime_ms + " )\r\n";
            String tmpZU = String.Format("{0:0.00000}", (sf.m_config.liftdistance * zdir)).Replace(',', '.');
            String tmpZD = String.Format("{0:0.00000}", ((sf.m_config.liftdistance - zdist) * zdir * -1)).Replace(',', '.');
            String tmpX1 = String.Format("{0:0.00000}", (sf.m_config.slidetiltval)).Replace(',', '.');
            String tmpX2 = String.Format("{0:0.00000}", (sf.m_config.slidetiltval * -1)).Replace(',', '.');

            for (int c = 0; c < sf.NumSlices; c++)
            {
                sb.Append(sf.m_config.PreSliceCode);//add in the pre-slice code
                // this is the marker the BuildManager uses to display the correct slice
                sb.Append(";(<Slice> " + c + " )\r\n");
                // add a pause for the UV resin to be set using this image
                if (c < numbottom)// check for the bottom layers
                {
                    sb.Append(firstlayerdelay);
                }
                else
                {
                    sb.Append(layerdelay);
                }
                sb.Append(";(<Slice> Blank )\r\n"); // show the blank layer
                sb.Append(sf.m_config.PreLiftCode); // append the pre-lift codes
                // I put the following two lines out of the loop to reduce calculationTime
                //String tmpZU = String.Format("{0:0.00000}", (sf.m_config.liftdistance * zdir)).Replace(',', '.');
                //String tmpZD = String.Format("{0:0.00000}", ((sf.m_config.liftdistance - zdist) * zdir * -1)).Replace(',', '.');
                if (sf.m_config.usemainliftgcode == true) // if you want to use the GCode from the MainLiftGCode-Tab
                {
                    sb.Append(sf.m_config.MainLiftCode);
                }
                else if (sf.m_config.slidetiltval == 0.0) // tilt/slide is not used here
                {
                    sb.Append("G1 Z" + tmpZU + " F" + liftfeed + " ;(Lift) \r\n");
                    sb.Append("G1 Z" + tmpZD + " F" + retractfeed + " ;(End Lift) \r\n");
                }
                else // tilt/slide has a value, so it is used
                {
                    // I put the following two lines out of the loop to reduce calculationTime
                    // format the X slide/tilt value
                    //String tmpX1 = String.Format("{0:0.00000}", (sf.m_config.slidetiltval)).Replace(',', '.');
                    //String tmpX2 = String.Format("{0:0.00000}", (sf.m_config.slidetiltval * -1)).Replace(',', '.');
                    sb.Append("G1 X" + tmpX1 + " Z" + tmpZU + " F" + liftfeed + " ;(Lift) \r\n");
                    sb.Append("G1 X" + tmpX2 + " Z" + tmpZD + " F" + retractfeed + " ;(End Lift) \r\n");
                }
                // add a delay for the lift sequence and the pre/post lift codes to execute
                sb.Append(blankdelay);
                // append the post-lift codes
                sb.Append(sf.m_config.PostLiftCode);
            }
            //append the footer
            sb.Append(sf.m_config.FooterCode);
            gcode = sb.ToString();
            GCodeFile gc = new GCodeFile(gcode);
            return gc;
        }
        /// <summary>
        /// This is the adaptive support generation, it should automatically 
        /// detect overhangs,
        /// The way that it does this is by generating a closed polyline loop for each layer
        /// and checking the 2d projection of the current layer with the previous layer
        /// </summary>
        public void GenerateAdaptive()
        {
            //iterate through all the layers starting from z=0
            // check every polyline in the current layer to make sure it is encased or overlaps polylines in the previous layer
            // generate a list of unsupported polylines
            // 'check' to see if the polyline can be dropped straight down
            // this has to do slicing of the scene
            try
            {

                SliceBuildConfig config = UVDLPApp.Instance().m_buildparms;
                config.UpdateFrom(UVDLPApp.Instance().m_printerinfo); // make sure we've got the correct display size and PixPerMM values

                if (UVDLPApp.Instance().m_slicer.SliceFile == null)
                {
                    SliceFile sf = new SliceFile(config);
                    sf.m_mode = SliceFile.SFMode.eImmediate;
                    UVDLPApp.Instance().m_slicer.SliceFile = sf; // wasn't set
                }

                List<UnsupportedRegions> lstunsup = new List<UnsupportedRegions>();
                List<Object3d> lstsupports = new List<Object3d>(); // final list of supports

                int numslices = UVDLPApp.Instance().m_slicer.GetNumberOfSlices(config);
                float zlev = 0.0f;
                Slice curslice = null;
                Slice prevslice = null;
                int hxres = config.xres / 2;
                int hyres = config.yres / 2;
                for (int c = 0; c < numslices; c++)
                {
                    //bool layerneedssupport = false;
                    if (m_cancel)
                    {
                        RaiseSupportEvent(UV_DLP_3D_Printer.SupportEvent.eCancel, "Support Generation Cancelled", null);
                        return;
                    }
                    RaiseSupportEvent(UV_DLP_3D_Printer.SupportEvent.eProgress, "" + c + "/" + numslices, null);

                    Slice sl = UVDLPApp.Instance().m_slicer.GetSliceImmediate(zlev);
                    zlev += (float)config.ZThick;

                    if (sl == null)
                        continue;
                    if (sl.m_segments == null)
                        continue;
                    if (sl.m_segments.Count == 0)
                        continue;
                    sl.Optimize();// find loops
                    //sl.DetermineInteriorExterior(config); // mark the interior/exterior loops
                    prevslice = curslice;
                    curslice = sl;
                    Bitmap bm = new Bitmap(config.xres, config.yres);
                    using (Graphics gfx = Graphics.FromImage(bm))
                    using (SolidBrush brush = new SolidBrush(Color.Black))
                    {
                        gfx.FillRectangle(brush, 0, 0, bm.Width, bm.Height);
                    }

                    if (prevslice != null && curslice != null)
                    {
                        //render current slice
                        curslice.RenderSlice(config, ref bm);
                        //now render the previous slice overtop the current slice in another color
                        Color savecol = UVDLPApp.Instance().m_appconfig.m_foregroundcolor;
                        UVDLPApp.Instance().m_appconfig.m_foregroundcolor = Color.HotPink;
                        //render previous slice over top
                        prevslice.RenderSlice(config, ref bm);
                        UVDLPApp.Instance().m_appconfig.m_foregroundcolor = savecol; // restore the color
                        // create a lock bitmap for faster pixel access
                        LockBitmap lbm = new LockBitmap(bm);
                        lbm.LockBits();
                        // now, iterate through all optimized polylines in current slice
                        // this approach isn't going to work, we need to iterate through all polyline
                        //segments in a slice at once, each individual segment needs to know 1 thing
                        // 1) the optimized segment it came from

                        //iterate through all optimized polygon segments

                        Dictionary<PolyLine3d, bool> supportmap = new Dictionary<PolyLine3d, bool>();
                        foreach (PolyLine3d pln in curslice.m_opsegs)
                        {
                            bool plysupported = false;
                            List<PolyLine3d> allsegments = new List<PolyLine3d>();
                            List<PolyLine3d> segments = pln.Split(); // split them, retaining the parent
                            allsegments.AddRange(segments);
                            //add all optimized polyline segments into the supported map
                            supportmap.Add(pln, true);
                            //split this optimized polyline back into 2-point segments for easier use

                            List<Line2d> lines2d = Get2dLines(config, allsegments);
                            if (lines2d.Count == 0) continue;

                            // find the x/y min/max
                            MinMax_XY mm = Slice.CalcMinMax_XY(lines2d);
                            // iterate from the ymin to the ymax
                            for (int y = mm.ymin; y < mm.ymax; y++) // this needs to be in scaled value
                            {
                                //      get a line of lines that intersect this 2d line
                                List<Line2d> intersecting = Slice.GetIntersecting2dYLines(y, lines2d);
                                //      get the list of point intersections
                                List<Point2d> points = Slice.GetIntersectingPoints(y, intersecting);
                                // sort the points in increasing x order
                                points.Sort();
                                if (points.Count % 2 == 0)  // is even
                                {
                                    for (int cnt = 0; cnt < points.Count; cnt += 2)  // increment by 2
                                    {
                                        Point2d p1 = (Point2d)points[cnt];
                                        Point2d p2 = (Point2d)points[cnt + 1];
                                        Point pnt1 = new Point(); // create some points for drawing
                                        Point pnt2 = new Point();
                                        pnt1.X = (int)(p1.x + config.XOffset + hxres);
                                        pnt1.Y = (int)(p1.y + config.YOffset + hyres);
                                        pnt2.X = (int)(p2.x + config.XOffset + hxres);
                                        pnt2.Y = (int)(p2.y + config.YOffset + hyres);
                                        //iterate from pnt1.X to pnt2.x and check colors
                                        for (int xc = pnt1.X; xc < pnt2.X; xc++)
                                        {
                                            if (xc >= lbm.Width || xc <=0 ) continue;
                                            if (pnt1.Y >= lbm.Height || pnt1.Y <= 0) continue;
                                            try
                                            {
                                                Color checkcol = lbm.GetPixel(xc, pnt1.Y);
                                                // need to check the locked BM here for the right color
                                                // if the pixel color is the hot pink, then this region has some support
                                                // we're going to need to beef this up and probably divide this all into regions on a grid
                                                if (checkcol.R == Color.HotPink.R && checkcol.G == Color.HotPink.G && checkcol.B == Color.HotPink.B)
                                                {
                                                    plysupported = true;
                                                }
                                            }
                                            catch (Exception ex)
                                            {
                                                DebugLogger.Instance().LogError(ex);
                                            }
                                        }
                                    }
                                }
                                else  // flag error
                                {
                                    DebugLogger.Instance().LogRecord("Row y=" + y + " odd # of points = " + points.Count + " - Model may have holes");
                                }
                            }// for y = startminY to endY
                            if (plysupported == false)
                            {

                               // layerneedssupport = true;
                                supportmap[pln] = false;
                                lstunsup.Add(new UnsupportedRegions(pln));
                            }
                        } // for each optimized polyline
                        lbm.UnlockBits(); // unlock the bitmap
                    } // prev and current slice are not null
                    //if (layerneedssupport)
                    //    SaveBM(bm, c); // uncomment this to see the layers that need support
                } // iterating through all slices
                // iterate through all unsupported regions
                // calculate the center
                // add a support from that region going down to the ground (or closest intersected)
                int scnt = 0;
                foreach (UnsupportedRegions region in lstunsup)
                {
                    Support s = new Support();
                    Point3d center = region.Center();
                    float lz = center.z;
                    AddNewSupport(center.x, center.y, center.z, scnt++, null, lstsupports);
                    //region.ply.m_derived.
                    /*s.Create(null,(float)m_sc.fbrad, (float)m_sc.ftrad, (float)m_sc.hbrad, (float)m_sc.htrad, lz * .2f, lz * .6f, lz * .2f, 11);
                    s.Translate((float)center.x, (float)center.y, 0);
                    s.Name = "Support " + scnt;
                    s.SetColor(Color.Yellow);
                    scnt++;
                    lstsupports.Add(s);
                    RaiseSupportEvent(UV_DLP_3D_Printer.SupportEvent.eSupportGenerated, s.Name, s);
                    */

                }
                RaiseSupportEvent(UV_DLP_3D_Printer.SupportEvent.eCompleted, "Support Generation Completed", lstsupports);
                m_generating = false;
            }
            catch (Exception ex)
            {
                DebugLogger.Instance().LogError(ex);
            }
        }
        public bool LoadModel(String filename)
        {
            try
            {
                Object3d obj = new Object3d();

                if (obj.LoadSTL(filename) == false)
                {
                    return false;
                }
                else
                {
                    m_engine3d.AddObject(obj);
                    m_selectedobject = obj;
                    m_slicefile = null; // the slice file is not longer current
                }
                RaiseAppEvent(eAppEvent.eModelLoaded, "Model Loaded");
                return true;
            }
            catch (Exception ex)
            {
                DebugLogger.Instance().LogRecord(ex.Message);
                return false;
            }
        }
        /*
         This is the main function to generate gcode files for the
         * already sliced model
         */
        public static GCodeFile Generate(SliceFile sf, MachineConfig pi)
        {
            String gcode;
            StringBuilder sb = new StringBuilder();
            PreProcessor pp = PreparePreprocessor(sf, pi);
            double zdist = 0.0;
               // double feedrate = pi.ZMaxFeedrate; // 10mm/min
            double liftfeed = sf.m_config.liftfeedrate;
            double bottomliftfeed = sf.m_config.bottomliftfeedrate;

            double retractfeed = sf.m_config.liftretractrate;
            double zdir = 1.0; // assume a bottom up machine
            int numbottom = sf.m_config.numfirstlayers;

            if (sf.m_config.direction == SliceBuildConfig.eBuildDirection.Top_Down)
            {
                zdir = -1.0;// top down machine, reverse the z direction
            }
            pp.SetVar("$ZDir", zdir);

            // append the build parameters as reference
            sb.Append(sf.m_config.ToString());
            sb.Append(";Number of Slices        =  " + sf.NumSlices.ToString() + "\r\n");

            sb.Append(pi.ToString());//add the machine build parameters string

            // append the header
            sb.Append(pp.Process(sf.m_config.HeaderCode));

            zdist = sf.m_config.ZThick;

            String firstlayerdelay = ";<Delay> " + sf.m_config.firstlayertime_ms + " \r\n";
            String layerdelay = ";<Delay> " + sf.m_config.layertime_ms + " \r\n";
            String blankdelay = ";<Delay> " + sf.m_config.blanktime_ms + " \r\n";

            String preSliceGCode = pp.Process(sf.m_config.PreSliceCode);
            String LiftGCode = pp.Process(sf.m_config.LiftCode);

            int numslices = sf.NumSlices;
            if (sf.m_modeltype == SliceFile.ModelType.eResinTest1)
                numslices -= 10;

            // for a per-slice basis, we're going to re-evaluate the prelift and lift gcode
            // doing this will allow us to have per-slice determinations based on slice index.
            int c;
            for (c = 0; c < numslices; c++)
            {
                pp.SetVar("$CURSLICE", c);
                preSliceGCode = pp.Process(sf.m_config.PreSliceCode);
                //pp.SetVar("$CURSLICE", c);
                sb.Append(preSliceGCode);//add in the pre-slice code
                // this is the marker the BuildManager uses to display the correct slice
                sb.Append(";<Slice> " + c + " \r\n");
                // add a pause for the UV resin to be set using this image
                if (c < numbottom)// check for the bottom layers
                {
                    sb.Append(firstlayerdelay);
                }
                else
                {
                    sb.Append(layerdelay);
                }
                sb.Append(";<Slice> Blank \r\n"); // show the blank layer
                LiftGCode = pp.Process(sf.m_config.LiftCode); // re-run the lift code
                sb.Append(LiftGCode); // append the pre-lift codes
            }

            // special ending on resin test model slicing
            if (sf.m_modeltype == SliceFile.ModelType.eResinTest1)
            {
                for (; c < sf.NumSlices; c++)
                {
                    sb.Append(";<Slice> " + c + " \r\n");
                    // add a pause for the UV resin to be set using this image
                    if (c == sf.NumSlices -1) // set minimus exposure time on final layer
                        sb.Append(";<Delay> " + sf.m_config.minExposure + " \r\n");
                    else
                        sb.Append(";<Delay> " + sf.m_config.exposureStep + " \r\n");
                }
                sb.Append(";<Slice> Blank \r\n"); // show the blank layer
                LiftGCode = pp.Process(sf.m_config.LiftCode); // re-run the lift code
                sb.Append(LiftGCode); // append the pre-lift codes
            }

            //append the footer
            sb.Append(pp.Process(sf.m_config.FooterCode));
            gcode = sb.ToString();
            GCodeFile gc = new GCodeFile(gcode);
            return gc;
        }
        //, Object3d obj)
        // slicing of special objects. this is done in immediate mode only. no thread needed
        public SliceFile Slice(SliceBuildConfig sp, SliceFile.ModelType modeltype)
        {
            int numslices = 0;
            string scenename = "";
            switch (modeltype)
            {
                case SliceFile.ModelType.eScene:
                    return Slice(sp);
                    //break;

                case SliceFile.ModelType.eResinTest1:
                    numslices = (int)(7.0 / sp.ZThick);
                    scenename = "Test Model V1";
                    break;
            }

            m_sf = new SliceFile(sp);
            m_sf.m_modeltype = modeltype;
            m_sf.m_mode = SliceFile.SFMode.eImmediate;
            m_sf.NumSlices = numslices;
            SliceStarted(scenename, numslices);
            DebugLogger.Instance().LogRecord("Test model slicing started");
            SliceCompleted(scenename, 0, numslices);
            return m_sf;
        }
        /*
         GCode Process for building 3d DVP UV objects

         * <Build Start>
         * <Slicing Comments> comments containing the slicing and building parameters
         * <Header Code> start.gcode - commands from this
         * file are inserted, they contain whatever intiailization sequences are need to initialize the machine
         * at this point, the build tray is in position to start printing a layer
         * <Layer Start>
         * Display the correct image slice for the current layer
         * Delay for <Layertime> to expose the UV resin
         * <Layer End>

        */
        // here we prepare the gcode preprocessor and fill all nessesary variables
        protected static PreProcessor PreparePreprocessor(SliceFile sf, MachineConfig pi)
        {
            PreProcessor pp = new PreProcessor();
            pp.SetVar("$LayerThickness", sf.m_config.ZThick);
            pp.SetVar("$ZLiftDist", sf.m_config.liftdistance);
            pp.SetVar("$ZLiftRate", sf.m_config.liftfeedrate);
            pp.SetVar("$ZRetractRate", sf.m_config.liftretractrate);
            pp.SetVar("$SlideTiltVal", sf.m_config.slidetiltval);
            pp.SetVar("$BlankTime", sf.m_config.blanktime_ms);
            pp.SetVar("$LayerTime", sf.m_config.layertime_ms);
            pp.SetVar("$FirstLayerTime", sf.m_config.firstlayertime_ms);
            return pp;
        }
 //, Object3d obj)
 // this function takes the object, the slicing parameters,
 // and the output directory. it generates the object slices
 // and saves them in the directory
 public SliceFile Slice(SliceBuildConfig sp)
 {
     //m_obj = obj;
         m_cancel = false;
         // create new slice file
         m_sf = new SliceFile(sp);
         if (sp.export == false)
         {
             m_sf.m_mode = SliceFile.SFMode.eImmediate;
         }
         m_slicethread = new Thread(new ThreadStart(slicefunc));
         m_slicethread.Start();
         isslicing = true;
         return m_sf;
 }
        public override string Export(Stream stream, string filename)
        {
            m_stream = stream;
            if ((m_name == null) || (m_name.Length == 0))
                m_name = Path.GetFileNameWithoutExtension(filename);
            if ((m_description == null) || (m_description.Length == 0))
                m_description = m_name;
            try
            {
                ReportStart();
                SliceBuildConfig config = UVDLPApp.Instance().m_buildparms;
                config.UpdateFrom(UVDLPApp.Instance().m_printerinfo); // make sure we've got the correct display size and PixPerMM values

                // write header
                WriteString("1");   // version
                WriteString(m_name);  // scene name
                WriteString(m_description);  // scene description
                WriteDouble(1 / config.dpmmX); // pixel size in mm
                WriteDouble(config.ZThick);    // slice thickness
                WriteInt32(0);      // base standoff layers (?)
                WriteInt32(0);      // Number of base offset layers where extents are filled (?)
                WriteString("Reserved3");
                WriteString("Reserved2");
                WriteString("Reserved1");

                // write slices
                int numslices = UVDLPApp.Instance().m_slicer.GetNumberOfSlices(config);
                WriteInt32(numslices);

                float zlev = (float)(config.ZThick * 0.5);
                int npix = config.xres * config.yres;
                int[] lbm = new int[npix];  // current slice
                int p;

                //Bitmap bm = new Bitmap(config.xres, config.yres, System.Drawing.Imaging.PixelFormat.Format32bppArgb); // working bitmap
                //Color savecol = UVDLPApp.Instance().m_appconfig.m_foregroundcolor;

                if (UVDLPApp.Instance().m_slicer.SliceFile == null)
                {
                    SliceFile sf = new SliceFile(config);
                    sf.m_mode = SliceFile.SFMode.eImmediate;
                    UVDLPApp.Instance().m_slicer.SliceFile = sf; // wasn't set
                }

                for (int c = 0; c < numslices; c++)
                {
                    //bool layerneedssupport = false;
                    if (CancelExport)
                    {
                        return "Info|Export operation canceled";
                    }
                    ReportProgress(c * 100 / numslices);

                    /*Slice sl = UVDLPApp.Instance().m_slicer.GetSliceImmediate(zlev);
                    zlev += (float)config.ZThick;

                    if ((sl == null) || (sl.m_segments == null) || (sl.m_segments.Count == 0))
                        continue;
                    sl.Optimize();// find loops
                    using (Graphics gfx = Graphics.FromImage(bm))
                        gfx.Clear(Color.Transparent);

                    //render current slice
                    UVDLPApp.Instance().m_appconfig.m_foregroundcolor = Color.White;
                    sl.RenderSlice(config, ref bm);*/

                    Bitmap bm = UVDLPApp.Instance().m_slicer.SliceImmediate(zlev);
                    zlev += (float)config.ZThick;
                    BitmapData data = bm.LockBits(new Rectangle(0, 0, bm.Width, bm.Height),
                            ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
                    Marshal.Copy(data.Scan0, lbm, 0, lbm.Length);
                    for (p = 0; p < npix; p++)
                        lbm[p] &= 0xFFFFFF;
                    bm.UnlockBits(data);
                    CrushSlice(lbm, config.xres, config.yres);
                }

                // write supports (currently not handled)
                WriteInt32(0); // zero supports
            }
            catch (Exception ex)
            {
                DebugLogger.Instance().LogError(ex);
                return "Error|Export terminated unexpectedly";
            }

            return "Export|Export completed successfully";
        }
        // This function is called to start the print job
        public void StartPrint(SliceFile sf, GCodeFile gcode)
        {
            if (m_printing)  // already printing
                return;

            m_printing = true;
            m_buildstarttime = new DateTime();
            m_buildstarttime = DateTime.Now;
            estimatedbuildtime = EstimateBuildTime(gcode);
            StartBuildTimer();

            m_sf = sf; // set the slicefile for rendering
            m_gcode = gcode; // set the file
            m_state = STATE_START; // set the state machine as started
            m_runthread = new Thread(new ThreadStart(BuildThread));
            m_running = true;
            m_runthread.Start();
        }
        // This function is called to start the print job
        public void StartPrint(SliceFile sf, GCodeFile gcode, bool snippet = false)
        {
            m_runningsnippet = snippet;

            if (m_printing)  // already printing
                return;
            //make sure to reset these
            m_pause_request = false;
            //m_cancel_request = false;

            m_printing = true;
            m_buildstarttime = new DateTime();
            m_buildstarttime = DateTime.Now;
            estimatedbuildtime = EstimateBuildTime(gcode);
            StartBuildTimer();

            m_sf = sf; // set the slicefile for rendering
            m_gcode = gcode; // set the file
            m_state = STATE_START; // set the state machine as started
            m_runthread = new Thread(new ThreadStart(BuildThread));
            m_running = true;
            m_runthread.Start();
        }
 private void SliceEv(Slicer.eSliceEvent ev, int layer, int totallayers,SliceFile sf)
 {
     try
     {
         if (InvokeRequired)
         {
             BeginInvoke(new MethodInvoker(delegate() { SliceEv(ev, layer, totallayers,sf); }));
         }
         else
         {
             switch (ev)
             {
                 case Slicer.eSliceEvent.eSliceStarted:
                     SetMainMessage("Slicing Started");
                     break;
                 case Slicer.eSliceEvent.eLayerSliced:
                     break;
                 case Slicer.eSliceEvent.eSliceCompleted:
                     //show the gcode
                     txtGCode.Text = UVDLPApp.Instance().m_gcode.RawGCode;
                     SetVScrollMax(totallayers);
                     SetMainMessage("Slicing Completed");
                     String timeest = BuildManager.EstimateBuildTime(UVDLPApp.Instance().m_gcode);
                     SetTimeMessage("Estimated Build Time: " + timeest);
                     //show the slice in the slice view
                     ViewLayer(0, null, BuildManager.SLICE_NORMAL);
                     break;
             }
         }
     }
     catch (Exception ex)
     {
         DebugLogger.Instance().LogError(ex.Message);
     }
 }
        /// <summary>
        /// Loads a model, adds it to the 3d engine to be shown, and raises an app event
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        public bool LoadModel(String filename) 
        {
            try
            {
                ModelLoader ml = new ModelLoader();
                List<Object3d> objs = ml.Load(filename);
                if (objs != null)
                {
                    foreach (Object3d obj in objs)
                    {
                        obj.CenterOnPlatform();
                        m_engine3d.AddObject(obj);
                        m_undoer.SaveAddition(obj);
                        SelectedObject = obj;
                    }
                    UVDLPApp.Instance().m_engine3d.UpdateLists();
                    m_slicefile = null; // the slice file is not longer current
                    RaiseAppEvent(eAppEvent.eModelAdded, "Model Loaded " + filename);
                }
                else 
                {
                    RaiseAppEvent(eAppEvent.eModelNotLoaded, "Model " + filename + " Failed to load");
                }

                return (objs != null);
            }
            catch (Exception ex) 
            {
                DebugLogger.Instance().LogRecord(ex.Message);
                return false;
            }
        }
        /// <summary>
        /// Loads a model, adds it to the 3d engine to be shown, and raises an app event
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        public bool LoadModel(String filename)
        {
            try
            {
                ModelLoader ml = new ModelLoader();
                List<Object3d> objs = ml.Load(filename);
                if (objs != null)
                {
                    foreach (Object3d obj in objs)
                    {
                        obj.CenterOnPlatform();
                        m_engine3d.AddObject(obj);
                        m_undoer.SaveAddition(obj);
                        SelectedObject = obj;
                        //test code to create a preview, this should definitely go somewhere else
                        /*PreviewGenerator pg = new PreviewGenerator();
                        Bitmap preview = pg.GeneratePreview(512, 512, obj);
                        if(preview !=null)
                            preview.Save(UVDLPApp.Instance().m_apppath + "\\testpreview.png");*/

                    }
                    UVDLPApp.Instance().m_engine3d.UpdateLists();
                    m_slicefile = null; // the slice file is not longer current
                    RaiseAppEvent(eAppEvent.eModelAdded, "Model Loaded " + filename);
                }
                else
                {
                    RaiseAppEvent(eAppEvent.eModelNotLoaded, "Model " + filename + " Failed to load");
                }

                return (objs != null);
            }
            catch (Exception ex)
            {
                DebugLogger.Instance().LogRecord(ex.Message);
                return false;
            }
        }
 /// <summary>
 /// This is called after the scene file is loaded
 /// It will also load the gcode file and slicing profile / vector slices
 /// </summary>
 public void PostLoadScene() 
 {
     m_gcode = SceneFile.Instance().LoadGCodeFromScene(SceneFileName);
     if (m_gcode == null) 
     {
         m_gcode = new GCodeFile(""); // create empty file
     }
     RaiseAppEvent(eAppEvent.eGCodeLoaded, "GCode Loaded ");
     SceneFile.Instance().LoadSliceProfileFromScene(SceneFileName);
     m_slicefile = new SliceFile(m_buildparms);
     m_slicefile.m_mode = SliceFile.SFMode.eLoaded;
     m_slicer.SliceFile = m_slicefile;
     //set the number of slices
     m_slicefile.NumSlices = m_slicer.GetNumberOfSlices(m_buildparms);
     RaiseAppEvent(eAppEvent.eSliceProfileChanged, "Slice Profile loaded");
     RaiseAppEvent(eAppEvent.eSlicedLoaded, "Slice Profile loaded");
 }