1 module ws.gl.batch; 2 3 import 4 std.algorithm, 5 std.conv, 6 ws.gl.gl, 7 ws.gl.context, 8 ws.exception, 9 ws.io; 10 11 __gshared: 12 13 14 struct Layout { 15 uint target; 16 uint size; 17 } 18 19 20 class Batch { 21 22 enum tex2 = [Layout(gl.attributeTexture, 2)]; 23 enum vert3 = [Layout(gl.attributeVertex, 3)]; 24 enum color4 = [Layout(gl.attributeColor, 4)]; 25 enum normal3 = [Layout(gl.attributeNormal, 3)]; 26 27 alias float[2] Tex; 28 alias float[3] Vec; 29 alias float[4] Color; 30 31 this(GlContext context, uint type, Layout[] layout, float[] data){ 32 this.context = context; 33 uint line; 34 foreach(l; layout) 35 line += l.size; 36 assert(data.length % line == 0, "Batch data is not divisible by row length"); 37 begin(cast(uint)(data.length/line), type); 38 foreach(i; 0..vertexCount){ 39 auto d = data[i*line .. (i+1)*line]; 40 int consumed = 0; 41 foreach(l; layout){ 42 add(l.target, d[consumed..consumed+l.size]); 43 consumed += l.size; 44 } 45 currentVert++; 46 } 47 finish; 48 } 49 50 void begin(int verts, uint type = GL_TRIANGLES){ 51 vertexCount = verts; 52 currentVert = 0; 53 this.type = type; 54 context.genVertexArrays(1, cast(uint*)&vao); 55 context.bindVertexArray(vao); 56 } 57 58 void finish(){ 59 assert(!done); 60 foreach(array; arrays){ 61 context.bindBuffer(GL_ARRAY_BUFFER, array.globj); 62 context.unmapBuffer(GL_ARRAY_BUFFER); 63 } 64 65 context.bindVertexArray(vao); 66 67 foreach(array; arrays){ 68 context.bindBuffer(GL_ARRAY_BUFFER, array.globj); 69 context.enableVertexAttribArray(array.attributeId), 70 context.vertexAttribPointer(array.attributeId, array.size, GL_FLOAT, GL_FALSE, 0, null); 71 } 72 73 done = true; 74 context.bindVertexArray(0); 75 } 76 77 void draw(){ 78 if(!done) 79 return; 80 context.bindVertexArray(vao); 81 context.drawArrays(type, 0, vertexCount); 82 //glBindVertexArray(0); 83 } 84 85 void add(Vec pos){ 86 add(gl.attributeVertex, pos[]); 87 currentVert++; 88 } 89 90 void addPoint(Vec pos, Color col){ 91 add(gl.attributeVertex, pos[]); 92 add(gl.attributeColor, col); 93 currentVert++; 94 } 95 96 void addPoint(Vec pos, Vec normal){ 97 add(gl.attributeVertex, pos[]); 98 add(gl.attributeNormal, normal[]); 99 currentVert++; 100 } 101 102 void addPoint(Vec pos, Vec normal, Color col){ 103 add(gl.attributeVertex, pos[]); 104 add(gl.attributeNormal, normal[]); 105 add(gl.attributeColor, col); 106 currentVert++; 107 } 108 109 void addPoint(Vec pos, Tex t){ 110 add(gl.attributeVertex, pos[]); 111 add(gl.attributeTexture, t); 112 currentVert++; 113 } 114 115 void addPoint(Vec pos, Vec normal, Tex t){ 116 add(gl.attributeVertex, pos[]); 117 add(gl.attributeNormal, normal[]); 118 add(gl.attributeTexture, t); 119 currentVert++; 120 } 121 122 /*~this(){ 123 glDeleteVertexArrays(1, &vao); 124 }*/ 125 126 void updateVertices(float[] data, size_t pos = 0, size_t length = 1){ 127 context.bindBuffer(GL_ARRAY_BUFFER, arrays[gl.attributeVertex].globj); 128 context.bufferSubData(GL_ARRAY_BUFFER, pos*3*float.sizeof, length*3*float.sizeof, data.ptr); 129 } 130 131 protected: 132 133 GlContext context; 134 135 uint vao; 136 uint type; 137 138 bool done = false; 139 int vertexCount = 0; 140 int currentVert = 0; 141 142 class Array { 143 this(uint size, uint attributeId){ 144 assert(!done); 145 assert(vao); 146 this.size = size; 147 this.attributeId = attributeId; 148 context.genBuffers(1, cast(uint*)&globj); 149 context.bindBuffer(GL_ARRAY_BUFFER, globj); 150 context.bufferData(GL_ARRAY_BUFFER, float.sizeof*size*vertexCount, null, GL_DYNAMIC_DRAW); 151 context.bindBuffer(GL_ARRAY_BUFFER, globj); 152 array = cast(float*)context.mapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); 153 arrays[attributeId] = this; 154 if(!array) 155 exception("Failed to create array buffer"); 156 } 157 float* array = null; 158 uint globj = 0; 159 uint size; 160 uint attributeId; 161 /*~this(){ 162 glDeleteBuffers(1, &globj); 163 }*/ 164 } 165 166 Array[uint] arrays; 167 168 void add(uint target, float[] data){ 169 if(target !in arrays) 170 arrays[target] = new Array(data.length.to!uint, target); 171 float* o = arrays[target].array+currentVert*data.length; 172 o[0..data.length] = data; 173 } 174 175 }