+ tex_tile_detail = vg_tex2d_rgba( "textures/tile_overlays.png" );
+ vg_tex2d_mipmap();
+ vg_tex2d_linear_mipmap();
+ vg_tex2d_repeat();
+
+ tex_tile_data = vg_tex2d_rgba( "textures/tileset.png" );
+ vg_tex2d_mipmap();
+ vg_tex2d_linear_mipmap();
+ vg_tex2d_repeat();
+
+ tex_wood = vg_tex2d_rgba( "textures/wood.png" );
+ vg_tex2d_mipmap();
+ vg_tex2d_linear_mipmap();
+ vg_tex2d_repeat();
+
+ tex_ball = vg_tex2d_rgba( "textures/ball.png" );
+ vg_tex2d_mipmap();
+ vg_tex2d_linear_mipmap();
+ vg_tex2d_clamp();
+ }
+
+ // Audio
+ {
+ sfx_set_init( &audio_tile_mod, NULL );
+ }
+
+ map_load( level_pack[ 0 ] );
+}
+
+void vg_free(void)
+{
+ free_mesh( &world.tile );
+ free_mesh( &world.circle );
+
+ map_free();
+
+ glDeleteTextures( 1, &tex_tile_data );
+ glDeleteTextures( 1, &tex_tile_detail );
+ glDeleteTextures( 1, &tex_wood );
+ glDeleteTextures( 1, &tex_ball );
+
+ sfx_set_free( &audio_tile_mod );
+}
+
+static int cell_interactive( v2i co )
+{
+ // Bounds check
+ if( co[0] < 2 || co[0] >= world.w-2 || co[1] < 2 || co[1] >= world.h-2 )
+ return 0;
+
+ // Flags check
+ if( world.data[ world.w*co[1] + co[0] ].state & (FLAG_WALL|FLAG_INPUT|FLAG_OUTPUT) )
+ return 0;
+
+ // List of 3x3 configurations that we do not allow
+ static u32 invalid_src[][9] =
+ {
+ { 0,1,0,
+ 1,1,1,
+ 0,1,0
+ },
+ { 0,0,0,
+ 0,1,1,
+ 0,1,1
+ },
+ { 0,0,0,
+ 1,1,0,
+ 1,1,0
+ },
+ { 0,1,1,
+ 0,1,1,
+ 0,0,0
+ },
+ { 1,1,0,
+ 1,1,0,
+ 0,0,0
+ },
+ { 0,1,0,
+ 0,1,1,
+ 0,1,0
+ },
+ { 0,1,0,
+ 1,1,0,
+ 0,1,0
+ }
+ };
+
+ // Statically compile invalid configurations into bitmasks
+ static u32 invalid[ vg_list_size(invalid_src) ];
+
+ for( int i = 0; i < vg_list_size(invalid_src); i ++ )
+ {
+ u32 comped = 0x00;
+
+ for( int j = 0; j < 3; j ++ )
+ for( int k = 0; k < 3; k ++ )
+ comped |= invalid_src[i][ j*3+k ] << ((j*5)+k);
+
+ invalid[i] = comped;
+ }
+
+ // Extract 5x5 grid surrounding tile
+ u32 blob = 0x1000;
+ for( int y = co[1]-2; y < co[1]+3; y ++ )
+ for( int x = co[0]-2; x < co[0]+3; x ++ )
+ {
+ struct cell *cell = pcell((v2i){x,y});
+
+ if( cell && (cell->state & (FLAG_CANAL|FLAG_INPUT|FLAG_OUTPUT)) )
+ blob |= 0x1 << ((y-(co[1]-2))*5 + x-(co[0]-2));
+ }
+
+ // Run filter over center 3x3 grid to check for invalid configurations
+ int kernel[] = { 0, 1, 2, 5, 6, 7, 10, 11, 12 };
+ for( int i = 0; i < vg_list_size(kernel); i ++ )
+ {
+ if( blob & (0x1 << (6+kernel[i])) )