/// <summary> /// Create OpenGL object specifying the referenced scene objects directly. /// </summary> /// <param name="block"></param> /// <param name="scene"></param> /// <param name="glbuff"></param> /// <param name="glimg"></param> public GLTexture(Compiler.Block block, Dict scene, GLBuffer glbuff, GLImage glimg) : base(block.Name, block.Anno) { var err = new CompileException($"texture '{Name}'"); // PARSE ARGUMENTS Cmds2Fields(block, err); // set name glBuff = glbuff; glImg = glimg; // GET REFERENCES if (Buff != null) { scene.TryGetValue(Buff, out glBuff, block, err); } if (Img != null) { scene.TryGetValue(Img, out glImg, block, err); } if (glBuff != null && glImg != null) { err.Add("Only an image or a buffer can be bound to a texture object.", block); } if (glBuff == null && glImg == null) { err.Add("Ether an image or a buffer has to be bound to a texture object.", block); } // IF THERE ARE ERRORS THROW AND EXCEPTION if (err.HasErrors) { throw err; } // INCASE THIS IS A TEXTURE OBJECT Link(block.Filename, block.LineInFile, err); if (HasErrorOrGlError(err, block)) { throw err; } }
private GLShader Attach(Compiler.Block block, string shadername, Dict classes, CompileException err) { GLShader obj = null; // get shader from class list if (shadername != null && classes.TryGetValue(shadername, out obj, block, err)) { GL.UseProgramStages(glname, ShaderType2ShaderBit(obj.ShaderType), obj.glname); } return(obj); }
/// <summary> /// Parse commands in block. /// </summary> /// <param name="list"></param> /// <param name="block"></param> /// <param name="scene"></param> /// <param name="err"></param> private void ParsePasses(ref List <GLPass> list, Compiler.Block block, Dict scene, CompileException err) { var cmdName = ReferenceEquals(list, init) ? "init" : ReferenceEquals(list, passes) ? "pass" : "uninit"; foreach (var cmd in block[cmdName]) { if (scene.TryGetValue(cmd[0].Text, out GLPass pass, block, err | $"command '{cmd.Text}'")) { list.Add(pass); } } }
private void ParseCsharpExec(Compiler.Command cmd, Dict classes, CompileException err) { // check if command provides the correct amount of parameters if (cmd.ArgCount == 0) { err.Add("Not enough arguments for exec command.", cmd); return; } // get instance if (!classes.TryGetValue(cmd[0].Text, out GLInstance instance, cmd, err)) { return; } csexec.Add(instance); }
/// <summary> /// Get text from scene objects. /// </summary> /// <param name="scene"></param> /// <param name="cmd"></param> /// <returns></returns> private static string GetText(Dict scene, Compiler.Command cmd) { GLText text = null; string dir = Path.GetDirectoryName(cmd.File) + Path.DirectorySeparatorChar; if (scene.TryGetValue(cmd[0].Text, ref text)) { return(text.Text.Trim()); } else if (File.Exists(cmd[0].Text)) { return(File.ReadAllText(cmd[0].Text)); } else if (File.Exists(dir + cmd[0].Text)) { return(File.ReadAllText(dir + cmd[0].Text)); } return(null); }
public static bool TryGetValue <T>(this Dict dict, string key, out T obj, Compiler.Block block, CompileException err) where T : GLObject { return(dict.TryGetValue(key, out obj, block.LineInFile, block.Filename, err)); }
public static bool TryGetValue <T>(this Dict dict, string key, out T obj, Compiler.Command cmd, CompileException err) where T : GLObject { return(dict.TryGetValue(key, out obj, cmd.LineInFile, cmd.File, err)); }
/// <summary> /// Create OpenGL object. Standard object constructor for ProtoFX. /// </summary> /// <param name="block"></param> /// <param name="scene"></param> /// <param name="genDebugInfo"></param> public GLPass(Compiler.Block block, Dict scene, bool genDebugInfo) : base(block.Name, block.Anno, 309, genDebugInfo) { var err = new CompileException($"pass '{Name}'"); GenDebugInfo = genDebugInfo; /// PARSE COMMANDS AND CONVERT THEM TO CLASS FIELDS Cmds2Fields(block, err); /// PARSE COMMANDS foreach (var cmd in block) { // ignore class fields var field = GetType().GetField(cmd.Name, Instance | Public | NonPublic); var attr = field?.GetCustomAttributes(typeof(FxField), false); if (attr?.Length > 0) { continue; } using (var e = err | $"command '{cmd.Name}' line {cmd.LineInFile}") { switch (cmd.Name) { case "draw": ParseDrawCall(cmd, scene, e); break; case "compute": ParseComputeCall(cmd, scene, e); break; case "tex": ParseTexCmd(cmd, scene, e); break; case "img": ParseImgCmd(cmd, scene, e); break; case "samp": ParseSampCmd(cmd, scene, e); break; case "exec": ParseCsharpExec(cmd, scene, e); break; case "vertout": vertoutput = new Vertoutput(cmd, scene, e); break; case "fragout": scene.TryGetValue(cmd[0].Text, out fragoutput, cmd, e); break; default: ParseOpenGLCall(cmd, e); break; } } } if (err.HasErrors) { throw err; } /// CREATE OPENGL OBJECT if (Vert != null || Comp != null) { GL.CreateProgramPipelines(1, out glname); // Attach shader objects. // First try attaching a compute shader. If that // fails, try attaching the default shader pipeline. if ((glcomp = Attach(block, Comp, scene, err)) == null) { glvert = Attach(block, Vert, scene, err); gltess = Attach(block, Tess, scene, err); gleval = Attach(block, Eval, scene, err); glgeom = Attach(block, Geom, scene, err); glfrag = Attach(block, Frag, scene, err); } // get debug shaders if (GenDebugInfo) { if (glcomp != null) { dbgcomp = (CompShader)glcomp.DebugShader; } else { Shader prev = dbgvert = (VertShader)glvert.DebugShader; dbgtess = (TessShader)gltess?.DebugShader; dbgeval = (EvalShader)gleval?.DebugShader; dbggeom = (GeomShader)glgeom?.DebugShader; dbgfrag = (FragShader)glfrag?.DebugShader; if (dbgtess != null) { dbgtess.Prev = prev; prev = dbgtess; } if (dbgeval != null) { dbgeval.Prev = prev; prev = dbgeval; } if (dbggeom != null) { dbggeom.Prev = prev; prev = dbggeom; } } } } /// CHECK FOR ERRORS if (GL.GetError() != ErrorCode.NoError) { err.Add($"OpenGL error '{GL.GetError()}' occurred " + "during shader program creation.", block); } if (err.HasErrors) { throw err; } }
private void ParseDrawCall(Compiler.Command cmd, Dict classes, CompileException err) { var args = new List <int>(); GLVertinput vertexin = null; GLVertoutput vertout = null; GLBuffer indexbuf = null; GLBuffer indirect = null; bool modeIsSet = false; bool typeIsSet = false; PrimType primitive = 0; ElementType indextype = 0; // parse draw call arguments foreach (var arg in cmd) { if (classes.TryGetValue(arg.Text, ref vertexin)) { continue; } if (classes.TryGetValue(arg.Text, ref vertout)) { continue; } if (classes.TryGetValue(arg.Text, ref indexbuf)) { continue; } if (classes.TryGetValue(arg.Text, ref indirect)) { continue; } if (int.TryParse(arg.Text, out int val)) { args.Add(val); } else if (typeIsSet == false && Enum.TryParse(arg.Text, true, out indextype)) { typeIsSet = true; } else if (modeIsSet == false && Enum.TryParse(arg.Text, true, out primitive)) { modeIsSet = true; } else { err.Add($"Unable to process argument '{arg.Text}'.", cmd); } } if (err.HasErrors) { return; } // a draw call must specify a primitive type if (modeIsSet == false) { err.Add("Draw call must specify a primitive type (e.g. triangles, " + "trianglefan, lines, points, ...).", cmd); return; } // determine the right draw call function int bits = (vertout != null ? 1 : 0) | (indexbuf != null ? 2 : 0) | (indirect != null ? 4 : 0) | (typeIsSet ? 8 : 0); if (!Enum.IsDefined(typeof(DrawFunc), bits)) { err.Add("Draw call function not recognized or ambiguous.", cmd); return; } var drawfunc = (DrawFunc)bits; // get index buffer object (if present) and find existing MultiDraw class var multidrawcall = drawcalls.Find( x => x.vertexin == (vertexin != null ? vertexin.glname : 0) && x.indexbuf == (indexbuf != null ? indexbuf.glname : 0) && x.vertout == (vertout != null ? vertout.glname : 0) && x.indirect == (indirect != null ? indirect.glname : 0)) ?? new MultiDrawCall(drawfunc, vertexin, vertout, indexbuf, indirect); // add new draw command to the MultiDraw class multidrawcall.cmd.Add(new DrawCall(drawfunc, primitive, indextype, args)); drawcalls.Add(multidrawcall); }
/// <summary> /// Parse command line and attach the buffer object /// to the specified unit (input stream). /// </summary> /// <param name="unit"></param> /// <param name="cmd"></param> /// <param name="scene"></param> /// <param name="err"></param> private void Attach(int unit, Compiler.Command cmd, Dict scene, CompileException err) { // check commands for errors if (cmd.ArgCount < 3) { err.Add("Command attr needs at least 3 attributes (e.g. 'attr buff_name float 4')", cmd); return; } // parse command arguments string buffname = cmd[0].Text; string typename = cmd[1].Text; int length = int.Parse(cmd[2].Text); int stride = cmd.ArgCount > 3 ? int.Parse(cmd[3].Text) : 0; int offset = cmd.ArgCount > 4 ? int.Parse(cmd[4].Text) : 0; int divisor = cmd.ArgCount > 5 ? int.Parse(cmd[5].Text) : 0; if (scene.TryGetValue(buffname, out GLBuffer buff, cmd, err) == false) { err.Add($"Buffer '{buffname}' could not be found.", cmd); return; } // enable vertex array attribute GL.BindBuffer(BufferTarget.ArrayBuffer, buff.glname); GL.EnableVertexAttribArray(unit); // bind buffer to vertex array attribute int type = 0; if (Enum.TryParse(typename, true, out VertAttrIntType typei)) { GL.VertexAttribIPointer(unit, length, (IntType)(type = (int)typei), stride, (IntPtr)offset); } else if (Enum.TryParse(typename, true, out VertAttrType typef)) { GL.VertexAttribPointer(unit, length, (PointerType)(type = (int)typef), false, stride, offset); } else { err.Add($"Type '{typename}' is not supported.", cmd); } if (divisor > 0) { GL.VertexAttribDivisor(unit, divisor); } GL.BindBuffer(BufferTarget.ArrayBuffer, 0); // add vertex attribute attributes.Add(new VertAttr() { buffer = buff, type = type, length = length, stride = stride, offset = offset, divisor = divisor, }); }