1 module ecs_utils.gfx.renderer;
2 
3 import bindbc.sdl;
4 
5 import bubel.ecs.std;
6 
7 //import ecs_utils.core : Backend;
8 import ecs_utils.gfx.buffer;
9 import ecs_utils.gfx.texture;
10 import ecs_utils.math.vector;
11 
12 import bubel.ecs.block_allocator;
13 import bubel.ecs.vector;
14 version(WebAssembly)import glad.gl.gles2;
15 else version(Android)import glad.gl.gles2;
16 else import glad.gl.gl;
17 
18 version = ver1;
19 /*version(ver5)version = vv2;
20 else version(ver6)version = vv2;*/
21 
22 extern(C) float sinf(float);
23 extern(C) float cosf(float);
24 
25 enum RenderTechnique
26 {
27     simple,//1
28     simple_array,//2
29     vbo_batch,//3
30     instanced_attrib_divisor,//4
31     uniform_buffer,//5
32     uniform_buffer_indexed,//6
33     uniform_buffer_multi_draw,//7
34     uniform_buffer_instanced,//8
35     uniform_buffer_instanced_mapped_gl2,//9
36     uniform_buffer_instanced_mapped,//10
37     uniform_buffer_instanced_persistent_mapped,//11
38     uniform_buffer_instanced_persistent_mapped_coherent,//12
39     ssbo_instanced,//13
40     uniform_buffer_draw_indirect,//14
41     uniform_buffer_multi_draw_indirect,//15
42     uniform_buffer_multi_draw_indirect_arb_draw_parameters//16
43 }
44 
45 struct Renderer
46 {
47     //static SDL_Renderer* main_sdl_renderer;
48     BlockAllocator allocator;
49 
50     enum MaxObjects = 1024 * 64 * 4;
51     enum BufferUsage = GL_DYNAMIC_DRAW;
52 
53     //SDL_Window* sdl_window;
54     //SDL_Renderer* sdl_renderer;
55     ivec2 resolution;
56     vec2 dres;
57     vec4 sdl_transform;
58     vec2 view_pos = vec2(-1,-1);
59     vec2 view_size = vec2(1,1);
60 
61     enum block_size = 2^^16;
62     enum batch_size  = block_size/68;//963;//16_384;
63     //uint[2] time_queries;
64 
65     struct VertexBlock
66     {
67         enum max_items = batch_size;//963;
68         byte[] batch_vertices;
69         ushort[] batch_indices;
70         void* memory = null;
71         uint items = 0;
72         uint material_id;
73         uint texture_id;
74     }
75 
76     Mutex* get_block_mutex;
77     Mutex* block_stack_mutex;
78 
79     VertexBlock getBlock()
80     {
81         VertexBlock block;
82         get_block_mutex.lock();
83         block.memory = allocator.getBlock();
84         get_block_mutex.unlock();
85         block.batch_vertices = (cast(byte*)block.memory)[0 .. VertexBlock.max_items * 4 * 14];
86         block.batch_indices = (cast(ushort*)block.memory)[VertexBlock.max_items * 4 * 7 .. VertexBlock.max_items * (4 * 7 + 6)];
87         return block;
88     }
89 
90     Vector!VertexBlock blocks;
91     uint current_block = 0;
92     uint render_blocks = 0;
93 
94     void pushBlock(VertexBlock block)
95     {
96         block_stack_mutex.lock();
97         prepared_items += block.items;
98         blocks.add(block);
99         render_blocks++;
100         block_stack_mutex.unlock();
101     }
102 
103     bool isRemainingBlocks()
104     {
105         if(render_blocks <= current_block)return false;
106         return true;
107     }
108 
109     VertexBlock fetchBlock()
110     {
111         block_stack_mutex.lock();
112         VertexBlock block = blocks[current_block];
113         current_block++;
114         block_stack_mutex.unlock();
115         return block;
116     }
117 
118     void freeBlocks()
119     {
120         /*block_stack_mutex.lock();
121         render_blocks = 0;
122         current_block = 0;
123         foreach(VertexBlock block; blocks)
124         {
125             allocator.freeBlock(block.memory);
126         }
127         blocks.clear;
128         prepared_items=0;
129         draw_list.clear();
130         block_stack_mutex.unlock();*/
131         foreach(ref Thread thread; threads)
132         {
133             foreach(VertexBlock block; thread.filled_blocks)
134             {
135                 allocator.freeBlock(block.memory);
136             }
137             thread.filled_blocks.clear();
138         }
139         render_blocks = 0;
140         current_block = 0;
141         prepared_items = 0;
142         draw_list.clear();
143     }
144 
145     void pushData()
146     {
147         foreach(ref Thread thread; threads)
148         {
149             foreach(VertexBlock block; thread.filled_blocks)
150             {
151                 uint items = block.items;
152                 if(items + item_id >= MaxObjects)items = MaxObjects - item_id;
153                 batch_vbo[0].bufferSubData(Buffer.BindTarget.array,items*4*14,item_id*4*14,block.batch_vertices.ptr);
154                 batch_ibo[0].bufferSubData(Buffer.BindTarget.element_array,items*2*6,item_id*2*6,block.batch_indices.ptr);
155                 draw_list.add(DrawCall(block.texture_id,block.material_id,item_id,items));
156                 item_id += items;
157             }
158             //thread.blocks.clear();
159         }
160         //if(!isRemainingBlocks())return;
161        /* while(isRemainingBlocks())
162         {
163             VertexBlock block = fetchBlock();
164             uint items = block.items;
165             if(items + item_id >= MaxObjects)items = MaxObjects - item_id;
166             batch_vbo[0].bufferSubData(Buffer.BindTarget.array,items*4*14,item_id*4*14,block.batch_vertices.ptr);
167             batch_ibo[0].bufferSubData(Buffer.BindTarget.element_array,items*2*6,item_id*2*6,block.batch_indices.ptr);
168             draw_list.add(DrawCall(item_id,items));
169             item_id += items;
170         }*/
171     }
172 
173     void pushThreadsBlocks()
174     {
175         foreach(i, ref Thread thread; threads)
176         {
177             //pushBlock(thread.block);
178             foreach(ref block; thread.blocks)
179             {
180                 if(block.items > 0)
181                 {
182                     thread.filled_blocks.add(block);
183                     block.items = 0;
184                 }
185             }
186             //thread.blocks = getBlock();
187         }
188     }
189 
190     struct DrawData
191     {
192         Texture texture;
193         vec2 position;
194         vec2 size;
195         vec4 coords;
196         short depth = 0;
197         uint color = uint.max;
198         float angle = 0;
199         uint material_id = 0;
200         uint mesh_id = 0;
201         uint thread_id = 0;
202     }
203 
204     struct Thread
205     {
206         //Vector!VertexBlock block;
207         RenderData[] render_list;
208         VertexBlock[] blocks;
209         Vector!VertexBlock filled_blocks;
210     }
211     Thread[] threads;
212 
213 
214     Buffer[2] ubos;
215     int block_alignment = 1;
216     int block_max_size = 16384;
217 
218     struct IndirectDraw
219     {
220         uint count = 6;
221         uint instances = 1;
222         uint first_index = 0;
223         uint base_vertex = 0;
224         uint base_instance = 0;
225     }
226 
227     Buffer[2] batch_vbo;
228     Buffer[2] batch_ibo;
229 
230     ubyte[] batch_vertices;
231     ushort[] batch_indices;
232 
233     Buffer indirect_buffer;
234     IndirectDraw[] indirect_block;
235 
236     Buffer id_buffer;
237 
238     int data_offset = 48;
239     int data_index;
240     ubyte[] uniform_block;
241 
242     struct RenderData
243     {
244         Texture texture;
245         uint material_id;
246         uint mesh_id;
247     }
248 
249     struct DrawCall
250     {
251         uint texture_id;
252         uint material_id;
253         uint start;
254         uint count;
255     }
256 
257     Vector!DrawCall draw_list;
258 
259     RenderData[] render_list;
260     uint item_id;
261     uint prepared_items;
262 
263     uint[] multi_count;
264     uint[] multi_offset;
265 
266     alias Technique = RenderTechnique;
267 
268     __gshared Technique technique = Technique.vbo_batch;
269     void* data_ptr;
270 
271     //import ecs_utils.core : RenderTechnique;
272 
273     
274 
275     void initialize()
276     {
277         import ecs_utils.gfx.config;
278         //this.technique = __ecs_used_technique;
279         __initialize(this);
280 
281         get_block_mutex = Mallocator.make!Mutex();
282         block_stack_mutex = Mallocator.make!Mutex();
283         get_block_mutex.initialize();
284         block_stack_mutex.initialize();
285 
286 
287         threads = Mallocator.makeArray!Thread(32);
288         foreach(ref Thread thread;threads)
289         {
290             //thread.blocks = getBlock();
291             thread.blocks = Mallocator.makeArray!VertexBlock(GfxConfig.materials.length);
292         }
293     }
294 
295     private static void __initialize_gl(ref Renderer this_)
296     {
297         with(this_)
298         {
299             //glGenQueries(2, time_queries.ptr);
300 
301             version(WebAssembly)
302             {
303                 
304             }
305             else
306             {
307                 glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &block_max_size);
308                 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &block_alignment);
309             }   
310             
311             //ubos[0].bufferStorage(1,64*MaxObjects,null);
312 
313             switch(technique)
314             {
315                 case Technique.simple:
316                     uniform_block = Mallocator.makeArray!ubyte(64*MaxObjects);
317                     data_ptr = uniform_block.ptr;
318                     data_offset = cast(ushort)((data_offset + block_alignment - 1) & (-cast(int) block_alignment));
319                     break;
320                 case Technique.simple_array:
321                     goto case(Technique.simple);
322                 case Technique.vbo_batch:
323                     batch_vbo[0].create();
324                     batch_ibo[0].create();
325                     batch_vbo[0].bufferData(Buffer.BindTarget.array,14,4*MaxObjects,BufferUsage,null);
326                     batch_ibo[0].bufferData(Buffer.BindTarget.element_array,2,6*MaxObjects,BufferUsage,null);
327 
328                     batch_vbo[1].create();
329                     batch_ibo[1].create();
330                     batch_vbo[1].bufferData(Buffer.BindTarget.array,14,4*MaxObjects,BufferUsage,null);
331                     batch_ibo[1].bufferData(Buffer.BindTarget.element_array,2,6*MaxObjects,BufferUsage,null);
332 
333                     //batch_vertices = Mallocator.makeArray!ubyte(14*4*MaxObjects);
334                     //batch_indices = Mallocator.makeArray!ushort(6*MaxObjects);
335                     break;
336                 case Technique.instanced_attrib_divisor:
337                     goto case(Technique.uniform_buffer_indexed);
338                 case Technique.uniform_buffer:
339                     ubos[0].create();
340                     ubos[0].bufferData(Buffer.BindTarget.uniform,1,64*MaxObjects,BufferUsage,null);
341                     ubos[1].create();
342                     ubos[1].bufferData(Buffer.BindTarget.uniform,1,64*MaxObjects,BufferUsage,null);
343                     goto case(Technique.simple);
344                 case Technique.uniform_buffer_indexed:
345                     ubos[0].create();
346                     ubos[0].bufferData(Buffer.BindTarget.uniform,1,64*MaxObjects,BufferUsage,null);
347                     ubos[1].create();
348                     ubos[1].bufferData(Buffer.BindTarget.uniform,1,64*MaxObjects,BufferUsage,null);
349                     uniform_block = Mallocator.makeArray!ubyte(64*MaxObjects);
350                     data_ptr = uniform_block.ptr;
351                     break;
352                 /*case Technique.uniform_buffer_multi_draw:
353                     multi_count = Mallocator.makeArray!uint(992,6);
354                     multi_offset = Mallocator.makeArray!uint(992,0);
355 
356                     {
357                         uint[] indices = Mallocator.makeArray!uint(992);
358                         scope(exit)Mallocator.dispose(indices);
359                         foreach(i;0..992)indices[i]=i;
360                         id_buffer.create();
361                         id_buffer.bufferData(uint.sizeof,992,BufferUsage,indices.ptr);
362                     }
363                     goto case(Technique.uniform_buffer_multi_draw_indirect_arb_draw_parameters);*/
364                 case Technique.uniform_buffer_instanced:
365                     goto case(Technique.uniform_buffer_indexed);
366                 case Technique.uniform_buffer_instanced_mapped_gl2:
367                     ubos[0].create();
368                     ubos[0].bufferData(Buffer.BindTarget.uniform,1,512*MaxObjects,BufferUsage,null);
369                     ubos[0].map(Buffer.BindTarget.uniform);
370                     ubos[1].create();
371                     ubos[1].bufferData(Buffer.BindTarget.uniform,1,512*MaxObjects,BufferUsage,null);
372                     ubos[1].map(Buffer.BindTarget.uniform);
373                     data_ptr = ubos[0].mappedPointer();
374                     break;
375                 case Technique.uniform_buffer_instanced_mapped:
376                     ubos[0].create();
377                     ubos[0].bufferData(Buffer.BindTarget.uniform,1,64*MaxObjects,BufferUsage,null);
378                     ubos[0].map(0, 64*MaxObjects, Buffer.BindTarget.uniform);
379                     ubos[1].create();
380                     ubos[1].bufferData(Buffer.BindTarget.uniform,1,64*MaxObjects,BufferUsage,null);
381                     ubos[1].map(0, 64*MaxObjects, Buffer.BindTarget.uniform);
382                     data_ptr = ubos[0].mappedPointer();
383                     break;
384                 /*case Technique.uniform_buffer_instanced_persistent_mapped:
385                     ubos[0].create();
386                     ubos[0].bufferStorage(1,64*MaxObjects,null,Buffer.StorageFlagBits.write|Buffer.StorageFlagBits.persistent);
387                     ubos[0].map(0, 64*MaxObjects, Buffer.BindTarget.uniform, Buffer.MapFlagBits.write | Buffer.MapFlagBits.persistent | Buffer.MapFlagBits.flush_explict);
388                     data_ptr = ubos[0].mappedPointer();
389                     break;
390                 case Technique.uniform_buffer_instanced_persistent_mapped_coherent:
391                     ubos[0].create();
392                     ubos[0].bufferStorage(1,64*MaxObjects,null,Buffer.StorageFlagBits.write|Buffer.StorageFlagBits.persistent|Buffer.StorageFlagBits.coherent);
393                     ubos[0].map(0, 64*MaxObjects, Buffer.BindTarget.uniform, Buffer.MapFlagBits.write | Buffer.MapFlagBits.persistent | Buffer.MapFlagBits.flush_explict | Buffer.MapFlagBits.coherent);
394                     ubos[1].create();
395                     ubos[1].bufferStorage(1,64*MaxObjects,null,Buffer.StorageFlagBits.write|Buffer.StorageFlagBits.persistent|Buffer.StorageFlagBits.coherent);
396                     ubos[1].map(0, 64*MaxObjects, Buffer.BindTarget.uniform, Buffer.MapFlagBits.write | Buffer.MapFlagBits.persistent | Buffer.MapFlagBits.flush_explict | Buffer.MapFlagBits.coherent);
397                     data_ptr = ubos[0].mappedPointer();
398                     break;
399                 case Technique.ssbo_instanced:
400                     goto case(Technique.uniform_buffer_indexed);
401                 case Technique.uniform_buffer_draw_indirect:
402                     indirect_block = Mallocator.makeArray!IndirectDraw(1);
403                     indirect_buffer.create();
404                     indirect_buffer.bufferData(IndirectDraw.sizeof,1,BufferUsage,indirect_block.ptr);
405                     indirect_buffer.bind(Buffer.BindTarget.indirect);
406                     goto case(Technique.uniform_buffer);
407                 case Technique.uniform_buffer_multi_draw_indirect:
408                     goto case(Technique.uniform_buffer_multi_draw_indirect_arb_draw_parameters);
409                 case Technique.uniform_buffer_multi_draw_indirect_arb_draw_parameters:
410                     indirect_block = Mallocator.makeArray!IndirectDraw(992);
411                     foreach(i;0..992)
412                     {
413                         IndirectDraw* idraw = &indirect_block[i];
414                         idraw.base_instance = i;
415                     }
416                     indirect_buffer.create();
417                     indirect_buffer.bufferData(IndirectDraw.sizeof,992,BufferUsage,indirect_block.ptr);
418                     indirect_buffer.bind(Buffer.BindTarget.indirect);
419                     goto case(Technique.uniform_buffer_indexed);*/
420                 default:break;
421             }//*/
422 
423            // if(batching)data_offset = cast(ushort)((data_offset + block_alignment - 1) & (-cast(int) block_alignment));
424             //data_offset = cast(ushort)((data_offset + block_alignment - 1) & (-cast(int) block_alignment));
425 
426             /*version(ver4){}
427             else version(ver5){}
428             else version(ver6){}
429             else data_offset = cast(ushort)((data_offset + block_alignment - 1) & (-cast(int) block_alignment));//*/
430             //data_offset = (data_offset + block_alignment - 1) - data_offset % block_alignment;
431 
432             render_list = Mallocator.makeArray!RenderData(MaxObjects);
433 
434             SDL_Log("Uniform block alignment: %u",block_alignment);
435             SDL_Log("Uniform block max size: %u",block_max_size);
436             SDL_Log("Data offset: %u",data_offset);
437 
438             allocator = BlockAllocator(block_size, 32);
439         }
440     }
441 
442     private static void __initialize_sdl(ref Renderer this_)
443     {
444 
445     }
446 
447     //void draw(Texture tex, vec2 pos, vec2 size, vec4 coords, short depth = 0, uint color = uint.max, float angle = 0, uint material_id = 0, uint mesh_id = 0, uint thread_id = 0)
448     void draw(scope ref const(DrawData) data)
449     {
450         if(prepared_items >= MaxObjects)return;
451         if(threads[data.thread_id].blocks.length <= data.material_id)return;
452         __draw(this,data);//tex,pos,size,coords,depth,color,angle,material_id,mesh_id,thread_id);
453     }
454 
455     //private static void __draw_sdl(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id)
456     private static void __draw_sdl(ref Renderer this_, scope ref const(DrawData) data)
457     {
458         /*with(this_)
459         {
460             SDL_Rect rect = SDL_Rect(cast(int)(coords.x*tex.data.size.x),cast(int)(coords.y*tex.data.size.y),cast(int)(coords.z*tex.data.size.x),cast(int)(coords.w*tex.data.size.y));
461             SDL_Rect rect2 = SDL_Rect(cast(int)((pos.x-size.x*0.5)),
462                                     cast(int)(resolution.y - pos.y - size.y*0.5),
463                                     cast(int)(size.x),
464                                     cast(int)(size.y));
465 
466             SDL_RenderCopyEx(sdl_renderer,
467                         tex.data.texture,
468                         &rect,
469                         &rect2,
470                         angle*360,
471                         null,
472                         SDL_FLIP_NONE);
473         }*/
474     }
475 
476     // private static void __draw_gl(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id)
477     private static void __draw_gl(ref Renderer this_, scope ref const(DrawData) data)
478     {
479         //import core.stdc.string;
480         with(this_)
481         {
482             //pos += view_pos;
483             vec2 pos = void;
484             vec2 size = void;
485             size.x = data.size.x * view_size.x;
486             size.y = data.size.y * view_size.y;
487             pos.x = data.position.x * view_size.x + view_pos.x;
488             pos.y = data.position.y * view_size.y + view_pos.y;//*/
489 
490             /*version(ver6)void* ptr = ubos[0].mappedPointer() + data_index;
491             else void* ptr = uniform_block.ptr + data_index;*/
492             if(data_ptr is null)return;
493             void* ptr = data_ptr + data_index;
494             if(data.angle == 0)
495             {
496                 *cast(float*)ptr = size.x;
497                 *cast(float*)(ptr+4) = 0;
498                 *cast(float*)(ptr+8) = 0;
499                 *cast(float*)(ptr+12) = size.y;
500             }
501             else
502             {
503                 //import core.stdc.math;
504                 float sinn = sinf(data.angle);
505                 float coss = cosf(data.angle);
506                 *cast(float*)ptr = coss * size.x;
507                 *cast(float*)(ptr+4) = -sinn * size.y;
508                 *cast(float*)(ptr+8) = sinn * size.x;
509                 *cast(float*)(ptr+12) = coss * size.y;
510             }
511             
512             //memcpy(ptr,);
513             memcpy(ptr+16,pos.data.ptr,8);
514             memcpy(ptr+32,data.coords.data.ptr,16);
515 
516             //render_list[item_id] = RenderData(tex,material_id,mesh_id);
517             render_list[item_id].texture = *cast(Texture*)&data.texture;
518             render_list[item_id].material_id = data.material_id;
519             render_list[item_id].mesh_id = data.mesh_id;
520             
521             data_index += data_offset;
522             item_id++;
523             prepared_items++;
524         }
525     }
526 
527     // private static void __draw_gl_vbo_batch(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id = 0)
528     private static void __draw_gl_vbo_batch(ref Renderer this_, scope ref const(DrawData) data)
529     {
530         import ecs_utils.gfx.config;
531         
532         //import core.stdc.string;
533         with(this_)
534         {
535             uint thread_id = data.thread_id;
536             //if(item_id >= MaxObjects)return;
537             //pos += view_pos;
538             Thread* thread = &threads[thread_id];
539             VertexBlock* block;
540             assert(thread.blocks.length > data.material_id);
541             block = &thread.blocks[data.material_id];
542             if(block.items == 0)
543             {
544                 thread.blocks[data.material_id] = getBlock();
545                 block = &thread.blocks[data.material_id];
546                 block.material_id = data.material_id;
547             }
548             else if(block.items >= VertexBlock.max_items)
549             {
550                 //pushBlock(thread.block);
551                 prepared_items += block.items;
552                 thread.filled_blocks.add(*block);
553                 thread.blocks[data.material_id] = getBlock();
554                 block = &thread.blocks[data.material_id];
555                 block.material_id = data.material_id;
556             }
557 
558             short[3] mem = [data.depth, *cast(short*)&data.color, *(cast(short*)&data.color + 1)];
559             
560             vec2 pos = void;
561             vec2 size = void;
562             pos.x = data.position.x * view_size.x + view_pos.x;
563             pos.y = data.position.y * view_size.y + view_pos.y;//*/
564 
565             /*void* ptr = data_ptr + data_index;
566             *cast(float*)ptr = size.x;
567             *cast(float*)(ptr+4) = 0;
568             *cast(float*)(ptr+8) = 0;
569             *cast(float*)(ptr+12) = size.y;
570             //memcpy(ptr,);
571             memcpy(ptr+16,pos.data.ptr,8);
572             memcpy(ptr+32,coords.data.ptr,16);*/
573 
574             short[] verts = (cast(short*)block.batch_vertices.ptr)[0..block.batch_vertices.length>>1];
575             uint item_id = block.items;
576 
577             uint mesh_id = data.mesh_id;
578             vec4 coords = data.coords;
579 
580             if(data.angle == 0)
581             {
582                 size.x = data.size.x * view_size.x;
583                 size.y = data.size.y * view_size.y;
584 
585                 verts[item_id*28]    = cast(short)((GfxConfig.meshes[mesh_id].vertices[0] * size.x + pos.x) * 8191);
586                 verts[item_id*28+1]  = cast(short)((GfxConfig.meshes[mesh_id].vertices[1] * size.y + pos.y) * 8191);
587                 verts[item_id*28+2]  = cast(short)((GfxConfig.meshes[mesh_id].vertices[2] * coords.z + coords.x)*32767);
588                 verts[item_id*28+3]  = cast(short)((GfxConfig.meshes[mesh_id].vertices[3] * coords.w + coords.y)*32767);
589                 memcpy(verts.ptr+item_id*28+4,mem.ptr,6);
590 
591 
592                 verts[item_id*28+7]  = cast(short)((GfxConfig.meshes[mesh_id].vertices[4] * size.x + pos.x) * 8191);
593                 verts[item_id*28+8]  = cast(short)((GfxConfig.meshes[mesh_id].vertices[5] * size.y + pos.y) * 8191);
594                 verts[item_id*28+9]  = cast(short)((GfxConfig.meshes[mesh_id].vertices[6] * coords.z + coords.x)*32767);
595                 verts[item_id*28+10]  = cast(short)((GfxConfig.meshes[mesh_id].vertices[7] * coords.w + coords.y)*32767);
596                 memcpy(verts.ptr+item_id*28+11,mem.ptr,6);
597 
598 
599                 verts[item_id*28+14]  = cast(short)((GfxConfig.meshes[mesh_id].vertices[8] * size.x + pos.x) * 8191);
600                 verts[item_id*28+15]  = cast(short)((GfxConfig.meshes[mesh_id].vertices[9] * size.y + pos.y) * 8191);
601                 verts[item_id*28+16] = cast(short)((GfxConfig.meshes[mesh_id].vertices[10] * coords.z + coords.x)*32767);
602                 verts[item_id*28+17] = cast(short)((GfxConfig.meshes[mesh_id].vertices[11] * coords.w + coords.y)*32767);
603                 memcpy(verts.ptr+item_id*28+18,mem.ptr,6);
604 
605 
606                 verts[item_id*28+21] = cast(short)((GfxConfig.meshes[mesh_id].vertices[12] * size.x + pos.x) * 8191);
607                 verts[item_id*28+22] = cast(short)((GfxConfig.meshes[mesh_id].vertices[13] * size.y + pos.y) * 8191);
608                 verts[item_id*28+23] = cast(short)((GfxConfig.meshes[mesh_id].vertices[14] * coords.z + coords.x)*32767);
609                 verts[item_id*28+24] = cast(short)((GfxConfig.meshes[mesh_id].vertices[15] * coords.w + coords.y)*32767);
610                 memcpy(verts.ptr+item_id*28+25,mem.ptr,6);
611             }
612             else
613             {
614                 //import core.stdc.math;
615                 float angle = data.angle;
616                 float sinx = sinf(angle) * data.size.x * view_size.y;
617                 float cosx = cosf(angle) * data.size.x * view_size.x;
618                 float siny = sinf(angle) * data.size.y * view_size.x;
619                 float cosy = cosf(angle) * data.size.y * view_size.y;
620 
621                 /*batch_vertices[item_id*28]    = GfxConfig.meshes[mesh_id].vertices[0]  * size.x;
622                 batch_vertices[item_id*28+1]  = GfxConfig.meshes[mesh_id].vertices[1]  * size.y;
623                 batch_vertices[item_id*28+4]  = GfxConfig.meshes[mesh_id].vertices[4]  * size.x;
624                 batch_vertices[item_id*28+5]  = GfxConfig.meshes[mesh_id].vertices[5]  * size.y;
625                 batch_vertices[item_id*28+8]  = GfxConfig.meshes[mesh_id].vertices[8]  * size.x;
626                 batch_vertices[item_id*28+9]  = GfxConfig.meshes[mesh_id].vertices[9]  * size.y;
627                 batch_vertices[item_id*28+12] = GfxConfig.meshes[mesh_id].vertices[12] * size.x;
628                 batch_vertices[item_id*28+13] = GfxConfig.meshes[mesh_id].vertices[13] * size.y;*/
629 
630                 verts[item_id*28]    = cast(short)(((GfxConfig.meshes[mesh_id].vertices[0]  * cosx + GfxConfig.meshes[mesh_id].vertices[1]  * siny) + pos.x) * 8191);
631                 verts[item_id*28+1]  = cast(short)(((GfxConfig.meshes[mesh_id].vertices[1]  * cosy - GfxConfig.meshes[mesh_id].vertices[0]  * sinx) + pos.y) * 8191);
632                 verts[item_id*28+2]  = cast(short)((GfxConfig.meshes[mesh_id].vertices[2] * coords.z + coords.x)*32767);
633                 verts[item_id*28+3]  = cast(short)((GfxConfig.meshes[mesh_id].vertices[3] * coords.w + coords.y)*32767);
634                 memcpy(verts.ptr+item_id*28+4,mem.ptr,6);
635 
636 
637                 verts[item_id*28+7]  = cast(short)(((GfxConfig.meshes[mesh_id].vertices[4]  * cosx + GfxConfig.meshes[mesh_id].vertices[5]  * siny) + pos.x) * 8191);
638                 verts[item_id*28+8]  = cast(short)(((GfxConfig.meshes[mesh_id].vertices[5]  * cosy - GfxConfig.meshes[mesh_id].vertices[4]  * sinx) + pos.y) * 8191);
639                 verts[item_id*28+9]  = cast(short)((GfxConfig.meshes[mesh_id].vertices[6] * coords.z + coords.x)*32767);
640                 verts[item_id*28+10]  = cast(short)((GfxConfig.meshes[mesh_id].vertices[7] * coords.w + coords.y)*32767);
641                 memcpy(verts.ptr+item_id*28+11,mem.ptr,6);
642 
643 
644                 verts[item_id*28+14]  = cast(short)(((GfxConfig.meshes[mesh_id].vertices[8]  * cosx + GfxConfig.meshes[mesh_id].vertices[9]  * siny) + pos.x) * 8191);
645                 verts[item_id*28+15]  = cast(short)(((GfxConfig.meshes[mesh_id].vertices[9]  * cosy - GfxConfig.meshes[mesh_id].vertices[8]  * sinx) + pos.y) * 8191);
646                 verts[item_id*28+16] = cast(short)((GfxConfig.meshes[mesh_id].vertices[10] * coords.z + coords.x)*32767);
647                 verts[item_id*28+17] = cast(short)((GfxConfig.meshes[mesh_id].vertices[11] * coords.w + coords.y)*32767);
648                 memcpy(verts.ptr+item_id*28+18,mem.ptr,6);
649 
650 
651                 verts[item_id*28+21] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[12] * cosx + GfxConfig.meshes[mesh_id].vertices[13] * siny) + pos.x) * 8191);
652                 verts[item_id*28+22] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[13] * cosy - GfxConfig.meshes[mesh_id].vertices[12] * sinx) + pos.y) * 8191);
653                 verts[item_id*28+23] = cast(short)((GfxConfig.meshes[mesh_id].vertices[14] * coords.z + coords.x)*32767);
654                 verts[item_id*28+24] = cast(short)((GfxConfig.meshes[mesh_id].vertices[15] * coords.w + coords.y)*32767);
655                 memcpy(verts.ptr+item_id*28+25,mem.ptr,6);
656             }
657 
658             /*verts[item_id*28+2]  = cast(short)((GfxConfig.meshes[mesh_id].vertices[2] * coords.z + coords.x)*32767);
659             verts[item_id*28+3]  = cast(short)((GfxConfig.meshes[mesh_id].vertices[3] * coords.w + coords.y)*32767);
660             verts[item_id*28+9]  = cast(short)((GfxConfig.meshes[mesh_id].vertices[6] * coords.z + coords.x)*32767);
661             verts[item_id*28+10]  = cast(short)((GfxConfig.meshes[mesh_id].vertices[7] * coords.w + coords.y)*32767);
662             verts[item_id*28+16] = cast(short)((GfxConfig.meshes[mesh_id].vertices[10] * coords.z + coords.x)*32767);
663             verts[item_id*28+17] = cast(short)((GfxConfig.meshes[mesh_id].vertices[11] * coords.w + coords.y)*32767);
664             verts[item_id*28+23] = cast(short)((GfxConfig.meshes[mesh_id].vertices[14] * coords.z + coords.x)*32767);
665             verts[item_id*28+24] = cast(short)((GfxConfig.meshes[mesh_id].vertices[15] * coords.w + coords.y)*32767);*/
666 
667             /*verts[item_id*28+4] = depth;
668             verts[item_id*28+11] = depth;
669             verts[item_id*28+18] = depth;
670             verts[item_id*28+25] = depth;
671 
672             *cast(uint*)&verts[item_id*28+5] = color;
673             *cast(uint*)&verts[item_id*28+12] = color;
674             *cast(uint*)&verts[item_id*28+19] = color;
675             *cast(uint*)&verts[item_id*28+26] = color;
676             
677             memcpy(verts.ptr+item_id*28+4,mem.ptr,6);
678             memcpy(verts.ptr+item_id*28+11,mem.ptr,6);
679             memcpy(verts.ptr+item_id*28+18,mem.ptr,6);
680             memcpy(verts.ptr+item_id*28+25,mem.ptr,6);*/
681 
682             uint ind_id = (item_id % batch_size)*4;
683 
684             ushort[] indices = block.batch_indices;
685 
686             indices[item_id*6]   = cast(ushort)(GfxConfig.meshes[mesh_id].indices[0] + ind_id);
687             indices[item_id*6+1] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[1] + ind_id);
688             indices[item_id*6+2] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[2] + ind_id);
689             indices[item_id*6+3] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[3] + ind_id);
690             indices[item_id*6+4] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[4] + ind_id);
691             indices[item_id*6+5] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[5] + ind_id);
692 
693             //render_list[item_id] = RenderData(tex,material_id,mesh_id);
694             //render_list[item_id].texture = tex;
695             //render_list[item_id].material_id = material_id;
696             //render_list[item_id].mesh_id = mesh_id;
697             
698             //data_index += 1;//data_offset;
699             block.items++;
700         }
701     }
702 
703     void clear()
704     {
705         __clear(this);
706     }
707 
708     private static void __clear_sdl(ref Renderer this_)
709     {
710         //SDL_RenderClear(this_.sdl_renderer);
711     }
712 
713     private static void __clear_gl(ref Renderer this_)
714     {
715         glClearColor(0,0,0,0);
716         glViewport(0,0,this_.resolution.x,this_.resolution.y);
717         glDepthMask(1);
718         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
719         //glDisable(GL_DEPTH_TEST);
720         glEnable(GL_DEPTH_TEST);
721         glDisable(GL_CULL_FACE);
722         glDepthFunc(GL_LESS);
723 
724         version(WebAssembly)
725         {
726             glDepthRangef(0,1);
727         }
728         else version(Android)
729         {
730             glDepthRangef(0,1);
731         }
732         else
733         {
734             glDepthRange(0,1);
735         }
736         //glDepthRange(0,1);
737         //glClearDepth(1);
738     }
739 
740     void present()
741     {
742         __present(this);
743     }
744 
745     private static void __present_sdl(ref Renderer this_)
746     {
747         //+SDL_RenderPresent(this_.sdl_renderer);
748     }
749 
750     private static void __present_gl(ref Renderer this_)
751     {
752 
753         this_.pushThreadsBlocks();
754         this_.pushData();
755 
756         glViewport(0,0,this_.resolution.x,this_.resolution.y);
757         //glEnable(GL_ALPHA_TEST);
758         //glAlphaFunc(GL_GREATER, 0.01);
759         glEnableVertexAttribArray(0);
760         glEnableVertexAttribArray(1);
761         import ecs_utils.gfx.config;
762         with(this_)
763         {
764             bool instanced = false;
765             bool indirect = false;
766             bool multi_draw = false;
767             Buffer.BindTarget buffer_target = Buffer.BindTarget.uniform;
768 
769             switch(technique)
770             {
771                 case Technique.simple:
772                     break;
773                 case Technique.simple_array:
774                     break;
775                 case Technique.vbo_batch:
776                 //if(data_index){
777                     //batch_vbo[0].bufferSubData(Buffer.BindTarget.array,item_id*4*14,0,batch_vertices.ptr);
778                     //batch_ibo[0].bufferSubData(Buffer.BindTarget.element_array,item_id*6*2,0,batch_indices.ptr);
779 
780                     batch_vbo[0].bind(Buffer.BindTarget.array);
781                     batch_ibo[0].bind(Buffer.BindTarget.element_array);
782 
783                     //glVertexAttribPointer(0,2,GL_SHORT,true,14,null);
784                     //glVertexAttribPointer(1,2,GL_SHORT,true,14,cast(void*)4);//}
785                     glEnableVertexAttribArray(2);
786                     glEnableVertexAttribArray(3);
787                     //glVertexAttribPointer(2,1,GL_SHORT,true,14,cast(void*)6);//}
788                     break;
789                 case Technique.instanced_attrib_divisor:
790                     ubos[0].bufferSubData(Buffer.BindTarget.uniform,data_index,0,uniform_block.ptr);
791                     ubos[0].bind(Buffer.BindTarget.uniform);
792                     glEnableVertexAttribArray(2);
793                     glEnableVertexAttribArray(3);
794                     glEnableVertexAttribArray(4);
795 
796                     glVertexAttribPointer(2,4,GL_FLOAT,false,48,null);
797                     glVertexAttribPointer(3,4,GL_FLOAT,false,48,cast(void*)16);
798                     glVertexAttribPointer(4,4,GL_FLOAT,false,48,cast(void*)32);
799                     glVertexAttribDivisor(2,1);
800                     glVertexAttribDivisor(3,1);
801                     glVertexAttribDivisor(4,1);
802                     //ubos[0].bindRange(Buffer.BindTarget.uniform,0,0,block_max_size);
803                     break;
804                 case Technique.uniform_buffer:
805                     //ubos[0].bufferData(1,64*MaxObjects,BufferUsage,null);
806                     /*if(data_index)*/ubos[0].bufferSubData(Buffer.BindTarget.uniform,data_index,0,uniform_block.ptr);
807                     break;
808                 case Technique.uniform_buffer_indexed:
809                     ubos[0].bindRange(Buffer.BindTarget.uniform,0,0,block_max_size);
810                     goto case(Technique.uniform_buffer);
811                 case Technique.uniform_buffer_multi_draw:
812                     id_buffer.bind(Buffer.BindTarget.array);
813                     glEnableVertexAttribArray(2);
814 
815                     glVertexAttribIPointer(2,1,GL_UNSIGNED_INT,cast(uint)uint.sizeof,cast(void*)0);
816                     glVertexAttribDivisor(2,1);
817                     multi_draw = true;
818                     goto case(Technique.uniform_buffer_instanced);
819                 case Technique.uniform_buffer_instanced:
820                     instanced = true;
821                     goto case(Technique.uniform_buffer);
822                 case Technique.uniform_buffer_instanced_mapped_gl2:
823                     instanced = true;
824                     ubos[0].unmap(Buffer.BindTarget.uniform);
825                     break;
826                 case Technique.uniform_buffer_instanced_mapped:
827                     instanced = true;
828                     ubos[0].flush(0,data_index,Buffer.BindTarget.uniform);
829                     ubos[0].unmap(Buffer.BindTarget.uniform);
830                     break;
831                 /*case Technique.uniform_buffer_instanced_persistent_mapped:
832                     instanced = true;
833                     ubos[0].flush(0,data_index,Buffer.BindTarget.uniform);
834                     //glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
835                     break;
836                 case Technique.uniform_buffer_instanced_persistent_mapped_coherent:
837                     instanced = true;
838                     break;
839                     //ubos[0].flush(0,data_index,Buffer.BindTarget.uniform);
840                     //goto case(Technique.uniform_buffer_instanced_mapped);
841                 case Technique.ssbo_instanced:
842                     //buffer_target = Buffer.BindTarget.shader_storage;
843                     ubos[0].bindRange(Buffer.BindTarget.shader_storage,0,0,48*MaxObjects);
844                     goto case(Technique.uniform_buffer_instanced);
845                 case Technique.uniform_buffer_draw_indirect:
846                     goto case(Technique.uniform_buffer);
847                 case Technique.uniform_buffer_multi_draw_indirect:
848                     indirect_buffer.bind(Buffer.BindTarget.array);
849                     glEnableVertexAttribArray(2);
850 
851                     glVertexAttribIPointer(2,1,GL_UNSIGNED_INT,cast(uint)IndirectDraw.sizeof,cast(void*)(4*uint.sizeof));
852                     glVertexAttribDivisor(2,1);
853                     goto case(Technique.uniform_buffer_multi_draw_indirect_arb_draw_parameters);
854                 case Technique.uniform_buffer_multi_draw_indirect_arb_draw_parameters:
855                     indirect = true;
856                     goto case(Technique.uniform_buffer_instanced);*/
857                 default:break;
858             }
859 
860             data_index = 0;
861 
862             int mesh_id = -1;
863             int material_id = -1;
864             int ubo_start = -1;
865             Texture texture;
866             uint item_ubo_id = 0;
867 
868             /*Buffer tmpb = ubos[0];
869             ubos[0] = ubos[1];
870             ubos[1] = tmpb;
871 
872             tmpb = batch_vbo[0];
873             batch_vbo[0] = batch_vbo[1];
874             batch_vbo[1] = tmpb;
875 
876             tmpb = batch_ibo[0];
877             batch_ibo[0] = batch_ibo[1];
878             batch_ibo[1] = tmpb;//*/
879             //glFinish();
880 
881             //glBeginQuery(GL_TIME_ELAPSED, time_queries[0]);
882             if(technique == Technique.vbo_batch)
883             {
884                 //uint items = item_id/batch_size+1;
885                 foreach(i; 0..draw_list.length)
886                 {
887                     if(material_id != draw_list[i].material_id)
888                     {
889                         material_id = draw_list[i].material_id;
890                         GfxConfig.materials[material_id].bind();
891                         float[3*4] data = [1,0,0,1,0,0,0,0,0,0,1,1];
892                         GfxConfig.materials[material_id].pushUniforms(data.ptr);
893                     }
894                     if(texture.data != render_list[i].texture.data)
895                     {
896                         texture.data = render_list[i].texture.data;
897                         render_list[i].texture.bind();
898                     }
899 
900                     /*uint instance_count = batch_size;
901                     if((i+1)*batch_size > item_id)
902                     {
903                         instance_count = item_id%batch_size;
904                     }*/
905 
906                     // glVertexAttribPointer(0,2,GL_FLOAT,false,16,cast(void*)(i*batch_size*4*16));
907                     // glVertexAttribPointer(1,2,GL_FLOAT,false,16,cast(void*)(i*batch_size*4*16+8));
908                     glVertexAttribPointer(0,2,GL_SHORT,true,14,cast(void*)(draw_list[i].start*4*14));
909                     glVertexAttribPointer(1,2,GL_SHORT,true,14,cast(void*)(draw_list[i].start*4*14+4));
910                     glVertexAttribPointer(2,1,GL_SHORT,true,14,cast(void*)(draw_list[i].start*4*14+8));
911                     glVertexAttribPointer(3,4,GL_UNSIGNED_BYTE,true,14,cast(void*)(draw_list[i].start*4*14+10));
912 
913                     glDrawElements(GL_TRIANGLES,draw_list[i].count*6,GL_UNSIGNED_SHORT,cast(void*)(draw_list[i].start*6*2));
914 
915                     //glDrawElementsBaseVertex(GL_TRIANGLES,instance_count*6,GL_UNSIGNED_SHORT,cast(void*)(i*16_384*6*2),i*16_384*4);
916                 }
917             }
918             else if(technique == Technique.ssbo_instanced || technique == Technique.instanced_attrib_divisor)
919             {
920                 if(mesh_id != render_list[0].mesh_id)
921                 {
922                     mesh_id = render_list[0].mesh_id;
923                     GfxConfig.meshes[mesh_id].bind();
924                 }
925                 if(material_id != render_list[0].material_id)
926                 {
927                     material_id = render_list[0].material_id;
928                     GfxConfig.materials[material_id].bind();
929                 }
930                 if(texture.data != render_list[0].texture.data)
931                 {
932                     texture.data = render_list[0].texture.data;
933                     render_list[0].texture.bind();
934                 }
935                 glDrawArraysInstanced(GL_TRIANGLE_STRIP,0,4,item_id);
936                 //glDrawElementsInstanced(GL_TRIANGLES,6,GL_UNSIGNED_SHORT,null,item_id);
937             }
938             else if(instanced)
939             {
940                 uint items = item_id/992+1;
941                 foreach(i; 0..items)
942                 {
943                     if(mesh_id != render_list[i].mesh_id)
944                     {
945                         mesh_id = render_list[i].mesh_id;
946                         GfxConfig.meshes[mesh_id].bind();
947                     }
948                     if(material_id != render_list[i].material_id)
949                     {
950                         material_id = render_list[i].material_id;
951                         GfxConfig.materials[material_id].bind();
952                     }
953                     if(texture.data != render_list[i].texture.data)
954                     {
955                         texture.data = render_list[0].texture.data;
956                         render_list[i].texture.bind();
957                     }
958                     ubos[0].bindRange(buffer_target,0,data_index,block_max_size);
959 
960                     uint instance_count = 992;
961                     if(i*992 > item_id)
962                     {
963                         instance_count = i*992 - item_id;
964                     }
965 
966                     /*if(indirect)glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, cast(void*)0, instance_count, 0);
967                     else if(multi_draw)glMultiDrawElements(GL_TRIANGLES,cast(int*)multi_count.ptr,GL_UNSIGNED_SHORT,cast(void**)multi_offset.ptr,instance_count); 
968                         //glMultiDrawElementsBaseVertex(GL_TRIANGLES,cast(int*)multi_count.ptr,GL_UNSIGNED_SHORT,cast(void**)multi_offset.ptr,instance_count,cast(int*)multi_offset.ptr);
969                     else */glDrawElementsInstanced(GL_TRIANGLES,6,GL_UNSIGNED_SHORT,null,instance_count);
970                     //glDrawArraysInstanced(GL_TRIANGLES,0,6,instance_count);
971                     data_index += data_offset * 992;
972                 }
973             }
974             else
975             foreach(item; render_list[0..item_id])
976             {
977                 if(mesh_id != item.mesh_id)
978                 {
979                     mesh_id = item.mesh_id;
980                     GfxConfig.meshes[mesh_id].bind();
981                 }
982                 if(material_id != item.material_id)
983                 {
984                     material_id = item.material_id;
985                     GfxConfig.materials[material_id].bind();
986                     GfxConfig.materials[material_id].pushBindings();
987                 }
988                 if(texture.data != item.texture.data)
989                 {
990                     texture.data = render_list[0].texture.data;
991                     item.texture.bind();
992                 }
993                 
994                 switch(technique)
995                 {
996                     case Technique.simple:
997                         /*glUniform4f(0, *cast(float*)&uniform_block[data_index], *cast(float*)&uniform_block[data_index+4], *cast(float*)&uniform_block[data_index+8], *cast(float*)&uniform_block[data_index+12]);
998                         glUniform4f(1, *cast(float*)&uniform_block[data_index+16], *cast(float*)&uniform_block[data_index+20], *cast(float*)&uniform_block[data_index+24], *cast(float*)&uniform_block[data_index+28]);
999                         glUniform4f(2, *cast(float*)&uniform_block[data_index+32], *cast(float*)&uniform_block[data_index+36], *cast(float*)&uniform_block[data_index+40], *cast(float*)&uniform_block[data_index+44]);
1000                         */
1001                             GfxConfig.materials[material_id].pushUniforms(&uniform_block[data_index]);break;
1002                     case Technique.simple_array:
1003                         glUniform4fv(0,12,cast(float*)(uniform_block.ptr+data_index));
1004                         break;
1005                     case Technique.uniform_buffer:
1006                         ubos[0].bindRange(Buffer.BindTarget.uniform,0,data_index,data_offset);
1007                         break;
1008                     /*case Technique.uniform_buffer_draw_indirect:
1009                          ubos[0].bindRange(Buffer.BindTarget.uniform,0,data_index,data_offset);
1010                          glDrawElementsIndirect(GL_TRIANGLES,GL_UNSIGNED_SHORT,null);
1011                          data_index += data_offset;
1012                          continue;*/
1013                     case Technique.uniform_buffer_indexed:
1014                         if(item_ubo_id >= 992)
1015                         {
1016                             item_ubo_id = 0;
1017                             ubo_start = data_index;
1018                             ubos[0].bindRange(Buffer.BindTarget.uniform,0,ubo_start,block_max_size);
1019                         }
1020                         glUniform1i(0,item_ubo_id++);
1021                         break;
1022                     default:break;
1023                 }//*/
1024 
1025                 /*version(ver3)ubos[0].bindRange(Buffer.BindTarget.uniform,0,data_index,data_offset);
1026                 else version(ver1)
1027                 {
1028                     glUniform4f(0, *cast(float*)&uniform_block[data_index], *cast(float*)&uniform_block[data_index+4], *cast(float*)&uniform_block[data_index+8], *cast(float*)&uniform_block[data_index+12]);
1029                     glUniform4f(1, *cast(float*)&uniform_block[data_index+16], *cast(float*)&uniform_block[data_index+20], *cast(float*)&uniform_block[data_index+24], *cast(float*)&uniform_block[data_index+28]);
1030                     glUniform4f(2, *cast(float*)&uniform_block[data_index+32], *cast(float*)&uniform_block[data_index+36], *cast(float*)&uniform_block[data_index+40], *cast(float*)&uniform_block[data_index+44]);
1031                 }
1032                 else version(ver2)glUniform4fv(0,12,cast(float*)(uniform_block.ptr+data_index));
1033                 else version(ver4)
1034                 {
1035                     if(item_ubo_id >= 992)
1036                     {
1037                         item_ubo_id = 0;
1038                         ubo_start = data_index;
1039                         ubos[0].bindRange(Buffer.BindTarget.uniform,0,ubo_start,block_max_size);
1040                     }
1041                     glUniform1i(0,item_ubo_id++);
1042                 }//*/
1043                 
1044                 glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_SHORT,null);
1045                 //glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1046                 data_index += data_offset;
1047             }
1048             //glEndQuery(GL_TIME_ELAPSED);
1049             //uint tmpq = time_queries[0];
1050             //time_queries[0] = time_queries[1];
1051             //time_queries[1] = tmpq;
1052             /*Buffer tmpb = ubos[0];
1053             ubos[0] = ubos[1];
1054             ubos[1] = tmpb;//*/
1055 
1056             data_index = 0;
1057             //data_offset = 0;
1058             item_id = 0;
1059             //SDL_GL_SwapWindow(sdl_window);
1060             //glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
1061             //version(ver6)ubos[0].map(0, 64*MaxObjects, Buffer.BindTarget.uniform);
1062             //ubos[0].map(Buffer.BindTarget.uniform);
1063 
1064             switch(technique)
1065             {
1066                 case Technique.uniform_buffer_instanced_mapped_gl2:
1067                     ubos[0].map(Buffer.BindTarget.uniform);
1068                     //data_ptr = ubos[0].mappedPointer();
1069                     break;
1070                 case Technique.uniform_buffer_instanced_mapped:
1071                     ubos[0].map(0, 64*MaxObjects, Buffer.BindTarget.uniform);
1072                     //data_ptr = ubos[0].mappedPointer();
1073                     break;
1074                 default:break;
1075             }
1076 
1077             if(ubos[0].data && ubos[0].mappedPointer)
1078             {
1079                 data_ptr = ubos[0].mappedPointer;
1080             }
1081 
1082             /*switch(technique)
1083             {
1084                 case Technique.simple:
1085                 case Technique.simple_array:
1086                 case Technique.uniform_buffer:
1087                 case Technique.uniform_buffer_indexed:
1088                 case Technique.uniform_buffer_instanced:
1089                 case Technique.uniform_buffer_instanced_mapped:
1090                 case Technique.uniform_buffer_instanced_persistent_mapped:
1091                 default:break;
1092             }*/
1093         }
1094         glDisableVertexAttribArray(0);
1095         glDisableVertexAttribArray(1);
1096         glDisableVertexAttribArray(2);
1097         glDisableVertexAttribArray(3);
1098         this_.freeBlocks();
1099         /*glUseProgram(0);
1100         glBindBuffer(GL_ARRAY_BUFFER, 0);
1101         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);*/
1102         //glDisable(GL_ALPHA_TEST);
1103     }
1104 
1105     void resize(ivec2 size)
1106     {
1107         resolution = size;
1108         dres = vec2(1.0/cast(float)size.x,1.0/cast(float)size.y);
1109     }
1110 
1111     void view(vec2 pos, vec2 size)
1112     {
1113         //view_pos = pos * size - 1;
1114         view_size = vec2(2/size.x,2/size.y);
1115         sdl_transform = vec4(0,0,1.0/size.x,1.0/size.y);
1116         view_pos = (pos - size * 0.5) * view_size;
1117     }
1118 
1119     // __gshared void function(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id) __draw;
1120     __gshared void function(ref Renderer this_, scope ref const(DrawData) data) __draw;
1121     __gshared void function(ref Renderer this_) __present;
1122     __gshared void function(ref Renderer this_) __clear;
1123     __gshared void function(ref Renderer this_) __initialize;
1124 
1125     static void __loadBackend() 
1126     {
1127         //this.technique = __ecs_used_technique;
1128         if(technique == Technique.vbo_batch)__draw = &__draw_gl_vbo_batch;
1129         else __draw = &__draw_gl;
1130         __present = &__present_gl;
1131         __clear = &__clear_gl;
1132         __initialize = &__initialize_gl;
1133     }
1134 
1135 }