/// <summary> /// /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <returns></returns> public static VertexArrayObject CreatePlane(float x, float y, float z, uint dx, uint dy) { VertexArrayObject vertexArray = new VertexArrayObject(); // Vertex generation Vertex3f[] position = new Vertex3f[(dx + 1) * (dy + 1)]; float x2 = x / 2.0f, y2 = y / 2.0f; float vdx = x / dx, vdy = y / dy; int vidx = 0; for (float vy = -y2; vy <= y2; vy += vdy) { for (float vx = -x2; vx <= x2; vx += vdx) { Debug.Assert(vidx < position.Length); position[vidx++] = new Vertex3f(vx, vy, z); } } // Elements generation List <uint> indices = new List <uint>(); uint vstride = dx + 1; for (uint i = 0; i < dy; i++) { uint yoffset = i * vstride; // Triangle strip start indices.Add(yoffset + vstride); for (uint ix = 0; ix < dx; ix++) { uint xoffset = yoffset + ix; indices.Add(xoffset); indices.Add(xoffset + vstride + 1); } indices.Add(yoffset + vstride - 1); if (Gl.CurrentExtensions.PrimitiveRestart == false) { throw new NotImplementedException(); } else { indices.Add(uint.MaxValue); } } // Buffer definition ArrayBufferObject <Vertex3f> positionBuffer = new ArrayBufferObject <Vertex3f>(BufferObjectHint.StaticCpuDraw); positionBuffer.Create(position); vertexArray.SetArray(positionBuffer, VertexArraySemantic.Position); ElementBufferObject <uint> elementBuffer = new ElementBufferObject <uint>(BufferObjectHint.StaticCpuDraw); elementBuffer.Create(indices.ToArray()); elementBuffer.RestartIndexEnabled = Gl.CurrentExtensions.PrimitiveRestart; vertexArray.SetElementArray(PrimitiveType.TriangleStrip, elementBuffer); return(vertexArray); }
/// <summary> /// Create a <see cref="VertexArrayObject"/> for rendering glyphs. /// </summary> /// <param name="fontFamily"></param> /// <param name="emSize"></param> /// <param name="glyphs"></param> /// <returns></returns> private static VertexArrayObject CreateVertexArray(GraphicsContext ctx, FontFamily fontFamily, uint emSize, FontStyle fontStyle, out Dictionary <char, Glyph> glyphs) { CheckCurrentContext(ctx); string resourceBaseId = String.Format("OpenGL.Objects.FontPatch.{0}-{1}-{2}", fontFamily, emSize, fontStyle); string vertexArrayId = resourceBaseId + ".VertexArray"; string glyphDbId = resourceBaseId + ".GlyphDb"; VertexArrayObject vertexArrays = (VertexArrayObject)ctx.GetSharedResource(vertexArrayId); Dictionary <char, Glyph> glyphsDb = (Dictionary <char, Glyph>)ctx.GetSharedResource(glyphDbId); if (vertexArrays != null && glyphsDb != null) { glyphs = glyphsDb; return(vertexArrays); } vertexArrays = new VertexArrayObject(); glyphsDb = new Dictionary <char, Glyph>(); List <GlyphPolygons> glyphPolygons = GenerateGlyphs(fontFamily, emSize, fontStyle); List <Vertex2f> glyphsVertices = new List <Vertex2f>(); GlyphPolygons gGlyph = null; uint gVertexIndex = 0; glyphs = new Dictionary <char, Glyph>(); using (Tessellator tessellator = new Tessellator()) { tessellator.Begin += delegate(object sender, TessellatorBeginEventArgs e) { gVertexIndex = (uint)glyphsVertices.Count; }; tessellator.End += delegate(object sender, EventArgs e) { // Create element (range) int glyphIndex = vertexArrays.SetElementArray(PrimitiveType.Triangles, gVertexIndex, (uint)glyphsVertices.Count - gVertexIndex); glyphsDb.Add(gGlyph.GlyphChar, new Glyph(gGlyph.GlyphChar, gGlyph.GlyphSize, glyphIndex)); }; tessellator.Vertex += delegate(object sender, TessellatorVertexEventArgs e) { glyphsVertices.Add((Vertex2f)e.Vertex); }; // Tessellate all glyphs foreach (GlyphPolygons glyph in glyphPolygons) { gGlyph = glyph; if (glyph.Contours.Count == 0) { glyphsDb.Add(gGlyph.GlyphChar, new Glyph(gGlyph.GlyphChar, gGlyph.GlyphSize, -1)); continue; } tessellator.BeginPolygon(); foreach (List <Vertex2f> countour in glyph.Contours) { tessellator.AddContour(countour.ToArray(), Vertex3f.UnitZ); } tessellator.EndPolygon(); } } // Element vertices ArrayBufferObject <Vertex2f> gVertexPosition = new ArrayBufferObject <Vertex2f>(BufferObjectHint.StaticCpuDraw); gVertexPosition.Create(glyphsVertices.ToArray()); vertexArrays.SetArray(gVertexPosition, VertexArraySemantic.Position); // Returns glyphs database glyphs = glyphsDb; // Share resources ctx.SetSharedResource(vertexArrayId, vertexArrays); ctx.SetSharedResource(glyphDbId, glyphsDb); return(vertexArrays); }
/// <summary> /// Generate tangents for this Element. /// </summary> /// <param name="vertexArray"> /// The <see cref="VertexArrayObject"/> /// </param> public override void GenerateTangents(VertexArrayObject vertexArray) { IVertexArray positionArray = vertexArray.GetVertexArray(VertexArraySemantic.Position); if (positionArray == null) { throw new InvalidOperationException("position semantic not set"); } IVertexArray texArray = vertexArray.GetVertexArray(VertexArraySemantic.TexCoord); if (texArray == null) { throw new InvalidOperationException("texture semantic not set"); } IVertexArray normalArray = vertexArray.GetVertexArray(VertexArraySemantic.Normal); if (normalArray == null) { throw new InvalidOperationException("normal semantic not set"); } if (normalArray.Array == null) { throw new InvalidOperationException("normal array not set"); } IVertexArray tanArray = vertexArray.GetVertexArray(VertexArraySemantic.Tangent); if (tanArray == null) { throw new InvalidOperationException("tangent semantic not set"); } if (tanArray.Array == null) { throw new InvalidOperationException("tangent array not set"); } IVertexArray bitanArray = vertexArray.GetVertexArray(VertexArraySemantic.Bitangent); if (bitanArray == null) { throw new InvalidOperationException("bitangent semantic not set"); } if (bitanArray.Array == null) { throw new InvalidOperationException("bitangent array not set"); } if (positionArray.Array != null) { positionArray.Array.Map(); } if (texArray.Array != null) { texArray.Array.Map(); } normalArray.Array.Map(); tanArray.Array.Map(); bitanArray.Array.Map(); ArrayIndices.Map(); try { switch (ElementsMode) { case PrimitiveType.TriangleStrip: switch (positionArray.ArraySection.ItemType) { case ArrayBufferItemType.Float3: GenerateTangentsTriangleStrip3f(positionArray, normalArray, texArray, tanArray, bitanArray); break; default: throw new NotSupportedException("normals generation not supported for elements of type " + positionArray.ArraySection.ItemType); } break; default: throw new NotSupportedException("normals generation not supported for primitive " + ElementsMode); } } finally { if (positionArray.Array != null) { positionArray.Array.Unmap(); } if (texArray.Array != null) { texArray.Array.Unmap(); } normalArray.Array.Unmap(); tanArray.Array.Unmap(); bitanArray.Array.Unmap(); ArrayIndices.Unmap(); } }
/// <summary> /// Create a <see cref="VertexArrayObject"/> for rendering glyphs. /// </summary> /// <param name="fontFamily"></param> /// <param name="emSize"></param> /// <param name="glyphs"></param> /// <returns></returns> private void LinkSharedResources(GraphicsContext ctx) { CheckCurrentContext(ctx); // Font-wide resources string resourceClassId = "OpenGL.Objects.FontTextureArray2d"; string instanceArrayId = resourceClassId + ".InstanceArray"; string vertexArrayId = resourceClassId + ".VertexArray"; _GlyphInstances = (ArrayBufferObjectInterleaved <GlyphInstance>)ctx.GetSharedResource(instanceArrayId); _VertexArrays = (VertexArrayObject)ctx.GetSharedResource(vertexArrayId); if (_GlyphInstances == null) { _GlyphInstances = new ArrayBufferObjectInterleaved <GlyphInstance>(BufferObjectHint.DynamicCpuDraw); _GlyphInstances.Create(256); // Share ctx.SetSharedResource(instanceArrayId, _GlyphInstances); } LinkResource(_GlyphInstances); if (_VertexArrays == null) { _VertexArrays = new VertexArrayObject(); ArrayBufferObject <Vertex2f> arrayPosition = new ArrayBufferObject <Vertex2f>(BufferObjectHint.StaticCpuDraw); arrayPosition.Create(new Vertex2f[] { new Vertex2f(0.0f, 1.0f), new Vertex2f(0.0f, 0.0f), new Vertex2f(1.0f, 1.0f), new Vertex2f(1.0f, 0.0f), }); _VertexArrays.SetArray(arrayPosition, VertexArraySemantic.Position); _VertexArrays.SetInstancedArray(_GlyphInstances, 0, 1, "glo_GlyphModelViewProjection"); _VertexArrays.SetInstancedArray(_GlyphInstances, 1, 1, "glo_GlyphVertexParams"); _VertexArrays.SetInstancedArray(_GlyphInstances, 2, 1, "glo_GlyphTexParams"); _VertexArrays.SetElementArray(PrimitiveType.TriangleStrip); // Share ctx.SetSharedResource(vertexArrayId, _VertexArrays); } LinkResource(_VertexArrays); // Font resources string resourceBaseId = String.Format("{0}.{1}-{2}-{3}", resourceClassId, Family, Size, Style); string glyphDbId = resourceBaseId + ".GlyphDb"; string textureId = resourceBaseId + ".Texture"; _GlyphDb = (Dictionary <char, Glyph>)ctx.GetSharedResource(glyphDbId); _FontTexture = (TextureArray2d)ctx.GetSharedResource(textureId); StringFormat stringFormat = StringFormat.GenericTypographic; if (_GlyphDb == null) { _GlyphDb = new Dictionary <char, Glyph>(); char[] fontChars = GetFontCharacters().ToCharArray(); uint layer = 0; using (Bitmap bitmap = new Bitmap(1, 1)) using (Graphics g = Graphics.FromImage(bitmap)) using (System.Drawing.Font font = new System.Drawing.Font(Family, Size, Style)) { // Avoid grid fitting g.TextRenderingHint = TextRenderingHint.AntiAlias; float glyphHeight = font.GetHeight(); foreach (char c in fontChars) { SizeF glyphSize; switch (c) { case ' ': glyphSize = g.MeasureString(c.ToString(), font, 0, StringFormat.GenericDefault); break; default: glyphSize = g.MeasureString(c.ToString(), font, 0, stringFormat); break; } Glyph glyph = new Glyph(c, glyphSize, layer++, new SizeF(1.0f, 1.0f)); _GlyphDb.Add(c, glyph); } } // Share ctx.SetSharedResource(glyphDbId, _GlyphDb); } if (_FontTexture == null) { // Get the size required for all glyphs float w = 0.0f, h = 0.0f; uint z = 0; foreach (Glyph glyph in _GlyphDb.Values) { w = Math.Max(w, glyph.GlyphSize.Width); h = Math.Max(h, glyph.GlyphSize.Height); z = Math.Max(z, glyph.Layer); } // Create texture _FontTexture = new TextureArray2d((uint)Math.Ceiling(w), (uint)Math.Ceiling(h), z + 1, PixelLayout.R8); _FontTexture.Create(ctx); using (System.Drawing.Font font = new System.Drawing.Font(Family, Size, Style)) using (Brush brush = new SolidBrush(Color.White)) { foreach (Glyph glyph in _GlyphDb.Values) { using (Bitmap bitmap = new Bitmap((int)_FontTexture.Width, (int)_FontTexture.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb)) using (Graphics g = Graphics.FromImage(bitmap)) { // Recompute texture scaling glyph.TexScale = new SizeF( glyph.GlyphSize.Width / bitmap.Width, glyph.GlyphSize.Height / bitmap.Height ); // Avoid grid fitting g.TextRenderingHint = TextRenderingHint.AntiAlias; g.Clear(Color.Black); g.DrawString(glyph.GlyphChar.ToString(), font, brush, 0.0f, 0.0f, stringFormat); _FontTexture.Create(ctx, PixelLayout.R8, bitmap, glyph.Layer); } } } // Share ctx.SetSharedResource(textureId, _FontTexture); } LinkResource(_FontTexture); }
/// <summary> /// Specify which elements shall be drawn by indexing them, specifying an offset and the number of element indices. /// </summary> /// <param name="mode"> /// A <see cref="PrimitiveType"/> that indicates how array elements are interpreted. /// </param> /// <param name="indices"> /// A <see cref="ElementBufferObject"/> containing the indices of the drawn vertices. /// </param> /// <exception cref="ArgumentNullException"> /// Exception thrown if <paramref name="indices"/> is null. /// </exception> /// <remarks> /// The element indices count is implictly defined by <paramref name="indices"/> at <see cref="Draw(GraphicsContext)"/> /// execution time. /// </remarks> public IndexedElement(VertexArrayObject vao, PrimitiveType mode, ElementBufferObject indices) : this(vao, mode, indices, 0, 0) { }
/// <summary> /// Specify which elements shall be drawn. /// </summary> /// <param name="mode"> /// A <see cref="PrimitiveType"/> that indicates how array elements are interpreted. /// </param> /// <remarks> /// The array elements count is implictly defined as the vertex array length at <see cref="Draw(GraphicsContext)"/> /// execution time. /// </remarks> public ArrayElement(VertexArrayObject vao, PrimitiveType mode) : this(vao, mode, 0, 0) { }
/// <summary> /// Specify which elements shall be drawn, specifying an offset and the number of elements. /// </summary> /// <param name="vao"> /// The <see cref="VertexArrayObject"/> to which this element belongs to. /// </param> /// <param name="mode"> /// A <see cref="PrimitiveType"/> that indicates how array elements are interpreted. /// </param> /// <param name="offset"> /// A <see cref="UInt32"/> that specify the offset applied to the drawn array elements. /// </param> /// <param name="count"> /// A <see cref="UInt32"/> that specify the number of array elements drawn. /// </param> public ArrayElement(VertexArrayObject vao, PrimitiveType mode, uint offset, uint count) : base(vao, mode) { ElementOffset = offset; ElementCount = count; }
/// <summary> /// Generate bitangents for this Element. /// </summary> /// <param name="vertexArray"> /// The <see cref="VertexArrayObject"/> /// </param> public virtual void GenerateBitangents(VertexArrayObject vertexArray) { throw new NotImplementedException(); }
/// <summary> /// Generate texture coordinates for this Element. /// </summary> /// <param name="vertexArray"> /// The <see cref="VertexArrayObject"/> /// </param> public virtual void GenerateTexCoord(VertexArrayObject vertexArray, VertexArrayTexGenDelegate genTexCoordCallback) { throw new NotImplementedException(); }