#include "gl_2d.h" #include "../util.h" #include "gl.h" GL_SHADER_PROGRAM* gl_2d_init( GL_DATA* gl, VEC2 screensize, const char* shadername ) { GL_SHADER_PROGRAM* program = gl_program_create( gl, shadername ); if( !OK( gl_program_compile( gl, program ) ) ) dlog( "gl_2d_init() : error compiling shader %s\n", shadername ); F32 screen_ratio[] = { 2.f / screensize.x, 2.f / screensize.y, 1.f, 1.f }; glUseProgram( program->id ); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); I32 ratio_location = glGetUniformLocation( program->id, "g_screenratio" ); glUniform4fv( ratio_location, 1, &screen_ratio[0] ); I32 samplers_location = glGetUniformLocation( program->id, "g_samplers" ); glUniform1iv( samplers_location, 255, SAMPLER_INDICES ); return program; } void gl_2d_batch_setup( GL_BATCH2D* batch ) { glUseProgram( batch->shader->id ); glBindBuffer( GL_ARRAY_BUFFER, batch->vbuffer ); I32 position = glGetAttribLocation( batch->shader->id, "in_pos" ); I32 color = glGetAttribLocation( batch->shader->id, "in_clr" ); I32 texcoord = glGetAttribLocation( batch->shader->id, "in_texcoord" ); I32 sampler = glGetAttribLocation( batch->shader->id, "in_sampler" ); glEnableVertexAttribArray( position ); glVertexAttribPointer( position, 2, GL_FLOAT, 0, sizeof(VERTEX), 0 ); glEnableVertexAttribArray( color ); glVertexAttribPointer( color, 4, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->clr ); glEnableVertexAttribArray( texcoord ); glVertexAttribPointer( texcoord, 2, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->uv ); glEnableVertexAttribArray( sampler ); glVertexAttribPointer( sampler, 1, GL_UNSIGNED_BYTE, 1, sizeof(VERTEX), &( (VERTEX*)nullptr)->sampler ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); } void gl_2d_line( GL_SHADER_PROGRAM* gl2d, VEC2 start, VEC2 end, CLR col ) { static const U16 order[] = { 0, 1 }; glUseProgram( gl2d->id ); VERTEX vertices[] = { { .pos = { start.x, start.y }, .clr = col }, { .pos = { end.x, end.y }, .clr = col }, }; glBindBuffer( GL_ARRAY_BUFFER, gl2d->gl->vbuffer ); glBufferData( GL_ARRAY_BUFFER, sizeof(vertices), &vertices[0], GL_DYNAMIC_DRAW ); I32 position = glGetAttribLocation( gl2d->id, "in_pos" ); glEnableVertexAttribArray( position ); glVertexAttribPointer( position, 2, GL_FLOAT, 0, sizeof(VERTEX), 0 ); I32 color = glGetAttribLocation( gl2d->id, "in_clr" ); glEnableVertexAttribArray( color ); glVertexAttribPointer( color, 4, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->clr ); I32 sampler = glGetAttribLocation( gl2d->id, "in_sampler" ); glEnableVertexAttribArray( sampler ); glVertexAttribPointer( sampler, 1, GL_UNSIGNED_BYTE, 1, sizeof(VERTEX), &( (VERTEX*)nullptr)->sampler ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); glDrawElements( GL_LINES, 2, GL_UNSIGNED_SHORT, order ); } void gl_2d_rect( GL_SHADER_PROGRAM* gl2d, VEC2 origin, VEC2 dim, CLR col ) { static const U16 order[] = { 0, 1, 2, 3, 4 }; glUseProgram( gl2d->id ); VERTEX vertices[] = { { .pos = { origin.x , origin.y }, .clr = col }, { .pos = { origin.x + dim.x, origin.y }, .clr = col }, { .pos = { origin.x + dim.x, origin.y + dim.y }, .clr = col }, { .pos = { origin.x , origin.y + dim.y }, .clr = col }, { .pos = { origin.x , origin.y }, .clr = col }, }; glBindBuffer( GL_ARRAY_BUFFER, gl2d->gl->vbuffer ); glBufferData( GL_ARRAY_BUFFER, sizeof(vertices), &vertices[0], GL_DYNAMIC_DRAW ); I32 position = glGetAttribLocation( gl2d->id, "in_pos" ); glEnableVertexAttribArray( position ); glVertexAttribPointer( position, 2, GL_FLOAT, 0, sizeof(VERTEX), 0 ); I32 color = glGetAttribLocation( gl2d->id, "in_clr" ); glEnableVertexAttribArray( color ); glVertexAttribPointer( color, 4, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->clr ); I32 sampler = glGetAttribLocation( gl2d->id, "in_sampler" ); glEnableVertexAttribArray( sampler ); glVertexAttribPointer( sampler, 1, GL_UNSIGNED_BYTE, 1, sizeof(VERTEX), &( (VERTEX*)nullptr)->sampler ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); glDrawElements( GL_LINE_STRIP, 5, GL_UNSIGNED_SHORT, order ); } void gl_2d_frect( GL_SHADER_PROGRAM* gl2d, VEC2 origin, VEC2 dim, CLR col ) { static const U16 order[] = { 0, 1, 2, 3 }; glUseProgram( gl2d->id ); VERTEX vertices[] = { { .pos = { origin.x, origin.y }, .uv = { 0.f, 0.f }, .clr = col }, { .pos = { origin.x + dim.x, origin.y }, .uv = { 1.f, 0.f }, .clr = col }, { .pos = { origin.x, origin.y + dim.y }, .uv = { 0.f, 1.f }, .clr = col }, { .pos = { origin.x + dim.x, origin.y + dim.y }, .uv = { 1.f, 1.f }, .clr = col } }; glBindBuffer( GL_ARRAY_BUFFER, gl2d->gl->vbuffer ); glBufferData( GL_ARRAY_BUFFER, sizeof(vertices), &vertices[0], GL_DYNAMIC_DRAW ); I32 position = glGetAttribLocation( gl2d->id, "in_pos" ); I32 color = glGetAttribLocation( gl2d->id, "in_clr" ); glEnableVertexAttribArray( position ); glVertexAttribPointer( position, 2, GL_FLOAT, 0, sizeof(VERTEX), 0 ); glEnableVertexAttribArray( color ); glVertexAttribPointer( color, 4, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->clr ); I32 texcoord = glGetAttribLocation( gl2d->id, "in_texcoord" ); glEnableVertexAttribArray( texcoord ); glVertexAttribPointer( texcoord, 2, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->uv ); I32 sampler = glGetAttribLocation( gl2d->id, "in_sampler" ); glEnableVertexAttribArray( sampler ); glVertexAttribPointer( sampler, 1, GL_UNSIGNED_BYTE, 1, sizeof(VERTEX), &( (VERTEX*)nullptr)->sampler ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); glDrawElements( GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, order ); } void gl_2d_circle( GL_SHADER_PROGRAM* gl2d, VEC2 origin, F32 radius, CLR col, U32 res ) { static U16* order = 0; const F32 step = 360.f / (F32)res; glUseProgram( gl2d->id ); if( !order ) { order = (U16*)malloc( sizeof( U16 ) * (res + 1) ); for( U32 i = 0; i < res + 1; ++i ) order[i] = i; } VERTEX* vertices = (VERTEX*)malloc( sizeof( VERTEX ) * (res + 1) ); for( U32 i = 0; i < res + 1; ++i ) { VEC2 offset = m_radial_offset( step * ( i == res? 0 : i ), radius ); vertices[i] = (VERTEX){ .pos = { origin.x + offset.x, origin.y + offset.y, }, .uv = {}, .clr = col }; } glBindBuffer( GL_ARRAY_BUFFER, gl2d->gl->vbuffer ); glBufferData( GL_ARRAY_BUFFER, sizeof(VERTEX) * (res + 1), &vertices[0], GL_STATIC_DRAW ); I32 position = glGetAttribLocation( gl2d->id, "in_pos" ); glEnableVertexAttribArray( position ); glVertexAttribPointer( position, 2, GL_FLOAT, 0, sizeof(VERTEX), 0 ); I32 color = glGetAttribLocation( gl2d->id, "in_clr" ); glEnableVertexAttribArray( color ); glVertexAttribPointer( color, 4, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->clr ); I32 sampler = glGetAttribLocation( gl2d->id, "in_sampler" ); glEnableVertexAttribArray( sampler ); glVertexAttribPointer( sampler, 1, GL_UNSIGNED_BYTE, 1, sizeof(VERTEX), &( (VERTEX*)nullptr)->sampler ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); glDrawElements( GL_LINE_STRIP, res + 1, GL_UNSIGNED_SHORT, order ); free( vertices ); } void gl_2d_fcircle( GL_SHADER_PROGRAM* gl2d, VEC2 origin, F32 radius, CLR col, U32 res ) { static U16* order = 0; const F32 step = 360.f / (F32)res; glUseProgram( gl2d->id ); if( !order ) { order = (U16*)malloc( sizeof( U16 ) * (res * 2) ); for( U32 i = 0; i < res * 2; ++i ) order[i] = i; } VERTEX* vertices = (VERTEX*)malloc( sizeof(VERTEX) * (res * 2) ); for( U32 i = 0; i < res * 2; i += 2 ) { VEC2 offset = m_radial_offset( step * i, radius ); vertices[i].pos = (VEC2){ origin.x, origin.y, }; vertices[i + 1].pos = (VEC2){ origin.x + offset.x, origin.y + offset.y, }; vertices[i].uv = (VEC2){ 0.5f, 0.5f }; vertices[i + 1].uv = (VEC2){ 0.5f + ( offset.x * 0.5f ) / radius, 0.5f + ( offset.y * 0.5f ) / radius }; vertices[i].clr = col; vertices[i + 1].clr = col; }; glBindBuffer( GL_ARRAY_BUFFER, gl2d->gl->vbuffer ); glBufferData( GL_ARRAY_BUFFER, sizeof(VERTEX) * res * 2, &vertices[0], GL_STATIC_DRAW ); I32 position = glGetAttribLocation( gl2d->id, "in_pos" ); glEnableVertexAttribArray( position ); glVertexAttribPointer( position, 2, GL_FLOAT, 0, sizeof(VERTEX), 0 ); I32 color = glGetAttribLocation( gl2d->id, "in_clr" ); glEnableVertexAttribArray( color ); glVertexAttribPointer( color, 4, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->clr ); I32 texcoord = glGetAttribLocation( gl2d->id, "in_texcoord" ); glEnableVertexAttribArray( texcoord ); glVertexAttribPointer( texcoord, 2, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->uv ); I32 sampler = glGetAttribLocation( gl2d->id, "in_sampler" ); glEnableVertexAttribArray( sampler ); glVertexAttribPointer( sampler, 1, GL_UNSIGNED_BYTE, 1, sizeof(VERTEX), &( (VERTEX*)nullptr)->sampler ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); glDrawElements( GL_TRIANGLE_STRIP, res + 2, GL_UNSIGNED_SHORT, order ); free( vertices ); } void gl_2d_polygon( GL_SHADER_PROGRAM* gl2d, VERTEX* vertices, U32 vertices_count ) { glUseProgram( gl2d->id ); glBindBuffer( GL_ARRAY_BUFFER, gl2d->gl->vbuffer ); glBufferData( GL_ARRAY_BUFFER, sizeof(VERTEX) * vertices_count, vertices, GL_STATIC_DRAW ); I32 position = glGetAttribLocation( gl2d->id, "in_pos" ); glEnableVertexAttribArray( position ); glVertexAttribPointer( position, 2, GL_FLOAT, 0, sizeof(VERTEX), 0 ); I32 color = glGetAttribLocation( gl2d->id, "in_clr" ); glEnableVertexAttribArray( color ); glVertexAttribPointer( color, 4, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->clr ); I32 texcoord = glGetAttribLocation( gl2d->id, "in_texcoord" ); glEnableVertexAttribArray( texcoord ); glVertexAttribPointer( texcoord, 2, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->uv ); I32 sampler = glGetAttribLocation( gl2d->id, "in_sampler" ); glEnableVertexAttribArray( sampler ); glVertexAttribPointer( sampler, 1, GL_UNSIGNED_BYTE, 1, sizeof(VERTEX), &( (VERTEX*)nullptr)->sampler ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); U16* order = (U16*)alloca( sizeof(U16) * vertices_count ); for( U32 i = 0; i < vertices_count; i++ ) order[i] = i; glDrawElements( GL_TRIANGLE_FAN, vertices_count, GL_UNSIGNED_SHORT, order ); } void gl_2d_textured_polygon( GL_SHADER_PROGRAM *gl2d, VERTEX *vertices, U32 vertices_count, GL_TEX2D *tex ) { glUseProgram( gl2d->id ); for( U32 i = 0; i < vertices_count; ++i ) vertices[i].sampler = 0; glBindBuffer( GL_ARRAY_BUFFER, gl2d->gl->vbuffer ); glBufferData( GL_ARRAY_BUFFER, sizeof(VERTEX) * vertices_count, vertices, GL_STATIC_DRAW ); I32 position = glGetAttribLocation( gl2d->id, "in_pos" ); glEnableVertexAttribArray( position ); glVertexAttribPointer( position, 2, GL_FLOAT, 0, sizeof(VERTEX), 0 ); I32 color = glGetAttribLocation( gl2d->id, "in_clr" ); glEnableVertexAttribArray( color ); glVertexAttribPointer( color, 4, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->clr ); I32 texcoord = glGetAttribLocation( gl2d->id, "in_texcoord" ); glEnableVertexAttribArray( texcoord ); glVertexAttribPointer( texcoord, 2, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->uv ); I32 sampler = glGetAttribLocation( gl2d->id, "in_sampler" ); glEnableVertexAttribArray( sampler ); glVertexAttribPointer( sampler, 1, GL_UNSIGNED_BYTE, 1, sizeof(VERTEX), &( (VERTEX*)nullptr)->sampler ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); glActiveTexture( GL_TEXTURE0 ); glBindTexture( GL_TEXTURE_2D, tex->id ); U16* order = (U16*)alloca( sizeof(U16) * vertices_count ); for( U32 i = 0; i < vertices_count; i++ ) order[i] = i; glDrawElements( GL_TRIANGLE_FAN, vertices_count, GL_UNSIGNED_SHORT, order ); } void gl_2d_textured_frect( GL_SHADER_PROGRAM* gl2d, VEC2 origin, VEC2 dim, GL_TEX2D* texture, CLR col, VEC2* uv, F32 rotation ) { static const U16 order[] = { 0, 1, 2, 3 }; glUseProgram( gl2d->id ); VERTEX vertices[] = { { { origin.x, origin.y }, uv? uv[0] : VEC2{ 0.f, 0.f }, col, 0 }, { { origin.x + dim.x, origin.y }, uv? uv[1] : VEC2{ 1.f, 0.f }, col, 0 }, { { origin.x, origin.y + dim.y }, uv? uv[2] : VEC2{ 0.f, 1.f }, col, 0 }, { { origin.x + dim.x, origin.y + dim.y }, uv? uv[3] : VEC2{ 1.f, 1.f }, col, 0 } }; rotation = remainderf( rotation, 360.f ); if( rotation != 0.f ) { F32 rad2dg = rotation * (M_PI / 180.f); // rotate texture coordinates for( U32 i = 0; i < 4; ++i ) { F32 x = vertices[i].uv.x - 0.5f; F32 y = vertices[i].uv.y - 0.5f; vertices[i].uv.x = x * cosf( rad2dg ) - y * sinf( rad2dg ) + 0.5f; vertices[i].uv.y = x * sinf( rad2dg ) + y * cosf( rad2dg ) + 0.5f; if( vertices[i].uv.x < 0.f ) vertices[i].uv.x = 0.f; if( vertices[i].uv.x > 1.f ) vertices[i].uv.x = 1.f; } } glBindBuffer( GL_ARRAY_BUFFER, gl2d->gl->vbuffer ); glBufferData( GL_ARRAY_BUFFER, sizeof(vertices), &vertices[0], GL_DYNAMIC_DRAW ); I32 position = glGetAttribLocation( gl2d->id, "in_pos" ); I32 color = glGetAttribLocation( gl2d->id, "in_clr" ); I32 texcoord = glGetAttribLocation( gl2d->id, "in_texcoord" ); I32 sampler = glGetAttribLocation( gl2d->id, "in_sampler" ); glEnableVertexAttribArray( position ); glVertexAttribPointer( position, 2, GL_FLOAT, 0, sizeof(VERTEX), 0 ); glEnableVertexAttribArray( color ); glVertexAttribPointer( color, 4, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->clr ); glEnableVertexAttribArray( texcoord ); glVertexAttribPointer( texcoord, 2, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->uv ); glEnableVertexAttribArray( sampler ); glVertexAttribPointer( sampler, 1, GL_UNSIGNED_BYTE, 1, sizeof(VERTEX), &( (VERTEX*)nullptr)->sampler ); glActiveTexture( GL_TEXTURE0 ); glBindTexture( GL_TEXTURE_2D, texture->id ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); glActiveTexture( GL_TEXTURE0 ); glBindTexture( GL_TEXTURE_2D, texture->id ); // glUniform1f( glGetUniformLocation( gl2d->id, "in_time" ), u_time() ); glDrawElements( GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, order ); glBindTexture( GL_TEXTURE_2D, 0 ); } void gl_2d_line( GL_BATCH2D* batch, VEC2 start, VEC2 end, CLR col ) { VERTEX vertices[] = { { .pos = { start.x, start.y }, .clr = col }, { .pos = { end.x, end.y }, .clr = col }, }; gl_batch_insert( batch, vertices, 2, 0, GL_LINES ); } void gl_2d_rect( GL_BATCH2D* batch, VEC2 origin, VEC2 dim, CLR col ) { VERTEX vertices[] = { { .pos = { origin.x , origin.y }, .clr = col }, { .pos = { origin.x + dim.x, origin.y }, .clr = col }, { .pos = { origin.x + dim.x, origin.y + dim.y }, .clr = col }, { .pos = { origin.x , origin.y + dim.y }, .clr = col }, { .pos = { origin.x , origin.y }, .clr = col }, }; gl_batch_insert( batch, vertices, 5, 0, GL_LINE_STRIP ); } void gl_2d_frect( GL_BATCH2D* batch, VEC2 origin, VEC2 dim, CLR col ) { VERTEX vertices[] = { { .pos = { origin.x, origin.y }, .uv = { 0.f, 0.f }, .clr = col }, { .pos = { origin.x + dim.x, origin.y }, .uv = { 1.f, 0.f }, .clr = col }, { .pos = { origin.x, origin.y + dim.y }, .uv = { 0.f, 1.f }, .clr = col }, { .pos = { origin.x + dim.x, origin.y + dim.y }, .uv = { 1.f, 1.f }, .clr = col } }; gl_batch_insert( batch, vertices, 4, 0, GL_TRIANGLE_STRIP ); } void gl_2d_circle( GL_BATCH2D* batch, VEC2 origin, F32 radius, CLR col, U32 res ) { const F32 step = 360.f / (F32)res; VERTEX* vertices = (VERTEX*)malloc( sizeof( VERTEX ) * (res + 1) ); for( U32 i = 0; i < res + 1; ++i ) { VEC2 offset = m_radial_offset( step * ( i == res? 0 : i ), radius ); vertices[i] = (VERTEX){ .pos = { origin.x + offset.x, origin.y + offset.y, }, .uv = {}, .clr = col }; } gl_batch_insert( batch, vertices, res + 1, 0, GL_LINE_STRIP ); } void gl_2d_fcircle( GL_BATCH2D* batch, VEC2 origin, F32 radius, CLR col, U32 res ) { const F32 step = 360.f / (F32)res; VERTEX* vertices = (VERTEX*)malloc( sizeof(VERTEX) * (res * 2) ); for( U32 i = 0; i < res * 2; i += 2 ) { VEC2 offset = m_radial_offset( step * i, radius ); vertices[i].pos = (VEC2){ origin.x, origin.y, }; vertices[i + 1].pos = (VEC2){ origin.x + offset.x, origin.y + offset.y, }; vertices[i].uv = (VEC2){ 0.5f, 0.5f }; vertices[i + 1].uv = (VEC2){ 0.5f + ( offset.x * 0.5f ) / radius, 0.5f + ( offset.y * 0.5f ) / radius }; vertices[i].clr = col; vertices[i + 1].clr = col; }; gl_batch_insert( batch, vertices, res * 2, 0, GL_TRIANGLE_STRIP ); } extern void gl_2d_textured_frect( GL_BATCH2D* batch, VEC2 origin, VEC2 dim, GL_TEX2D* texture, CLR col, VEC2* uv, F32 rotation ) { VERTEX vertices[] = { { { origin.x, origin.y }, uv? uv[0] : VEC2{ 0.f, 0.f }, col, 0 }, { { origin.x + dim.x, origin.y }, uv? uv[1] : VEC2{ 1.f, 0.f }, col, 0 }, { { origin.x, origin.y + dim.y }, uv? uv[2] : VEC2{ 0.f, 1.f }, col, 0 }, { { origin.x + dim.x, origin.y + dim.y }, uv? uv[3] : VEC2{ 1.f, 1.f }, col, 0 } }; rotation = remainderf( rotation, 360.f ); if( rotation != 0.f ) { F32 rad2dg = rotation * (M_PI / 180.f); // rotate texture coordinates for( U32 i = 0; i < 4; ++i ) { F32 x = vertices[i].uv.x - 0.5f; F32 y = vertices[i].uv.y - 0.5f; vertices[i].uv.x = x * cosf( rad2dg ) - y * sinf( rad2dg ) + 0.5f; vertices[i].uv.y = x * sinf( rad2dg ) + y * cosf( rad2dg ) + 0.5f; if( vertices[i].uv.x < 0.f ) vertices[i].uv.x = 0.f; if( vertices[i].uv.x > 1.f ) vertices[i].uv.x = 1.f; } } gl_batch_insert( batch, vertices, 4, texture, GL_TRIANGLE_FAN ); } void gl_2d_polygon( GL_BATCH2D* batch, VERTEX* vertices, U32 vertices_count ) { gl_batch_insert( batch, vertices, vertices_count, 0, GL_TRIANGLE_FAN ); } void gl_2d_textured_polygon( GL_BATCH2D* batch, VERTEX* vertices, U32 vertices_count, GL_TEX2D* tex ) { gl_batch_insert( batch, vertices, vertices_count, tex, GL_TRIANGLE_FAN ); }