#include "gl_3d.h" #include "../util/matrix.h" #include "gl.h" #include "gl_batch.h" GL3D* gl_3d_init( GL_DATA* gl, VEC2 screensize, const char* shadername ) { GL3D *gl3d = (GL3D*)gl_program_create( gl, shadername, sizeof(GL3D) ); if( !OK( gl_program_compile( gl, gl3d ) ) ) dlog( "gl_2d_init() : error compiling shader %s\n", shadername ); gl3d->winsize = screensize; gl3d->aspect = screensize.x / screensize.y; glUseProgram( gl3d->id ); I32 samplers_location = glGetUniformLocation( gl3d->id, "g_samplers" ); glUniform1iv( samplers_location, gl->shader_texture_limit, SAMPLER_INDICES ); return gl3d; } void gl_3d_projection_setup( GL_SHADER_PROGRAM *_gl3d, VEC3 pos, F32 fov_deg, F32 yaw, F32 pitch, F32 near, F32 far, VEC2 winsize ) { GL3D* gl3d = (GL3D*)_gl3d; MAT4 proj, yaw_rot, pitch_rot, view, transl, tmp; F32 fov_rad = m_deg2rad( fov_deg ); F32 yaw_rad = m_deg2rad( remainderf( yaw + 90.f, 360.f ) ); F32 pitch_rad = m_deg2rad( remainderf( pitch , 360.f ) ); gl3d->aspect = winsize.x / winsize.y; gl3d->winsize = winsize; mat4_perspective( &proj, fov_rad, gl3d->aspect, near, far ); mat4_rotation_y( &yaw_rot, -yaw_rad ); mat4_rotation_x( &pitch_rot, -pitch_rad ); mat4_translation( &transl, -pos.x, -pos.z, -pos.y ); mat4_mul( &yaw_rot, &transl, &tmp ); mat4_mul( &pitch_rot, &tmp, &view ); mat4_mul( &proj, &view, &gl3d->projmat ); gl3d->gl->proj_matrix = &gl3d->projmat; glUseProgram( gl3d->id ); I32 location = glGetUniformLocation( gl3d->id, "in_proj_matrix" ); glUniformMatrix4fv( location, 1, 1, (GLfloat*)&gl3d->projmat ); glUniform1f( glGetUniformLocation( gl3d->id, "in_time" ), u_time() ); } void gl_3d_batch_setup( GL_BATCH3D *batch ) { glUseProgram( batch->shader->id ); glBindBuffer( GL_ARRAY_BUFFER, batch->vbuffer ); I32 position = glGetAttribLocation( batch->shader->id, "in_pos" ); glEnableVertexAttribArray( position ); glVertexAttribPointer( position, 3, GL_FLOAT, 0, sizeof(VERTEX3D), 0 ); I32 color = glGetAttribLocation( batch->shader->id, "in_clr" ); glEnableVertexAttribArray( color ); glVertexAttribPointer( color, 3, GL_FLOAT, 0, sizeof(VERTEX3D), &( (VERTEX3D*)nullptr )->clr ); I32 texcoord = glGetAttribLocation( batch->shader->id, "in_texcoord" ); glEnableVertexAttribArray( texcoord ); glVertexAttribPointer( texcoord, 2, GL_FLOAT, 0, sizeof(VERTEX3D), &( (VERTEX3D*)nullptr )->uv ); I32 sampler = glGetAttribLocation( batch->shader->id, "in_sampler" ); glEnableVertexAttribArray( sampler ); glVertexAttribPointer( sampler, 1, GL_UNSIGNED_BYTE, 1, sizeof(VERTEX3D), &( (VERTEX3D*)nullptr )->sampler ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); } void gl_3d_polygon( GL_SHADER_PROGRAM* gl3d, VERTEX3D* vertices, U32 vertices_count, GL_TEX2D* tex ) { glUseProgram( gl3d->id ); if( !!tex ) { glActiveTexture( GL_TEXTURE0 ); glBindTexture( GL_TEXTURE_2D, tex->id ); } else { for( U32 i = 0; i < vertices_count; ++i ) vertices[i].sampler = SAMPLER_ID_NONE; } glBindBuffer( GL_ARRAY_BUFFER, gl3d->gl->vbuffer ); glBufferData( GL_ARRAY_BUFFER, sizeof(VERTEX3D) * vertices_count, vertices, GL_STATIC_DRAW ); I32 position = glGetAttribLocation( gl3d->id, "in_pos" ); glEnableVertexAttribArray( position ); glVertexAttribPointer( position, 3, GL_FLOAT, 0, sizeof(VERTEX3D), 0 ); I32 color = glGetAttribLocation( gl3d->id, "in_clr" ); glEnableVertexAttribArray( color ); glVertexAttribPointer( color, 3, GL_FLOAT, 0, sizeof(VERTEX3D), &( (VERTEX3D*)nullptr )->clr ); I32 texcoord = glGetAttribLocation( gl3d->id, "in_texcoord" ); glEnableVertexAttribArray( texcoord ); glVertexAttribPointer( texcoord, 2, GL_FLOAT, 0, sizeof(VERTEX3D), &( (VERTEX3D*)nullptr )->uv ); I32 sampler = glGetAttribLocation( gl3d->id, "in_sampler" ); glEnableVertexAttribArray( sampler ); glVertexAttribPointer( sampler, 1, GL_UNSIGNED_BYTE, 1, sizeof(VERTEX3D), &( (VERTEX3D*)nullptr )->sampler ); U16* order = (U16*)alloca( sizeof(U16) * vertices_count ); for( U32 i = 0; i < vertices_count; i++ ) order[i] = i; glBindBuffer( GL_ARRAY_BUFFER, 0 ); glDrawElements( GL_TRIANGLE_FAN, vertices_count, GL_UNSIGNED_SHORT, order ); } void gl_3d_polygon_fan( GL_BATCH3D* batch, VERTEX3D* vertices, U32 vertices_count, GL_TEX2D* tex ) { if( vertices_count < 3 ) return; LIST list = triangle_fan_to_list( vertices, vertices_count ); gl_batch_insert( batch, list.data, list.size, tex ); } void gl_3d_polygon( GL_BATCH3D* batch, VERTEX3D* vertices, U32 vertices_count, GL_TEX2D* tex ) { gl_batch_insert( batch, vertices, vertices_count, tex ); } void build_plane( VERTEX3D* v, VEC3 pos, VEC2 size, VEC2 rot, CLR col ) { F32 half_width = size.x * 0.5f; F32 half_height = size.y * 0.5f; VEC3 vertices[4] = { { -half_width, -half_height, 0 }, { half_width, -half_height, 0 }, { half_width, half_height, 0 }, { -half_width, half_height, 0 } }; F32 sin_pitch = sinf( m_deg2rad( rot.x ) ); F32 cos_pitch = cosf( m_deg2rad( rot.x ) ); F32 sin_yaw = sinf( m_deg2rad( rot.y ) ); F32 cos_yaw = cosf( m_deg2rad( rot.y ) ); for( I32 i = 0; i < 4; i++) { F32 x = vertices[i].x; F32 y = vertices[i].y; F32 z = vertices[i].z; vertices[i].y = y * cos_pitch - z * sin_pitch; vertices[i].z = y * sin_pitch + z * cos_pitch; y = vertices[i].y; vertices[i].x = x * cos_yaw - y * sin_yaw; vertices[i].y = x * sin_yaw + y * cos_yaw; vertices[i].x += pos.x; vertices[i].y += pos.y; vertices[i].z += pos.z; } VEC2 uvs[4] = { { 0.0f, 1.0f }, { 1.0f, 1.0f }, { 1.0f, 0.0f }, { 0.0f, 0.0f } }; v[0] = { .pos = { vertices[0].x, vertices[0].z, vertices[0].y }, .uv = uvs[0], .clr = col, .sampler = 0 }; v[1] = { .pos = { vertices[1].x, vertices[1].z, vertices[1].y }, .uv = uvs[1], .clr = col, .sampler = 0 }; v[2] = { .pos = { vertices[2].x, vertices[2].z, vertices[2].y }, .uv = uvs[2], .clr = col, .sampler = 0 }; v[3] = { .pos = { vertices[3].x, vertices[3].z, vertices[3].y }, .uv = uvs[3], .clr = col, .sampler = 0 }; } void gl_3d_plane( GL_SHADER_PROGRAM* gl3d, VEC3 pos, VEC2 size, VEC2 rot, GL_TEX2D* tex, CLR col ) { VERTEX3D v[4]; build_plane( v, pos, size, rot, col ); gl_3d_polygon( gl3d, v, 4, tex ); } void gl_3d_plane( GL_BATCH3D* batch, VEC3 pos, VEC2 size, VEC2 rot, GL_TEX2D* tex, CLR col ) { VERTEX3D v[4]; build_plane( v, pos, size, rot, col ); gl_3d_polygon_fan( batch, v, 4, tex ); }