+ //glDisable(GL_BLEND);
+
+ glDisable(GL_BLEND);
+
+ SHADER_USE( shader_tile_colour );
+ glUniformMatrix3fv( SHADER_UNIFORM( shader_tile_colour, "uPv" ), 1, GL_FALSE, (float *)vg_pv );
+ use_mesh( &world.circle );
+
+ // Draw i/o arrays
+ for( int i = 0; i < arrlen( world.io ); i ++ )
+ {
+ struct cell_terminal *term = &world.io[ i ];
+ int posx = term->id % world.w;
+ int posy = (term->id - posx)/world.w;
+ int is_input = world.data[ term->id ].state & FLAG_INPUT;
+
+ int const filled_start = 0;
+ int const filled_count = 32;
+ int const empty_start = 32;
+ int const empty_count = 32*2;
+
+ v4f dot_colour = { 0.0f, 0.0f, 0.0f, 1.0f };
+
+ for( int j = 0; j < arrlen( term->conditions ); j ++ )
+ {
+ float y_offset = is_input? 0.8f: 0.2f;
+ glUniform3f( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), (float)posx + 0.2f + 0.2f * (float)j, (float)posy + y_offset, 0.1f );
+
+ if( is_input )
+ {
+ colour_code_v3( term->conditions[j], dot_colour );
+ glUniform4fv( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 1, dot_colour );
+
+ // Draw filled if tick not passed, draw empty if empty
+ if( world.sim_frame > j )
+ draw_mesh( empty_start, empty_count );
+ else
+ draw_mesh( filled_start, filled_count );
+ }
+ else
+ {
+ if( term->recv_count > j )
+ {
+ colour_code_v3( term->recv[j], dot_colour );
+ v3_muls( dot_colour, 0.8f, dot_colour );
+ glUniform4fv( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 1, dot_colour );
+
+ draw_mesh( filled_start, filled_count );
+ }
+
+ colour_code_v3( term->conditions[j], dot_colour );
+ glUniform4fv( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 1, dot_colour );
+
+ draw_mesh( empty_start, empty_count );
+ }
+ }
+ }
+
+ if( world.simulating )
+ {
+ glUniform4f( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 0.0f, 0.0f, 0.0f, 1.0f );
+ glUniform3f( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), -0.5f + cosf( vg_time * 4.0f ) * 0.2f, sinf( vg_time * 4.0f ) * 0.2f + (float)world.h * 0.5f, 0.05f );
+ draw_mesh( 0, 32 );
+ }