From: jpbruyere Date: Fri, 22 Apr 2016 10:19:40 +0000 (+0200) Subject: copy old glbackend files, no changes made for now, not working X-Git-Url: https://git.osiis.dedyn.io/?a=commitdiff_plain;h=68056c452876b77bb443e89f49b6dd52ca50cfbb;p=jp%2Fcrow.git copy old glbackend files, no changes made for now, not working --- diff --git a/OTKCrow/OTKCrow.csproj b/OTKCrow/OTKCrow.csproj index f4e1604a..6baba708 100644 --- a/OTKCrow/OTKCrow.csproj +++ b/OTKCrow/OTKCrow.csproj @@ -21,6 +21,7 @@ prompt 4 false + true full @@ -29,8 +30,10 @@ prompt 4 false + true + @@ -45,6 +48,9 @@ ..\..\Chess\build\Debug\GGL.dll + + ..\packages\SharpFont.3.1.0\lib\net20\SharpFont.dll + @@ -52,6 +58,22 @@ + + + + + + + + + + + + + + + + @@ -62,5 +84,9 @@ + + + + \ No newline at end of file diff --git a/OTKCrow/OpenGL/GLBackend/ClipShader.cs b/OTKCrow/OpenGL/GLBackend/ClipShader.cs new file mode 100644 index 00000000..8c98cad7 --- /dev/null +++ b/OTKCrow/OpenGL/GLBackend/ClipShader.cs @@ -0,0 +1,41 @@ +using System; +using OpenTK.Graphics.OpenGL; +using Crow; + +namespace Crow.GLBackend +{ + public class ClipShader : Shader + { + public ClipShader () + { + vertSource = @" + #version 130 + + precision highp float; + + uniform mat4 projection_matrix; + uniform mat4 modelview_matrix; + + in vec2 in_position; + + void main(void) + { + gl_Position = projection_matrix * modelview_matrix * vec4(in_position,0, 1); + }"; + + fragSource = @" + #version 130 + precision highp float; + + out vec4 out_frag_color; + + void main(void) + { + out_frag_color = vec4(1.0,1.0,1.0,1.0); + }"; + + Compile (); + } + } +} + diff --git a/OTKCrow/OpenGL/GLBackend/Context.cs b/OTKCrow/OpenGL/GLBackend/Context.cs new file mode 100644 index 00000000..0ff1efa7 --- /dev/null +++ b/OTKCrow/OpenGL/GLBackend/Context.cs @@ -0,0 +1,887 @@ +#define MPERF +//#define GPU_TIME_MSR + +using System; +using OpenTK.Graphics.OpenGL; +using OpenTK; +using System.Collections.Generic; +using System.Linq; +using System.Diagnostics; +using System.Drawing.Imaging; + + + +namespace Crow.GLBackend +{ + public class Context : IDisposable + { + #region CTOR + public Context (Surface _surf) + { + surf = _surf; + + saveGLConfig (); + + createStencilTexture (); + + fboId = createFbo (surf.texId); + + projectionMatrix = Matrix4.CreateOrthographicOffCenter + (0, surf.width, surf.height, 0, 0, 1); + modelviewMatrix = Matrix4.Identity; + + if (shader == null) + shader = new Shader (); + if (texturedShader == null) + texturedShader = new TexturedShader (); + if (clipShader == null) + clipShader = new ClipShader (); + if (fontShader == null) + fontShader = new FontShader (); + + + GL.Viewport (0, 0, surf.width, surf.height); + GL.PrimitiveRestartIndex (int.MaxValue); + GL.Enable (EnableCap.PrimitiveRestart); + GL.Enable (EnableCap.Blend); + GL.BlendFunc (BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha); + + //GL.BindFramebuffer(FramebufferTarget.Framebuffer, fboId); + + // GL.ClearColor(0.0f, 0.0f, 0.0f, 0.0f); + // GL.Clear(ClearBufferMask.ColorBufferBit); + } + #endregion + + #if (DEBUG && MPERF) + Stopwatch sw_fill = new Stopwatch (); + Stopwatch sw_stroke = new Stopwatch (); + #endif + + #if GPU_TIME_MSR + ulong gpuTime = 0; + ulong gpuTimeCpt = 0; + #endif + + public float coef1 = 1.0f; + public float coef2 = 0.5f; + public float coef3 = 0.0f; + public float coefA = 1.0f; + + static Shader shader; + static Shader clipShader; + static Shader texturedShader; + static FontShader fontShader; + + static List fontsCache = new List(); + + #region Private Fields + Surface surf; + Surface sourceSurface;//should be a pattern object from which surf would be derrived + + double lineWidth = 1.0; + Color color = Color.White; + LineCap lineCap = LineCap.Butt; + LineJoin lineJoint = LineJoin.Miter; + + FontFace fontFace; + uint fontSize = 10; + //path building temp fields + Vector2 curPos = new Vector2(0f,0f); + List pathes = new List (); + Path cpath;//current path + + int fboId; + int stencilTexId; + VertexArrayObject vao; + + Matrix4 projectionMatrix, + modelviewMatrix; + + bool stencilTest = false; + + VertexArrayObject paint_vao; //quad used to paint source on context + + //path limits used in fill + float minX,maxX,minY,maxY, + polyWidth, polyHeight; + + #endregion + + #region Public properties + public double LineWidth { + get { return lineWidth; } + set { lineWidth = value; } + } + public Color Color { + get { return color; } + set { color = value; } + } + public LineCap LineCap { + get { return lineCap;} + set {lineCap = value;} + } + public LineJoin LineJoint { + get {return lineJoint;} + set {lineJoint = value;} + } + #endregion + + #region Private functions + int createFbo(int texID) + { + //GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0); + int fbo; + GL.GenFramebuffers(1,out fbo); + GL.BindFramebuffer(FramebufferTarget.Framebuffer, fbo); + GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, + FramebufferAttachment.ColorAttachment0, + TextureTarget.Texture2D,texID,0); + + //GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0); + FramebufferErrorCode fbErr = GL.CheckFramebufferStatus (FramebufferTarget.Framebuffer); + + switch (fbErr) { + case FramebufferErrorCode.FramebufferUndefined: + break; + case FramebufferErrorCode.FramebufferComplete: + //Debug.WriteLine ("FBO complete"); + break; + case FramebufferErrorCode.FramebufferIncompleteAttachment: + Debug.WriteLine ("FBO incomplete attachment"); + break; + case FramebufferErrorCode.FramebufferIncompleteMissingAttachment: + Debug.WriteLine ("FBO missing attachment"); + break; + default: + Debug.WriteLine ("FBO error"); + break; + } + return fbo; + } + public int copyCurentSurfaceToTexture() + { + //create a new fbo to blit to with an empty texture + Surface tmp = surf.CreateSimilar (); + int dstFbo = createFbo (tmp.texId);//we are binded to new fbo (read&write) + //bind read to Context fbo; + GL.BindFramebuffer (FramebufferTarget.ReadFramebuffer, fboId); + GL.BindFramebuffer (FramebufferTarget.DrawFramebuffer, dstFbo); + + GL.BlitFramebuffer (0, 0, surf.width, surf.height, 0, 0, surf.width, surf.height, + ClearBufferMask.ColorBufferBit,BlitFramebufferFilter.Nearest); + + //bind write fbo to Context + GL.BindFramebuffer (FramebufferTarget.Framebuffer, fboId); + //delete temp fbo + GL.DeleteFramebuffer (dstFbo); + return tmp.texId; + } + void createStencilTexture(){ + stencilTexId = GL.GenTexture(); + GL.BindTexture(TextureTarget.Texture2D, stencilTexId); + GL.TexImage2D(TextureTarget.Texture2D,0, + PixelInternalFormat.R8, surf.width, surf.height,0, + OpenTK.Graphics.OpenGL.PixelFormat.Red, PixelType.UnsignedByte,IntPtr.Zero); + + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); + GL.BindTexture(TextureTarget.Texture2D, 0); + } + void clear_path() + { + pathes.Clear (); + curPos = new Vector2 (0f, 0f); + cpath = null; + } + void addPath(Path _path){ + if (_path == null) + return; + if (_path.Count > 1) + pathes.Add (_path); + } + //TODO: 360° will fail + double NormalizeAngle(double a) + { + double res = a % (2*Math.PI); + return res < 0 ? res + 2*Math.PI : res; + } + #endregion + + #region Public functions + #region Main drawing functions + public void Stroke() + { + stroke_internal (); + clear_path (); + } + public void StrokePreserve() + { + stroke_internal (); + } + public void Fill() + { + fill_internal (); + clear_path (); + } + public void FillPreserve() + { + fill_internal (); + } + public void Paint() + { + if (paint_vao == null) + return; + texturedShader.Enable (); + //shader.LineWidth = lineWidth; + texturedShader.ProjectionMatrix = projectionMatrix; + texturedShader.ModelViewMatrix = modelviewMatrix; + texturedShader.Color = new Vector4(1f,1f,1f,1f); + + GL.ActiveTexture (TextureUnit.Texture0); + GL.BindTexture (TextureTarget.Texture2D, sourceSurface.texId); + + paint_vao.Render (PrimitiveType.TriangleStrip); + + GL.BindTexture (TextureTarget.Texture2D, 0); + + texturedShader.Disable (); + } + public void SetSourceSurface (Surface _source, int x, int y) + { + sourceSurface = _source; + + if (paint_vao != null) + paint_vao.Dispose (); + + + paint_vao = new QuadVAO (x,y,sourceSurface.width,sourceSurface.height); + } + #region Clipping + public void Clip() + { + clip_internal (); + clear_path (); + } + public void ClipPreserve() + { + clip_internal (); + clear_path (); + } + public void ResetClip() + { + stencilTest = false; + + GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, + FramebufferAttachment.ColorAttachment0, + TextureTarget.Texture2D,stencilTexId,0); + + + GL.Clear (ClearBufferMask.ColorBufferBit); + + GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, + FramebufferAttachment.ColorAttachment0, + TextureTarget.Texture2D,surf.texId,0); + } + #endregion + + #region Fonts & text handling + public void SelectFontFace(string _fontName, FontSlant _slant, FontWeight _weight){ + Font tmp = _fontName; + switch (_slant) { + case FontSlant.Italic: + tmp.Style |= FontStyle.Italic; + break; + case FontSlant.Oblique: + tmp.Style |= FontStyle.Oblique; + break; + } + if (_weight == FontWeight.Bold) + tmp.Style |= FontStyle.Bold; + + fontFace = FontFace.SearchFont (tmp); + } + public void SetFontSize(uint _fontSize){ + fontSize = _fontSize; + if (!fontFace.glyphesCache.ContainsKey(fontSize)) + fontFace.buildGlyphesTextures (fontSize, 0, 0xFF); + } + public FontExtents FontExtents { + get { + return fontFace.originalFontExtents; + } + } + public TextExtents TextExtents(string s) + { + TextExtents te = new Crow.GLBackend.TextExtents (); + + int penX = 0, + penY = 0; + + for (int i = 0; i < s.Length; i++) { + uint c = (uint)s [i]; + glGlyph g = fontFace.glyphesCache [fontSize] [c]; + penX += (int)g.advanceX; + penY += (int)g.advanceY; + } + + te.XAdvance = penX; + te.YAdvance = penY; + return te; + } + public void FillText(string text, Point _pt) + { + buildTextVAO (text,_pt); + + int backTex = copyCurentSurfaceToTexture (); + + fontShader.Enable (); + //shader.LineWidth = lineWidth; + fontShader.ProjectionMatrix = projectionMatrix; + fontShader.ModelViewMatrix = modelviewMatrix; + fontShader.Color = new Vector4( + (float)color.R, + (float)color.G, + (float)color.B, + (float)color.A); + fontShader.Resolution = new Vector2 (surf.width, surf.height); + fontShader.coef1 = coef1; + fontShader.coef2 = coef2; + fontShader.coef3 = coef3; + fontShader.coefA = coefA; +// shader.StencilTest = stencilTest; +// +// if (stencilTest) { +// shader.Resolution = new Vector2 (surf.width, surf.height); +// GL.ActiveTexture (TextureUnit.Texture0); +// GL.BindTexture (TextureTarget.Texture2D, stencilTexId); +// } + + GL.ActiveTexture (TextureUnit.Texture0); + GL.BindTexture (TextureTarget.Texture2D, curFontTex); + GL.ActiveTexture (TextureUnit.Texture1); + GL.BindTexture (TextureTarget.Texture2D, backTex); + + vao.Render (PrimitiveType.TriangleStrip); + vao.Dispose (); + + // #if DEBUG + // ErrorCode err = GL.GetError (); + // if (err != ErrorCode.NoError) + // Debug.WriteLine ("Stroke_internal error: " + err.ToString ()); + // #endif + + fontShader.Disable (); + + GL.BindTexture (TextureTarget.Texture2D, 0); + GL.ActiveTexture (TextureUnit.Texture0); + GL.BindTexture (TextureTarget.Texture2D, 0); + + //destroy background texture + GL.DeleteTexture (backTex); + //GL.Enable (EnableCap.Blend); + } + #endregion + + #endregion + + + + #region Path handling functions + public void MoveTo(double x, double y) + { + addPath (cpath); + cpath = new Path (); + curPos = new Vector2 ((float)x, (float)y); + } + public void LineTo(double x, double y) + { + if (cpath==null) + cpath = new Path (); + if (cpath.Count == 0) + cpath.Add (curPos); + curPos = new Vector2 ((float)x, (float)y); + cpath.Add (curPos); + } + public void Rectangle(Rectangle r) + { + MoveTo (r.X, r.Y); + LineTo (r.Right, r.Y); + LineTo (r.Right, r.Bottom); + LineTo (r.X, r.Bottom); + ClosePath (); + } + public void Arc(double xc, double yc, double radius, double angle1, double angle2) + { + angle1 = NormalizeAngle (angle1); + angle2 = NormalizeAngle (angle2); + + if (angle1 > angle2) + angle2 += Math.PI * 2.0; + double a = angle1, + //step = Math.PI/16; + step =Math.PI * 2/(radius+20); + + Vector2 v = new Vector2 ((float)(Math.Cos (a) * radius + xc), (float)(Math.Sin (a) * radius + yc)); + if (v!=curPos) + cpath.Add (v); + int cpt = 0; + while(true){ + if (a angle2) + break; + //a = angle2; + }else + break; + cpt++; +// if (a == angle2) {//add a point very close to a to get good termination angle +// v = new Vector2 ((float)(Math.Cos (a-0.001) * radius + xc), (float)(Math.Sin (a-0.001) * radius + yc)); +// cpath.Add (v); +// } + + v = new Vector2 ((float)(Math.Cos (a) * radius + xc), (float)(Math.Sin (a) * radius + yc)); + cpath.Add (v); + + } + curPos = cpath [cpath.Count - 1]; + } + public void ClosePath() + { + if (cpath == null) + return; + if (cpath.Count < 3)//cannot close path with less than 3 points + return; + + cpath.IsClosed = true; + + MoveTo (cpath [0].X, cpath [0].Y); + } + #endregion + + #region Transformations + public void Translate(double tx, double ty) + { + modelviewMatrix *= Matrix4.CreateTranslation ((float)tx, (float)ty, 0f); + } + public void Scale(double sx, double sy) + { + modelviewMatrix *= Matrix4.CreateScale ((float)sx, (float)sy, 0f); + } + public void Rotate(double angle){ + modelviewMatrix *= Matrix4.CreateRotationZ ((float)angle); + } + #endregion + #endregion + + //temp Lists used to build arrays for vao + List vertices = new List (); + List indices = new List (); + List texCoords = new List (); + int idxOffset = 0; //offset in vertices array between pathes + + + void initVAOsCache() + { + if (vertices != null) + return; + vertices = new List (); + indices = new List (); + texCoords = new List (); + idxOffset = 0; + } + void flush(){ + vao = new VertexArrayObject ( + vertices.ToArray (), + texCoords.ToArray (), + indices.ToArray ()); + + vertices = null; + indices = null; + texCoords = null; + } + + void stroke_internal() + { + buildStrokeVAOs (); + + #if GPU_TIME_MSR + ulong gpuTimeStart, gpuTimeStop; + gpuTimeStart = (ulong)GL.GetInteger64 (GetPName.Timestamp); + #endif + + shader.Enable (); + //shader.LineWidth = lineWidth; + shader.ProjectionMatrix = projectionMatrix; + shader.ModelViewMatrix = modelviewMatrix; + shader.Color = new Vector4( + (float)color.R, + (float)color.G, + (float)color.B, + (float)color.A); + shader.StencilTest = stencilTest; + + if (stencilTest) { + shader.Resolution = new Vector2 (surf.width, surf.height); + GL.ActiveTexture (TextureUnit.Texture0); + GL.BindTexture (TextureTarget.Texture2D, stencilTexId); + } + + vao.Render (PrimitiveType.TriangleStrip); + vao.Dispose (); + +// #if DEBUG +// ErrorCode err = GL.GetError (); +// if (err != ErrorCode.NoError) +// Debug.WriteLine ("Stroke_internal error: " + err.ToString ()); +// #endif + + shader.Disable (); + + GL.BindTexture (TextureTarget.Texture2D, 0); + + #if GPU_TIME_MSR + gpuTimeStop = (ulong)GL.GetInteger64 (GetPName.Timestamp); + Debug.WriteLine(gpuTimeStop - gpuTimeStart); + #endif + } + void fill_internal() + { + buildFillVAOs (); + + shader.Enable (); + //shader.LineWidth = lineWidth; + shader.ProjectionMatrix = projectionMatrix; + shader.ModelViewMatrix = modelviewMatrix; + shader.Color = new Vector4( + (float)color.R, + (float)color.G, + (float)color.B, + (float)color.A); + shader.StencilTest = stencilTest; + + if (stencilTest) { + shader.Resolution = new Vector2 (surf.width, surf.height); + GL.ActiveTexture (TextureUnit.Texture0); + GL.BindTexture (TextureTarget.Texture2D, stencilTexId); + } + + vao.Render (PrimitiveType.Triangles); + vao.Dispose (); + + shader.Disable (); + + GL.BindTexture (TextureTarget.Texture2D, 0); + } + void clip_internal() + { + GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, + FramebufferAttachment.ColorAttachment0, + TextureTarget.Texture2D,stencilTexId,0); + + if (!stencilTest) + GL.Clear (ClearBufferMask.ColorBufferBit); + stencilTest = true; + + buildFillVAOs (); + + clipShader.Enable (); + //shader.LineWidth = lineWidth; + clipShader.ProjectionMatrix = projectionMatrix; + clipShader.ModelViewMatrix = modelviewMatrix; + + vao.Render (PrimitiveType.Triangles); + vao.Dispose (); + + clipShader.Disable (); + + GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, + FramebufferAttachment.ColorAttachment0, + TextureTarget.Texture2D,surf.texId,0); + } + + void buildFillVAOs() + { + #if (DEBUG && MPERF) + sw_fill.Start(); + #endif + + addPath (cpath); + + initVAOsCache (); + + float hlw = (float)lineWidth / 2.0f;//half line width + + Vector2 vDir,vDir2; + bool genTexCoords = false; + + for (int j = 0; j < pathes.Count; j++) { + Path path = new Path(pathes[j]); + //keep an array containing real vertex indice + List vertIdx = new List (Enumerable.Range(0,path.Count)); + + #region get polygon bounds for texture mapping + if (genTexCoords){ + minX = float.MaxValue; + maxX = float.MinValue; + minY = float.MaxValue; + maxY = float.MinValue; + + foreach (Vector2 p in path) { + if (p.X < minX) + minX = p.X; + if (p.Y < minY) + minY = p.Y; + if (p.X > maxX) + maxX = p.X; + if (p.Y > maxY) + maxY = p.Y; + } + polyWidth = maxX - minX; + polyHeight = maxY - minY; + } + #endregion + + vertices.AddRange (path);//we only play on indices + int ptrS = 0, ptrS1, ptrS2; //index du sommet dans le path + while (path.Count > 3) { + if (ptrS == path.Count) + ptrS = 0; + + if (ptrS < path.Count - 2) { + ptrS1 = ptrS + 1; + ptrS2 = ptrS + 2; + } else if (ptrS < path.Count - 1) { + ptrS1 = ptrS + 1; + ptrS2 = 0; + } else { + ptrS1 = 0; + ptrS2 = 1; + } + + //should test only concavity points if any + vDir = Vector2.NormalizeFast (path [ptrS1] - path [ptrS]); + vDir2 = Vector2.NormalizeFast (path [ptrS2] - path [ptrS]); + + float dotP = Vector2.Dot (vDir.PerpendicularLeft, vDir2); + //double angle = Math.Acos((double)dotP); +// +// Debug.WriteLine (dotP); +// Debug.WriteLine (angle); + + if (dotP <= 0) { + //triangle is invalid + ptrS++; + continue; + } + + //check if no other points of path is inside tri +// bool triangleIsValid = true; +// int i = ptrS + 3; +// if (i >= path.Count) +// i -= path.Count; +// while (i != ptrS) { +// if (PointInTriangle (path [i],path [ptrS] , path [ptrS1], path [ptrS2])) { +// ptrS++; +// triangleIsValid = false; +// break; +// } +// i++; +// if (i == path.Count) +// i = 0; +// } +// if (!triangleIsValid) +// continue; + //triangle is valid, add tri to primitive to draw + //and remove middle sommet from path[]; + addFillTriangle (j, vertIdx [ptrS], vertIdx [ptrS1], vertIdx [ptrS2]); + + path.RemoveAt (ptrS1); + vertIdx.RemoveAt (ptrS1); + } + if (path.Count == 3) + addFillTriangle (j, vertIdx [0], vertIdx [1], vertIdx [2]); + + if (j < pathes.Count - 1) { + idxOffset += pathes[j].Count; + } + } + flush (); + + #if (DEBUG && MPERF) + sw_fill.Stop(); + #endif + } + + int curFontTex; + void buildTextVAO(string text, Point pt) + { + initVAOsCache (); + + int penX = pt.X, + penY = pt.Y + (int)fontFace.originalFontExtents.Ascent; + + for (int i = 0; i < text.Length; i++) { + uint c = (uint)text [i]; + glGlyph g = fontFace.glyphesCache [fontSize] [c]; + curFontTex = g.texId; + vertices.Add (new Vector2(penX + g.bmpLeft, penY - g.bmpTop)); + vertices.Add (new Vector2(penX + g.bmpLeft, penY - g.bmpTop + g.dims.Height)); + vertices.Add (new Vector2(penX + g.bmpLeft + g.dims.Width, penY - g.bmpTop)); + vertices.Add (new Vector2(penX + g.bmpLeft + g.dims.Width, penY - g.bmpTop + g.dims.Height)); + indices.Add (int.MaxValue);//primitive restart + indices.Add (i*4); + indices.Add (i*4 + 1); + indices.Add (i*4 + 2); + indices.Add (i*4 + 3); + texCoords.Add (new Vector2(g.texX,g.texY)); + texCoords.Add (new Vector2(g.texX,g.texY + g.texHeight)); + texCoords.Add (new Vector2(g.texX + g.texWidth,g.texY)); + texCoords.Add (new Vector2(g.texX + g.texWidth,g.texY + g.texHeight)); + + penX += (int)g.advanceX; + penY += (int)g.advanceY; + } + + flush (); + } + void buildStrokeVAOs() + { + addPath (cpath); + + initVAOsCache (); + + float hlw = (float)lineWidth / 2.0f;//half line width + + Vector2 vDir,vDir2, vPerp; + float lPerp; + int i; + //current offset in index + for (int j = 0; j < pathes.Count; j++) { + Path path = pathes[j]; + for (i = 0; i < path.Count; i++) { + lPerp = hlw; + vDir2 = Vector2.Zero; + + if (i < path.Count - 1) { + vDir = Vector2.Normalize (path [i + 1] - path [i]); + if (i > 0) { + vDir2 = Vector2.Normalize (path [i] - path [i - 1]); + } else if (path.IsClosed) + vDir2 = Vector2.Normalize (path [0] - path [path.Count - 1]); + } else { + vDir = Vector2.Normalize (path [i] - path [i - 1]); + if (path.IsClosed) + vDir2 = Vector2.Normalize (path [0]-path [i]); + } + + vPerp = Vector2.Normalize(vDir+vDir2).PerpendicularLeft; + + if (vDir2 != Vector2.Zero) { + double dotP = Vector2.Dot (vDir.PerpendicularLeft, vPerp); + double angle = Math.Acos(dotP); + double x = Math.Tan (angle) * hlw; + + if (dotP == 0) + lPerp = hlw; + else + lPerp = (float)Math.Sqrt (Math.Pow (x, 2) + Math.Pow (hlw, 2)); + } + + vertices.Add (path [i] + vPerp * (float)lPerp); + vertices.Add (path [i] - vPerp * (float)lPerp); + indices.Add (idxOffset + i*2); + indices.Add (idxOffset + i*2 + 1); + texCoords.Add (Vector2.Zero); + texCoords.Add (Vector2.One); + } + if (path.IsClosed) { + indices.Add (idxOffset); + indices.Add (idxOffset+1); + texCoords.Add (Vector2.Zero); + texCoords.Add (Vector2.One); + } + if (j < pathes.Count - 1) { + indices.Add (int.MaxValue); //restart primitive idex + idxOffset += path.Count * 2; + } + } + flush (); + } + + void addFillTriangle(int pathIdx, int vx1, int vx2, int vx3){ + addFillVertex (pathIdx, vx1); + addFillVertex (pathIdx, vx2); + addFillVertex (pathIdx, vx3); + } + + void addFillVertex(int pathIdx, int vx){ + Vector2 p = pathes [pathIdx] [vx]; + indices.Add (idxOffset + vx); + //texCoords.Add (new Vector2(1.0f/polyWidth*(p.X-minX),1.0f/polyHeight*(p.Y-minY))); + } + + float sign (Vector2 p1, Vector2 p2, Vector2 p3) + { + return (p1.X - p3.X) * (p2.Y - p3.Y) - (p2.X - p3.X) * (p1.Y - p3.Y); + } + bool PointInTriangle (Vector2 pt, Vector2 v1, Vector2 v2, Vector2 v3) + { + bool b1, b2, b3; + + b1 = sign(pt, v1, v2) < 0.0f; + b2 = sign(pt, v2, v3) < 0.0f; + b3 = sign(pt, v3, v1) < 0.0f; + + return ((b1 == b2) && (b2 == b3)); + } + + #region GL Ctx Save and restore + int savedFbo, + savedPriRstIdx, + savedBlendSrc, + savedBlendDst; + int[] viewport = new int[4]; + float[] savedClsColor = new float[4]; + bool savedBlend,savedPriRstCap; + void saveGLConfig(){ + GL.GetInteger (GetPName.FramebufferBinding, out savedFbo); + GL.GetInteger ((GetPName)All.PrimitiveRestartIndex, out savedPriRstIdx); + GL.GetBoolean ((GetPName)All.PrimitiveRestart, out savedPriRstCap); + GL.GetInteger(GetPName.Viewport, viewport); + GL.GetFloat (GetPName.ColorClearValue, savedClsColor); + GL.GetBoolean (GetPName.Blend, out savedBlend); + GL.GetInteger (GetPName.BlendSrc, out savedBlendSrc); + GL.GetInteger (GetPName.BlendDst, out savedBlendDst); + } + void restoreGLConfig(){ + GL.BindFramebuffer(FramebufferTarget.Framebuffer, savedFbo); + + GL.Viewport (viewport[0],viewport[1],viewport[2],viewport[3]); + GL.PrimitiveRestartIndex (savedPriRstIdx); + GL.ClearColor (savedClsColor [0], savedClsColor [1], savedClsColor [2], savedClsColor [3]); + if (!savedBlend) + GL.Disable (EnableCap.Blend); + if (!savedPriRstCap) + GL.Disable (EnableCap.PrimitiveRestart); + GL.BlendFunc ((BlendingFactorSrc) savedBlendSrc,(BlendingFactorDest)savedBlendDst); + } + #endregion + + #region IDisposable implementation + + public void Dispose () + { + restoreGLConfig (); + + if (GL.IsFramebuffer (fboId)) + GL.DeleteFramebuffer (fboId); + if (GL.IsTexture(stencilTexId)) + GL.DeleteTexture(stencilTexId); + } + + #endregion + + } +} + diff --git a/OTKCrow/OpenGL/GLBackend/Font/Font.cs b/OTKCrow/OpenGL/GLBackend/Font/Font.cs new file mode 100644 index 00000000..d07b9bd0 --- /dev/null +++ b/OTKCrow/OpenGL/GLBackend/Font/Font.cs @@ -0,0 +1,115 @@ +using System; + + +namespace Crow.GLBackend +{ + public class Font + { + public Font () + { + } + + public Font (string name, FontSlant fs, FontWeight fw) + { + _name = name; + switch (fs) { + case FontSlant.Italic: + Style |= FontStyle.Italic; + break; + case FontSlant.Oblique: + Style |= FontStyle.Oblique; + break; + } + if (fw == FontWeight.Bold) + Style |= FontStyle.Bold; + } + + string _name = "droid"; + FontStyle _style = FontStyle.Normal; + FontFlag _flags = FontFlag.None; + + int _size = 10; + + public string Name { + get { return _name; } + set { _name = value; } + } + public FontStyle Style { + get { return _style; } + set { _style = value; } + } + public FontFlag Flags { + get { return _flags; } + set { _flags = value; } + } + public FontSlant Slant { + get{ + if ((Style & FontStyle.Italic) == FontStyle.Italic) + return FontSlant.Italic; + if ((Style & FontStyle.Oblique) == FontStyle.Oblique) + return FontSlant.Oblique; + return FontSlant.Normal; + } + } + public FontWeight Wheight { + get{ return (Style & FontStyle.Bold) == FontStyle.Bold ? FontWeight.Bold : FontWeight.Normal; } + } + public int Size { + get { return _size; } + set { _size = value; } + } + + #region Operators + public static implicit operator string(Font c) + { + return c.ToString(); + } + public static implicit operator Font(string s) + { + Font f = new Font (); + + if (!string.IsNullOrEmpty (s)) { + f.Name = ""; + string[] attribs = s.TrimStart().TrimEnd().Split(','); + for (int i = 0; i < attribs.Length; i++) { + FontFlag fl; + FontStyle fs; + int sz; + if (Enum.TryParse (attribs [i], true, out fl)) + f.Flags |= fl; + else if (Enum.TryParse (attribs [i], true, out fs)) + f.Style |= fs; + else if (int.TryParse (attribs [i], out sz)) + f.Size = sz; + else + f.Name += attribs[i] + " "; + } + f.Name = f.Name.Trim(); + } + + return f; + } + #endregion + public string FontFaceString + { + get { + string tmp = Name; + if (Style != FontStyle.Normal) + tmp += "," + Style.ToString (); + if (Flags != FontFlag.None) + tmp += "," + Flags.ToString (); + return tmp; + } + } + public override string ToString() + { + return string.Format("{0},{1}", FontFaceString, _size); + } + + public static object Parse(string s) + { + return (Font)s; + } + } +} + diff --git a/OTKCrow/OpenGL/GLBackend/Font/FontExtents.cs b/OTKCrow/OpenGL/GLBackend/Font/FontExtents.cs new file mode 100644 index 00000000..fba77cb0 --- /dev/null +++ b/OTKCrow/OpenGL/GLBackend/Font/FontExtents.cs @@ -0,0 +1,39 @@ +using System; + +namespace Crow.GLBackend +{ + public class FontExtents + { + double ascent; + double descent; + double height; + double maxXAdvance; + double maxYAdvance; + + public double Ascent { + get { return ascent; } + set { ascent = value; } + } + public double Descent { + get { return descent; } + set { descent = value; } + } + public double Height { + get { return height; } + set { height = value; } + } + public double MaxXAdvance { + get { return maxXAdvance; } + set { maxXAdvance = value; } + } + public double MaxYAdvance { + get { return maxYAdvance; } + set { maxYAdvance = value; } + } + + public FontExtents () + { + } + } +} + diff --git a/OTKCrow/OpenGL/GLBackend/Font/FontFace.cs b/OTKCrow/OpenGL/GLBackend/Font/FontFace.cs new file mode 100644 index 00000000..88bdaa15 --- /dev/null +++ b/OTKCrow/OpenGL/GLBackend/Font/FontFace.cs @@ -0,0 +1,307 @@ +using System; +using System.Collections.Generic; +using System.IO; +using SharpFont; +using System.Diagnostics; +using System.Linq; +using System.Text.RegularExpressions; +using OpenTK.Graphics.OpenGL; + +namespace Crow.GLBackend +{ + public class FontFace + { + public static int testTexture; + + static List fonts = new List(); + public Dictionary> glyphesCache = new Dictionary>(); + + #region CTOR + public FontFace () + { + } + #endregion + + string _name = "droid"; + string _family; + string _fontPath; + public FontExtents originalFontExtents; + + FontStyle _style = FontStyle.Normal; + FontFlag _flags = FontFlag.None; + + public string Name { + get { return _name; } + set { _name = value; } + } + public string Family { + get {return _family;} + set {_family = value;} + } + public string FontPath { + get { return _fontPath; } + set { _fontPath = value; } + } + + public FontStyle Style { + get { return _style; } + set { _style = value; } + } + public FontFlag Flags { + get { return _flags; } + set { _flags = value; } + } + + public FontSlant Slant { + get{ + if ((Style & FontStyle.Italic) == FontStyle.Italic) + return FontSlant.Italic; + if ((Style & FontStyle.Oblique) == FontStyle.Oblique) + return FontSlant.Oblique; + return FontSlant.Normal; + } + } + public FontWeight Wheight { + get{ return (Style & FontStyle.Bold) == FontStyle.Bold ? FontWeight.Bold : FontWeight.Normal; } + } + + public static FontFace SearchFont(Font font) + { + FontFace[] tmp = fonts.Where (f => + (string.Compare(f.Name,font.Name,true)==0 && f.Style == font.Style)).ToArray(); + + tmp = tmp.Where (f => (f.Flags & font.Flags) == font.Flags).OrderBy(f=>f.Flags).ToArray(); + + return tmp.FirstOrDefault(); + } + + public static void BuildFontsList(string _path) + { + DirectoryInfo dir = new DirectoryInfo (_path); + try + { + using (Library lib = new Library()) + { + foreach (FileInfo f in dir.GetFiles("*.ttf",SearchOption.AllDirectories)) { + try { + + Face face = new Face(lib,f.FullName, 0); + FontFace font = new FontFace(); + + //TODO:test if font is scalable, if not=>continue + font.Family = face.FamilyName; + font.FontPath = f.FullName; + + //check if no particularities hidde in family name + font.Name = ""; + string[] styles = face.FamilyName.Split(' '); + for (int i = 0; i < styles.Length; i++) { + FontFlag fl; + FontStyle fs; + if (Enum.TryParse (styles [i], true, out fl)) + font.Flags |= fl; + else if (Enum.TryParse (styles [i], true, out fs)) + font.Style |= fs; + else//add only unknown word to create shortest possible name + font.Name += styles[i] + " "; + } + font.Name = font.Name.Trim(); + + styles = face.StyleName.Split(' '); + for (int i = 0; i < styles.Length; i++) { + switch (styles[i].ToLowerInvariant()) { + case "regular": + case "normal": + break; + case "bold": + font.Style |= FontStyle.Bold; + break; + case "italic": + font.Style |= FontStyle.Italic; + break; + case "oblique": + font.Style |= FontStyle.Oblique; + break; + default: + FontFlag fl; + if (Enum.TryParse(styles[i], true, out fl)) + font.Flags |= fl; + break; + } + + } + fonts.Add(font); + face.Dispose(); + } + catch (FreeTypeException ee) + { Console.Write(ee.Error.ToString() + ": " + f.FullName); } + } + } + } + catch (FreeTypeException e) + { Console.Write(e.Error.ToString()); } + } + + const int FONT_TEX_SIZE = 1024; + + public void buildGlyphesTextures(uint activeSize, uint startChar, uint endChar){ + try + { + using (Library lib = new Library()) + { + Face face = new Face(lib,_fontPath, 0); + + face.SetPixelSizes(0,activeSize); + + //face.SetCharSize(0, 32 * 64, 0, 96); + + originalFontExtents = new FontExtents(); + originalFontExtents.Ascent = face.Size.Metrics.Ascender >> 6; + originalFontExtents.Descent = face.Size.Metrics.Descender >> 6; + originalFontExtents.Height = face.Size.Metrics.Height >> 6; + originalFontExtents.MaxXAdvance = face.Size.Metrics.MaxAdvance >> 6; + originalFontExtents.MaxYAdvance = face.MaxAdvanceHeight >> 6; + + if (!glyphesCache.ContainsKey(activeSize)) + glyphesCache [activeSize] = new Dictionary(); + + buildTexture(ref face,activeSize,startChar,endChar); + + face.Dispose(); + } + } + catch (FreeTypeException e) + { Console.Write(e.Error.ToString()); } + } + + void setTextureData(int tex, byte[] _buffer) + { + GL.BindTexture(TextureTarget.Texture2D, tex); + GL.TexImage2D(TextureTarget.Texture2D,0, + PixelInternalFormat.R8, FONT_TEX_SIZE, FONT_TEX_SIZE,0, + OpenTK.Graphics.OpenGL.PixelFormat.Red, PixelType.UnsignedByte,_buffer); + + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); + GL.BindTexture(TextureTarget.Texture2D, 0); + + byte[] pixels = new byte[FONT_TEX_SIZE * FONT_TEX_SIZE * 4]; + + for (int x = 0; x < FONT_TEX_SIZE; x++) + { + for (int y = 0; y < FONT_TEX_SIZE; y++) + { + byte v = _buffer[x + y * FONT_TEX_SIZE]; + + pixels[(x + y * FONT_TEX_SIZE) * 4] = v; + pixels[(x + y * FONT_TEX_SIZE) * 4 + 1] = v; + pixels[(x + y * FONT_TEX_SIZE) * 4 + 2] = v; + pixels[(x + y * FONT_TEX_SIZE) * 4 + 3] = 255; + } + } + System.Drawing.Bitmap bmp; + unsafe + { + bmp = new System.Drawing.Bitmap(FONT_TEX_SIZE, FONT_TEX_SIZE, System.Drawing.Imaging.PixelFormat.Format32bppArgb);//, ptr); + System.Drawing.Imaging.BitmapData data = bmp.LockBits(new System.Drawing.Rectangle(0, 0, FONT_TEX_SIZE, FONT_TEX_SIZE), + System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + + System.Runtime.InteropServices.Marshal.Copy(pixels, 0, data.Scan0, FONT_TEX_SIZE * FONT_TEX_SIZE * 4); + + bmp.UnlockBits(data); + } + + bmp.Save(@"/home/jp/fonttex.png"); + + + } + + + void buildTexture(ref Face face,uint activeSize, uint startChar, uint endChar){ + int texPage = GL.GenTexture (); + byte[] buffer = new byte[FONT_TEX_SIZE*FONT_TEX_SIZE]; + + int penX = 0, + penY = 0; + + int maxBmpHeight = 0; + + for(uint c=startChar;c FONT_TEX_SIZE){ + penX = 0; + penY += maxBmpHeight; + maxBmpHeight = 0; + } + + if (penY+bmp.Rows > FONT_TEX_SIZE) + { + //glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + setTextureData (texPage, buffer); + texPage = GL.GenTexture (); + buffer = new byte[FONT_TEX_SIZE*FONT_TEX_SIZE]; + penX = 0; + penY = 0; + maxBmpHeight = 0; + } + + Rectangle tmp = new Rectangle ( + penX, + penY, + bmp.Width, bmp.Rows); + + for(int y=0; y>6,advanceY = slot.Advance.Y>>6 + }; + + if (bmp.Rows>maxBmpHeight) + maxBmpHeight=bmp.Rows; + + penX += bmp.Width; + } + + if (penX>0 || penY>0) + setTextureData(texPage, buffer); + } + + public override string ToString() + { + string tmp = Name; + if (Style != FontStyle.Normal) + tmp += "," + Style.ToString (); + if (Flags != FontFlag.None) + tmp += "," + Flags.ToString (); + return tmp; + } + } +} + diff --git a/OTKCrow/OpenGL/GLBackend/Font/FontFlag.cs b/OTKCrow/OpenGL/GLBackend/Font/FontFlag.cs new file mode 100644 index 00000000..f748ec17 --- /dev/null +++ b/OTKCrow/OpenGL/GLBackend/Font/FontFlag.cs @@ -0,0 +1,18 @@ +using System; + +namespace Crow +{ + [Flags] + public enum FontFlag + { + None = 0x00, + Sans = 0x01, + Serif = 0x02, + Mono = 0x04, + Condensed = 0x08, + Medium = 0x16, + Book = 0x32, + ExtraLight = 0x64 + } +} + diff --git a/OTKCrow/OpenGL/GLBackend/Font/FontShader (copier).cs b/OTKCrow/OpenGL/GLBackend/Font/FontShader (copier).cs new file mode 100644 index 00000000..2a4c1571 --- /dev/null +++ b/OTKCrow/OpenGL/GLBackend/Font/FontShader (copier).cs @@ -0,0 +1,146 @@ +using System; +using OpenTK.Graphics.OpenGL; + +namespace Crow.GLBackend +{ + public class FontShader : Shader + { + public FontShader () + { + vertSource = @" + #version 130 + + precision highp float; + + uniform mat4 projection_matrix; + uniform mat4 modelview_matrix; + + in vec2 in_position; + in vec2 in_tex; + out vec2 texCoord; + + + void main(void) + { + texCoord = in_tex; + gl_Position = projection_matrix * modelview_matrix * vec4(in_position,0, 1); + }"; + + fragSource = @" + #version 130 + precision highp float; + + uniform vec4 color; + uniform sampler2D tex; + uniform sampler2D stencil; + uniform vec2 resolution; + + in vec2 texCoord; + out vec4 out_frag_color; + + vec3 + energy_distribution( vec4 previous, vec4 current, vec4 next ) + { + float primary = 1.0/3.0; + float secondary = 1.0/3.0; + float tertiary = 0.0; + + // Energy distribution as explained on: + // http://www.grc.com/freeandclear.htm + // + // .. v.. + // RGB RGB RGB + // previous.g + previous.b + current.r + current.g + current.b + // + // . .v. . + // RGB RGB RGB + // previous.b + current.r + current.g + current.b + next.r + // + // ..v .. + // RGB RGB RGB + // current.r + current.g + current.b + next.r + next.g + + float r = + tertiary * previous.g + + secondary * previous.b + + primary * current.r + + secondary * current.g + + tertiary * current.b; + + float g = + tertiary * previous.b + + secondary * current.r + + primary * current.g + + secondary * current.b + + tertiary * next.r; + + float b = + tertiary * current.r + + secondary * current.g + + primary * current.b + + secondary * next.r + + tertiary * next.g; + + return vec3(r,g,b); + } + void main(void) + { + float a = texture( tex, texCoord).r; + + if (a==0.) + discard; + + float x = gl_FragCoord.x / resolution.x; + float s = mod(x,x); + + vec4 current = color * texture( tex, texCoord).r; + vec4 previous = color * texture( tex, texCoord + vec2(-x,0)).r; + vec4 next = color * texture( tex, texCoord + vec2(x,0)).r; + + float r = current.r; + float g = current.g; + float b = current.b; + + if( s <= 0.333 ) + { + float z = s/0.333; + r = mix(current.r, previous.b, z); + g = mix(current.g, current.r, z); + b = mix(current.b, current.g, z); + } + else if( s <= 0.666 ) + { + float z = (s-0.33)/0.333; + r = mix(previous.b, previous.g, z); + g = mix(current.r, previous.b, z); + b = mix(current.g, current.r, z); + } + else if( s < 1.0 ) + { + float z = (s-0.66)/0.334; + r = mix(previous.g, previous.r, z); + g = mix(previous.b, previous.g, z); + b = mix(current.r, previous.b, z); + } + + + out_frag_color = vec4(energy_distribution(previous, current, next),1); + }"; + + Compile (); + + } + + protected override void BindVertexAttributes () + { + base.BindVertexAttributes (); + GL.BindAttribLocation(pgmId, 1, "in_tex"); + } + protected override void BindSamplesSlots () + { + GL.Uniform1(GL.GetUniformLocation (pgmId, "tex"),0); + //GL.Uniform1(GL.GetUniformLocation (pgmId, "stencil"),1); + } + } +} + diff --git a/OTKCrow/OpenGL/GLBackend/Font/FontShader.cs b/OTKCrow/OpenGL/GLBackend/Font/FontShader.cs new file mode 100644 index 00000000..6086f7b9 --- /dev/null +++ b/OTKCrow/OpenGL/GLBackend/Font/FontShader.cs @@ -0,0 +1,128 @@ +using System; +using OpenTK.Graphics.OpenGL; +using OpenTK; + +namespace Crow.GLBackend +{ + public class FontShader : Shader + { + protected int coef1Location, coef2Location, coef3Location, coefALocation, resolutionLoc; + public float coef1 { + set {GL.Uniform1 (coef1Location, value);} + } + public float coef2 { + set {GL.Uniform1 (coef2Location, value);} + } + public float coef3 { + set {GL.Uniform1 (coef3Location, value);} + } + public float coefA { + set {GL.Uniform1 (coefALocation, value);} + } + public Vector2 Resolution { + set { GL.Uniform2 (resolutionLoc, value); } + } + public FontShader () + { + vertSource = @" + #version 130 + + precision highp float; + + uniform mat4 projection_matrix; + uniform mat4 modelview_matrix; + + in vec2 in_position; + in vec2 in_tex; + out vec2 texCoord; + + + void main(void) + { + texCoord = in_tex; + gl_Position = projection_matrix * modelview_matrix * vec4(in_position,0, 1); + }"; + + fragSource = @" + #version 130 + precision highp float; + + uniform vec4 color; + uniform sampler2D tex; + uniform sampler2D backTex; + uniform sampler2D stencil; + uniform vec2 resolution; + uniform float coef1; + uniform float coef2; + uniform float coef3; + uniform float coefA; + + + in vec2 texCoord; + out vec4 out_frag_color; + + void main(void) + { + vec2 uv = gl_FragCoord.xy / resolution; + vec2 pix = 1.0 / resolution; + + float c = texture( tex, texCoord).r; + vec4 bc = texture( backTex, uv); + + vec4 diff = bc - color; + + if (c==0.) + discard; + +// if (c > 0.75) +// out_frag_color = vec4(color.rgb,c); +// else{ + float p = texture( tex, texCoord + vec2(-pix.x,0)).r; + float n = texture( tex, texCoord + vec2( pix.x,0)).r; + + vec3 current = vec3(0,0,0); + + float a = n - c; + current.r += coef1 * a * diff.r; + current.g += coef2 * a * diff.g; + current.b += coef3 * a * diff.b; + //current.a *= coefA * a * diff.a; + + a = p - c; + current.r += coef3 * a * diff.r; + current.g += coef2 * a * diff.g; + current.b += coef1 * a * diff.b; + //current.a *= coefA * a * diff.a; + + out_frag_color = vec4(color.rgb+current,c*coefA); + +// } + }"; + + Compile (); + + } + protected override void GetUniformLocations () + { + base.GetUniformLocations (); + + resolutionLoc = GL.GetUniformLocation (pgmId, "resolution"); + coef1Location = GL.GetUniformLocation (pgmId, "coef1"); + coef2Location = GL.GetUniformLocation (pgmId, "coef2"); + coef3Location = GL.GetUniformLocation (pgmId, "coef3"); + coefALocation = GL.GetUniformLocation (pgmId, "coefA"); + } + protected override void BindVertexAttributes () + { + base.BindVertexAttributes (); + GL.BindAttribLocation(pgmId, 1, "in_tex"); + } + protected override void BindSamplesSlots () + { + GL.Uniform1(GL.GetUniformLocation (pgmId, "tex"),0); + GL.Uniform1(GL.GetUniformLocation (pgmId, "backTex"),1); + //GL.Uniform1(GL.GetUniformLocation (pgmId, "stencil"),1); + } + } +} + diff --git a/OTKCrow/OpenGL/GLBackend/Font/FontSlant.cs b/OTKCrow/OpenGL/GLBackend/Font/FontSlant.cs new file mode 100644 index 00000000..8bfd5a6a --- /dev/null +++ b/OTKCrow/OpenGL/GLBackend/Font/FontSlant.cs @@ -0,0 +1,42 @@ +// +// Mono.Cairo.FontSlant.cs +// +// Authors: +// Duncan Mak (duncan@ximian.com) +// Hisham Mardam Bey (hisham.mardambey@gmail.com) +// +// (C) Ximian, Inc. 2003 +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace Crow.GLBackend +{ + [Serializable] + public enum FontSlant + { + Normal, + Italic, + Oblique + } +} diff --git a/OTKCrow/OpenGL/GLBackend/Font/FontStyle.cs b/OTKCrow/OpenGL/GLBackend/Font/FontStyle.cs new file mode 100644 index 00000000..eed35057 --- /dev/null +++ b/OTKCrow/OpenGL/GLBackend/Font/FontStyle.cs @@ -0,0 +1,15 @@ +using System; + +namespace Crow +{ + [Flags] + public enum FontStyle + { + Normal = 0x00, + Bold = 0x01, + Italic = 0x02, + Oblique = 0x4, + Underlined = 0x8 + } +} + diff --git a/OTKCrow/OpenGL/GLBackend/Font/FontWeight.cs b/OTKCrow/OpenGL/GLBackend/Font/FontWeight.cs new file mode 100644 index 00000000..d361378c --- /dev/null +++ b/OTKCrow/OpenGL/GLBackend/Font/FontWeight.cs @@ -0,0 +1,41 @@ +// +// Mono.Cairo.FontWeight.cs +// +// Authors: +// Duncan Mak (duncan@ximian.com) +// Hisham Mardam Bey (hisham.mardambey@gmail.com) +// +// (C) Ximian, Inc. 2003 +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace Crow.GLBackend +{ + [Serializable] + public enum FontWeight + { + Normal, + Bold, + } +} diff --git a/OTKCrow/OpenGL/GLBackend/Font/TextExtents.cs b/OTKCrow/OpenGL/GLBackend/Font/TextExtents.cs new file mode 100644 index 00000000..a0bc6440 --- /dev/null +++ b/OTKCrow/OpenGL/GLBackend/Font/TextExtents.cs @@ -0,0 +1,98 @@ +// +// Mono.Cairo.TextExtents.cs +// +// Authors: +// Duncan Mak (duncan@ximian.com) +// Hisham Mardam Bey (hisham.mardambey@gmail.com) +// +// (C) Ximian, Inc. 2003 +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Runtime.InteropServices; + +namespace Crow.GLBackend +{ + [StructLayout (LayoutKind.Sequential)] + public struct TextExtents + { + double xbearing; + double ybearing; + double width; + double height; + double xadvance; + double yadvance; + + public double XBearing { + get { return xbearing; } + set { xbearing = value; } + } + + public double YBearing { + get { return ybearing; } + set { ybearing = value; } + } + + public double Width { + get { return width; } + set { width = value; } + } + + public double Height { + get { return height; } + set { height = value; } + } + + public double XAdvance { + get { return xadvance; } + set { xadvance = value; } + } + + public double YAdvance { + get { return yadvance; } + set { yadvance = value; } + } + + public override bool Equals (object obj) + { + if (obj is TextExtents) + return this == (TextExtents)obj; + return false; + } + + public override int GetHashCode () + { + return (int)XBearing ^ (int)YBearing ^ (int)Width ^ (int)Height ^ (int)XAdvance ^ (int)YAdvance; + } + + public static bool operator == (TextExtents extents, TextExtents other) + { + return extents.XBearing == other.XBearing && extents.YBearing == other.YBearing && extents.Width == other.Width && extents.Height == other.Height && extents.XAdvance == other.XAdvance && extents.YAdvance == other.YAdvance; + } + + public static bool operator != (TextExtents extents, TextExtents other) + { + return !(extents == other); + } + } +} diff --git a/OTKCrow/OpenGL/GLBackend/Font/glFont.cs b/OTKCrow/OpenGL/GLBackend/Font/glFont.cs new file mode 100644 index 00000000..059fca6a --- /dev/null +++ b/OTKCrow/OpenGL/GLBackend/Font/glFont.cs @@ -0,0 +1,90 @@ +using System; +using SharpFont; +using OpenTK.Graphics.OpenGL; +using System.Collections.Generic; +using System.IO; +using System.Diagnostics; + +namespace Crow +{ + public class glFont + { + Dictionary glyphs = new Dictionary(); + + public static void dumpFontsDirectories(string _path) + { + List stylesList = new List (); + List namesList = new List (); + List attribsList = new List (); + + DirectoryInfo dir = new DirectoryInfo (_path); + try + { + using (Library lib = new Library()) + { + Console.WriteLine("FreeType version: " + lib.Version + "\n"); + + foreach (FileInfo f in dir.GetFiles("*.ttf",SearchOption.AllDirectories)) { + try { + + Face face = new Face(lib,f.FullName, 0); + + Console.Write(System.IO.Path.GetFileNameWithoutExtension(f.Name) + " => "); + Console.WriteLine("{0} Faces:{1} Flags:{2}\nStyle:{3} StyleFlags:{4}\n", + face.FamilyName, + face.FaceCount, + face.FaceFlags, + face.StyleName, + face.StyleFlags); + string[] styles = face.StyleName.Split(' '); + foreach (string s in styles) { + if (stylesList.Contains(s)) + continue; + stylesList.Add(s); + } + + string[] names = face.FamilyName.Split(' '); + if (!namesList.Contains(names[0])) + namesList.Add(names[0]); + for (int i = 1; i < names.Length; i++) { + if (attribsList.Contains(names[i])) + continue; + attribsList.Add(names[i]); + } + + face.Dispose(); + } + catch (FreeTypeException ee) + { + Console.Write(ee.Error.ToString() + ": " + f.FullName); + } + } + } + } + catch (FreeTypeException e) + { + Console.Write(e.Error.ToString()); + } + Console.Write ("Names => "); + foreach (string s in namesList) { + Console.Write (s + " "); + } + Console.Write ("\n\nAttrib => "); + foreach (string s in attribsList) { + Console.Write (s + " "); + } + + Console.Write ("\n\nStyles => "); + foreach (string s in stylesList) { + Console.Write (s + " "); + } + } + + public glFont (string _fontPath) + { + + } + + } +} + diff --git a/OTKCrow/OpenGL/GLBackend/Font/glGlyph.cs b/OTKCrow/OpenGL/GLBackend/Font/glGlyph.cs new file mode 100644 index 00000000..f0d15d36 --- /dev/null +++ b/OTKCrow/OpenGL/GLBackend/Font/glGlyph.cs @@ -0,0 +1,22 @@ +using System; + +namespace Crow +{ + public struct glGlyph + { + public int texId; + public Rectangle texCoord; + public float texX; + public float texY; + public float texWidth; + public float texHeight; + public Size dims; + public int bmpLeft; + public int bmpTop; + public long advanceX; + public long advanceY; + + + } +} + diff --git a/OTKCrow/OpenGL/GLBackend/Path.cs b/OTKCrow/OpenGL/GLBackend/Path.cs new file mode 100644 index 00000000..67f2103f --- /dev/null +++ b/OTKCrow/OpenGL/GLBackend/Path.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using OpenTK; + +namespace Crow +{ + public class Path : List + { + public bool IsClosed; + + public Path () : base() + { + } + public Path (IEnumerable collection) : base(collection){ + } + } +} + diff --git a/OTKCrow/OpenGL/GLBackend/Shader (copier).cs b/OTKCrow/OpenGL/GLBackend/Shader (copier).cs new file mode 100644 index 00000000..465409cc --- /dev/null +++ b/OTKCrow/OpenGL/GLBackend/Shader (copier).cs @@ -0,0 +1,135 @@ +using System; +using OpenTK.Graphics.OpenGL; +using System.Diagnostics; +using OpenTK; + +namespace Crow.GLBackend +{ + public class TestShader + { + string vertexShaderSource = @" + #version 130 + + //precision highp float; + + uniform float lw; + uniform mat4 projection_matrix; + uniform mat4 modelview_matrix; + + in vec2 in_position; + in vec2 in_tex; + + out vec2 texcoord; + + void main(void) + { + texcoord = in_tex; + gl_Position = projection_matrix * modelview_matrix * vec4(in_position,0, 1); + }"; + + string fragmentShaderSource = @" + #version 130 + + //precision highp float; + uniform float lw; + uniform vec4 color; + + in vec2 texcoord; + out vec4 out_frag_color; + + void main(void) + { +// float smoothWidth = 1.0 / lineWidth; +// +// if (texcoord.y < smoothWidth) +// out_frag_color = vec4(color,texcoord.y/smoothWidth); +// else if (texcoord.y > 1.0 - smoothWidth) +// out_frag_color = vec4(color,(1.0-texcoord.y)/smoothWidth); +// else +// out_frag_color = vec4(color,1.0); + out_frag_color = color; + }"; + + int vertexShaderHandle, + fragmentShaderHandle, + shaderProgramHandle, + modelviewMatrixLocation, + projectionMatrixLocation, + colorLocation, + lineWidthLocation; + + Matrix4 projectionMatrix, + modelviewMatrix; + + double lineWidth = 1.0; + + public TestShader () + { + vertexShaderHandle = GL.CreateShader(ShaderType.VertexShader); + fragmentShaderHandle = GL.CreateShader(ShaderType.FragmentShader); + + GL.ShaderSource(vertexShaderHandle, vertexShaderSource); + GL.ShaderSource(fragmentShaderHandle, fragmentShaderSource); + + GL.CompileShader(vertexShaderHandle); + GL.CompileShader(fragmentShaderHandle); + + Debug.WriteLine(GL.GetShaderInfoLog(vertexShaderHandle)); + Debug.WriteLine(GL.GetShaderInfoLog(fragmentShaderHandle)); + + // Create program + shaderProgramHandle = GL.CreateProgram(); + + GL.AttachShader(shaderProgramHandle, vertexShaderHandle); + GL.AttachShader(shaderProgramHandle, fragmentShaderHandle); + + GL.BindAttribLocation(shaderProgramHandle, 0, "in_position"); + GL.BindAttribLocation(shaderProgramHandle, 1, "in_tex"); + + GL.LinkProgram(shaderProgramHandle); + Debug.WriteLine(GL.GetProgramInfoLog(shaderProgramHandle)); + GL.UseProgram(shaderProgramHandle); + + + lineWidthLocation = GL.GetUniformLocation (shaderProgramHandle, "lw"); + projectionMatrixLocation = GL.GetUniformLocation(shaderProgramHandle, "projection_matrix"); + modelviewMatrixLocation = GL.GetUniformLocation(shaderProgramHandle, "modelview_matrix"); + colorLocation = GL.GetUniformLocation (shaderProgramHandle, "color"); + + } + + int savedPgm = 0; + public virtual void Enable(){ + GL.GetInteger (GetPName.CurrentProgram, out savedPgm); + GL.UseProgram (shaderProgramHandle); + } + public virtual void Disable(){ + GL.UseProgram (savedPgm); + } + + public Matrix4 ProjectionMatrix{ + set { + projectionMatrix = value; + GL.UniformMatrix4(projectionMatrixLocation, false, ref projectionMatrix); + } + } + public Matrix4 ModelViewMatrix { + set { + modelviewMatrix = value; + GL.UniformMatrix4 (modelviewMatrixLocation, false, ref modelviewMatrix); + } + } + public double LineWidth { + set { + lineWidth = value; + GL.Uniform1 (lineWidthLocation, (float)lineWidth); + } + } + public Vector4 Color { + set { + GL.Uniform4 (colorLocation, value); + } + } + } +} + diff --git a/OTKCrow/OpenGL/GLBackend/Surface.cs b/OTKCrow/OpenGL/GLBackend/Surface.cs new file mode 100644 index 00000000..a9d9a024 --- /dev/null +++ b/OTKCrow/OpenGL/GLBackend/Surface.cs @@ -0,0 +1,103 @@ +using System; +using OpenTK.Graphics.OpenGL; + +namespace Crow.GLBackend +{ + [Serializable] + public enum Format + { + Argb32, + Rgb24, + A8, + A1, + Rgb16565, + ARGB32, + RGB24 + } + [Serializable] + public enum LineJoin + { + Miter, + Round, + Bevel + } + [Serializable] + public enum LineCap + { + Butt, + Round, + Square + } + public class Surface : IDisposable + { + public static int samples; + + public int texId, + width, + height; + Format format; + + public PixelFormat PixelFormat; + public PixelInternalFormat InternalFormat; + + public Surface (int _width, int _height) + { + format = Format.Argb32; + width = _width; + height = _height; + + createTexture (); + } + + public Surface (Format _format,int _width, int _height) + { + format = _format; + width = _width; + height = _height; + + InternalFormat = PixelInternalFormat.Rgba; + PixelFormat = PixelFormat.Bgra; + + createTexture (); + } + + public Surface CreateSimilar() + { + return new Surface (format, width, height); + } + + void createTexture() + { + texId = GL.GenTexture(); + GL.BindTexture(TextureTarget.Texture2D, texId); + GL.TexImage2D(TextureTarget.Texture2D,0, + PixelInternalFormat.Rgba, width, height,0,PixelFormat.Bgra,PixelType.UnsignedByte,IntPtr.Zero); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest); + GL.BindTexture(TextureTarget.Texture2D, 0); + } + + + public void Save(string fileName) + { + GL.BindTexture(TextureTarget.Texture2D, texId); + System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + System.Drawing.Imaging.BitmapData data = bmp.LockBits(new System.Drawing.Rectangle(0, 0, width, height), + System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + GL.GetTexImage(TextureTarget.Texture2D, 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0); + bmp.UnlockBits(data); + bmp.RotateFlip (System.Drawing.RotateFlipType.RotateNoneFlipY); + bmp.Save(fileName); + GL.BindTexture(TextureTarget.Texture2D, 0); + } + + #region IDisposable implementation + public void Dispose () + { + if (GL.IsTexture (texId)) + GL.DeleteTexture (texId); + } + #endregion + } +} + diff --git a/OTKCrow/packages.config b/OTKCrow/packages.config index 6e6f39d4..f5d2a566 100644 --- a/OTKCrow/packages.config +++ b/OTKCrow/packages.config @@ -1,4 +1,5 @@  + \ No newline at end of file diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 3f808727..abf33dc1 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -69,6 +69,8 @@ Interfaces\test_stack.goml.cs + + diff --git a/Tests/testGLBackend (copier).cs b/Tests/testGLBackend (copier).cs new file mode 100644 index 00000000..1a527e9c --- /dev/null +++ b/Tests/testGLBackend (copier).cs @@ -0,0 +1,384 @@ +#define MONO_CAIRO_DEBUG_DISPOSE + + +using System; +using System.Runtime.InteropServices; +using OpenTK; +using OpenTK.Graphics.OpenGL; +using OpenTK.Input; + +using System.Diagnostics; + +using go; +using System.Threading; +using GGL; +//using Cairo; +using Crow.GLBackend; + +namespace testGLBackend2 +{ + class GOLIBTestglb : OpenTKGameWindow + { + #region FPS + static int _fps = 0; + + public static int fps { + get { return _fps; } + set { + _fps = value; + if (_fps > fpsMax) + fpsMax = _fps; + else if (_fps < fpsMin) + fpsMin = _fps; + } + + } + + public static int fpsMin = int.MaxValue; + public static int fpsMax = 0; + + static void resetFps () + { + fpsMin = int.MaxValue; + fpsMax = 0; + _fps = 0; + } + #endregion + + public GOLIBTestglb () + : base(1024, 800) + { + VSync = VSyncMode.Off; + } + + #region scene matrix and vectors + public static Matrix4 modelview; + public static Matrix4 projection; + + public static Vector3 vEye = new Vector3(5.0f, 5.0f, 5.0f); // Camera Position + public static Vector3 vEyeTarget = Vector3.Zero; + public static Vector3 vLook = new Vector3(0f, 1f, -0.7f); // Camera vLook Vector + + float _zFar = 6400.0f; + + public float zFar { + get { return _zFar; } + set { + _zFar = value; + } + } + + public float zNear = 0.1f; + public float fovY = (float)Math.PI / 4; + + float MoveSpeed = 0.5f; + float RotationSpeed = 0.02f; + #endregion + + Context ctx; + Surface surf; + + QuadVAO testQuad; + Crow.GLBackend.Shader shad; + Matrix4 projectionMatrix, + modelviewMatrix; + Texture testTex; + + void drawScene() + { + //shad.Enable (); + //shader.LineWidth = lineWidth; + shad.ProjectionMatrix = projectionMatrix; + shad.ModelViewMatrix = modelviewMatrix; + shad.Color = new Vector4(1f,1f,1f,1f); + + GL.ActiveTexture (TextureUnit.Texture0); + GL.BindTexture(TextureTarget.Texture2D, surf.texId); + + testQuad.Render (PrimitiveType.TriangleStrip); + + GL.BindTexture(TextureTarget.Texture2D, 0); + + //shad.Disable (); + } + + protected override void OnLoad (EventArgs e) + { + base.OnLoad (e); + + + Mouse.WheelChanged += new EventHandler(Mouse_WheelChanged); + Mouse.Move += new EventHandler(Mouse_Move); + + GL.Viewport (0, 0, ClientRectangle.Width, ClientRectangle.Height); + GL.ClearColor(0.0f, 0.0f, 0.2f, 1.0f); + +// GL.Enable(EnableCap.DepthTest); +// GL.DepthFunc(DepthFunction.Less); + //GL.Enable(EnableCap.CullFace); + //GL.Enable(EnableCap.Texture2D); + + GL.Enable (EnableCap.Blend); + GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha); + + //GL.FrontFace(FrontFaceDirection.Ccw); + + //GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest); + //GL.ShadeModel(ShadingModel.Smooth); + //GL.Hint (HintTarget.LineSmoothHint, HintMode.Nicest); + ErrorCode err = GL.GetError (); + Debug.Assert (err == ErrorCode.NoError, "OpenGL Error"); + + surf = new Surface (Format.Argb32, 600, 600); + + testQuad = new QuadVAO (100, 100, 600, 600); + shad = new TexturedShader (); + + projectionMatrix = Matrix4.CreateOrthographicOffCenter + (0, ClientRectangle.Width, ClientRectangle.Height, 0, 0, 1); + modelviewMatrix = Matrix4.Identity; + + testTex = new Texture (rootDir + @"Images/texture/structures/639-diffuse.jpg"); + //string[] extensions = GL.GetString(StringName.Version).Split(' '); + LoadInterface("Interfaces/test0.goml"); + + } + public static void DrawRoundedRectangle(Context gr, double x, double y, double width, double height, double radius) + { + + if ((radius > height / 2) || (radius > width / 2)) + radius = Math.Min(height / 2, width / 2); + + gr.MoveTo(x, y + radius); + gr.Arc(x + radius, y + radius, radius, Math.PI, -Math.PI / 2); + gr.LineTo(x + width - radius, y); + gr.Arc(x + width - radius, y + radius, radius, -Math.PI / 2, 0); + gr.LineTo(x + width, y + height - radius); + gr.Arc(x + width - radius, y + height - radius, radius, 0, Math.PI / 2); + gr.LineTo(x + radius, y + height); + gr.Arc(x + radius, y + height - radius, radius, Math.PI / 2, Math.PI); + gr.ClosePath(); + } + double angle; + public override void GLClear () + { + GL.ClearColor(0.0f, 0.0f, 0.2f, 1.0f); + GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); + } + public override void OnRender (FrameEventArgs e) + { + drawScene (); + } + + protected override void OnUpdateFrame (FrameEventArgs e) + { + base.OnUpdateFrame (e); + + fps = (int)RenderFrequency; + + using (Context ctx = new Context (surf)) { + ctx.LineWidth = 1.0; + ctx.Rectangle (new Rectangle (0, 0, 600, 600)); + DrawRoundedRectangle (ctx, 100, 100, 70, 70, 10); + ctx.Color = go.Color.Green; + ctx.FillPreserve (); + + for (int i = 0; i < 5; i++) { + + + angle += Math.PI / 1000; + if (angle > Math.PI * 2) + angle = 0; + + ctx.Translate (-200, -200); + ctx.Rotate (angle); + ctx.Translate (200, 200); + + //ctx.FillPreserve (); + ctx.Color = go.Color.White; + //ctx.Color.AdjustAlpha (1.0 / i); + ctx.StrokePreserve (); + } + } + //surf.Save (@"/home/jp/test.png"); + //Debug.WriteLine (fps); + this.Title = fps.ToString (); + } + protected override void OnResize (EventArgs e) + { + base.OnResize (e); + UpdateViewMatrix(); + } + + #region Mouse Handling + void Object_Mouse_Move(object sender, MouseMoveEventArgs e){ + if (activeWidget == null) + return; + + activeWidget.registerClipRect (); + if (activeWidget!=null) { + activeWidget.Left += e.XDelta; + activeWidget.Top += e.YDelta; + } + } + void Mouse_Move(object sender, MouseMoveEventArgs e) + { + if (e.XDelta != 0 || e.YDelta != 0) + { + if (e.Mouse.MiddleButton == OpenTK.Input.ButtonState.Pressed) + { + Matrix4 m = Matrix4.CreateRotationZ(-e.XDelta * RotationSpeed); + m *= Matrix4.CreateFromAxisAngle(-vLookPerpendicularOnXYPlane, -e.YDelta * RotationSpeed); + vEyeTarget = Vector3.Zero; + vEye = Vector3.Transform(vEye, Matrix4.CreateTranslation(-vEyeTarget) * m * Matrix4.CreateTranslation(vEyeTarget)); + UpdateViewMatrix(); + } + if (e.Mouse.RightButton == ButtonState.Pressed) + { + + Matrix4 m = Matrix4.CreateRotationZ(-e.XDelta * RotationSpeed); + Matrix4 m2 = Matrix4.Rotate(vLookPerpendicularOnXYPlane, e.YDelta * RotationSpeed); + + vEyeTarget = Vector3.Transform(vEyeTarget, Matrix4.CreateTranslation(-vEye) * m * m2 * Matrix4.CreateTranslation(vEye)); + + //vLook = Vector3.Transform(vLook, m2); + UpdateViewMatrix(); + + } + } + } + void Mouse_WheelChanged(object sender, MouseWheelEventArgs e) + { + float speed = MoveSpeed; + if (Keyboard[Key.ShiftLeft]) + speed *= 0.1f; + else if (Keyboard[Key.ControlLeft]) + speed *= 20.0f; + + vLook = Vector3.NormalizeFast(vEye - vEyeTarget); + vEye -= vLook * e.Delta * speed; + UpdateViewMatrix(); + } + #endregion + + #region vLookCalculations + Vector3 vLookDirOnXYPlane + { + get + { + Vector3 v = Vector3.NormalizeFast(vEye - vEyeTarget); + v.Z = 0; + return v; + } + } + public Vector3 vLookPerpendicularOnXYPlane + { + get + { + Vector3 vLook = Vector3.NormalizeFast(vEye - vEyeTarget); + vLook.Z = 0; + + Vector3 vHorizDir = Vector3.Cross(vLook, Vector3.UnitZ); + return vHorizDir; + } + } + + void moveCamera(Vector3 v) + { + vEye += v; + vEyeTarget += v; + } + #endregion + + public void UpdateViewMatrix() + { +// Rectangle r = this.ClientRectangle; +// GL.Viewport( r.X, r.Y, r.Width, r.Height); +// projection = Matrix4.CreatePerspectiveFieldOfView(fovY, r.Width / (float)r.Height, zNear, zFar); +// GL.MatrixMode(MatrixMode.Projection); +// GL.LoadIdentity(); +// +// GL.LoadMatrix(ref projection); +// +// modelview = Matrix4.LookAt(vEye, vEyeTarget, Vector3.UnitZ); +// GL.MatrixMode(MatrixMode.Modelview); +// GL.LoadIdentity(); +// GL.LoadMatrix(ref modelview); + } + [STAThread] + static void Main () + { + Console.WriteLine ("starting example"); + + using (GOLIBTestglb win = new GOLIBTestglb( )) { + win.Run (30.0); + } + } + } +} +//using (Context ctx = new Context (surf)) { +// //for (int i = 0; i < 150; i++) { +// +// +// // angle += Math.PI / 100000; +// // if (angle > Math.PI * 2) +// // angle = 0; +// //GL. +// //drawScene(); +// +// // ctx.Color = new Color (1.0/i, 1, 0, 1); +// // ctx.Translate (-512, -400); +// // ctx.Rotate (angle); +// // ctx.Translate (512, 400); +// ctx.LineWidth = 1.0; +// ctx.Color = go.Color.LightBlue.AdjustAlpha(0.2); +// // ctx.MoveTo (100, 100); +// // ctx.LineTo (150, 150); +// // ctx.LineTo (300, 100); +// // ctx.LineTo (150, 200); +// // ctx.LineTo (500, 200); +// // ctx.LineTo (400, 100); +// // ctx.LineTo (600, 100); +// // ctx.LineTo (600, 600); +// // ctx.LineTo (200, 600); +// // ctx.LineTo (300, 300); +// // ctx.LineTo (100, 300); +// // //ctx.ClosePath (); +// //ctx.Rectangle(new go.Rectangle(100,600,60,80)); +// +// DrawRoundedRectangle (ctx, 200, 200, 70, 70,10); +// // DrawRoundedRectangle (ctx, 300, 300, 70, 70,5); +// // DrawRoundedRectangle (ctx, 400, 400, 70, 70,25); +// // DrawRoundedRectangle (ctx, 500, 500, 70, 70,25); +// // DrawRoundedRectangle (ctx, 600, 600, 100, 100,25); +// +// +// //**** concave shape +// +// // ctx.LineTo (110, 200); +// // ctx.LineTo (400, 200); +// // ctx.LineTo (400, 100); +// // ctx.LineTo (200, 100); +// // ctx.LineTo (200, 50); +// // ctx.LineTo (500, 50); +// // ctx.LineTo (500, 200); +// // ctx.LineTo (400, 300); +// // ctx.LineTo (100, 300); +// // ctx.LineTo (50, 200); +// ctx.FillPreserve (); +// //***************************** +// +// ctx.Color = go.Color.White; +// //ctx.Stroke (); +// // ctx.LineTo (500, 50); +// // ctx.LineTo (750, 500); +// // ctx.LineTo (750, 50); +// // ctx.MoveTo (100, 100); +// // ctx.LineTo (200, 200); +// // ctx.LineTo (100, 400); +// // ctx.LineTo (300, 400); +// // //ctx.LineTo (250, 300); +// // ctx.Arc (300, 600, 100, 0, Math.PI); +// ctx.Stroke (); +//} +////} diff --git a/Tests/testGLBackend.cs b/Tests/testGLBackend.cs new file mode 100644 index 00000000..9d38da8b --- /dev/null +++ b/Tests/testGLBackend.cs @@ -0,0 +1,494 @@ +#define MONO_CAIRO_DEBUG_DISPOSE + + +using System; +using System.Runtime.InteropServices; +using OpenTK; +using OpenTK.Graphics.OpenGL; +using OpenTK.Input; + +using System.Diagnostics; + +using go; +using System.Threading; +using GGL; +//using Cairo; +using Crow.GLBackend; + +namespace testGLBackend +{ + class GOLIBTestglb : OpenTKGameWindow + { + #region FPS + static int _fps = 0; + + public static int fps { + get { return _fps; } + set { + _fps = value; + if (_fps > fpsMax) + fpsMax = _fps; + else if (_fps < fpsMin) + fpsMin = _fps; + } + + } + + public static int fpsMin = int.MaxValue; + public static int fpsMax = 0; + + static void resetFps () + { + fpsMin = int.MaxValue; + fpsMax = 0; + _fps = 0; + } + #endregion + + public float coef1 = 1.0f; + public float coef2 = 0.5f; + public float coef3 = 0.0f; + public float coefA = 1.0f; + + Color foreground = Color.Black; + Color background = Color.White; + + public GOLIBTestglb () + : base(1024, 800) + { + VSync = VSyncMode.Off; + } + + #region scene matrix and vectors + public static Matrix4 modelview; + public static Matrix4 projection; + + public static Vector3 vEye = new Vector3(5.0f, 5.0f, 5.0f); // Camera Position + public static Vector3 vEyeTarget = Vector3.Zero; + public static Vector3 vLook = new Vector3(0f, 1f, -0.7f); // Camera vLook Vector + + float _zFar = 6400.0f; + + public float zFar { + get { return _zFar; } + set { + _zFar = value; + } + } + + public float zNear = 0.1f; + public float fovY = (float)Math.PI / 4; + + float MoveSpeed = 0.5f; + float RotationSpeed = 0.02f; + #endregion + + Context ctx; + Surface surf; + + QuadVAO testQuad; + QuadVAO magnifierQuad; + int magTex; //mignified texture + Crow.GLBackend.Shader shade; + Matrix4 projectionMatrix, + modelviewMatrix; + Texture testTex; + + + void drawScene() + { + shade.Enable (); + //shader.LineWidth = lineWidth; + shade.ProjectionMatrix = projectionMatrix; + shade.ModelViewMatrix = modelviewMatrix; + shade.Color = new Vector4(1f,1f,1f,1f); + + GL.ActiveTexture (TextureUnit.Texture0); + GL.BindTexture(TextureTarget.Texture2D, surf.texId); + //GL.BindTexture(TextureTarget.Texture2D, FontFace.testTexture); + + testQuad.Render (PrimitiveType.TriangleStrip); + + GL.BindTexture(TextureTarget.Texture2D, magTex); + magnifierQuad.Render (PrimitiveType.TriangleStrip); + + GL.BindTexture(TextureTarget.Texture2D, 0); + + //shader.Disable (); + } + glFont testFont; + + protected override void OnLoad (EventArgs e) + { + base.OnLoad (e); + + + Mouse.WheelChanged += new EventHandler(Mouse_WheelChanged); + Mouse.Move += new EventHandler(Mouse_Move); + + GL.Viewport (0, 0, ClientRectangle.Width, ClientRectangle.Height); + GL.ClearColor(0.0f, 0.0f, 0.2f, 1.0f); + + //GL.Enable(EnableCap.DepthTest); + //GL.DepthFunc(DepthFunction.Less); + //GL.Enable(EnableCap.CullFace); + //GL.Enable(EnableCap.Texture2D); + + + + //GL.FrontFace(FrontFaceDirection.Ccw); + + //GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest); + //GL.ShadeModel(ShadingModel.Smooth); + //GL.Hint (HintTarget.LineSmoothHint, HintMode.Nicest); + ErrorCode err = GL.GetError (); + Debug.Assert (err == ErrorCode.NoError, "OpenGL Error"); + + surf = new Surface (Format.Argb32, 512, 512); + + testQuad = new QuadVAO (0, 0, 512, 512); + magnifierQuad = new QuadVAO (150, 300, 400, 400,1.1f,0.73f,0.05f,0.05f); + + shade = new TexturedShader (); + + projectionMatrix = Matrix4.CreateOrthographicOffCenter + (0, ClientRectangle.Width, ClientRectangle.Height, 0, 0, 1); + modelviewMatrix = Matrix4.Identity; + + testTex = new Texture (rootDir + @"Images/texture/structures/639-diffuse.jpg"); + //string[] extensions = GL.GetString(StringName.Version).Split(' '); + FontFace.BuildFontsList(@"/usr/share/fonts/truetype/"); + //glFont.dumpFontsDirectories (@"/usr/share/fonts/"); + //glFont.dumpFontsDirectories (@"/usr/share/fonts/opentype"); + LoadInterface("Interfaces/test0.goml"); + + //testFont = new glFont (@"/usr/share/fonts/truetype/droid/DroidSans-Bold.ttf"); + } + + public static void DrawRoundedRectangle(Context gr, double x, double y, double width, double height, double radius) + { + + if ((radius > height / 2) || (radius > width / 2)) + radius = Math.Min(height / 2, width / 2); + + gr.MoveTo(x, y + radius); + gr.Arc(x + radius, y + radius, radius, Math.PI, -Math.PI / 2); + gr.LineTo(x + width - radius, y); + gr.Arc(x + width - radius, y + radius, radius, -Math.PI / 2, 0); + gr.LineTo(x + width, y + height - radius); + gr.Arc(x + width - radius, y + height - radius, radius, 0, Math.PI / 2); + gr.LineTo(x + radius, y + height); + gr.Arc(x + radius, y + height - radius, radius, Math.PI / 2, Math.PI); + gr.ClosePath(); + } + double angle; + public override void GLClear () + { + GL.ClearColor(1.0f, 0.0f, 0.2f, 1.0f); + GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); + } + public override void OnRender (FrameEventArgs e) + { + drawScene (); + } + protected override void OnUpdateFrame (FrameEventArgs e) + { + base.OnUpdateFrame (e); + + fps = (int)RenderFrequency; + + using (Context ctx = new Context (surf)) { + ctx.coef1 = coef1; + ctx.coef2 = coef2; + ctx.coef3 = coef3; + ctx.coefA = coefA; + + ctx.Rectangle(new Rectangle(0,0,512,512)); + ctx.Color = background;//new Color(1.0,0.1,0.2,1); + ctx.Fill (); + ctx.LineWidth = 1.0; + ctx.Color = foreground; + ctx.SelectFontFace ("courier new", FontSlant.Normal, FontWeight.Normal); + ctx.SetFontSize (6); + ctx.FillText ("Test d'une string a petite échelle", new Point (50, 50)); + ctx.SetFontSize (8); + ctx.FillText ("Test d'une string a petite échelle", new Point (50, 60)); + ctx.SetFontSize (10); + ctx.FillText ("Test d'une string a petite échelle", new Point (50, 70)); + ctx.SetFontSize (12); + ctx.FillText ("Test d'une string a petite échelle", new Point (50, 85)); + ctx.SetFontSize (14); + ctx.FillText ("Test d'une string a petite échelle", new Point (50, 100)); + + ctx.FillText ("c1: " + string.Format("{0:##.000}",coef1), new Point (300, 100)); + ctx.FillText ("c2: " + string.Format("{0:##.000}",coef2), new Point (300, 120)); + ctx.FillText ("c3: " + string.Format("{0:##.000}",coef3), new Point (300, 140)); + ctx.FillText ("cA: " + string.Format("{0:##.000}",coefA), new Point (300, 160)); + + ctx.Rectangle(new Rectangle(10,10,40,100)); + ctx.Stroke (); + ctx.SetFontSize (40); + ctx.FillText ("ceci est un test de string", new Point (2, 200)); + ctx.Fill (); +// ctx.LineWidth = 1.0; +// ctx.MoveTo (300, 10); +// ctx.LineTo (300, 350); +// ctx.Color = new Color (1.0, 0.5, 0.0, 1.0); +// ctx.Stroke (); +// ctx.MoveTo (301, 10); +// ctx.LineTo (301, 350); +// ctx.Color = new Color (0.0, 0.5, 1.0, 1.0); +// ctx.Stroke (); +// ctx.Rectangle(new Rectangle(100,100,200,200)); + //ctx.Clip (); +// for (int i = 0; i < 25; i++) { +// +// +// angle += Math.PI / 10000; +// if (angle > Math.PI * 2) +// angle = 0; +// +// +// ctx.Color = new Color (1.0 / i, 1, 0, 0.1); +// ctx.Translate (-200, -200); +// ctx.Rotate (angle); +// ctx.Translate (200, 200); +// +// +// ctx.Rectangle (new Rectangle (0, 0, 400, 400)); +// DrawRoundedRectangle (ctx, 100, 100, 70, 70, 10); +// ctx.FillPreserve (); +// ctx.Color = go.Color.White; +// ctx.Stroke (); +// } + surf.Save (@"/home/jp/surf.png"); + + if (GL.IsTexture(magTex)) + GL.DeleteTexture(magTex); + + magTex = ctx.copyCurentSurfaceToTexture (); + +// GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); +// GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); +// + } + + float inc = 0.01f; + if (Keyboard [Key.ShiftLeft]) + inc = 0.1f; + if (Keyboard[Key.Keypad1]) + coef1 -= inc; + if (Keyboard[Key.Keypad2]) + coef2 -= inc; + if (Keyboard[Key.Keypad3]) + coef3 -= inc; + if (Keyboard[Key.Keypad4]) + coef1 = 0f; + if (Keyboard[Key.Keypad5]) + coef2 = 0f; + if (Keyboard[Key.Keypad6]) + coef3 = 0f; + if (Keyboard[Key.Keypad7]) + coef1 += inc; + if (Keyboard[Key.Keypad8]) + coef2 += inc; + if (Keyboard[Key.Keypad9]) + coef3 += inc; + if (Keyboard[Key.KeypadAdd]) + coefA += inc; + if (Keyboard[Key.KeypadSubtract]) + coefA -= inc; + //Debug.WriteLine (fps); + + } + protected override void OnKeyPress (KeyPressEventArgs e) + { + base.OnKeyPress (e); + if (e.KeyChar == 'c') { + if (background == Color.Black) { + background = Color.White; + foreground = Color.Black; + } else { + background = Color.Black; + foreground = Color.White; + } + } + } + protected override void OnResize (EventArgs e) + { + base.OnResize (e); + UpdateViewMatrix(); + } + + #region Mouse Handling + void Object_Mouse_Move(object sender, MouseMoveEventArgs e){ + if (activeWidget == null) + return; + + activeWidget.registerClipRect (); + if (activeWidget!=null) { + activeWidget.Left += e.XDelta; + activeWidget.Top += e.YDelta; + } + } + void Mouse_Move(object sender, MouseMoveEventArgs e) + { + if (e.XDelta != 0 || e.YDelta != 0) + { + if (e.Mouse.MiddleButton == OpenTK.Input.ButtonState.Pressed) + { + Matrix4 m = Matrix4.CreateRotationZ(-e.XDelta * RotationSpeed); + m *= Matrix4.CreateFromAxisAngle(-vLookPerpendicularOnXYPlane, -e.YDelta * RotationSpeed); + vEyeTarget = Vector3.Zero; + vEye = Vector3.Transform(vEye, Matrix4.CreateTranslation(-vEyeTarget) * m * Matrix4.CreateTranslation(vEyeTarget)); + UpdateViewMatrix(); + } + if (e.Mouse.RightButton == ButtonState.Pressed) + { + + Matrix4 m = Matrix4.CreateRotationZ(-e.XDelta * RotationSpeed); + Matrix4 m2 = Matrix4.Rotate(vLookPerpendicularOnXYPlane, e.YDelta * RotationSpeed); + + vEyeTarget = Vector3.Transform(vEyeTarget, Matrix4.CreateTranslation(-vEye) * m * m2 * Matrix4.CreateTranslation(vEye)); + + //vLook = Vector3.Transform(vLook, m2); + UpdateViewMatrix(); + + } + } + } + void Mouse_WheelChanged(object sender, MouseWheelEventArgs e) + { + float speed = MoveSpeed; + if (Keyboard[Key.ShiftLeft]) + speed *= 0.1f; + else if (Keyboard[Key.ControlLeft]) + speed *= 20.0f; + + vLook = Vector3.NormalizeFast(vEye - vEyeTarget); + vEye -= vLook * e.Delta * speed; + UpdateViewMatrix(); + } + #endregion + + #region vLookCalculations + Vector3 vLookDirOnXYPlane + { + get + { + Vector3 v = Vector3.NormalizeFast(vEye - vEyeTarget); + v.Z = 0; + return v; + } + } + public Vector3 vLookPerpendicularOnXYPlane + { + get + { + Vector3 vLook = Vector3.NormalizeFast(vEye - vEyeTarget); + vLook.Z = 0; + + Vector3 vHorizDir = Vector3.Cross(vLook, Vector3.UnitZ); + return vHorizDir; + } + } + + void moveCamera(Vector3 v) + { + vEye += v; + vEyeTarget += v; + } + #endregion + + public void UpdateViewMatrix() + { +// Rectangle r = this.ClientRectangle; +// GL.Viewport( r.X, r.Y, r.Width, r.Height); +// projection = Matrix4.CreatePerspectiveFieldOfView(fovY, r.Width / (float)r.Height, zNear, zFar); +// GL.MatrixMode(MatrixMode.Projection); +// GL.LoadIdentity(); +// +// GL.LoadMatrix(ref projection); +// +// modelview = Matrix4.LookAt(vEye, vEyeTarget, Vector3.UnitZ); +// GL.MatrixMode(MatrixMode.Modelview); +// GL.LoadIdentity(); +// GL.LoadMatrix(ref modelview); + } + [STAThread] + static void Main () + { + Console.WriteLine ("starting example"); + + using (GOLIBTestglb win = new GOLIBTestglb( )) { + win.Run (30.0); + } + } + } +} +//using (Context ctx = new Context (surf)) { +// //for (int i = 0; i < 150; i++) { +// +// +// // angle += Math.PI / 100000; +// // if (angle > Math.PI * 2) +// // angle = 0; +// //GL. +// //drawScene(); +// +// // ctx.Color = new Color (1.0/i, 1, 0, 1); +// // ctx.Translate (-512, -400); +// // ctx.Rotate (angle); +// // ctx.Translate (512, 400); +// ctx.LineWidth = 1.0; +// ctx.Color = go.Color.LightBlue.AdjustAlpha(0.2); +// // ctx.MoveTo (100, 100); +// // ctx.LineTo (150, 150); +// // ctx.LineTo (300, 100); +// // ctx.LineTo (150, 200); +// // ctx.LineTo (500, 200); +// // ctx.LineTo (400, 100); +// // ctx.LineTo (600, 100); +// // ctx.LineTo (600, 600); +// // ctx.LineTo (200, 600); +// // ctx.LineTo (300, 300); +// // ctx.LineTo (100, 300); +// // //ctx.ClosePath (); +// //ctx.Rectangle(new go.Rectangle(100,600,60,80)); +// +// DrawRoundedRectangle (ctx, 200, 200, 70, 70,10); +// // DrawRoundedRectangle (ctx, 300, 300, 70, 70,5); +// // DrawRoundedRectangle (ctx, 400, 400, 70, 70,25); +// // DrawRoundedRectangle (ctx, 500, 500, 70, 70,25); +// // DrawRoundedRectangle (ctx, 600, 600, 100, 100,25); +// +// +// //**** concave shape +// +// // ctx.LineTo (110, 200); +// // ctx.LineTo (400, 200); +// // ctx.LineTo (400, 100); +// // ctx.LineTo (200, 100); +// // ctx.LineTo (200, 50); +// // ctx.LineTo (500, 50); +// // ctx.LineTo (500, 200); +// // ctx.LineTo (400, 300); +// // ctx.LineTo (100, 300); +// // ctx.LineTo (50, 200); +// ctx.FillPreserve (); +// //***************************** +// +// ctx.Color = go.Color.White; +// //ctx.Stroke (); +// // ctx.LineTo (500, 50); +// // ctx.LineTo (750, 500); +// // ctx.LineTo (750, 50); +// // ctx.MoveTo (100, 100); +// // ctx.LineTo (200, 200); +// // ctx.LineTo (100, 400); +// // ctx.LineTo (300, 400); +// // //ctx.LineTo (250, 300); +// // ctx.Arc (300, 600, 100, 0, Math.PI); +// ctx.Stroke (); +//} +////}