-added webpage deploymnet stage -added separate build stage which build all binaries and generate documentation -added Emscripten build stage for merge to master only -added VBO batch rendering (current default, no render mode switch yet) -fixed camera positioning calculation -fixed buffer issue with WebGL -added viewport scalling (at least 300 pixels height). Pixels are scalled if screen is bigger. -center demos gameplay area -added fullpage html template for Emscripten build
821 lines
No EOL
37 KiB
D
821 lines
No EOL
37 KiB
D
module ecs_utils.gfx.renderer;
|
|
|
|
import bindbc.sdl;
|
|
|
|
import ecs.std;
|
|
|
|
//import ecs_utils.core : Backend;
|
|
import ecs_utils.gfx.buffer;
|
|
import ecs_utils.gfx.texture;
|
|
import ecs_utils.math.vector;
|
|
|
|
import glad.gl.gl;
|
|
|
|
version = ver1;
|
|
/*version(ver5)version = vv2;
|
|
else version(ver6)version = vv2;*/
|
|
|
|
extern(C) float sinf(float);
|
|
extern(C) float cosf(float);
|
|
|
|
enum RenderTechnique
|
|
{
|
|
simple,//1
|
|
simple_array,//2
|
|
vbo_batch,//3
|
|
instanced_attrib_divisor,//4
|
|
uniform_buffer,//5
|
|
uniform_buffer_indexed,//6
|
|
uniform_buffer_multi_draw,//7
|
|
uniform_buffer_instanced,//8
|
|
uniform_buffer_instanced_mapped_gl2,//9
|
|
uniform_buffer_instanced_mapped,//10
|
|
uniform_buffer_instanced_persistent_mapped,//11
|
|
uniform_buffer_instanced_persistent_mapped_coherent,//12
|
|
ssbo_instanced,//13
|
|
uniform_buffer_draw_indirect,//14
|
|
uniform_buffer_multi_draw_indirect,//15
|
|
uniform_buffer_multi_draw_indirect_arb_draw_parameters//16
|
|
}
|
|
|
|
struct Renderer
|
|
{
|
|
//static SDL_Renderer* main_sdl_renderer;
|
|
|
|
enum MaxObjects = 1024 * 64 * 4;
|
|
enum BufferUsage = GL_STATIC_DRAW;
|
|
|
|
//SDL_Window* sdl_window;
|
|
//SDL_Renderer* sdl_renderer;
|
|
ivec2 resolution;
|
|
vec2 dres;
|
|
vec4 sdl_transform;
|
|
vec2 view_pos = vec2(-1,-1);
|
|
vec2 view_size = vec2(1,1);
|
|
|
|
//uint[2] time_queries;
|
|
|
|
Buffer[2] ubos;
|
|
int block_alignment = 1;
|
|
int block_max_size = 16384;
|
|
|
|
struct IndirectDraw
|
|
{
|
|
uint count = 6;
|
|
uint instances = 1;
|
|
uint first_index = 0;
|
|
uint base_vertex = 0;
|
|
uint base_instance = 0;
|
|
}
|
|
|
|
Buffer[2] batch_vbo;
|
|
Buffer[2] batch_ibo;
|
|
|
|
float[] batch_vertices;
|
|
ushort[] batch_indices;
|
|
|
|
Buffer indirect_buffer;
|
|
IndirectDraw[] indirect_block;
|
|
|
|
Buffer id_buffer;
|
|
|
|
int data_offset = 48;
|
|
int data_index;
|
|
ubyte[] uniform_block;
|
|
|
|
struct RenderData
|
|
{
|
|
Texture texture;
|
|
uint material_id;
|
|
uint mesh_id;
|
|
}
|
|
|
|
RenderData[] render_list;
|
|
uint item_id;
|
|
|
|
uint[] multi_count;
|
|
uint[] multi_offset;
|
|
|
|
alias Technique = RenderTechnique;
|
|
|
|
__gshared Technique technique = Technique.vbo_batch;
|
|
void* data_ptr;
|
|
|
|
//import ecs_utils.core : RenderTechnique;
|
|
|
|
|
|
|
|
void initialize()
|
|
{
|
|
//this.technique = __ecs_used_technique;
|
|
__initialize(this);
|
|
}
|
|
|
|
private static void __initialize_gl(ref Renderer this_)
|
|
{
|
|
with(this_)
|
|
{
|
|
//glGenQueries(2, time_queries.ptr);
|
|
|
|
version(WebAssembly)
|
|
{
|
|
|
|
}
|
|
else
|
|
{
|
|
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &block_max_size);
|
|
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &block_alignment);
|
|
}
|
|
|
|
//ubos[0].bufferStorage(1,64*MaxObjects,null);
|
|
|
|
switch(technique)
|
|
{
|
|
case Technique.simple:
|
|
uniform_block = Mallocator.makeArray!ubyte(64*MaxObjects);
|
|
data_ptr = uniform_block.ptr;
|
|
data_offset = cast(ushort)((data_offset + block_alignment - 1) & (-cast(int) block_alignment));
|
|
break;
|
|
case Technique.simple_array:
|
|
goto case(Technique.simple);
|
|
case Technique.vbo_batch:
|
|
batch_vbo[0].create();
|
|
batch_ibo[0].create();
|
|
batch_vbo[0].bufferData(Buffer.BindTarget.array,16,4*MaxObjects,BufferUsage,null);
|
|
batch_ibo[0].bufferData(Buffer.BindTarget.element_array,2,6*MaxObjects,BufferUsage,null);
|
|
|
|
batch_vbo[1].create();
|
|
batch_ibo[1].create();
|
|
batch_vbo[1].bufferData(Buffer.BindTarget.array,16,4*MaxObjects,BufferUsage,null);
|
|
batch_ibo[1].bufferData(Buffer.BindTarget.element_array,2,6*MaxObjects,BufferUsage,null);
|
|
|
|
batch_vertices = Mallocator.makeArray!float(16*MaxObjects);
|
|
batch_indices = Mallocator.makeArray!ushort(6*MaxObjects);
|
|
break;
|
|
case Technique.instanced_attrib_divisor:
|
|
goto case(Technique.uniform_buffer_indexed);
|
|
case Technique.uniform_buffer:
|
|
ubos[0].create();
|
|
ubos[0].bufferData(Buffer.BindTarget.uniform,1,64*MaxObjects,BufferUsage,null);
|
|
ubos[1].create();
|
|
ubos[1].bufferData(Buffer.BindTarget.uniform,1,64*MaxObjects,BufferUsage,null);
|
|
goto case(Technique.simple);
|
|
case Technique.uniform_buffer_indexed:
|
|
ubos[0].create();
|
|
ubos[0].bufferData(Buffer.BindTarget.uniform,1,64*MaxObjects,BufferUsage,null);
|
|
ubos[1].create();
|
|
ubos[1].bufferData(Buffer.BindTarget.uniform,1,64*MaxObjects,BufferUsage,null);
|
|
uniform_block = Mallocator.makeArray!ubyte(64*MaxObjects);
|
|
data_ptr = uniform_block.ptr;
|
|
break;
|
|
/*case Technique.uniform_buffer_multi_draw:
|
|
multi_count = Mallocator.makeArray!uint(992,6);
|
|
multi_offset = Mallocator.makeArray!uint(992,0);
|
|
|
|
{
|
|
uint[] indices = Mallocator.makeArray!uint(992);
|
|
scope(exit)Mallocator.dispose(indices);
|
|
foreach(i;0..992)indices[i]=i;
|
|
id_buffer.create();
|
|
id_buffer.bufferData(uint.sizeof,992,BufferUsage,indices.ptr);
|
|
}
|
|
goto case(Technique.uniform_buffer_multi_draw_indirect_arb_draw_parameters);*/
|
|
case Technique.uniform_buffer_instanced:
|
|
goto case(Technique.uniform_buffer_indexed);
|
|
case Technique.uniform_buffer_instanced_mapped_gl2:
|
|
ubos[0].create();
|
|
ubos[0].bufferData(Buffer.BindTarget.uniform,1,512*MaxObjects,BufferUsage,null);
|
|
ubos[0].map(Buffer.BindTarget.uniform);
|
|
ubos[1].create();
|
|
ubos[1].bufferData(Buffer.BindTarget.uniform,1,512*MaxObjects,BufferUsage,null);
|
|
ubos[1].map(Buffer.BindTarget.uniform);
|
|
data_ptr = ubos[0].mappedPointer();
|
|
break;
|
|
case Technique.uniform_buffer_instanced_mapped:
|
|
ubos[0].create();
|
|
ubos[0].bufferData(Buffer.BindTarget.uniform,1,64*MaxObjects,BufferUsage,null);
|
|
ubos[0].map(0, 64*MaxObjects, Buffer.BindTarget.uniform);
|
|
ubos[1].create();
|
|
ubos[1].bufferData(Buffer.BindTarget.uniform,1,64*MaxObjects,BufferUsage,null);
|
|
ubos[1].map(0, 64*MaxObjects, Buffer.BindTarget.uniform);
|
|
data_ptr = ubos[0].mappedPointer();
|
|
break;
|
|
/*case Technique.uniform_buffer_instanced_persistent_mapped:
|
|
ubos[0].create();
|
|
ubos[0].bufferStorage(1,64*MaxObjects,null,Buffer.StorageFlagBits.write|Buffer.StorageFlagBits.persistent);
|
|
ubos[0].map(0, 64*MaxObjects, Buffer.BindTarget.uniform, Buffer.MapFlagBits.write | Buffer.MapFlagBits.persistent | Buffer.MapFlagBits.flush_explict);
|
|
data_ptr = ubos[0].mappedPointer();
|
|
break;
|
|
case Technique.uniform_buffer_instanced_persistent_mapped_coherent:
|
|
ubos[0].create();
|
|
ubos[0].bufferStorage(1,64*MaxObjects,null,Buffer.StorageFlagBits.write|Buffer.StorageFlagBits.persistent|Buffer.StorageFlagBits.coherent);
|
|
ubos[0].map(0, 64*MaxObjects, Buffer.BindTarget.uniform, Buffer.MapFlagBits.write | Buffer.MapFlagBits.persistent | Buffer.MapFlagBits.flush_explict | Buffer.MapFlagBits.coherent);
|
|
ubos[1].create();
|
|
ubos[1].bufferStorage(1,64*MaxObjects,null,Buffer.StorageFlagBits.write|Buffer.StorageFlagBits.persistent|Buffer.StorageFlagBits.coherent);
|
|
ubos[1].map(0, 64*MaxObjects, Buffer.BindTarget.uniform, Buffer.MapFlagBits.write | Buffer.MapFlagBits.persistent | Buffer.MapFlagBits.flush_explict | Buffer.MapFlagBits.coherent);
|
|
data_ptr = ubos[0].mappedPointer();
|
|
break;
|
|
case Technique.ssbo_instanced:
|
|
goto case(Technique.uniform_buffer_indexed);
|
|
case Technique.uniform_buffer_draw_indirect:
|
|
indirect_block = Mallocator.makeArray!IndirectDraw(1);
|
|
indirect_buffer.create();
|
|
indirect_buffer.bufferData(IndirectDraw.sizeof,1,BufferUsage,indirect_block.ptr);
|
|
indirect_buffer.bind(Buffer.BindTarget.indirect);
|
|
goto case(Technique.uniform_buffer);
|
|
case Technique.uniform_buffer_multi_draw_indirect:
|
|
goto case(Technique.uniform_buffer_multi_draw_indirect_arb_draw_parameters);
|
|
case Technique.uniform_buffer_multi_draw_indirect_arb_draw_parameters:
|
|
indirect_block = Mallocator.makeArray!IndirectDraw(992);
|
|
foreach(i;0..992)
|
|
{
|
|
IndirectDraw* idraw = &indirect_block[i];
|
|
idraw.base_instance = i;
|
|
}
|
|
indirect_buffer.create();
|
|
indirect_buffer.bufferData(IndirectDraw.sizeof,992,BufferUsage,indirect_block.ptr);
|
|
indirect_buffer.bind(Buffer.BindTarget.indirect);
|
|
goto case(Technique.uniform_buffer_indexed);*/
|
|
default:break;
|
|
}//*/
|
|
|
|
// if(batching)data_offset = cast(ushort)((data_offset + block_alignment - 1) & (-cast(int) block_alignment));
|
|
//data_offset = cast(ushort)((data_offset + block_alignment - 1) & (-cast(int) block_alignment));
|
|
|
|
/*version(ver4){}
|
|
else version(ver5){}
|
|
else version(ver6){}
|
|
else data_offset = cast(ushort)((data_offset + block_alignment - 1) & (-cast(int) block_alignment));//*/
|
|
//data_offset = (data_offset + block_alignment - 1) - data_offset % block_alignment;
|
|
|
|
render_list = Mallocator.makeArray!RenderData(MaxObjects);
|
|
|
|
SDL_Log("Uniform block alignment: %u",block_alignment);
|
|
SDL_Log("Uniform block max size: %u",block_max_size);
|
|
SDL_Log("Data offset: %u",data_offset);
|
|
}
|
|
}
|
|
|
|
private static void __initialize_sdl(ref Renderer this_)
|
|
{
|
|
|
|
}
|
|
|
|
void draw(Texture tex, vec2 pos, vec2 size, vec4 coords, float angle = 0, uint material_id = 0, uint mesh_id = 0)
|
|
{
|
|
__draw(this,tex,pos,size,coords,angle,material_id,mesh_id);
|
|
}
|
|
|
|
private static void __draw_sdl(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, float angle, uint material_id, uint mesh_id)
|
|
{
|
|
/*with(this_)
|
|
{
|
|
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));
|
|
SDL_Rect rect2 = SDL_Rect(cast(int)((pos.x-size.x*0.5)),
|
|
cast(int)(resolution.y - pos.y - size.y*0.5),
|
|
cast(int)(size.x),
|
|
cast(int)(size.y));
|
|
|
|
SDL_RenderCopyEx(sdl_renderer,
|
|
tex.data.texture,
|
|
&rect,
|
|
&rect2,
|
|
angle*360,
|
|
null,
|
|
SDL_FLIP_NONE);
|
|
}*/
|
|
}
|
|
|
|
private static void __draw_gl(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, float angle, uint material_id, uint mesh_id)
|
|
{
|
|
//import core.stdc.string;
|
|
with(this_)
|
|
{
|
|
//pos += view_pos;
|
|
size.x *= view_size.x;
|
|
size.y *= view_size.y;
|
|
pos.x = pos.x * view_size.x + view_pos.x;
|
|
pos.y = pos.y * view_size.y + view_pos.y;//*/
|
|
|
|
/*version(ver6)void* ptr = ubos[0].mappedPointer() + data_index;
|
|
else void* ptr = uniform_block.ptr + data_index;*/
|
|
if(data_ptr is null)return;
|
|
void* ptr = data_ptr + data_index;
|
|
if(angle == 0)
|
|
{
|
|
*cast(float*)ptr = size.x;
|
|
*cast(float*)(ptr+4) = 0;
|
|
*cast(float*)(ptr+8) = 0;
|
|
*cast(float*)(ptr+12) = size.y;
|
|
}
|
|
else
|
|
{
|
|
//import core.stdc.math;
|
|
float sinn = sinf(angle);
|
|
float coss = cosf(angle);
|
|
*cast(float*)ptr = coss * size.x;
|
|
*cast(float*)(ptr+4) = -sinn * size.y;
|
|
*cast(float*)(ptr+8) = sinn * size.x;
|
|
*cast(float*)(ptr+12) = coss * size.y;
|
|
}
|
|
|
|
//memcpy(ptr,);
|
|
memcpy(ptr+16,pos.data.ptr,8);
|
|
memcpy(ptr+32,coords.data.ptr,16);
|
|
|
|
//render_list[item_id] = RenderData(tex,material_id,mesh_id);
|
|
render_list[item_id].texture = tex;
|
|
render_list[item_id].material_id = material_id;
|
|
render_list[item_id].mesh_id = mesh_id;
|
|
|
|
data_index += data_offset;
|
|
item_id++;
|
|
}
|
|
}
|
|
|
|
private static void __draw_gl_vbo_batch(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, float angle, uint material_id, uint mesh_id)
|
|
{
|
|
import ecs_utils.gfx.config;
|
|
//import core.stdc.string;
|
|
with(this_)
|
|
{
|
|
if(item_id >= MaxObjects)return;
|
|
//pos += view_pos;
|
|
size.x *= view_size.x;
|
|
size.y *= view_size.y;
|
|
pos.x = pos.x * view_size.x + view_pos.x;
|
|
pos.y = pos.y * view_size.y + view_pos.y;//*/
|
|
|
|
/*void* ptr = data_ptr + data_index;
|
|
*cast(float*)ptr = size.x;
|
|
*cast(float*)(ptr+4) = 0;
|
|
*cast(float*)(ptr+8) = 0;
|
|
*cast(float*)(ptr+12) = size.y;
|
|
//memcpy(ptr,);
|
|
memcpy(ptr+16,pos.data.ptr,8);
|
|
memcpy(ptr+32,coords.data.ptr,16);*/
|
|
|
|
if(angle == 0)
|
|
{
|
|
batch_vertices[item_id*16] = GfxConfig.meshes[mesh_id].vertices[0] * size.x + pos.x;
|
|
batch_vertices[item_id*16+1] = GfxConfig.meshes[mesh_id].vertices[1] * size.y + pos.y;
|
|
batch_vertices[item_id*16+4] = GfxConfig.meshes[mesh_id].vertices[4] * size.x + pos.x;
|
|
batch_vertices[item_id*16+5] = GfxConfig.meshes[mesh_id].vertices[5] * size.y + pos.y;
|
|
batch_vertices[item_id*16+8] = GfxConfig.meshes[mesh_id].vertices[8] * size.x + pos.x;
|
|
batch_vertices[item_id*16+9] = GfxConfig.meshes[mesh_id].vertices[9] * size.y + pos.y;
|
|
batch_vertices[item_id*16+12] = GfxConfig.meshes[mesh_id].vertices[12] * size.x + pos.x;
|
|
batch_vertices[item_id*16+13] = GfxConfig.meshes[mesh_id].vertices[13] * size.y + pos.y;
|
|
}
|
|
else
|
|
{
|
|
//import core.stdc.math;
|
|
float sinn = sinf(angle);
|
|
float coss = cosf(angle);
|
|
|
|
/*batch_vertices[item_id*16] = GfxConfig.meshes[mesh_id].vertices[0] * size.x;
|
|
batch_vertices[item_id*16+1] = GfxConfig.meshes[mesh_id].vertices[1] * size.y;
|
|
batch_vertices[item_id*16+4] = GfxConfig.meshes[mesh_id].vertices[4] * size.x;
|
|
batch_vertices[item_id*16+5] = GfxConfig.meshes[mesh_id].vertices[5] * size.y;
|
|
batch_vertices[item_id*16+8] = GfxConfig.meshes[mesh_id].vertices[8] * size.x;
|
|
batch_vertices[item_id*16+9] = GfxConfig.meshes[mesh_id].vertices[9] * size.y;
|
|
batch_vertices[item_id*16+12] = GfxConfig.meshes[mesh_id].vertices[12] * size.x;
|
|
batch_vertices[item_id*16+13] = GfxConfig.meshes[mesh_id].vertices[13] * size.y;*/
|
|
|
|
batch_vertices[item_id*16] = (GfxConfig.meshes[mesh_id].vertices[0] * coss + GfxConfig.meshes[mesh_id].vertices[1] * sinn) * size.x + pos.x;
|
|
batch_vertices[item_id*16+1] = (GfxConfig.meshes[mesh_id].vertices[1] * coss - GfxConfig.meshes[mesh_id].vertices[0] * sinn) * size.y + pos.y;
|
|
batch_vertices[item_id*16+4] = (GfxConfig.meshes[mesh_id].vertices[4] * coss + GfxConfig.meshes[mesh_id].vertices[5] * sinn) * size.x + pos.x;
|
|
batch_vertices[item_id*16+5] = (GfxConfig.meshes[mesh_id].vertices[5] * coss - GfxConfig.meshes[mesh_id].vertices[4] * sinn) * size.y + pos.y;
|
|
batch_vertices[item_id*16+8] = (GfxConfig.meshes[mesh_id].vertices[8] * coss + GfxConfig.meshes[mesh_id].vertices[9] * sinn) * size.x + pos.x;
|
|
batch_vertices[item_id*16+9] = (GfxConfig.meshes[mesh_id].vertices[9] * coss - GfxConfig.meshes[mesh_id].vertices[8] * sinn) * size.y + pos.y;
|
|
batch_vertices[item_id*16+12] = (GfxConfig.meshes[mesh_id].vertices[12] * coss + GfxConfig.meshes[mesh_id].vertices[13] * sinn) * size.x + pos.x;
|
|
batch_vertices[item_id*16+13] = (GfxConfig.meshes[mesh_id].vertices[13] * coss - GfxConfig.meshes[mesh_id].vertices[12] * sinn) * size.y + pos.y;
|
|
}
|
|
|
|
batch_vertices[item_id*16+2] = GfxConfig.meshes[mesh_id].vertices[2] * coords.z + coords.x;
|
|
batch_vertices[item_id*16+3] = GfxConfig.meshes[mesh_id].vertices[3] * coords.w + coords.y;
|
|
batch_vertices[item_id*16+6] = GfxConfig.meshes[mesh_id].vertices[6] * coords.z + coords.x;
|
|
batch_vertices[item_id*16+7] = GfxConfig.meshes[mesh_id].vertices[7] * coords.w + coords.y;
|
|
batch_vertices[item_id*16+10] = GfxConfig.meshes[mesh_id].vertices[10] * coords.z + coords.x;
|
|
batch_vertices[item_id*16+11] = GfxConfig.meshes[mesh_id].vertices[11] * coords.w + coords.y;
|
|
batch_vertices[item_id*16+14] = GfxConfig.meshes[mesh_id].vertices[14] * coords.z + coords.x;
|
|
batch_vertices[item_id*16+15] = GfxConfig.meshes[mesh_id].vertices[15] * coords.w + coords.y;
|
|
|
|
uint ind_id = item_id % 16_384;
|
|
|
|
batch_indices[item_id*6] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[0] + ind_id*4);
|
|
batch_indices[item_id*6+1] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[1] + ind_id*4);
|
|
batch_indices[item_id*6+2] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[2] + ind_id*4);
|
|
batch_indices[item_id*6+3] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[3] + ind_id*4);
|
|
batch_indices[item_id*6+4] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[4] + ind_id*4);
|
|
batch_indices[item_id*6+5] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[5] + ind_id*4);
|
|
|
|
//render_list[item_id] = RenderData(tex,material_id,mesh_id);
|
|
render_list[item_id].texture = tex;
|
|
render_list[item_id].material_id = material_id;
|
|
render_list[item_id].mesh_id = mesh_id;
|
|
|
|
//data_index += 1;//data_offset;
|
|
item_id++;
|
|
}
|
|
}
|
|
|
|
void clear()
|
|
{
|
|
__clear(this);
|
|
}
|
|
|
|
private static void __clear_sdl(ref Renderer this_)
|
|
{
|
|
//SDL_RenderClear(this_.sdl_renderer);
|
|
}
|
|
|
|
private static void __clear_gl(ref Renderer this_)
|
|
{
|
|
glClearColor(0,0,0,0);
|
|
glViewport(0,0,this_.resolution.x,this_.resolution.y);
|
|
glClear(GL_COLOR_BUFFER_BIT);// | GL_DEPTH_BUFFER_BIT);
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_CULL_FACE);
|
|
}
|
|
|
|
void present()
|
|
{
|
|
__present(this);
|
|
}
|
|
|
|
private static void __present_sdl(ref Renderer this_)
|
|
{
|
|
//+SDL_RenderPresent(this_.sdl_renderer);
|
|
}
|
|
|
|
private static void __present_gl(ref Renderer this_)
|
|
{
|
|
glViewport(0,0,this_.resolution.x,this_.resolution.y);
|
|
//glEnable(GL_ALPHA_TEST);
|
|
//glAlphaFunc(GL_GREATER, 0.01);
|
|
glEnableVertexAttribArray(0);
|
|
glEnableVertexAttribArray(1);
|
|
import ecs_utils.gfx.config;
|
|
with(this_)
|
|
{
|
|
bool instanced = false;
|
|
bool indirect = false;
|
|
bool multi_draw = false;
|
|
Buffer.BindTarget buffer_target = Buffer.BindTarget.uniform;
|
|
|
|
switch(technique)
|
|
{
|
|
case Technique.simple:
|
|
break;
|
|
case Technique.simple_array:
|
|
break;
|
|
case Technique.vbo_batch:
|
|
//if(data_index){
|
|
batch_vbo[0].bufferSubData(Buffer.BindTarget.array,item_id*4*16,0,batch_vertices.ptr);
|
|
batch_ibo[0].bufferSubData(Buffer.BindTarget.element_array,item_id*6*2,0,batch_indices.ptr);
|
|
|
|
batch_vbo[0].bind(Buffer.BindTarget.array);
|
|
batch_ibo[0].bind(Buffer.BindTarget.element_array);
|
|
|
|
glVertexAttribPointer(0,2,GL_FLOAT,false,16,null);
|
|
glVertexAttribPointer(1,2,GL_FLOAT,false,16,cast(void*)8);//}
|
|
break;
|
|
case Technique.instanced_attrib_divisor:
|
|
ubos[0].bufferSubData(Buffer.BindTarget.uniform,data_index,0,uniform_block.ptr);
|
|
ubos[0].bind(Buffer.BindTarget.uniform);
|
|
glEnableVertexAttribArray(2);
|
|
glEnableVertexAttribArray(3);
|
|
glEnableVertexAttribArray(4);
|
|
|
|
glVertexAttribPointer(2,4,GL_FLOAT,false,48,null);
|
|
glVertexAttribPointer(3,4,GL_FLOAT,false,48,cast(void*)16);
|
|
glVertexAttribPointer(4,4,GL_FLOAT,false,48,cast(void*)32);
|
|
glVertexAttribDivisor(2,1);
|
|
glVertexAttribDivisor(3,1);
|
|
glVertexAttribDivisor(4,1);
|
|
//ubos[0].bindRange(Buffer.BindTarget.uniform,0,0,block_max_size);
|
|
break;
|
|
case Technique.uniform_buffer:
|
|
//ubos[0].bufferData(1,64*MaxObjects,BufferUsage,null);
|
|
/*if(data_index)*/ubos[0].bufferSubData(Buffer.BindTarget.uniform,data_index,0,uniform_block.ptr);
|
|
break;
|
|
case Technique.uniform_buffer_indexed:
|
|
ubos[0].bindRange(Buffer.BindTarget.uniform,0,0,block_max_size);
|
|
goto case(Technique.uniform_buffer);
|
|
case Technique.uniform_buffer_multi_draw:
|
|
id_buffer.bind(Buffer.BindTarget.array);
|
|
glEnableVertexAttribArray(2);
|
|
|
|
glVertexAttribIPointer(2,1,GL_UNSIGNED_INT,cast(uint)uint.sizeof,cast(void*)0);
|
|
glVertexAttribDivisor(2,1);
|
|
multi_draw = true;
|
|
goto case(Technique.uniform_buffer_instanced);
|
|
case Technique.uniform_buffer_instanced:
|
|
instanced = true;
|
|
goto case(Technique.uniform_buffer);
|
|
case Technique.uniform_buffer_instanced_mapped_gl2:
|
|
instanced = true;
|
|
ubos[0].unmap(Buffer.BindTarget.uniform);
|
|
break;
|
|
case Technique.uniform_buffer_instanced_mapped:
|
|
instanced = true;
|
|
ubos[0].flush(0,data_index,Buffer.BindTarget.uniform);
|
|
ubos[0].unmap(Buffer.BindTarget.uniform);
|
|
break;
|
|
/*case Technique.uniform_buffer_instanced_persistent_mapped:
|
|
instanced = true;
|
|
ubos[0].flush(0,data_index,Buffer.BindTarget.uniform);
|
|
//glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
|
|
break;
|
|
case Technique.uniform_buffer_instanced_persistent_mapped_coherent:
|
|
instanced = true;
|
|
break;
|
|
//ubos[0].flush(0,data_index,Buffer.BindTarget.uniform);
|
|
//goto case(Technique.uniform_buffer_instanced_mapped);
|
|
case Technique.ssbo_instanced:
|
|
//buffer_target = Buffer.BindTarget.shader_storage;
|
|
ubos[0].bindRange(Buffer.BindTarget.shader_storage,0,0,48*MaxObjects);
|
|
goto case(Technique.uniform_buffer_instanced);
|
|
case Technique.uniform_buffer_draw_indirect:
|
|
goto case(Technique.uniform_buffer);
|
|
case Technique.uniform_buffer_multi_draw_indirect:
|
|
indirect_buffer.bind(Buffer.BindTarget.array);
|
|
glEnableVertexAttribArray(2);
|
|
|
|
glVertexAttribIPointer(2,1,GL_UNSIGNED_INT,cast(uint)IndirectDraw.sizeof,cast(void*)(4*uint.sizeof));
|
|
glVertexAttribDivisor(2,1);
|
|
goto case(Technique.uniform_buffer_multi_draw_indirect_arb_draw_parameters);
|
|
case Technique.uniform_buffer_multi_draw_indirect_arb_draw_parameters:
|
|
indirect = true;
|
|
goto case(Technique.uniform_buffer_instanced);*/
|
|
default:break;
|
|
}
|
|
|
|
data_index = 0;
|
|
|
|
int mesh_id = -1;
|
|
int material_id = -1;
|
|
int ubo_start = -1;
|
|
Texture texture;
|
|
uint item_ubo_id = 0;
|
|
|
|
/*Buffer tmpb = ubos[0];
|
|
ubos[0] = ubos[1];
|
|
ubos[1] = tmpb;
|
|
|
|
tmpb = batch_vbo[0];
|
|
batch_vbo[0] = batch_vbo[1];
|
|
batch_vbo[1] = tmpb;
|
|
|
|
tmpb = batch_ibo[0];
|
|
batch_ibo[0] = batch_ibo[1];
|
|
batch_ibo[1] = tmpb;//*/
|
|
//glFinish();
|
|
|
|
//glBeginQuery(GL_TIME_ELAPSED, time_queries[0]);
|
|
if(technique == Technique.vbo_batch)
|
|
{
|
|
uint items = item_id/16_384+1;
|
|
foreach(i; 0..items)
|
|
{
|
|
if(material_id != render_list[i].material_id)
|
|
{
|
|
material_id = render_list[i].material_id;
|
|
GfxConfig.materials[material_id].bind();
|
|
float[3*4] data = [1,0,0,1,0,0,0,0,0,0,1,1];
|
|
GfxConfig.materials[material_id].pushUniforms(data.ptr);
|
|
}
|
|
if(texture.data != render_list[i].texture.data)
|
|
{
|
|
texture.data = render_list[i].texture.data;
|
|
render_list[i].texture.bind();
|
|
}
|
|
|
|
uint instance_count = 16_384;
|
|
if((i+1)*16_384 > item_id)
|
|
{
|
|
instance_count = item_id%16_384;
|
|
}
|
|
|
|
glVertexAttribPointer(0,2,GL_FLOAT,false,16,cast(void*)(i*16_384*4*16));
|
|
glVertexAttribPointer(1,2,GL_FLOAT,false,16,cast(void*)(i*16_384*4*16+8));
|
|
|
|
glDrawElements(GL_TRIANGLES,instance_count*6,GL_UNSIGNED_SHORT,cast(void*)(i*16_384*6*2));
|
|
|
|
//glDrawElementsBaseVertex(GL_TRIANGLES,instance_count*6,GL_UNSIGNED_SHORT,cast(void*)(i*16_384*6*2),i*16_384*4);
|
|
}
|
|
}
|
|
else if(technique == Technique.ssbo_instanced || technique == Technique.instanced_attrib_divisor)
|
|
{
|
|
if(mesh_id != render_list[0].mesh_id)
|
|
{
|
|
mesh_id = render_list[0].mesh_id;
|
|
GfxConfig.meshes[mesh_id].bind();
|
|
}
|
|
if(material_id != render_list[0].material_id)
|
|
{
|
|
material_id = render_list[0].material_id;
|
|
GfxConfig.materials[material_id].bind();
|
|
}
|
|
if(texture.data != render_list[0].texture.data)
|
|
{
|
|
texture.data = render_list[0].texture.data;
|
|
render_list[0].texture.bind();
|
|
}
|
|
glDrawArraysInstanced(GL_TRIANGLE_STRIP,0,4,item_id);
|
|
//glDrawElementsInstanced(GL_TRIANGLES,6,GL_UNSIGNED_SHORT,null,item_id);
|
|
}
|
|
else if(instanced)
|
|
{
|
|
uint items = item_id/992+1;
|
|
foreach(i; 0..items)
|
|
{
|
|
if(mesh_id != render_list[i].mesh_id)
|
|
{
|
|
mesh_id = render_list[i].mesh_id;
|
|
GfxConfig.meshes[mesh_id].bind();
|
|
}
|
|
if(material_id != render_list[i].material_id)
|
|
{
|
|
material_id = render_list[i].material_id;
|
|
GfxConfig.materials[material_id].bind();
|
|
}
|
|
if(texture.data != render_list[i].texture.data)
|
|
{
|
|
texture.data = render_list[0].texture.data;
|
|
render_list[i].texture.bind();
|
|
}
|
|
ubos[0].bindRange(buffer_target,0,data_index,block_max_size);
|
|
|
|
uint instance_count = 992;
|
|
if(i*992 > item_id)
|
|
{
|
|
instance_count = i*992 - item_id;
|
|
}
|
|
|
|
/*if(indirect)glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, cast(void*)0, instance_count, 0);
|
|
else if(multi_draw)glMultiDrawElements(GL_TRIANGLES,cast(int*)multi_count.ptr,GL_UNSIGNED_SHORT,cast(void**)multi_offset.ptr,instance_count);
|
|
//glMultiDrawElementsBaseVertex(GL_TRIANGLES,cast(int*)multi_count.ptr,GL_UNSIGNED_SHORT,cast(void**)multi_offset.ptr,instance_count,cast(int*)multi_offset.ptr);
|
|
else */glDrawElementsInstanced(GL_TRIANGLES,6,GL_UNSIGNED_SHORT,null,instance_count);
|
|
//glDrawArraysInstanced(GL_TRIANGLES,0,6,instance_count);
|
|
data_index += data_offset * 992;
|
|
}
|
|
}
|
|
else
|
|
foreach(item; render_list[0..item_id])
|
|
{
|
|
if(mesh_id != item.mesh_id)
|
|
{
|
|
mesh_id = item.mesh_id;
|
|
GfxConfig.meshes[mesh_id].bind();
|
|
}
|
|
if(material_id != item.material_id)
|
|
{
|
|
material_id = item.material_id;
|
|
GfxConfig.materials[material_id].bind();
|
|
GfxConfig.materials[material_id].pushBindings();
|
|
}
|
|
if(texture.data != item.texture.data)
|
|
{
|
|
texture.data = render_list[0].texture.data;
|
|
item.texture.bind();
|
|
}
|
|
|
|
switch(technique)
|
|
{
|
|
case Technique.simple:
|
|
/*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]);
|
|
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]);
|
|
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]);
|
|
*/
|
|
GfxConfig.materials[material_id].pushUniforms(&uniform_block[data_index]);break;
|
|
case Technique.simple_array:
|
|
glUniform4fv(0,12,cast(float*)(uniform_block.ptr+data_index));
|
|
break;
|
|
case Technique.uniform_buffer:
|
|
ubos[0].bindRange(Buffer.BindTarget.uniform,0,data_index,data_offset);
|
|
break;
|
|
/*case Technique.uniform_buffer_draw_indirect:
|
|
ubos[0].bindRange(Buffer.BindTarget.uniform,0,data_index,data_offset);
|
|
glDrawElementsIndirect(GL_TRIANGLES,GL_UNSIGNED_SHORT,null);
|
|
data_index += data_offset;
|
|
continue;*/
|
|
case Technique.uniform_buffer_indexed:
|
|
if(item_ubo_id >= 992)
|
|
{
|
|
item_ubo_id = 0;
|
|
ubo_start = data_index;
|
|
ubos[0].bindRange(Buffer.BindTarget.uniform,0,ubo_start,block_max_size);
|
|
}
|
|
glUniform1i(0,item_ubo_id++);
|
|
break;
|
|
default:break;
|
|
}//*/
|
|
|
|
/*version(ver3)ubos[0].bindRange(Buffer.BindTarget.uniform,0,data_index,data_offset);
|
|
else version(ver1)
|
|
{
|
|
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]);
|
|
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]);
|
|
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]);
|
|
}
|
|
else version(ver2)glUniform4fv(0,12,cast(float*)(uniform_block.ptr+data_index));
|
|
else version(ver4)
|
|
{
|
|
if(item_ubo_id >= 992)
|
|
{
|
|
item_ubo_id = 0;
|
|
ubo_start = data_index;
|
|
ubos[0].bindRange(Buffer.BindTarget.uniform,0,ubo_start,block_max_size);
|
|
}
|
|
glUniform1i(0,item_ubo_id++);
|
|
}//*/
|
|
|
|
glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_SHORT,null);
|
|
//glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
|
data_index += data_offset;
|
|
}
|
|
//glEndQuery(GL_TIME_ELAPSED);
|
|
//uint tmpq = time_queries[0];
|
|
//time_queries[0] = time_queries[1];
|
|
//time_queries[1] = tmpq;
|
|
/*Buffer tmpb = ubos[0];
|
|
ubos[0] = ubos[1];
|
|
ubos[1] = tmpb;//*/
|
|
|
|
data_index = 0;
|
|
//data_offset = 0;
|
|
item_id = 0;
|
|
//SDL_GL_SwapWindow(sdl_window);
|
|
//glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
|
|
//version(ver6)ubos[0].map(0, 64*MaxObjects, Buffer.BindTarget.uniform);
|
|
//ubos[0].map(Buffer.BindTarget.uniform);
|
|
|
|
switch(technique)
|
|
{
|
|
case Technique.uniform_buffer_instanced_mapped_gl2:
|
|
ubos[0].map(Buffer.BindTarget.uniform);
|
|
//data_ptr = ubos[0].mappedPointer();
|
|
break;
|
|
case Technique.uniform_buffer_instanced_mapped:
|
|
ubos[0].map(0, 64*MaxObjects, Buffer.BindTarget.uniform);
|
|
//data_ptr = ubos[0].mappedPointer();
|
|
break;
|
|
default:break;
|
|
}
|
|
|
|
if(ubos[0].data && ubos[0].mappedPointer)
|
|
{
|
|
data_ptr = ubos[0].mappedPointer;
|
|
}
|
|
|
|
/*switch(technique)
|
|
{
|
|
case Technique.simple:
|
|
case Technique.simple_array:
|
|
case Technique.uniform_buffer:
|
|
case Technique.uniform_buffer_indexed:
|
|
case Technique.uniform_buffer_instanced:
|
|
case Technique.uniform_buffer_instanced_mapped:
|
|
case Technique.uniform_buffer_instanced_persistent_mapped:
|
|
default:break;
|
|
}*/
|
|
}
|
|
glDisableVertexAttribArray(0);
|
|
glDisableVertexAttribArray(1);
|
|
/*glUseProgram(0);
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);*/
|
|
//glDisable(GL_ALPHA_TEST);
|
|
}
|
|
|
|
void resize(ivec2 size)
|
|
{
|
|
resolution = size;
|
|
dres = vec2(1.0/cast(float)size.x,1.0/cast(float)size.y);
|
|
}
|
|
|
|
void view(vec2 pos, vec2 size)
|
|
{
|
|
//view_pos = pos * size - 1;
|
|
view_size = vec2(2/size.x,2/size.y);
|
|
sdl_transform = vec4(0,0,1.0/size.x,1.0/size.y);
|
|
view_pos = (pos - size * 0.5) * view_size;
|
|
}
|
|
|
|
__gshared void function(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, float angle, uint material_id, uint mesh_id) __draw;
|
|
__gshared void function(ref Renderer this_) __present;
|
|
__gshared void function(ref Renderer this_) __clear;
|
|
__gshared void function(ref Renderer this_) __initialize;
|
|
|
|
static void __loadBackend()
|
|
{
|
|
//this.technique = __ecs_used_technique;
|
|
if(technique == Technique.vbo_batch)__draw = &__draw_gl_vbo_batch;
|
|
else __draw = &__draw_gl;
|
|
__present = &__present_gl;
|
|
__clear = &__clear_gl;
|
|
__initialize = &__initialize_gl;
|
|
}
|
|
|
|
} |