--- /dev/null
+static void init_mesh( struct mesh *m, float const *tris, u32 length ){
+ m->elements = length/3;
+ glGenVertexArrays( 1, &m->vao );
+ glGenBuffers( 1, &m->vbo );
+
+ glBindVertexArray( m->vao );
+ glBindBuffer( GL_ARRAY_BUFFER, m->vbo );
+ glBufferData( GL_ARRAY_BUFFER, length*sizeof(float), tris, GL_STATIC_DRAW );
+
+ glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), (void*)0 );
+ glEnableVertexAttribArray( 0 );
+
+ VG_CHECK_GL();
+}
+
+static void free_mesh( struct mesh *m ){
+ glDeleteVertexArrays( 1, &m->vao );
+ glDeleteBuffers( 1, &m->vbo );
+}
+
+static void draw_mesh( int const start, int const count ){
+ glDrawArrays( GL_TRIANGLES, start*3, count*3 );
+}
+
+static void use_mesh( struct mesh *m ){
+ glBindVertexArray( m->vao );
+}
+
+#define TRANSFORM_TRI_2D( S, OX, OY, X1, Y1, X2, Y2, X3, Y3 ) \
+ X1*S+OX, Y1*S+OY, X2*S+OX, Y2*S+OY, X3*S+OX, Y3*S+OY
+
+static void render_init(void){
+ // Combined quad, long quad / empty circle / filled circle mesh
+ float combined_mesh[6*6 + 32*6*3] = {
+ 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f,
+
+ 0.0f, 0.0f, 0.0f, 0.2f, 1.0f, 0.2f,
+ 0.0f, 0.0f, 1.0f, 0.2f, 1.0f, 0.0f,
+
+ TRANSFORM_TRI_2D( 0.15f,0.05f,0.4f, 0.0f, 1.0f, 1.0f, 2.0f, 1.0f, 0.0f ),
+ TRANSFORM_TRI_2D( 0.15f,0.80f,0.4f, 0.0f, 0.0f, 0.0f, 2.0f, 1.0f, 1.0f )
+ };
+
+ float *circle_mesh = combined_mesh + 6*6;
+ int const res = 32;
+ for( int i=0; i < res; i ++ ){
+ v2f v0 = { sinf( ((float)i/(float)res)*VG_TAUf ),
+ cosf( ((float)i/(float)res)*VG_TAUf ) };
+ v2f v1 = { sinf( ((float)(i+1)/(float)res)*VG_TAUf ),
+ cosf( ((float)(i+1)/(float)res)*VG_TAUf ) };
+
+ circle_mesh[ i*6+0 ] = 0.0f;
+ circle_mesh[ i*6+1 ] = 0.0f;
+
+ v2_copy( v0, circle_mesh + 32*6 + i*12 );
+ v2_muls( v0, 0.8f, circle_mesh + 32*6 + i*12+2 );
+ v2_copy( v1, circle_mesh + 32*6 + i*12+4 );
+
+ v2_copy( v1, circle_mesh + 32*6 + i*12+6 );
+ v2_muls( v1, 0.8f, circle_mesh + 32*6 + i*12+8 );
+ v2_muls( v0, 0.8f, circle_mesh + 32*6 + i*12+10 );
+
+ v2_copy( v0, circle_mesh + i*6+4 );
+ v2_copy( v1, circle_mesh + i*6+2 );
+ v2_copy( v0, circle_mesh+i*6+4 );
+ v2_copy( v1, circle_mesh+i*6+2 );
+ }
+ init_mesh( &world.shapes, combined_mesh, vg_list_size( combined_mesh ) );
+
+ // Create wire mesh
+ int const num_segments = 64;
+ struct mesh_wire *mw = &world.wire;
+
+ v2f wire_points[ num_segments * 2 ];
+ u16 wire_indices[ 6*(num_segments-1) ];
+
+ for( int i = 0; i < num_segments; i ++ ){
+ float l = (float)i / (float)(num_segments-1);
+
+ v2_copy( (v2f){ l, -0.5f }, wire_points[i*2+0] );
+ v2_copy( (v2f){ l, 0.5f }, wire_points[i*2+1] );
+
+ if( i < num_segments-1 ){
+ wire_indices[ i*6+0 ] = i*2 + 0;
+ wire_indices[ i*6+1 ] = i*2 + 1;
+ wire_indices[ i*6+2 ] = i*2 + 3;
+ wire_indices[ i*6+3 ] = i*2 + 0;
+ wire_indices[ i*6+4 ] = i*2 + 3;
+ wire_indices[ i*6+5 ] = i*2 + 2;
+ }
+ }
+
+ glGenVertexArrays( 1, &mw->vao );
+ glGenBuffers( 1, &mw->vbo );
+ glGenBuffers( 1, &mw->ebo );
+ glBindVertexArray( mw->vao );
+
+ glBindBuffer( GL_ARRAY_BUFFER, mw->vbo );
+
+ glBufferData( GL_ARRAY_BUFFER, sizeof( wire_points ),
+ wire_points, GL_STATIC_DRAW );
+ glBindVertexArray( mw->vao );
+
+ glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, mw->ebo );
+ glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof( wire_indices ),
+ wire_indices, GL_STATIC_DRAW );
+
+ // XY
+ glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), (void*)0 );
+ glEnableVertexAttribArray( 0 );
+
+ VG_CHECK_GL();
+ mw->em = vg_list_size( wire_indices );
+
+ // Create info data texture
+ glGenTextures( 1, &world.background_data );
+ glBindTexture( GL_TEXTURE_2D, world.background_data );
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 64, 64, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, NULL );
+ vg_tex2d_nearest();
+
+ // Create random smaples texture
+ u8 *data = malloc(512*512*2);
+ for( int i = 0; i < 512*512*2; i ++ )
+ data[ i ] = rand()/(RAND_MAX/255);
+
+ glGenTextures( 1, &world.random_samples );
+ glBindTexture( GL_TEXTURE_2D, world.random_samples );
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RG, 512, 512, 0, GL_RG,
+ GL_UNSIGNED_BYTE, data );
+ vg_tex2d_nearest();
+ vg_tex2d_repeat();
+ free( data );
+
+ resource_load_main();
+
+ // Init world text
+ //ui_init_context( &world.st.world_text, 15000 );
+
+ // Restore gamestate
+ career_local_data_init();
+ career_load();
+
+ /* Create framebuffers */
+ glGenFramebuffers( 1, &world.st.framebuffer );
+ glBindFramebuffer( GL_FRAMEBUFFER, world.st.framebuffer );
+
+ glGenTextures( 1, &world.st.colourbuffer );
+ glBindTexture( GL_TEXTURE_2D, world.st.colourbuffer );
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, vg_window_x, vg_window_y,
+ 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
+
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ world.st.colourbuffer, 0);
+
+ /* Bloom framebuffer (quater res) */
+ glGenFramebuffers( 2, world.st.bloomframebuffer );
+ glGenTextures( 2, world.st.bloomcolourbuffer );
+
+ for( int i=0; i<2; i++ ){
+ glBindFramebuffer( GL_FRAMEBUFFER, world.st.bloomframebuffer[i] );
+
+ glBindTexture( GL_TEXTURE_2D, world.st.bloomcolourbuffer[i] );
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB,
+ vg_window_x/EFFECT_BUFFER_RATIO, vg_window_y/EFFECT_BUFFER_RATIO,
+ 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
+ vg_tex2d_clamp();
+
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D, world.st.bloomcolourbuffer[i], 0);
+ }
+}