예제 #1
0
        /// <summary>
        /// Cargar shader
        /// </summary>
        public static List <QShaderData> GetFxFromText(string code, string mediaPath)
        {
            List <QShaderData> shaders   = new List <QShaderData>();
            QShaderTokenizer   tokenizer = new QShaderTokenizer(code);

            // Parse a shader
            while (!tokenizer.EOF)
            {
                var shader = ParseShader(tokenizer);
                if (shader != null)
                {
                    if (shader.Stages != null)
                    {
                        // Crea un shader de directx En base a los del formato quake
                        shader.ShaderSrc = QShaderBuilderDX.BuildShaderSource(shader);
                        //shader.BuildFx();
                        foreach (QShaderStage qStage in shader.Stages)
                        {
                            qStage.LoadTextures(mediaPath);
                        }
                    }
                }
                shaders.Add(shader);
            }
            return(shaders);
        }
예제 #2
0
 private static QWaveForm ParseWaveform(QShaderTokenizer tokenizer)
 {
     return(new QWaveForm()
     {
         Name = tokenizer.GetNext().ToLower(),
         Bas = ParserTools.ToFloat(tokenizer.GetNext()),
         Amp = ParserTools.ToFloat(tokenizer.GetNext()),
         Phase = ParserTools.ToFloat(tokenizer.GetNext()),
         Freq = ParserTools.ToFloat(tokenizer.GetNext())
     });
 }
예제 #3
0
        private static QShaderStage ParseStage(QShaderTokenizer tokenizer)
        {
            QShaderStage stage = new QShaderStage();

            // Parse a Stage
            while (!tokenizer.EOF)
            {
                string token = tokenizer.GetNext();
                if (token.Equals("}"))
                {
                    break;
                }

                switch (token.ToLower())
                {
                case "clampmap":
                    stage.Clamp = true;
                    goto case "map";

                case "map":
                    stage.Map = tokenizer.GetNext();     //.replace()/(\.jpg|\.tga)/, '.png');
                    break;

                case "animmap":
                    stage.Map      = "anim";
                    stage.AnimFreq = ParserTools.ToFloat(tokenizer.GetNext());
                    var   nextMap = tokenizer.GetNext();
                    Match match   = Regex.Match(nextMap, @"(\.jpg|\.tga)");
                    while (match.Success)
                    {
                        stage.AnimMaps.Add(nextMap);
                        nextMap = tokenizer.GetNext();
                        match   = Regex.Match(nextMap, @"(\.jpg|\.tga)");
                    }
                    tokenizer.MovePrev();
                    break;

                case "rgbgen":
                    stage.RgbGen = tokenizer.GetNext().ToLower();
                    switch (stage.RgbGen)
                    {
                    case "wave":
                        stage.RgbWaveform = ParseWaveform(tokenizer);
                        if (stage.RgbWaveform == null)
                        {
                            stage.RgbGen = "identity";
                        }
                        break;
                    }
                    ;
                    break;

                case "alphagen":
                    stage.AlphaGen = tokenizer.GetNext().ToLower();
                    switch (stage.AlphaGen)
                    {
                    case "wave":
                        stage.AlphaWaveform = ParseWaveform(tokenizer);
                        if (stage.AlphaWaveform == null)
                        {
                            stage.AlphaGen = "1.0";
                        }
                        break;

                    default:
                        break;
                    }
                    break;

                case "alphafunc":
                    stage.AlphaFunc = tokenizer.GetNext().ToUpper();
                    break;

                case "blendfunc":
                    stage.BlendSrc     = tokenizer.GetNext();
                    stage.HasBlendFunc = true;
                    if (stage.DepthWriteOverride)
                    {
                        stage.DepthWrite = false;
                    }
                    switch (stage.BlendSrc)
                    {
                    case "add":
                        stage.BlendSrc  = "GL_ONE";
                        stage.BlendDest = "GL_ONE";
                        break;

                    case "blend":
                        stage.BlendSrc  = "GL_SRC_ALPHA";
                        stage.BlendDest = "GL_ONE_MINUS_SRC_ALPHA";
                        break;

                    case "filter":
                        stage.BlendSrc  = "GL_DST_COLOR";
                        stage.BlendDest = "GL_ZERO";
                        break;

                    default:
                        stage.BlendDest = tokenizer.GetNext();
                        break;
                    }
                    break;

                case "depthfunc":
                    stage.DepthFunc = tokenizer.GetNext().ToLower();
                    break;

                case "depthwrite":
                    stage.DepthWrite         = true;
                    stage.DepthWriteOverride = true;
                    break;

                case "tcmod":
                    var tcMod = new QTcMod()
                    {
                        Type = tokenizer.GetNext().ToLower()
                    };

                    switch (tcMod.Type)
                    {
                    case "rotate":
                        tcMod.Angle = Geometry.DegreeToRadian(ParserTools.ToFloat(tokenizer.GetNext()));
                        break;

                    case "scale":
                        tcMod.ScaleX = ParserTools.ToFloat(tokenizer.GetNext());
                        tcMod.ScaleY = ParserTools.ToFloat(tokenizer.GetNext());
                        break;

                    case "scroll":
                        tcMod.SSpeed = ParserTools.ToFloat(tokenizer.GetNext());
                        tcMod.TSpeed = ParserTools.ToFloat(tokenizer.GetNext());
                        break;

                    case "stretch":
                        tcMod.WaveForm = ParseWaveform(tokenizer);
                        if (tcMod.WaveForm == null)
                        {
                            tcMod.Type = "";
                        }
                        break;

                    case "turb":
                        tcMod.Turbulance = new QWaveForm()
                        {
                            Name = char.IsLetter(tokenizer.GetToken()[0])
                                                                      ? tokenizer.GetNext() : "",
                            Bas   = ParserTools.ToFloat(tokenizer.GetNext()),
                            Amp   = ParserTools.ToFloat(tokenizer.GetNext()),
                            Phase = ParserTools.ToFloat(tokenizer.GetNext()),
                            Freq  = ParserTools.ToFloat(tokenizer.GetNext())
                        };
                        break;

                    default:
                        tcMod.Type = "";
                        break;
                    }
                    if (!tcMod.Type.Equals(""))
                    {
                        stage.TcMods.Add(tcMod);
                    }
                    break;

                case "tcgen":
                    stage.TcGen = tokenizer.GetNext();
                    break;

                default:
                    break;
                }
            }

            if (stage.BlendSrc.Equals("GL_ONE") && stage.BlendDest.Equals("GL_ZERO"))
            {
                stage.HasBlendFunc = false;
                stage.DepthWrite   = true;
            }

            return(stage);
        }
예제 #4
0
        /// <summary>
        /// Parsear shader
        /// </summary>
        private static QShaderData ParseShader(QShaderTokenizer tokenizer)
        {
            QShaderData qsd = new QShaderData();

            qsd.Name = tokenizer.GetNext();

            string token = tokenizer.GetNext();

            if (!token.Equals("{"))
            {
                return(null);
            }

            // Parse a shader
            while (!tokenizer.EOF)
            {
                token = tokenizer.GetNext().ToLower();

                if (token.Equals("}"))
                {
                    break;
                }

                switch (token)
                {
                case "{":
                    QShaderStage stage = ParseStage(tokenizer);

                    // I really really really don't like doing this, which basically just forces lightmaps to use the 'filter' blendmode
                    // but if I don't a lot of textures end up looking too bright. I'm sure I'm jsut missing something, and this shouldn't
                    // be needed.
                    if (stage.IsLightMap() && (stage.HasBlendFunc))
                    {
                        stage.BlendSrc  = "GL_DST_COLOR";
                        stage.BlendDest = "GL_ZERO";
                    }

                    // I'm having a ton of trouble getting lightingSpecular to work properly,
                    // so this little hack gets it looking right till I can figure out the problem
                    if (stage.AlphaGen.Equals("lightingspecular"))
                    {
                        stage.BlendSrc     = "GL_ONE";
                        stage.BlendDest    = "GL_ZERO";
                        stage.HasBlendFunc = false;
                        stage.DepthWrite   = true;
                    }

                    if (stage.HasBlendFunc)
                    {
                        qsd.Blend = true;
                    }
                    else
                    {
                        qsd.Opaque = true;
                    }

                    qsd.Stages.Add(stage);
                    break;

                case "cull":
                    qsd.Cull = tokenizer.GetNext();
                    break;

                case "deformvertexes":
                    QShaderDeform deform = new QShaderDeform()
                    {
                        Type = tokenizer.GetNext().ToLower()
                    };

                    switch (deform.Type)
                    {
                    case "wave":
                        deform.Spread   = 1.0f / ParserTools.ToFloat(tokenizer.GetNext());
                        deform.WaveForm = ParseWaveform(tokenizer);
                        break;

                    case "bulge":
                        deform.BulgeWidth  = ParserTools.ToFloat(tokenizer.GetNext());
                        deform.BulgeHeight = ParserTools.ToFloat(tokenizer.GetNext());
                        deform.BulgeSpeed  = ParserTools.ToFloat(tokenizer.GetNext());
                        break;

                    default: deform = null; break;
                    }

                    if (deform != null)
                    {
                        qsd.VertexDeforms.Add(deform);
                    }
                    break;

                case "sort":
                    var sort = tokenizer.GetNext().ToLower();
                    switch (sort)
                    {
                    case "portal": qsd.Sort = 1; break;

                    case "sky": qsd.Sort = 2; break;

                    case "opaque": qsd.Sort = 3; break;

                    case "banner": qsd.Sort = 6; break;

                    case "underwater": qsd.Sort = 8; break;

                    case "additive": qsd.Sort = 9; break;

                    case "nearest": qsd.Sort = 16; break;

                    default: qsd.Sort = int.Parse(sort); break;
                    }
                    ;
                    break;

                case "surfaceparm":
                    var param = tokenizer.GetNext().ToLower();

                    switch (param)
                    {
                    case "sky":
                        qsd.Sky = true;
                        break;

                    default: break;
                    }
                    break;

                default: break;
                }
            }

            if (qsd.Sort > 0)
            {
                qsd.Sort = (qsd.Opaque ? 3 : 9);
            }

            return(qsd);
        }
예제 #5
0
        private static QShaderStage ParseStage(QShaderTokenizer tokenizer)
        {
            QShaderStage stage = new QShaderStage();
            // Parse a Stage
            while (!tokenizer.EOF)
            {
                string token = tokenizer.GetNext();
                if (token.Equals("}"))
                {
                    break;
                }

                switch (token.ToLower())
                {
                    case "clampmap":
                        stage.Clamp = true;
                        goto case "map";

                    case "map":
                        stage.Map = tokenizer.GetNext(); //.replace()/(\.jpg|\.tga)/, '.png');
                        break;

                    case "animmap":
                        stage.Map = "anim";
                        stage.AnimFreq = ParserTools.ToFloat(tokenizer.GetNext());
                        var nextMap = tokenizer.GetNext();
                        Match match = Regex.Match(nextMap, @"(\.jpg|\.tga)");
                        while (match.Success)
                        {
                            stage.AnimMaps.Add(nextMap);
                            nextMap = tokenizer.GetNext();
                            match = Regex.Match(nextMap, @"(\.jpg|\.tga)");
                        }
                        tokenizer.MovePrev();
                        break;

                    case "rgbgen":
                        stage.RgbGen = tokenizer.GetNext().ToLower();
                        switch (stage.RgbGen)
                        {
                            case "wave":
                                stage.RgbWaveform = ParseWaveform(tokenizer);
                                if (stage.RgbWaveform == null)
                                {
                                    stage.RgbGen = "identity";
                                }
                                break;
                        }
                        ;
                        break;

                    case "alphagen":
                        stage.AlphaGen = tokenizer.GetNext().ToLower();
                        switch (stage.AlphaGen)
                        {
                            case "wave":
                                stage.AlphaWaveform = ParseWaveform(tokenizer);
                                if (stage.AlphaWaveform == null)
                                {
                                    stage.AlphaGen = "1.0";
                                }
                                break;
                            default:
                                break;
                        }
                        break;

                    case "alphafunc":
                        stage.AlphaFunc = tokenizer.GetNext().ToUpper();
                        break;

                    case "blendfunc":
                        stage.BlendSrc = tokenizer.GetNext();
                        stage.HasBlendFunc = true;
                        if (stage.DepthWriteOverride)
                        {
                            stage.DepthWrite = false;
                        }
                        switch (stage.BlendSrc)
                        {
                            case "add":
                                stage.BlendSrc = "GL_ONE";
                                stage.BlendDest = "GL_ONE";
                                break;

                            case "blend":
                                stage.BlendSrc = "GL_SRC_ALPHA";
                                stage.BlendDest = "GL_ONE_MINUS_SRC_ALPHA";
                                break;

                            case "filter":
                                stage.BlendSrc = "GL_DST_COLOR";
                                stage.BlendDest = "GL_ZERO";
                                break;

                            default:
                                stage.BlendDest = tokenizer.GetNext();
                                break;
                        }
                        break;

                    case "depthfunc":
                        stage.DepthFunc = tokenizer.GetNext().ToLower();
                        break;

                    case "depthwrite":
                        stage.DepthWrite = true;
                        stage.DepthWriteOverride = true;
                        break;

                    case "tcmod":
                        var tcMod = new QTcMod()
                                        {
                                            Type = tokenizer.GetNext().ToLower()
                                        };

                        switch (tcMod.Type)
                        {
                            case "rotate":
                                tcMod.Angle = Geometry.DegreeToRadian(ParserTools.ToFloat(tokenizer.GetNext()));
                                break;

                            case "scale":
                                tcMod.ScaleX = ParserTools.ToFloat(tokenizer.GetNext());
                                tcMod.ScaleY = ParserTools.ToFloat(tokenizer.GetNext());
                                break;

                            case "scroll":
                                tcMod.SSpeed = ParserTools.ToFloat(tokenizer.GetNext());
                                tcMod.TSpeed = ParserTools.ToFloat(tokenizer.GetNext());
                                break;

                            case "stretch":
                                tcMod.WaveForm = ParseWaveform(tokenizer);
                                if (tcMod.WaveForm == null)
                                {
                                    tcMod.Type = "";
                                }
                                break;

                            case "turb":
                                tcMod.Turbulance = new QWaveForm()
                                                       {
                                                           Name = char.IsLetter(tokenizer.GetToken()[0])
                                                                      ? tokenizer.GetNext() : "",
                                                           Bas = ParserTools.ToFloat(tokenizer.GetNext()),
                                                           Amp = ParserTools.ToFloat(tokenizer.GetNext()),
                                                           Phase = ParserTools.ToFloat(tokenizer.GetNext()),
                                                           Freq = ParserTools.ToFloat(tokenizer.GetNext())
                                                       };
                                break;

                            default:
                                tcMod.Type = "";
                                break;
                        }
                        if (!tcMod.Type.Equals(""))
                        {
                            stage.TcMods.Add(tcMod);
                        }
                        break;

                    case "tcgen":
                        stage.TcGen = tokenizer.GetNext();
                        break;

                    default:
                        break;
                }
            }

            if (stage.BlendSrc.Equals("GL_ONE") && stage.BlendDest.Equals("GL_ZERO"))
            {
                stage.HasBlendFunc = false;
                stage.DepthWrite = true;
            }

            return stage;
        }
예제 #6
0
        /// <summary>
        /// Parsear shader
        /// </summary>
        private static QShaderData ParseShader(QShaderTokenizer tokenizer)
        {
            QShaderData qsd = new QShaderData();

            qsd.Name = tokenizer.GetNext();

            string token = tokenizer.GetNext();

            if (!token.Equals("{"))
            {
                return null;
            }

            // Parse a shader
	        while(!tokenizer.EOF) {
		        token = tokenizer.GetNext().ToLower();

		        if(token.Equals("}")) { break; }
        		
		        switch (token) {
			        case "{":
				        QShaderStage stage = ParseStage(tokenizer);
        				
				        // I really really really don't like doing this, which basically just forces lightmaps to use the 'filter' blendmode
				        // but if I don't a lot of textures end up looking too bright. I'm sure I'm jsut missing something, and this shouldn't
				        // be needed.
				        if(stage.IsLightMap() && (stage.HasBlendFunc))
                        {
					        stage.BlendSrc = "GL_DST_COLOR";
					        stage.BlendDest = "GL_ZERO";
				        }
        				
				        // I'm having a ton of trouble getting lightingSpecular to work properly, 
				        // so this little hack gets it looking right till I can figure out the problem
				        if(stage.AlphaGen.Equals("lightingspecular"))
                        {
					        stage.BlendSrc = "GL_ONE";
					        stage.BlendDest = "GL_ZERO";
					        stage.HasBlendFunc = false;
					        stage.DepthWrite = true;
				        }
        				
				        if(stage.HasBlendFunc)
				        {
				            qsd.Blend = true;
				        }
                        else
				        {
				            qsd.Opaque = true;
				        }
        				
				        qsd.Stages.Add(stage);
			            break;
        			
			        case "cull":
		                qsd.Cull = tokenizer.GetNext();
				        break;
        				
			        case "deformvertexes":
		                QShaderDeform deform = new QShaderDeform() {Type = tokenizer.GetNext().ToLower()};
        				
				        switch(deform.Type) {
					        case "wave":
						        deform.Spread = 1.0f / ParserTools.ToFloat(tokenizer.GetNext());
						        deform.WaveForm = ParseWaveform(tokenizer);
						        break;
								 case "bulge":
                     deform.BulgeWidth = ParserTools.ToFloat(tokenizer.GetNext());
                     deform.BulgeHeight = ParserTools.ToFloat(tokenizer.GetNext());
                     deform.BulgeSpeed = ParserTools.ToFloat(tokenizer.GetNext());
                     break;
					        default: deform = null; break;
				        }
        				
				        if(deform != null) { qsd.VertexDeforms.Add(deform); }
				        break;
        				
			        case "sort":
				        var sort = tokenizer.GetNext().ToLower();
				        switch(sort) {
					        case "portal": qsd.Sort = 1; break;
					        case "sky": qsd.Sort = 2; break;
					        case "opaque": qsd.Sort = 3; break;
					        case "banner": qsd.Sort = 6; break;
					        case "underwater": qsd.Sort = 8; break;
					        case "additive": qsd.Sort = 9; break;
					        case "nearest": qsd.Sort = 16; break;
					        default: qsd.Sort = int.Parse(sort); break; 
				        };
				        break;
        				
			        case "surfaceparm":
				        var param = tokenizer.GetNext().ToLower();
        				
				        switch(param) {
					        case "sky":
						        qsd.Sky = true;
						        break;
					        default: break;
				        }
				        break;
        				
			        default: break;
		        }
	        }

            if (qsd.Sort > 0)
            {
                qsd.Sort = (qsd.Opaque ? 3 : 9);
            }

            return qsd;
	
        }
예제 #7
0
        /// <summary>
        /// Cargar shader
        /// </summary>
        public static List<QShaderData> GetFxFromText(string code, string mediaPath)
        {
            List<QShaderData> shaders = new List<QShaderData>();
            QShaderTokenizer tokenizer = new QShaderTokenizer(code);

            // Parse a shader
            while (!tokenizer.EOF)
            {
                var shader = ParseShader(tokenizer);
                if (shader != null)
                {
                    if (shader.Stages != null)
                    {
                        // Crea un shader de directx En base a los del formato quake
                        shader.ShaderSrc = QShaderBuilderDX.BuildShaderSource(shader);
                        //shader.BuildFx();
                        foreach (QShaderStage qStage in shader.Stages)
                        {
                            qStage.LoadTextures(mediaPath);
                        }
                        
                    }
                }
                shaders.Add(shader);

            }
            return shaders;
        }
예제 #8
0
 private static QWaveForm ParseWaveform(QShaderTokenizer tokenizer)
 {
     return new QWaveForm()
                {
                    Name = tokenizer.GetNext().ToLower(),
                    Bas = ParserTools.ToFloat(tokenizer.GetNext()),
                    Amp = ParserTools.ToFloat(tokenizer.GetNext()),
                    Phase = ParserTools.ToFloat(tokenizer.GetNext()),
                    Freq = ParserTools.ToFloat(tokenizer.GetNext())
                };
 }
예제 #9
0
        /// <summary>
        /// Utilidad para detectar los recursos necesarios de mapa (texturas, shaders, etc)
        /// y empaquetarlos en una carpeta destino.
        /// Es útil para depurar todos los archivos no utilizados y crear una copia limpia
        /// del mapa.
        /// </summary>
        /// <param name="bspMap">Mapa ya cargado</param>
        /// <param name="mediaPath">Carpeta root de todas las texturas, shaders y modelos de Quake 3</param>
        /// <param name="targetFolder">Carpeta destino</param>
        public void packLevel(BspMap bspMap, string mediaPath, string targetFolder)
        {
            GuiController.Instance.Logger.log("Empaquetando: nivel: " + bspMap.Data.filePath);
            //copia el archivo bsp en la carpeta maps
            string mapa = bspMap.Data.filePath.Substring(bspMap.Data.filePath.LastIndexOf("\\") + 1);
            fileCopy(bspMap.Data.filePath, targetFolder + "\\maps\\" + mapa);


            //salva todas las texturas y los shaders
            textures = new TgcTexture[bspMap.Data.shaders.Length];
            shaderXTextura = new QShaderData[bspMap.Data.shaders.Length];
            textureFullPath = new string[bspMap.Data.shaders.Length];

            for (int i = 0; i < bspMap.Data.shaders.Length; i++)
            {
                // Find the extension if any and append it to the file name
                string file = FindTextureExtension(bspMap.Data.shaders[i].shader, mediaPath);

                // Create a texture from the image
                if (file.Length > 0)
                {
                    string shader_text = bspMap.Data.shaders[i].shader.TrimEnd(new char[] { '\0' }).Replace('/', '\\');
                    string ext = file.Substring(file.LastIndexOf("."));
                    string newTex = targetFolder + "\\" + shader_text + ext;
                    fileCopy(file, newTex);
                }
                //Si no tiene textura entonces tiene un shader
                else
                {
                    string shader_text = bspMap.Data.shaders[i].shader.TrimEnd(new char[] { '\0' });

                    if (!shader_text.Contains("/") && !bspMap.Data.shaders[i].shader.Contains("\\"))
                        continue;

                    string scriptDir = mediaPath + @"scripts\";
                    string fileScript = shader_text.Split(new char[] { '\\', '/' })[1] + ".shader";
                    string pathScript = scriptDir + fileScript;
                    if (File.Exists(pathScript))
                    {
                        string newShader = targetFolder + @"\scripts\" + fileScript;
                        fileCopy(pathScript, newShader);

                        //Reviso si el shader hace llamada a alguna textura y la guardo
                        QShaderTokenizer tokenizer = new QShaderTokenizer(File.ReadAllText(pathScript));
                        while (!tokenizer.EOF)
                        {
                            string token = tokenizer.GetNext();
                            if (token.Contains(".tga") || token.Contains(".jpg"))
                            {
                                token = token.Replace('/', '\\');
                                string src = mediaPath + "\\" + token;
                                //hay una textura que debe ser salvada
                                if (File.Exists(src))
                                {
                                    fileCopy(src, targetFolder + "\\" + token);
                                }
                            }
                        }
                    }
                }
            }

            GuiController.Instance.Logger.log("Empaquetando Exitoso");
        }
예제 #10
0
        /// <summary>
        /// Utilidad para detectar los recursos necesarios de mapa (texturas, shaders, etc)
        /// y empaquetarlos en una carpeta destino.
        /// Es útil para depurar todos los archivos no utilizados y crear una copia limpia
        /// del mapa.
        /// </summary>
        /// <param name="bspMap">Mapa ya cargado</param>
        /// <param name="mediaPath">Carpeta root de todas las texturas, shaders y modelos de Quake 3</param>
        /// <param name="targetFolder">Carpeta destino</param>
        public void packLevel(BspMap bspMap, string mediaPath, string targetFolder)
        {
            GuiController.Instance.Logger.log("Empaquetando: nivel: " + bspMap.Data.filePath);
            //copia el archivo bsp en la carpeta maps
            string mapa = bspMap.Data.filePath.Substring(bspMap.Data.filePath.LastIndexOf("\\") + 1);

            fileCopy(bspMap.Data.filePath, targetFolder + "\\maps\\" + mapa);


            //salva todas las texturas y los shaders
            textures        = new TgcTexture[bspMap.Data.shaders.Length];
            shaderXTextura  = new QShaderData[bspMap.Data.shaders.Length];
            textureFullPath = new string[bspMap.Data.shaders.Length];

            for (int i = 0; i < bspMap.Data.shaders.Length; i++)
            {
                // Find the extension if any and append it to the file name
                string file = FindTextureExtension(bspMap.Data.shaders[i].shader, mediaPath);

                // Create a texture from the image
                if (file.Length > 0)
                {
                    string shader_text = bspMap.Data.shaders[i].shader.TrimEnd(new char[] { '\0' }).Replace('/', '\\');
                    string ext         = file.Substring(file.LastIndexOf("."));
                    string newTex      = targetFolder + "\\" + shader_text + ext;
                    fileCopy(file, newTex);
                }
                //Si no tiene textura entonces tiene un shader
                else
                {
                    string shader_text = bspMap.Data.shaders[i].shader.TrimEnd(new char[] { '\0' });

                    if (!shader_text.Contains("/") && !bspMap.Data.shaders[i].shader.Contains("\\"))
                    {
                        continue;
                    }

                    string scriptDir  = mediaPath + @"scripts\";
                    string fileScript = shader_text.Split(new char[] { '\\', '/' })[1] + ".shader";
                    string pathScript = scriptDir + fileScript;
                    if (File.Exists(pathScript))
                    {
                        string newShader = targetFolder + @"\scripts\" + fileScript;
                        fileCopy(pathScript, newShader);

                        //Reviso si el shader hace llamada a alguna textura y la guardo
                        QShaderTokenizer tokenizer = new QShaderTokenizer(File.ReadAllText(pathScript));
                        while (!tokenizer.EOF)
                        {
                            string token = tokenizer.GetNext();
                            if (token.Contains(".tga") || token.Contains(".jpg"))
                            {
                                token = token.Replace('/', '\\');
                                string src = mediaPath + "\\" + token;
                                //hay una textura que debe ser salvada
                                if (File.Exists(src))
                                {
                                    fileCopy(src, targetFolder + "\\" + token);
                                }
                            }
                        }
                    }
                }
            }

            GuiController.Instance.Logger.log("Empaquetando Exitoso");
        }