+VG_STATIC void world_link_nonlocal_gates( int index_a, int index_b )
+{
+ vg_info( "Linking non-local gates\n" );
+ world_instance *a = &world_global.worlds[ index_a ],
+ *b = &world_global.worlds[ index_b ];
+
+ for( int i=0; i<a->nonlocalgate_count; i++ )
+ {
+ struct nonlocal_gate *ga = &a->nonlocal_gates[i];
+ struct classtype_gate *ga_inf = mdl_get_entdata( a->meta, ga->node );
+ const char *ga_name = mdl_pstr( a->meta, ga_inf->target );
+
+ for( int j=0; j<b->nonlocalgate_count; j++ )
+ {
+ struct nonlocal_gate *gb = &b->nonlocal_gates[j];
+ struct classtype_gate *gb_inf = mdl_get_entdata( b->meta, gb->node );
+ const char *gb_name = mdl_pstr( b->meta, gb_inf->target );
+
+ if( !strcmp( ga_name, gb_name ) )
+ {
+ vg_success( "Created longjump for ID '%s'\n", ga_name );
+
+ v4f qYflip;
+ q_axis_angle( qYflip, (v3f){0.0f,1.0f,0.0f}, VG_PIf );
+
+ /* TODO: Gates are created very wonkily. refactor. */
+ ga->target_map_index = index_b;
+ gb->target_map_index = index_a;
+ ga->working = 1;
+ gb->working = 1;
+
+ v4_copy( ga->node->q, ga->gate.q[0] );
+ v4_copy( gb->node->q, ga->gate.q[1] );
+ v3_copy( ga->node->co, ga->gate.co[0] );
+ v3_copy( gb->node->co, ga->gate.co[1] );
+
+ v4_copy( gb->node->q, gb->gate.q[0] );
+ v4_copy( ga->node->q, gb->gate.q[1] );
+ v3_copy( gb->node->co, gb->gate.co[0] );
+ v3_copy( ga->node->co, gb->gate.co[1] );
+
+ /* reverse B's direction */
+ q_mul( gb->gate.q[0], qYflip, gb->gate.q[0] );
+ q_mul( gb->gate.q[1], qYflip, gb->gate.q[1] );
+ q_normalize( gb->gate.q[0] );
+ q_normalize( gb->gate.q[1] );
+
+ gate_transform_update( &ga->gate );
+ gate_transform_update( &gb->gate );
+ }
+ }
+ }
+}
+
+VG_STATIC float colour_luminance( v3f v )
+{
+ return v3_dot( v, (v3f){0.2126f, 0.7152f, 0.0722f} );
+}
+
+VG_STATIC float calc_light_influence( world_instance *world, v3f position,
+ int light )
+{
+ struct world_light *world_light = &world->lights[ light ];
+ struct classtype_world_light *inf = world_light->inf;
+
+ v3f light_delta;
+ v3_sub( world_light->node->co, position, light_delta );
+ v3_muls( light_delta, 10.0f, light_delta );
+
+ float quadratic = v3_dot( light_delta, light_delta ),
+ attenuation = 1.0f/( 1.0f + quadratic );
+
+ float quadratic_light = attenuation * colour_luminance( inf->colour );
+
+ if( (inf->type == k_light_type_point) ||
+ (inf->type == k_light_type_point_nighttime_only) )
+ {
+ return quadratic_light;
+ }
+ else if( (inf->type == k_light_type_spot) ||
+ (inf->type == k_light_type_spot_nighttime_only) )
+ {
+ v3f dir;
+ q_mulv( world_light->node->q, (v3f){0.0f,1.0f,0.0f}, dir );
+
+ float spot_theta = vg_maxf( 0.0f, v3_dot( light_delta, dir ) ),
+ falloff = spot_theta >= 0.0f? 1.0f: 0.0f;
+
+ return quadratic_light * falloff;
+ }
+ else
+ return 0.0f;
+}
+