sizeof(struct logic_achievement)
},
{
- k_classtype_point_light,
+ k_classtype_world_light,
(void*)&world->lights,
sizeof(struct world_light)
},
world->achievement_count ++;
}
-VG_STATIC void world_pct_point_light( world_instance *world, mdl_node *pnode )
+VG_STATIC void world_pct_world_light( world_instance *world, mdl_node *pnode )
{
- struct world_light *light = &world->lights[ world->light_count ];
- v3_copy( pnode->co, light->co );
-
- struct classtype_point_light *inf = mdl_get_entdata( world->meta, pnode );
- v4_copy( inf->colour, light->colour );
-
- world->light_count ++;
+ struct world_light *light = &world->lights[ world->light_count ++ ];
+ light->node = pnode;
+ light->inf = mdl_get_entdata( world->meta, pnode );
}
VG_STATIC void world_pct_nonlocal_gate( world_instance *world, mdl_node *pnode )
{ k_classtype_trigger, world_pct_trigger },
{ k_classtype_logic_relay, world_pct_relay },
{ k_classtype_logic_achievement, world_pct_achievement },
- { k_classtype_point_light, world_pct_point_light },
+ { k_classtype_world_light, world_pct_world_light },
{ k_classtype_nonlocal_gate, world_pct_nonlocal_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;
+}
+
VG_STATIC void world_scene_compute_light_clusters( world_instance *world,
scene *sc )
{
for( int i=0; i<sc->vertex_count; i++ )
{
scene_vert *vert = &sc->arrvertices[i];
- vert->lights[0] = 255;
- vert->lights[1] = 255;
- vert->lights[2] = 255;
- vert->lights[3] = 255;
+ vert->lights[0] = 0;
+ vert->lights[1] = 1;
+ vert->lights[2] = 2;
+ vert->lights[3] = 0;
- float distances[4] = { INFINITY, INFINITY, INFINITY, INFINITY };
+ float influences[3] = { 0.0f, 0.0f, 0.0f };
+ const int N = vg_list_size( influences );
for( int j=0; j<world->light_count; j ++ )
{
- float dist = v3_dist2( world->lights[j].co, vert->co );
+ float influence = calc_light_influence( world, vert->co, j );
- int best_pos = 4;
+ int best_pos = N;
for( int k=best_pos-1; k>=0; k -- )
- if( dist < distances[k] )
+ if( influence > influences[k] )
best_pos = k;
- if( best_pos < 4 )
+ if( best_pos < N )
{
- for( int k=3; k>best_pos; k -- )
+ for( int k=N-1; k>best_pos; k -- )
{
- distances[k] = distances[k-1];
+ influences[k] = influences[k-1];
vert->lights[k] = vert->lights[k-1];
}
- distances[best_pos] = dist;
+ influences[best_pos] = influence;
vert->lights[best_pos] = j;
}
}
+
+ for( int j=0; j<N; j++ )
+ {
+ if( influences[j] > 0.00000125f )
+ vert->lights[3] ++ ;
+ }
}
}
vg_acquire_thread_sync();
{
/* create scene lighting buffer */
+
+ u32 size = VG_MAX(world->light_count,1) * sizeof(float)*12;
+
+ vg_info( "Upload %ubytes (lighting)\n", size );
+
glGenBuffers( 1, &world->tbo_light_entities );
glBindBuffer( GL_TEXTURE_BUFFER, world->tbo_light_entities );
- glBufferData( GL_TEXTURE_BUFFER, world->light_count*sizeof(float)*8,
- NULL, GL_DYNAMIC_DRAW );
+ glBufferData( GL_TEXTURE_BUFFER, size, NULL, GL_DYNAMIC_DRAW );
+
+ /* buffer layout
+ *
+ * colour position direction (spots)
+ * | . . . . | . . . . | . . . . |
+ * | Re Ge Be Night | Xco Yco Zco | Dx Dy Dz Da |
+ *
+ */
v4f *light_dst = glMapBuffer( GL_TEXTURE_BUFFER, GL_WRITE_ONLY );
for( int i=0; i<world->light_count; i++ )
{
struct world_light *light = &world->lights[i];
+ struct classtype_world_light *inf = light->inf;
+
+ /* colour + night */
+ v3_muls( inf->colour, inf->colour[3] * 2.0f, light_dst[i*3+0] );
+ light_dst[i*3+0][3] = 0.0f;
+
+ if( (inf->type == k_light_type_spot_nighttime_only) ||
+ (inf->type == k_light_type_point_nighttime_only ) )
+ {
+ u32 hash = (i * 29986577) & 0xff;
+ float switch_on = hash;
+ switch_on *= (1.0f/255.0f);
- v3_muls( light->colour, light->colour[3] * 2.0f, light_dst[i*2+0] );
- v3_copy( light->co, light_dst[i*2+1] );
+ light_dst[i*3+0][3] = 0.44f + switch_on * 0.015f;
+ }
+
+ /* position + nothing */
+ v3_copy( light->node->co, light_dst[i*3+1] );
+
+ /* direction + angle */
+ q_mulv( light->node->q, (v3f){0.0f,-1.0f,0.0f}, light_dst[i*3+2]);
+ light_dst[i*3+2][3] = inf->angle;
}
glUnmapBuffer( GL_TEXTURE_BUFFER );
mesh_free( &world->mesh_geo );
mesh_free( &world->mesh_no_collide );
+ glDeleteBuffers( 1, &world->tbo_light_entities );
+ glDeleteTextures( 1, &world->tex_light_entities );
+
/* FIXME: CANT DO THIS HERE */
world_global.time = 0.0;
world_global.rewind_from = 0.0;