public PositionFromIndex Z = null; //Z isn't used unless the VBO object has PositionDimensions set to 3. #endregion Fields #region Methods public static CellLayout Create(Surface s,int cell_height_px,int cell_width_px,int v_offset_px,int h_offset_px,PositionFromIndex x,PositionFromIndex y,PositionFromIndex z = null) { CellLayout c = new CellLayout(); //todo: fix x/y order for entire file? c.CellHeightPx = cell_height_px; c.CellWidthPx = cell_width_px; c.VerticalOffsetPx = v_offset_px; c.HorizontalOffsetPx = h_offset_px; c.X = x; c.Y = y; c.Z = z; if(s != null){ s.layouts.Add(c); } return c; }
public static CellLayout CreateGrid(Surface s,int rows,int cols,int cell_height_px,int cell_width_px,int v_offset_px,int h_offset_px,PositionFromIndex z = null) { CellLayout c = new CellLayout(); c.CellHeightPx = cell_height_px; c.CellWidthPx = cell_width_px; c.VerticalOffsetPx = v_offset_px; c.HorizontalOffsetPx = h_offset_px; c.X = idx => (idx % cols) * c.CellWidthPx; c.Y = idx => (idx / cols) * c.CellHeightPx; c.Z = z; if(s != null){ s.layouts.Add(c); } return c; }
public TextPanel(GLWindow parent_window,int rows,int cols,int cell_h_px,int cell_w_px,int v_offset_px,int h_offset_px,string font_filename,int char_width_px,int padding_between_chars_px,bool antialiased_font) { memory = new PosArray<colorchar>(rows,cols); colorchar cch = TextPanel.GetBlackChar(); for(int i=0;i<rows;++i){ for(int j=0;j<cols;++j){ memory[i,j] = cch; } } height = rows * cell_h_px; width = cols * cell_w_px; string shader = antialiased_font? Shader.AAFontFS() : Shader.FontFS(); surface = Surface.Create(parent_window,font_filename,shader,false,2,4,4); //todo: maybe a bool to control whether the panel gets added to the window's list? SpriteType.DefineSingleRowSprite(surface,char_width_px,padding_between_chars_px); //also todo, TransparentFontFS exists now...? CellLayout.CreateGrid(surface,rows,cols,cell_h_px,cell_w_px,0,0); surface.SetOffsetInPixels(h_offset_px,v_offset_px); surface.SetEasyLayoutCounts(rows*cols); surface.DefaultUpdatePositions(); UpdateSurface(0,rows*cols-1); }
public static SpriteType DefineSpriteDown(Surface surface,int sprite_width_px,int sprite_height_px,int num_rows,int h_offset_px,int v_offset_px) { SpriteType s = new SpriteType(); float texcoord_width = (float)sprite_width_px * 1.0f / (float)surface.texture.TextureWidthPx; float texcoord_height = (float)sprite_height_px * 1.0f / (float)surface.texture.TextureHeightPx; s.X = idx => ((idx / num_rows) * sprite_width_px + h_offset_px) * 1.0f / (float)surface.texture.TextureWidthPx; s.Y = idx => ((idx % num_rows) * sprite_height_px + v_offset_px) * 1.0f / (float)surface.texture.TextureHeightPx; s.SpriteWidth = texcoord_width; s.SpriteHeight = texcoord_height; if(surface != null){ surface.texture.Sprite.Add(s); } return s; }
public static CellLayout CreateIso(Surface s,int rows,int cols,int cell_height_px,int cell_width_px,int v_offset_px,int h_offset_px,int cell_v_offset_px,int cell_h_offset_px,PositionFromIndex z = null,PositionFromIndex elevation = null) { CellLayout c = new CellLayout(); c.CellHeightPx = cell_height_px; c.CellWidthPx = cell_width_px; c.VerticalOffsetPx = v_offset_px; c.HorizontalOffsetPx = h_offset_px; c.X = idx => (rows - 1 - (idx/cols) + (idx%cols)) * cell_h_offset_px; if(elevation == null){ c.Y = idx => ((idx/cols) + (idx%cols)) * cell_v_offset_px; } else{ c.Y = idx => ((idx/cols) + (idx%cols)) * cell_v_offset_px + elevation(idx); } c.Z = z; if(s != null){ s.layouts.Add(c); } return c; }
public static SpriteType DefineSpriteAcross(Surface surface,int sprite_width_px,int sprite_height_px,int num_columns) { SpriteType s = new SpriteType(); float texcoord_width = (float)sprite_width_px * 1.0f / (float)surface.texture.TextureWidthPx; float texcoord_height = (float)sprite_height_px * 1.0f / (float)surface.texture.TextureHeightPx; s.X = idx => (idx % num_columns) * texcoord_width; s.Y = idx => (idx / num_columns) * texcoord_height; s.SpriteWidth = texcoord_width; s.SpriteHeight = texcoord_height; if(surface != null){ surface.texture.Sprite.Add(s); } return s; }
public static SpriteType DefineSingleRowSprite(Surface surface,int sprite_width_px,int padding_between_sprites_px) { SpriteType s = new SpriteType(); float px_width = 1.0f / (float)surface.texture.TextureWidthPx; float texcoord_width = (float)sprite_width_px * px_width; float texcoord_start = texcoord_width + (float)padding_between_sprites_px * px_width; s.X = idx => idx * texcoord_start; s.Y = idx => 0; s.SpriteWidth = texcoord_width; s.SpriteHeight = 1.0f; if(surface != null){ surface.texture.Sprite.Add(s); } return s; }
/*public static void ReplaceTexture(int texture_unit,string filename){ //binds a texture to the given texture unit, replacing the texture that's already there if(String.IsNullOrEmpty(filename)){ throw new ArgumentException(filename); } GL.ActiveTexture(TextureUnit.Texture0 + texture_unit); int id = GL.GenTexture(); GL.BindTexture(TextureTarget.Texture2D,id); Bitmap bmp = new Bitmap(filename); BitmapData bmp_data = bmp.LockBits(new Rectangle(0,0,bmp.Width,bmp.Height),ImageLockMode.ReadOnly,System.Drawing.Imaging.PixelFormat.Format32bppArgb); GL.TexImage2D(TextureTarget.Texture2D,0,PixelInternalFormat.Rgba,bmp_data.Width,bmp_data.Height,0,OpenTK.Graphics.OpenGL.PixelFormat.Bgra,PixelType.UnsignedByte,bmp_data.Scan0); bmp.UnlockBits(bmp_data); GL.TexParameter(TextureTarget.Texture2D,TextureParameterName.TextureMinFilter,(int)TextureMinFilter.Nearest); GL.TexParameter(TextureTarget.Texture2D,TextureParameterName.TextureMagFilter,(int)TextureMagFilter.Nearest); }*/ public void UpdatePositionVertexArray(Surface s,IList<int> index_list,IList<int> layout_list = null) { UpdatePositionVertexArray(s,-1,index_list,layout_list); }
public void UpdatePositionVertexArray(Surface s,int start_index,IList<int> index_list,IList<int> layout_list = null) { int count = index_list.Count; if(layout_list == null){ layout_list = new int[count]; //if not supplied, assume layout 0. } float[] values = new float[count * 4 * s.vbo.PositionDimensions]; //2 or 3 dimensions for 4 vertices for each tile int[] indices = null; if(start_index < 0 && s.vbo.NumElements != count * 6){ indices = new int[count * 6]; s.vbo.NumElements = count * 6; } else{ if(start_index >= 0){ if((start_index + count) * 6 > s.vbo.NumElements && s.vbo.NumElements > 0){ throw new ArgumentException("Error: start_index + count is bigger than VBO size. To always replace the previous data, set start_index to -1."); } //todo: I could also just ignore the start_index if there's too much data. if((start_index + count) * 4 * s.vbo.PositionDimensions > s.vbo.PositionDataSize && s.vbo.PositionDataSize > 0){ throw new ArgumentException("Error: (start_index + count) * total_attrib_size is bigger than VBO size. To always replace the previous data, set start_index to -1."); } } } float width_ratio = 2.0f / (float)ClientRectangle.Width; //todo: eventually this part might not be based on the current window. Seems like a good idea. float height_ratio = 2.0f / (float)ClientRectangle.Height; int current_total = 0; foreach(int i in index_list){ float x_offset = (float)s.layouts[layout_list[current_total]].HorizontalOffsetPx; float y_offset = (float)s.layouts[layout_list[current_total]].VerticalOffsetPx; float x_w = (float)s.layouts[layout_list[current_total]].CellWidthPx; float y_h = (float)s.layouts[layout_list[current_total]].CellHeightPx; float cellx = s.layouts[layout_list[current_total]].X(i) + x_offset; float celly = s.layouts[layout_list[current_total]].Y(i) + y_offset; float x = cellx * width_ratio - 1.0f; float y = celly * height_ratio - 1.0f; float x_plus1 = (cellx + x_w) * width_ratio - 1.0f; float y_plus1 = (celly + y_h) * height_ratio - 1.0f; int N = s.vbo.PositionDimensions; int idxN = current_total * 4 * N; values[idxN] = x; //the 4 corners, flipped so it works with the inverted Y axis values[idxN + 1] = y_plus1; values[idxN + N] = x; values[idxN + N + 1] = y; values[idxN + N*2] = x_plus1; values[idxN + N*2 + 1] = y; values[idxN + N*3] = x_plus1; values[idxN + N*3 + 1] = y_plus1; if(N == 3){ float z = s.layouts[layout_list[current_total]].Z(i); values[idxN + 2] = z; values[idxN + N + 2] = z; values[idxN + N*2 + 2] = z; values[idxN + N*3 + 2] = z; } if(indices != null){ int idx4 = current_total * 4; int idx6 = current_total * 6; indices[idx6] = idx4; indices[idx6 + 1] = idx4 + 1; indices[idx6 + 2] = idx4 + 2; indices[idx6 + 3] = idx4; indices[idx6 + 4] = idx4 + 2; indices[idx6 + 5] = idx4 + 3; } current_total++; } GL.BindBuffer(BufferTarget.ArrayBuffer,s.vbo.PositionArrayBufferID); if((start_index < 0 && s.vbo.PositionDataSize != values.Length) || s.vbo.PositionDataSize == 0){ GL.BufferData(BufferTarget.ArrayBuffer,new IntPtr(sizeof(float)*values.Length),values,BufferUsageHint.StreamDraw); s.vbo.PositionDataSize = values.Length; } else{ int offset = start_index; if(offset < 0){ offset = 0; } GL.BufferSubData(BufferTarget.ArrayBuffer,new IntPtr(sizeof(float) * 4 * s.vbo.PositionDimensions * offset),new IntPtr(sizeof(float) * values.Length),values); //GL.BufferSubData(BufferTarget.ArrayBuffer,new IntPtr(0),new IntPtr(sizeof(float) * values.Length),values); } if(indices != null){ GL.BindBuffer(BufferTarget.ElementArrayBuffer,s.vbo.ElementArrayBufferID); GL.BufferData(BufferTarget.ElementArrayBuffer,new IntPtr(sizeof(int)*indices.Length),indices,BufferUsageHint.StaticDraw); } }
public void UpdatePositionSingleVertex(Surface s,int index,int layout = 0) { float[] values = new float[4 * s.vbo.PositionDimensions]; //2 or 3 dimensions for 4 vertices float width_ratio = 2.0f / (float)ClientRectangle.Width; //todo: eventually this part might not be based on the current window. Seems like a good idea. float height_ratio = 2.0f / (float)ClientRectangle.Height; float x_offset = (float)s.layouts[layout].HorizontalOffsetPx; float y_offset = (float)s.layouts[layout].VerticalOffsetPx; float x_w = (float)s.layouts[layout].CellWidthPx; float y_h = (float)s.layouts[layout].CellHeightPx; float cellx = s.layouts[layout].X(index) + x_offset; float celly = s.layouts[layout].Y(index) + y_offset; float x = cellx * width_ratio - 1.0f; float y = celly * height_ratio - 1.0f; float x_plus1 = (cellx + x_w) * width_ratio - 1.0f; float y_plus1 = (celly + y_h) * height_ratio - 1.0f; int N = s.vbo.PositionDimensions; values[0] = x; //the 4 corners, flipped so it works with the inverted Y axis values[1] = y_plus1; values[N] = x; values[N + 1] = y; values[N*2] = x_plus1; values[N*2 + 1] = y; values[N*3] = x_plus1; values[N*3 + 1] = y_plus1; if(N == 3){ float z = s.layouts[layout].Z(index); values[2] = z; values[N + 2] = z; values[N*2 + 2] = z; values[N*3 + 2] = z; } GL.BindBuffer(BufferTarget.ArrayBuffer,s.vbo.PositionArrayBufferID); GL.BufferSubData(BufferTarget.ArrayBuffer,new IntPtr(sizeof(float) * 4 * s.vbo.PositionDimensions * index),new IntPtr(sizeof(float) * values.Length),values); }
public void UpdateOtherVertexArray(Surface s,int start_index,IList<int> sprite_index,IList<int> sprite_type,params IList<float>[] vertex_attributes) { int count = sprite_index.Count; int a = s.vbo.VertexAttribs.TotalSize; int a4 = a * 4; if(start_index >= 0 && (start_index + count) * a4 > s.vbo.OtherDataSize && s.vbo.OtherDataSize > 0){ throw new ArgumentException("Error: (start_index + count) * total_attrib_size is bigger than VBO size. To always replace the previous data, set start_index to -1."); } if(sprite_type == null){ sprite_type = new int[sprite_index.Count]; } float[] all_values = new float[count * a4]; for(int i=0;i<count;++i){ SpriteType sprite = s.texture.Sprite[sprite_type[i]]; float tex_start_x = sprite.X(sprite_index[i]); float tex_start_y = sprite.Y(sprite_index[i]); float tex_end_x = tex_start_x + sprite.SpriteWidth; float tex_end_y = tex_start_y + sprite.SpriteHeight; float[] values = new float[a4]; values[0] = tex_start_x; //the 4 corners, texcoords: values[1] = tex_end_y; values[a] = tex_start_x; values[a + 1] = tex_start_y; values[a*2] = tex_end_x; values[a*2 + 1] = tex_start_y; values[a*3] = tex_end_x; values[a*3 + 1] = tex_end_y; int prev_total = 2; for(int g=1;g<s.vbo.VertexAttribs.Size.Length;++g){ //starting at 1 because texcoords are already done int attrib_size = s.vbo.VertexAttribs.Size[g]; for(int k=0;k<attrib_size;++k){ float attrib = vertex_attributes[g-1][k + i*attrib_size]; // -1 because the vertex_attributes array doesn't contain texcoords here in the update method. values[prev_total + k] = attrib; values[prev_total + k + a] = attrib; values[prev_total + k + a*2] = attrib; values[prev_total + k + a*3] = attrib; } prev_total += attrib_size; } values.CopyTo(all_values,i * a4); } GL.BindBuffer(BufferTarget.ArrayBuffer,s.vbo.OtherArrayBufferID); if((start_index < 0 && s.vbo.OtherDataSize != a4 * count) || s.vbo.OtherDataSize == 0){ GL.BufferData(BufferTarget.ArrayBuffer,new IntPtr(sizeof(float) * a4 * count),all_values,BufferUsageHint.StreamDraw); s.vbo.OtherDataSize = a4 * count; } else{ int offset = start_index; if(offset < 0){ offset = 0; } GL.BufferSubData(BufferTarget.ArrayBuffer,new IntPtr(sizeof(float) * a4 * offset),new IntPtr(sizeof(float) * a4 * count),all_values); //GL.BufferSubData(BufferTarget.ArrayBuffer,new IntPtr(0),new IntPtr(sizeof(float) * a4 * count),all_values); } }
public void UpdateOtherVertexArray(Surface s,IList<int> sprite_index,params IList<float>[] vertex_attributes) { UpdateOtherVertexArray(s,-1,sprite_index,new int[sprite_index.Count],vertex_attributes); //default to sprite type 0. }
public void UpdateOtherSingleVertex(Surface s,int index,int sprite_index,int sprite_type,params IList<float>[] vertex_attributes) { int a = s.vbo.VertexAttribs.TotalSize; int a4 = a * 4; float[] values = new float[a4]; SpriteType sprite = s.texture.Sprite[sprite_type]; float tex_start_x = sprite.X(sprite_index); float tex_start_y = sprite.Y(sprite_index); float tex_end_x = tex_start_x + sprite.SpriteWidth; float tex_end_y = tex_start_y + sprite.SpriteHeight; values[0] = tex_start_x; //the 4 corners, texcoords: values[1] = tex_end_y; values[a] = tex_start_x; values[a + 1] = tex_start_y; values[a*2] = tex_end_x; values[a*2 + 1] = tex_start_y; values[a*3] = tex_end_x; values[a*3 + 1] = tex_end_y; int prev_total = 2; for(int g=1;g<s.vbo.VertexAttribs.Size.Length;++g){ //starting at 1 because texcoords are already done int attrib_size = s.vbo.VertexAttribs.Size[g]; for(int k=0;k<attrib_size;++k){ float attrib = vertex_attributes[g-1][k]; // -1 because the vertex_attributes array doesn't contain texcoords here in the update method. values[prev_total + k] = attrib; values[prev_total + k + a] = attrib; values[prev_total + k + a*2] = attrib; values[prev_total + k + a*3] = attrib; } prev_total += attrib_size; } GL.BindBuffer(BufferTarget.ArrayBuffer,s.vbo.OtherArrayBufferID); GL.BufferSubData(BufferTarget.ArrayBuffer,new IntPtr(sizeof(float) * a4 * index),new IntPtr(sizeof(float) * a4),values); }
public static Surface Create(GLWindow window_,string texture_filename,string frag_shader,bool has_depth,params int[] vertex_attrib_counts) { Surface s = new Surface(); s.window = window_; int dims = has_depth? 3 : 2; s.UseDepthBuffer = has_depth; VertexAttributes attribs = VertexAttributes.Create(vertex_attrib_counts); s.vbo = VBO.Create(dims,attribs); s.texture = Texture.Create(texture_filename); s.shader = Shader.Create(s.texture.TextureIndex,frag_shader); if(window_ != null){ window_.Surfaces.Add(s); } return s; }