aboutsummaryrefslogtreecommitdiffstatsci
path: root/OTKCrow/OpenGL
diff options
context:
space:
mode:
authorjpbruyere <jp.bruyere@hotmail.com>2016-04-22 12:19:40 +0200
committerjpbruyere <jp.bruyere@hotmail.com>2016-04-22 12:19:40 +0200
commit68056c452876b77bb443e89f49b6dd52ca50cfbb (patch)
tree7d6ef98f0dc7e688fe85b8b07701c1357962807b /OTKCrow/OpenGL
parent88769581ad8993ae9e3b1cb60ccbdc4cb5008fe7 (diff)
copy old glbackend files, no changes made for now, not workingtestglbackend2
Diffstat (limited to 'OTKCrow/OpenGL')
-rw-r--r--OTKCrow/OpenGL/GLBackend/ClipShader.cs41
-rw-r--r--OTKCrow/OpenGL/GLBackend/Context.cs887
-rw-r--r--OTKCrow/OpenGL/GLBackend/Font/Font.cs115
-rw-r--r--OTKCrow/OpenGL/GLBackend/Font/FontExtents.cs39
-rw-r--r--OTKCrow/OpenGL/GLBackend/Font/FontFace.cs307
-rw-r--r--OTKCrow/OpenGL/GLBackend/Font/FontFlag.cs18
-rw-r--r--OTKCrow/OpenGL/GLBackend/Font/FontShader (copier).cs146
-rw-r--r--OTKCrow/OpenGL/GLBackend/Font/FontShader.cs128
-rw-r--r--OTKCrow/OpenGL/GLBackend/Font/FontSlant.cs42
-rw-r--r--OTKCrow/OpenGL/GLBackend/Font/FontStyle.cs15
-rw-r--r--OTKCrow/OpenGL/GLBackend/Font/FontWeight.cs41
-rw-r--r--OTKCrow/OpenGL/GLBackend/Font/TextExtents.cs98
-rw-r--r--OTKCrow/OpenGL/GLBackend/Font/glFont.cs90
-rw-r--r--OTKCrow/OpenGL/GLBackend/Font/glGlyph.cs22
-rw-r--r--OTKCrow/OpenGL/GLBackend/Path.cs18
-rw-r--r--OTKCrow/OpenGL/GLBackend/Shader (copier).cs135
-rw-r--r--OTKCrow/OpenGL/GLBackend/Surface.cs103
17 files changed, 2245 insertions, 0 deletions
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<glFont> fontsCache = new List<glFont>();
+
+ #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<Path> pathes = new List<Path> ();
+ 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){
+ a+=step;
+ 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<Vector2> vertices = new List<Vector2> ();
+ List<int> indices = new List<int> ();
+ List<Vector2> texCoords = new List<Vector2> ();
+ int idxOffset = 0; //offset in vertices array between pathes
+
+
+ void initVAOsCache()
+ {
+ if (vertices != null)
+ return;
+ vertices = new List<Vector2> ();
+ indices = new List<int> ();
+ texCoords = new List<Vector2> ();
+ 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<int> vertIdx = new List<int> (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<FontFlag> (attribs [i], true, out fl))
+ f.Flags |= fl;
+ else if (Enum.TryParse<FontStyle> (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<FontFace> fonts = new List<FontFace>();
+ public Dictionary<uint,Dictionary<uint, glGlyph>> glyphesCache = new Dictionary<uint, Dictionary<uint, glGlyph>>();
+
+ #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<FontFlag> (styles [i], true, out fl))
+ font.Flags |= fl;
+ else if (Enum.TryParse<FontStyle> (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<FontFlag>(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<uint, glGlyph>();
+
+ 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<endChar;c++)
+ {
+ uint glyphIndex = face.GetCharIndex((uint)c);
+ if (glyphIndex==0)
+ continue;
+ //face.LoadChar((uint)c, LoadFlags.Render, LoadTarget.Normal);
+ face.LoadGlyph(glyphIndex, LoadFlags.Render, LoadTarget.Normal);
+ testTexture = texPage;
+
+ GlyphSlot slot = face.Glyph;
+ FTBitmap bmp = slot.Bitmap;
+
+ if (penX+bmp.Width > 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<bmp.Rows; y++)
+ {
+ for(int x=0; x<bmp.Width; x++)
+ buffer[ penX + x + (penY + y)* FONT_TEX_SIZE ] =
+ bmp.BufferData[x + y * bmp.Width];
+ }
+ glyphesCache [activeSize][c] = new glGlyph()
+ {
+ texId = texPage,
+ texX = (float)penX / FONT_TEX_SIZE,
+ texY = (float)penY / FONT_TEX_SIZE,
+ texWidth = (float)(bmp.Width) / FONT_TEX_SIZE,
+ texHeight = (float)(bmp.Rows) / FONT_TEX_SIZE,
+
+// texCoord = new Rectangle(
+// penX / FONT_TEX_SIZE,
+// penY / FONT_TEX_SIZE,
+// (bmp.Width) / FONT_TEX_SIZE,
+// (bmp.Rows) / FONT_TEX_SIZE),
+ dims = new Size(bmp.Width , bmp.Rows),
+ bmpLeft = slot.BitmapLeft, bmpTop = slot.BitmapTop, advanceX = slot.Advance.X>>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<int, glGlyph> glyphs = new Dictionary<int,glGlyph>();
+
+ public static void dumpFontsDirectories(string _path)
+ {
+ List<string> stylesList = new List<string> ();
+ List<string> namesList = new List<string> ();
+ List<string> attribsList = new List<string> ();
+
+ 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<Vector2>
+ {
+ public bool IsClosed;
+
+ public Path () : base()
+ {
+ }
+ public Path (IEnumerable<Vector2> 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
+ }
+}
+