1 module Engine.Batch; 2 3 import std.stdio; 4 import derelict.opengl3.gl; 5 import Engine.Buffer; 6 import gl3n.linalg; 7 import Engine.CStorage; 8 import Engine.Texture; 9 import Engine.Material; 10 import Engine.Core; 11 import engine = Engine.Entity; 12 import Engine.Transform; 13 import std.parallelism; 14 import std.bitmanip; 15 import Engine.Allocator; 16 import std.datetime; 17 import Engine.Component; 18 19 struct BatchData { 20 enum Type { 21 Transform, 22 UV, 23 Color, 24 Vertex, 25 Index, 26 Size, 27 } 28 29 this(Batch batch, Transform transform, Batchable batchable,int vertexIndex,int indexIndex,int vertexCount,int indexCount,int totalVertexCount,int totalIndexCount) { 30 this.batch = batch; 31 this.transform = transform; 32 this.batchable = batchable; 33 this.vertexIndex = vertexIndex; 34 this.indexIndex = indexIndex; 35 this.vertexCount = vertexCount; 36 this.indexCount = indexCount; 37 this.totalIndexCount = totalIndexCount; 38 this.totalVertexCount = totalVertexCount; 39 updateTransform = true; 40 updateUV = true; 41 updateColor = true; 42 updateVertex = true; 43 updateIndex = true; 44 } 45 46 Batch batch; 47 Transform transform; 48 Batchable batchable; 49 size_t batchIndex; 50 int vertexIndex; 51 int indexIndex; 52 int vertexCount; 53 int indexCount; 54 55 int totalVertexCount; 56 int totalIndexCount; 57 58 /* 59 bool updateColor; 60 bool updateTransform; 61 bool updateUV; 62 bool updateVertex; 63 bool updateIndex; 64 bool updateSize; 65 */ 66 package mixin(bitfields!( 67 bool, "updateTransform", 1, 68 bool, "updateUV", 1, 69 bool, "updateColor", 1, 70 bool, "updateVertex", 1, 71 bool, "updateIndex", 1, 72 bool, "updateSize", 1, 73 int, "", 2)); 74 75 void MarkCheck(const Type[] types...) { 76 foreach (t;types) { 77 switch(t) { 78 case Type.Transform: 79 updateTransform = true; 80 break; 81 case Type.UV: 82 updateUV = true; 83 break; 84 case Type.Color: 85 updateColor = true; 86 break; 87 case Type.Vertex: 88 updateVertex = true; 89 break; 90 case Type.Index: 91 updateIndex = true; 92 break; 93 case Type.Size: 94 if (updateSize) 95 return; 96 batch.CheckBatches ~= &this; 97 this.updateSize = true; 98 break; 99 default: 100 break; 101 } 102 } 103 } 104 105 final void Update()(vec3[] vertex,vec2[] uv, vec4[] color,uint[] index, uint indexPosition) { 106 int call = 4; 107 if (!updateUV) { 108 uv = null; 109 call--; 110 } 111 if (!updateColor) { 112 color = null; 113 call--; 114 } 115 if (!updateVertex) { 116 vertex = null; 117 call--; 118 } 119 if (!updateIndex) { 120 index = null; 121 call--; 122 } 123 if (call > 0) { 124 batchable.UpdateBatch(vertex,uv,color,index,indexPosition); 125 updateUV = false; 126 updateIndex = false; 127 updateVertex = false; 128 updateColor = false; 129 } 130 } 131 132 final void ForceUpdate()(vec3[] vertex,vec2[] uv, vec4[] color,uint[] index, uint indexPosition) { 133 batchable.UpdateBatch(vertex,uv,color,index,indexPosition); 134 } 135 } 136 137 class Batch { 138 139 Buffer vertex; 140 Buffer uv; 141 Buffer color; 142 Buffer index; 143 Buffer matrix; 144 145 //ChunkAllocator!(BatchData, 100) batchAllocator; 146 147 BatchData*[] Batches; 148 BatchData*[] CheckBatches; 149 BatchData[] DeleteBatches; 150 int totalIndecies; 151 Material material; 152 153 int vertexIndex; 154 int indexIndex; 155 int vsize; 156 int isize; 157 int deletedIndecies = 0; 158 bool resize; 159 160 this(int size,Material material) { 161 Batches = new BatchData*[size]; 162 CheckBatches = new BatchData*[4]; 163 DeleteBatches = new BatchData[4]; 164 DeleteBatches.length = 0; 165 CheckBatches.length = 0; 166 this.vsize = size*4; 167 this.isize = size*6; 168 Batches.length = 0; 169 vertex = new Buffer(this.vsize*vec3.sizeof, GL_ARRAY_BUFFER,GL_STREAM_DRAW); 170 color = new Buffer(this.vsize*vec4.sizeof, GL_ARRAY_BUFFER,GL_STREAM_DRAW); 171 uv = new Buffer(this.vsize*vec2.sizeof,GL_ARRAY_BUFFER,GL_STREAM_DRAW); 172 index = new Buffer(this.isize*int.sizeof,GL_ELEMENT_ARRAY_BUFFER,GL_STREAM_DRAW); 173 matrix = new Buffer(this.vsize*mat4.sizeof,GL_ARRAY_BUFFER,GL_STREAM_DRAW); 174 this.material = material; 175 } 176 177 178 void Rebuild() { 179 vertexIndex = 0; 180 indexIndex = 0; 181 foreach (batch; Batches) { 182 batch.vertexIndex = vertexIndex; 183 batch.indexIndex = indexIndex; 184 vertexIndex += batch.totalVertexCount; 185 indexIndex += batch.totalIndexCount; 186 } 187 } 188 189 void Add(engine.Entity entity, Batchable batch) { 190 if (vertexIndex + batch.vertecies > vsize || 191 indexIndex + batch.indecies > isize ) { 192 vsize = 2 * (vertexIndex + batch.vertecies); 193 isize = 2 * (indexIndex + batch.indecies); 194 resize = true; 195 } 196 auto b = new BatchData(this,entity.transform,batch,vertexIndex,indexIndex,batch.vertecies,batch.indecies,batch.vertecies,batch.indecies); 197 entity.AddComponent(b); 198 Batches ~= b; 199 b.batchIndex = Batches.length-1; 200 vertexIndex += batch.vertecies; 201 indexIndex += batch.indecies; 202 batch.OnBatchSetup(b); 203 } 204 205 void Remove(engine.Entity entity, Batchable batch) { 206 foreach(c;entity.components) { 207 auto b = c.Cast!BatchData(); 208 if (b !is null && b.batchable == batch) { 209 DeleteBatches ~= *b; 210 auto bd = Batches[Batches.length-1]; 211 Batches[b.batchIndex] = bd; 212 Batches.length--; 213 bd.batchIndex = b.batchIndex; 214 break; 215 } 216 } 217 } 218 219 void Resize(BatchData* batch) { 220 if (vertexIndex + batch.totalVertexCount > vsize || 221 indexIndex + batch.totalIndexCount > isize ) { 222 vsize = 2 * (vertexIndex + batch.totalVertexCount); 223 isize = 2 * (indexIndex + batch.totalIndexCount); 224 resize = true; 225 } else { 226 batch.vertexIndex = vertexIndex; 227 batch.indexIndex = indexIndex; 228 vertexIndex += batch.totalVertexCount; 229 indexIndex += batch.totalIndexCount; 230 } 231 } 232 233 void Update() { 234 //Checking for resizing/deactiving/etc 235 for (int i = 0;i<CheckBatches.length;i++) { 236 auto b = CheckBatches[i]; 237 b.updateSize = false; 238 239 b.updateUV = true; 240 b.updateColor = true; 241 b.updateIndex = true; 242 b.updateVertex = true; 243 244 b.vertexCount = b.batchable.vertecies; 245 b.indexCount = b.batchable.indecies; 246 auto tic = b.totalIndexCount; 247 auto ii = b.indexIndex; 248 //Increase vertex size if needed 249 if (b.vertexCount > b.totalVertexCount || b.indexCount > b.totalIndexCount) { 250 b.totalVertexCount = b.vertexCount * 2; 251 b.totalIndexCount = b.indexCount * 2; 252 Resize(b); 253 } 254 //Delete batch data if needed 255 if (!resize ) { 256 DeleteBatches ~= BatchData(null,null,null,0,ii,0,0,0,tic); 257 } 258 } 259 CheckBatches.length = 0; 260 261 //Resizing & rebuilding 262 bool updateAll = false; 263 if (resize) { 264 DeleteBatches.length = 0; 265 vertex.Resize(vsize*vec3.sizeof); 266 color.Resize(vsize*vec4.sizeof); 267 uv.Resize(vsize*vec2.sizeof); 268 index.Resize(isize*int.sizeof); 269 matrix.Resize(vsize*mat4.sizeof); 270 resize = false; 271 updateAll = true; 272 Rebuild(); 273 } 274 275 276 StopWatch t1; 277 StopWatch t2; 278 t2.start(); 279 t1.start(); 280 auto varr = vertex.Map!vec3(0, vertexIndex*vec3.sizeof); 281 auto carr = color.Map!vec4(0, vertexIndex*vec4.sizeof); 282 auto uvarr = uv.Map!vec2(0, vertexIndex*vec2.sizeof); 283 auto iarr = index.Map!uint(0, indexIndex*uint.sizeof); 284 auto matrcies = matrix.Map!(vec3[3])(0, vertexIndex*(vec3[3]).sizeof); 285 t1.stop(); 286 // writeln("buffer map", cast(double)t1.peek().nsecs / 1000000); 287 288 uint vindex = 0; 289 totalIndecies = 0; 290 scope(exit) { 291 t1.start(); 292 vertex.Unmap(); 293 color.Unmap(); 294 uv.Unmap(); 295 index.Unmap(); 296 matrix.Unmap(); 297 t1.stop(); 298 t2.stop(); 299 // writeln("buffer unmap", cast(double)t1.peek().nsecs / 1000000); 300 // writeln("batch update", cast(double)t2.peek().nsecs / 1000000); 301 } 302 303 //deactiving batches 304 for (int i = 0;i<DeleteBatches.length;i++) { 305 auto e = &DeleteBatches[i]; 306 iarr[e.indexIndex..e.indexIndex+e.totalIndexCount] = 0; 307 } 308 DeleteBatches.length = 0; 309 310 311 //Multithreaded batch updates. 312 auto ti = taskPool.workerLocalStorage(0); 313 if (updateAll) { 314 foreach( e; parallel(Batches)) { 315 auto indx = e.vertexIndex; 316 auto max = indx+e.vertexCount; 317 e.ForceUpdate(varr[indx..max],uvarr[indx..max],carr[indx..max],iarr[e.indexIndex..e.indexIndex+e.indexCount],indx); 318 319 //if (e.updateTransform || 1 == 1) { 320 auto t = e.transform; 321 auto p = t.position; 322 auto r = t.rotation; 323 auto s = t.scale; 324 325 for (;indx<max;indx++) { 326 matrcies[indx][0] = p; 327 matrcies[indx][1] = r; 328 matrcies[indx][2] = s; 329 } 330 } 331 } else { 332 foreach( e; parallel(Batches)) { 333 334 auto indx = e.vertexIndex; 335 auto max = indx+e.vertexCount; 336 e.Update(varr[indx..max],uvarr[indx..max],carr[indx..max],iarr[e.indexIndex..e.indexIndex+e.indexCount],indx); 337 338 //if (e.updateTransform || 1 == 1) { 339 auto t = e.transform; 340 auto p = t.position; 341 auto r = t.rotation; 342 auto s = t.scale; 343 344 for (;indx<max;indx++) { 345 matrcies[indx][0] = p; 346 matrcies[indx][1] = r; 347 matrcies[indx][2] = s; 348 } 349 } 350 } 351 352 353 totalIndecies = indexIndex; 354 355 356 /* 357 foreach(ref e; Core.entities) { 358 if (e.sprite !is null && e.sprite.texture.id == texture.id) { 359 int vertecies,indecies; 360 e.sprite.Sizes(vertecies,indecies); 361 e.sprite.UpdateBatch(varr,uvarr,carr,iarr,vindex); 362 vindex += vertecies; 363 totalIndecies += indecies; 364 varr = varr[vertecies..$]; 365 carr = carr[vertecies..$]; 366 uvarr = uvarr[vertecies..$]; 367 iarr = iarr[indecies..$]; 368 369 auto t = e.Transform; 370 auto p = t.Position; 371 auto r = t.Rotation; 372 auto s = t.Scale; 373 374 for (int i=0;i<vertecies;i++) { 375 matrcies[i] = [p,r,s]; 376 } 377 matrcies = matrcies[vertecies..$]; 378 } 379 } 380 381 auto mat = this.Transform.Matrix(); 382 vertex[0] = (mat*vec4(-0.5f, -0.5f, 0.0f,1)).xyz; 383 vertex[1] = (mat*vec4(0.5f, -0.5f, 0.0f,1)).xyz; 384 vertex[2] = (mat*vec4(0.5f, 0.5f, 0.0f,1)).xyz; 385 vertex[3] = (mat*vec4(-0.5f, 0.5f, 0.0f,1)).xyz; 386 */ 387 } 388 389 void Draw() { 390 StopWatch t1; 391 t1.start(); 392 material.render(this); 393 t1.stop(); 394 //writeln("batch Draw", cast(double)t1.peek().nsecs / 1000000); 395 } 396 } 397 398 interface Batchable { 399 @property Material material(); 400 @property int vertecies(); 401 @property int indecies(); 402 403 void OnBatchSetup( BatchData* data); 404 void UpdateBatch(vec3[] vertex, vec2[] uv, vec4[] color, uint[] index, uint indexPosition); 405 }