/* OBJECT_LIGHTS.C symbols in this file: 00128730 0030: _texture_cache_bitmap_load (0000) 00128760 0020: _shade_scalar (0000) 00128780 0040: _shade_vector2d (0000) 001287C0 0060: _shade_vector3d (0000) 00128820 0100: _sample_lightmap (0000) 00128920 00f0: _sample_diffuse_texture (0000) 00128A10 0020: _should_render_lights (0000) 00128A30 00c0: _lights_initialize (0000) 00128AF0 0010: _lights_dispose (0000) 00128B00 0030: _lights_initialize_for_new_map (0000) 00128B30 0020: _lights_dispose_from_old_map (0000) 00128B50 0010: _lights_enable (0000) 00128B60 0040: _light_delete (0000) 00128BA0 0060: _light_build_cluster_array (0000) 00128C00 00d0: _object_get_self_illumination (0000) 00128CD0 0260: _light_particle (0000) 00128F30 0060: _light_disconnect_from_map (0000) 00128F90 00b0: _lights_disconnect_from_structure_bsp (0000) 00129040 0020: _light_attenuation (0000) 00129060 00a0: _brighten_real_rgb_color (0000) 00129100 0020: _cluster_get_first_light (0000) 00129120 0020: _cluster_get_next_light (0000) 00129140 0040: _light_marker_begin (0000) 00129180 0060: _light_unmarked (0000) 001291E0 0060: _light_mark (0000) 00129240 0040: _light_marker_end (0000) 00129280 0110: _render_debug_light (0000) 00129390 00e0: _lights_queue_lens_flare (0000) 00129470 0230: _find_point_lights_for_object_in_cluster (0000) 001296A0 0400: _build_distant_lights (0000) 00129AA0 00f0: _light_compute_bounding_sphere (0000) 00129B90 00e0: _light_get_bounding_sphere (0000) 00129C70 01d0: _lights_render_diffuse (0000) 00129E40 0150: _lights_render_specular (0000) 00129F90 02d0: _lights_illumination_at_point (0000) 0012A260 0110: _lights_prepare_for_object_dynamic (0000) 0012A370 03b0: _lights_distant_lighting_at_point (0000) 0012A720 0280: _light_reconnect_to_map (0000) 0012A9A0 0060: _lights_reconnect_to_structure_bsp (0000) 0012AA00 00e0: _light_new (0000) 0012AAE0 00f0: _light_new_unattached (0000) 0012ABD0 0960: _lights_preprocess_scene (0000) 0012B530 0340: _lights_prepare_for_object_static (0000) 002896C0 00b0: _default_object_lighting (0000) 00289770 0021: ??_C@_0CB@NDAECIIM@c?3?2halo?2source?2objects?2objects?4h@ (0000) 00289798 00b9: ??_C@_0LJ@HECDDFBP@material?9?$DOlightmap_vertices?4type@ (0000) 00289854 0027: ??_C@_0CH@GHJLLMCD@c?3?2halo?2SOURCE?2objects?2object_li@ (0000) 00289880 0095: ??_C@_0JF@BFHNCHBA@material?9?$DOvertices?4type?$DN?$DN_raster@ (0000) 00289918 002c: ??_C@_0CM@CCFOPHPG@couldn?8t?5allocate?5memory?5for?5obj@ (0000) 00289944 0014: ??_C@_0BE@MMBBLMKK@lights_game_globals?$AA@ (0000) 00289958 000b: ??_C@_0L@PNIBKHKO@light_data?$AA@ (0000) 00289964 000f: ??_C@_0P@MLOLKFEJ@lights?5globals?$AA@ (0000) 00289974 0007: ??_C@_06IDBEMGIK@lights?$AA@ (0000) 0028997C 003b: ??_C@_0DL@OAOFOGFN@TEST_FLAG?$CIlight?9?$DOflags?0?5_point_l@ (0000) 002899B8 0023: ??_C@_0CD@CEANBCDI@?$CBlights_globals?4marker_initializ@ (0000) 002899DC 0022: ??_C@_0CC@DMOOLGHL@lights_globals?4marker_initialize@ (0000) 00289A00 0004: __real@3f34fdf4 (0000) 00289A04 003c: ??_C@_0DM@NOKGCMAM@?$CBTEST_FLAG?$CIlight?9?$DOflags?0?5_point_@ (0000) 00289A40 002a: ??_C@_0CK@JMHDKADE@lens_flare_parameters?4light_iden@ (0000) 00289A6C 0035: ??_C@_0DF@MMLEIBDB@light?9?$DOcolor?4blue?5?$DO?$DN0?40f?5?$CG?$CG?5ligh@ (0000) 00289AA4 0035: ??_C@_0DF@KFPEGOCE@light?9?$DOcolor?4green?$DO?$DN0?40f?5?$CG?$CG?5ligh@ (0000) 00289ADC 0033: ??_C@_0DD@NIPJINKE@light?9?$DOcolor?4red?5?$DO?$DN0?40f?5?$CG?$CG?5light@ (0000) 00289B10 0004: __real@bf3504f3 (0000) 0030B388 0605: _data_0030b388 (0000) _object_light_ambient_base (05f8) _object_light_ambient_scale (05fc) _object_light_secondary_scale (0600) _object_light_interpolate (0604) 00456E94 0004: _lights_game_globals (0000) */ /* ---------- headers */ /* objects.h lies in this unit's own directory, so January's __FILE__ for it was the absolute path (see OBJECTS_H_FILE in objects.h) */ #define OBJECTS_H_FILE "c:\\halo\\source\\objects\\objects.h" #include "cseries/cseries.h" #include "cseries/errors.h" #include "cseries/profile.h" #include "bitmaps/bitmaps.h" #include "bitmaps/bitmap_group.h" #include "bitmaps/bitmap_group_lookup.h" #include "bitmaps/bitmaps_sampling.h" #include "bitmaps/bitmap_utilities.h" #include "effects/decals.h" #include "math/real_math.h" #include "cache/texture_cache.h" #include "game/game.h" #include "game/game_engine.h" #include "interface/first_person_weapons.h" #include "math/periodic_functions.h" #include "memory/data.h" #include "objects/light_definitions.h" #include "objects/object_lights.h" #include "objects/object_lights_rendering.h" #include "objects/objects.h" #include "render/render.h" #include "render/render_debug.h" #include "rasterizer/rasterizer.h" #include "rasterizer/rasterizer_environment.h" #include "rasterizer/rasterizer_geometry.h" #include "rasterizer/rasterizer_geometry_environment.h" #include "rasterizer/rasterizer_lights.h" #include "saved games/game_state.h" #include "scenario/scenario.h" #include "shaders/shader_definitions.h" #include "structures/cluster_partitions.h" #include "structures/structure_bsp_definitions.h" #include "structures/structure_render.h" #include "structures/structure_render_lights.h" #include "structures/structures.h" #include "structures/structure_vector_tests.h" #include "structures/structure_visibility.h" #include "tag_files/tag_groups.h" #include "units/units.h" /* ---------- constants */ enum { _light_definition_dynamic_bit = 0, _light_definition_no_specular_bit, _light_definition_dont_light_own_object_bit, _light_definition_supersize_in_first_person_bit, _light_definition_is_first_person_flashlight_bit, _light_definition_dont_fade_active_camouflage_bit, }; enum { _point_light_dynamic_bit = 0, _point_light_connects_to_map_bit = 1, _point_light_connected_to_map_bit = 2, _point_light_attached_to_first_person_weapon_bit = 3, }; enum { MAXIMUM_CLUSTERS_PER_LIGHT = 512, LENS_FLARE_FIRST_PERSON_MARKER_FLAG = FLAG(7), }; enum { _distant_lighting_raycast_sideways_bit = 0, _distant_lighting_block_on_textures_bit, _distant_lighting_brighten_bit, }; enum { NUMBER_OF_LIGHTMAP_SAMPLE_SIDEWAYS_RAYCASTS = 4, }; enum { LENS_FLARE_DEFINITION_TAG = 'lens', }; enum { _shader_type_environment = 3, }; /* ---------- macros */ #define light_get(index) \ ((struct light_datum *)datum_get(light_data, (index))) #define light_definition_get(index) \ ((struct point_light_definition *)tag_get(LIGHT_DEFINITION_TAG, (index))) #define lens_flare_definition_get(index) \ ((struct lens_flare_definition *)tag_get(LENS_FLARE_DEFINITION_TAG, (index))) #define shader_environment_definition_get(shader) \ ((struct shader_environment_definition *)shader_get_and_verify_type( \ (shader), \ _shader_type_environment)) #define structure_material_get_vertex(material, vertex_index) \ ((struct environment_vertex_compressed const *)(material)->compressed_vertex_data.address \ + (vertex_index)) #define structure_material_get_lightmap_vertex(material, vertex_index) \ ((struct environment_lightmap_vertex_compressed const *) \ ((struct environment_vertex_compressed const *)(material)->compressed_vertex_data.address \ + (material)->vertices.count) \ + (vertex_index)) /* ---------- structures */ struct environment_vertex_compressed { real_point3d position; unsigned long normal; unsigned long binormal; unsigned long tangent; real_point2d texcoord; }; struct environment_lightmap_vertex_compressed { unsigned long incident_radiosity; short lightmap_u; short lightmap_v; }; struct shader_environment_definition { struct shader shader; byte reserved28[0x60]; struct tag_reference base_map; }; struct lights_game_globals { boolean render_lights; byte reserved01[3]; }; struct point_light_definition { long flags; real radius; real radius_modifier_lower_bound; real radius_modifier_upper_bound; real falloff_angle; real cutoff_angle; real lens_flare_radius; real runtime_cosine_falloff_angle; real runtime_cosine_cutoff_angle; real specular_radius_multiplier; real runtime_sine_cutoff_angle; byte reserved2C[0x8]; unsigned long color_interpolation_flags; real_argb_color color_lower_bound; real_argb_color color_upper_bound; byte reserved58[0x54]; struct tag_reference lens_flare; byte reservedBC[0x38]; real transition_duration; word reservedF8; short falloff_function; byte reservedFC[0x8]; }; struct light_datum { struct datum_header header; word flags; long definition_index; long rasterizer_light_index; long marker; long cluster_reference; real_rgb_color color; byte reserved20[0xC]; long object_index; real_point3d position; real_vector3d forward; real_vector3d up; real radius; long parent_light_index; short attachment_marker_index; short function_index; union { short color_function_index; struct { real_point3d relative_position; real_vector3d relative_forward; } node; }; real intensity_scale; }; struct rasterizer_lens_flare_submit_parameters { struct lens_flare_definition *definition; real_point3d position; unsigned long compressed_direction; unsigned long compressed_up; unsigned long compressed_light_color; short light_identifier; short light_index; short lens_flare_index; byte compressed_window_index; byte compressed_light_scale; long internal_occlusion_pixels; }; struct lights_globals { boolean marker_initialized; byte pad1[3]; long marker; short scene_point_light_count; short padA; long scene_point_lights[128]; struct rasterizer_lens_flare_submit_parameters queued_lens_flares[8]; short queued_lens_flare_count; short pad34E; }; typedef char verify_lights_game_globals_size[ sizeof(struct lights_game_globals) == 0x4 ? 1 : -1]; typedef char verify_light_datum_flags_offset[ offsetof(struct light_datum, flags) == 0x2 ? 1 : -1]; typedef char verify_light_datum_cluster_reference_offset[ offsetof(struct light_datum, cluster_reference) == 0x10 ? 1 : -1]; typedef char verify_light_definition_lens_flare_offset[ offsetof(struct point_light_definition, lens_flare) == 0xAC ? 1 : -1]; typedef char verify_light_definition_color_offset[ offsetof(struct point_light_definition, color_interpolation_flags) == 0x34 ? 1 : -1]; typedef char verify_light_definition_transition_duration_offset[ offsetof(struct point_light_definition, transition_duration) == 0xF4 ? 1 : -1]; typedef char verify_light_definition_falloff_function_offset[ offsetof(struct point_light_definition, falloff_function) == 0xFA ? 1 : -1]; typedef char verify_light_datum_size[ sizeof(struct light_datum) == 0x7C ? 1 : -1]; typedef char verify_rasterizer_light_submit_parameters_size[ sizeof(struct rasterizer_light_submit_parameters) == 0x38 ? 1 : -1]; typedef char verify_lights_globals_size[ sizeof(struct lights_globals) == 0x350 ? 1 : -1]; /* ---------- prototypes */ static boolean should_render_lights( void); static void light_marker_begin( void); static void light_marker_end( void); static boolean light_unmarked( long light_index); static boolean light_mark( long light_index); static long cluster_get_first_light( long *reference_index, short cluster_index); static long cluster_get_next_light( long *reference_index); static void find_point_lights_for_object_in_cluster( long object_index, short cluster_index, real_point3d const *center, real radius, long *light_indices, real *light_intensities, real *light_attenuations, short *light_count, short maximum_light_count); static void shade_vector3d( real_vector3d const *vertex0, real_vector3d const *vertex1, real_vector3d const *vertex2, real b, real c, real_vector3d *result); static void brighten_real_rgb_color( real_rgb_color *color, real fraction); static void build_distant_lights( long flags, real_vector3d const *surface_normal, real_rgb_color const *diffuse_color, real_vector3d const *radiosity_normal, real radiosity_accuracy, real_rgb_color const *lightmap_color, struct render_lighting *lighting); static short light_build_cluster_array( long light_index, short maximum_count, short *cluster_indices); static void light_compute_bounding_sphere( long light_index, boolean maximum, boolean specular, boolean lens_flare_only, real_point3d *position, real *radius); static void render_debug_light( long light_index); static void light_get_bounding_sphere( long light_index, real_point3d *position, real *radius); /* ---------- globals */ struct render_lighting const default_object_lighting = { { 0.2f, 0.2f, 0.2f }, 2, 0, { { { 1.0f, 1.0f, 1.0f }, { -0.577f, -0.577f, -0.577f } }, { { 0.4f, 0.4f, 0.5f }, { 0.0f, 0.0f, 1.0f } }, }, 0, 0, { 0, 0 }, { 0.5f, 1.0f, 1.0f, 1.0f }, { 0.0f, 0.0f, -1.0f }, { 0.0f, 0.0f, 0.0f }, }; static real_vector3d const lightmap_sample_raycast_down = { 0.0f, 0.0f, -10.0f }; static real_vector3d const lightmap_sample_raycast_sideways[NUMBER_OF_LIGHTMAP_SAMPLE_SIDEWAYS_RAYCASTS] = { { -10.0f, 0.0f, 0.0f }, { 10.0f, 0.0f, 0.0f }, { 0.0f, -10.0f, 0.0f }, { 0.0f, 10.0f, 0.0f }, }; static struct profile_section lights_section = { "render_lights", NONE, TRUE }; real object_light_ambient_base = 0.03f; real object_light_ambient_scale = 0.4f; real object_light_secondary_scale = 1.0f; boolean object_light_interpolate = TRUE; boolean debug_lights; boolean debug_object_lights; struct data_array *light_data; struct cluster_partition light_cluster_partition; struct lights_game_globals *lights_game_globals = NULL; short debug_rasterizer_light_count; struct lights_globals lights_globals; /* ---------- public code */ void *texture_cache_bitmap_load( struct bitmap_data *bitmap) { void *hardware_format; profile_texture_start(); hardware_format = _texture_cache_bitmap_get_hardware_format( bitmap, TRUE, TRUE); profile_texture_end(); return hardware_format; } static real shade_scalar( real scalar0, real scalar1, real scalar2, real b, real c) { return (scalar1 - scalar0) * b + (scalar2 - scalar0) * c + scalar0; } static void shade_vector2d( real_point2d const *vertex0, real_point2d const *vertex1, real_point2d const *vertex2, real b, real c, real_point2d *result) { result->x = shade_scalar(vertex0->x, vertex1->x, vertex2->x, b, c); result->y = shade_scalar(vertex0->y, vertex1->y, vertex2->y, b, c); return; } static void shade_vector3d( real_vector3d const *vertex0, real_vector3d const *vertex1, real_vector3d const *vertex2, real b, real c, real_vector3d *result) { result->i = shade_scalar(vertex0->i, vertex1->i, vertex2->i, b, c); result->j = shade_scalar(vertex0->j, vertex1->j, vertex2->j, b, c); result->k = shade_scalar(vertex0->k, vertex1->k, vertex2->k, b, c); return; } void sample_lightmap( struct structure_material *material, struct bitmap_data *bitmap, struct structure_surface const *surface, real s, real t, real_rgb_color *color) { real_point2d texcoords[3]; real_point2d texcoord; match_assert( "c:\\halo\\SOURCE\\objects\\object_lights.c", 143, material->lightmap_vertices.type==_rasterizer_vertex_type_environment_lightmap_uncompressed || material->lightmap_vertices.type==_rasterizer_vertex_type_environment_lightmap_compressed); environment_lightmap_vertex_compressed_get_texcoord( structure_material_get_lightmap_vertex(material, surface->vertex_indices[0]), &texcoords[0]); environment_lightmap_vertex_compressed_get_texcoord( structure_material_get_lightmap_vertex(material, surface->vertex_indices[1]), &texcoords[1]); environment_lightmap_vertex_compressed_get_texcoord( structure_material_get_lightmap_vertex(material, surface->vertex_indices[2]), &texcoords[2]); shade_vector2d( &texcoords[0], &texcoords[1], &texcoords[2], s, t, &texcoord); pixel32_to_real_rgb_color( bitmap_2d_get_pixel(bitmap, &texcoord, 1.0f), color); return; } void sample_diffuse_texture( struct structure_material *material, struct bitmap_data *bitmap, struct structure_surface const *surface, real s, real t, real_rgb_color *color) { real_point2d texcoords[3]; real_point2d texcoord; match_assert( "c:\\halo\\SOURCE\\objects\\object_lights.c", 167, material->vertices.type==_rasterizer_vertex_type_environment_uncompressed || material->vertices.type==_rasterizer_vertex_type_environment_compressed); environment_vertex_compressed_get_texcoord( structure_material_get_vertex(material, surface->vertex_indices[0]), &texcoords[0]); environment_vertex_compressed_get_texcoord( structure_material_get_vertex(material, surface->vertex_indices[1]), &texcoords[1]); environment_vertex_compressed_get_texcoord( structure_material_get_vertex(material, surface->vertex_indices[2]), &texcoords[2]); shade_vector2d( &texcoords[0], &texcoords[1], &texcoords[2], s, t, &texcoord); pixel32_to_real_rgb_color( bitmap_2d_get_pixel(bitmap, &texcoord, 0.3f), color); return; } static boolean should_render_lights( void) { if (lights_game_globals->render_lights && game_engine_allow_dynamic_lighting()) { return TRUE; } return FALSE; } void lights_initialize( void) { light_data = game_state_data_new( "lights", MAXIMUM_LIGHTS_PER_MAP, sizeof(struct light_datum)); lights_game_globals = game_state_malloc( "lights globals", NULL, sizeof(struct lights_game_globals)); match_assert( "c:\\halo\\SOURCE\\objects\\object_lights.c", 0xC2, light_data); match_assert( "c:\\halo\\SOURCE\\objects\\object_lights.c", 0xC3, lights_game_globals); lights_game_globals->render_lights = TRUE; if (light_data) { cluster_partition_new(&light_cluster_partition, "light"); } else { error(_error_silent, "couldn't allocate memory for object lights."); } return; } void lights_dispose( void) { cluster_partition_delete(&light_cluster_partition); return; } void lights_initialize_for_new_map( void) { data_make_valid(light_data); lights_game_globals->render_lights = TRUE; cluster_partition_make_valid(&light_cluster_partition); return; } void lights_dispose_from_old_map( void) { data_make_invalid(light_data); cluster_partition_make_invalid(&light_cluster_partition); return; } boolean lights_enable( boolean enable) { lights_game_globals->render_lights = enable; return enable; } long light_new( long definition_index, long object_index, short object_attachment_index, short object_function_index, short object_change_color_index) { struct point_light_definition *definition = light_definition_get(definition_index); long light_index = NONE; if (TEST_FLAG(definition->flags, _light_definition_dynamic_bit) || definition->lens_flare.index != NONE) { light_index = datum_new(light_data); if (light_index != NONE) { struct light_datum *light = light_get(light_index); light->definition_index = definition_index; light->object_index = object_index; light->attachment_marker_index = object_attachment_index; light->function_index = object_function_index; light->color_function_index = object_change_color_index; light->flags = 0; SET_FLAG(light->flags, _point_light_dynamic_bit, TEST_FLAG(definition->flags, _light_definition_dynamic_bit)); SET_FLAG(light->flags, _point_light_connects_to_map_bit, TEST_FLAG(light->flags, _point_light_dynamic_bit) || definition->lens_flare.index != NONE); light->cluster_reference = NONE; light->parent_light_index = NONE; light_reconnect_to_map(light_index); light->marker = lights_globals.marker - 1; } } return light_index; } long light_new_unattached( long definition_index, long object_index, short object_node_index, real_point3d const *position, real_vector3d const *direction, real scale) { long light_index = datum_new(light_data); if (light_index != NONE) { struct light_datum *light = light_get(light_index); struct point_light_definition *definition = light_definition_get(definition_index); light->flags = 0; light->parent_light_index = game_time_get(); light->definition_index = definition_index; light->object_index = object_index; light->intensity_scale = scale; light->cluster_reference = NONE; SET_FLAG(light->flags, _point_light_dynamic_bit, TRUE); SET_FLAG(light->flags, _point_light_connects_to_map_bit, TRUE); if (object_index == NONE) { light->position = *position; light->forward = *direction; } else { light->attachment_marker_index = object_node_index; light->node.relative_position = *position; light->node.relative_forward = *direction; } light_reconnect_to_map(light_index); light->marker = lights_globals.marker - 1; } return light_index; } void lights_preprocess_scene( void) { long current_time = game_time_get(); long light_index; short rendered_cluster_index; short scene_light_index; short queued_lens_flare_index; profile_enter(lights_section); debug_rasterizer_light_count = 0; for (light_index = data_next_index(light_data, NONE); light_index != NONE; light_index = data_next_index(light_data, light_index)) { struct light_datum *light = light_get(light_index); SET_FLAG( light->flags, _point_light_attached_to_first_person_weapon_bit, FALSE); light->rasterizer_light_index = NONE; if (light->parent_light_index != NONE) { struct point_light_definition *definition = light_definition_get( light->definition_index); real elapsed = (real)(current_time - light->parent_light_index); if (elapsed > definition->transition_duration) { cluster_partition_disconnect( &light_cluster_partition, light_index, &light_get(light_index)->cluster_reference); datum_delete(light_data, light_index); } else if (object_try_and_get(light->object_index)) { light_disconnect_from_map(light_index); light_reconnect_to_map(light_index); } } } light_marker_begin(); lights_globals.scene_point_light_count = structure_visibility_find_objects( lights_globals.scene_point_lights, MAXIMUM_RENDERED_LIGHTS, cluster_get_first_light, cluster_get_next_light, light_get_bounding_sphere, light_unmarked, light_mark); light_marker_end(); rasterizer_lights_begin(); for (rendered_cluster_index = 0; rendered_cluster_index < render.rendered_cluster_count; rendered_cluster_index++) { rasterizer_lens_flare_submit_for_cluster( rendered_cluster_get(rendered_cluster_index)->cluster_index); } for (scene_light_index = 0; scene_light_index < lights_globals.scene_point_light_count; scene_light_index++) { long scene_light_handle = lights_globals.scene_point_lights[scene_light_index]; struct light_datum *light = light_get(scene_light_handle); struct point_light_definition *definition = light_definition_get( light->definition_index); struct object_datum *object; real intensity; real inverse_intensity; real lens_flare_scale = 1.0f; render_debug_light(scene_light_handle); object = light->object_index != NONE ? object_try_and_get(light->object_index) : NULL; if (light->parent_light_index == NONE) { real_rgb_color const *color; match_assert( "c:\\halo\\SOURCE\\objects\\object_lights.c", 0x1AC, object); object_get_function_value( light->object_index, light->function_index, &intensity); color = light->color_function_index == NONE ? global_real_rgb_white : &object->object.outgoing_change_colors[light->color_function_index]; rgb_colors_interpolate_and_scale( &light->color, definition->color_interpolation_flags, &definition->color_lower_bound, &definition->color_upper_bound, color, intensity); } else { intensity = (1.0f - transition_function_evaluate( definition->falloff_function, (real)(current_time - light->parent_light_index) / definition->transition_duration)) * light->intensity_scale; rgb_colors_interpolate( &light->color, definition->color_interpolation_flags, &definition->color_lower_bound.rgb, &definition->color_upper_bound.rgb, intensity); } inverse_intensity = 1.0f - intensity; match_assert( "c:\\halo\\SOURCE\\objects\\object_lights.c", 0x1BB, light->color.red >=0.0f && light->color.red <=1.0f); match_assert( "c:\\halo\\SOURCE\\objects\\object_lights.c", 0x1BC, light->color.green>=0.0f && light->color.green<=1.0f); match_assert( "c:\\halo\\SOURCE\\objects\\object_lights.c", 0x1BD, light->color.blue >=0.0f && light->color.blue <=1.0f); if (object) { long ultimate_parent_index = object_get_ultimate_parent( light->object_index); struct object_datum *ultimate_parent = object_get( ultimate_parent_index); if (TEST_FLAG(_object_mask_unit, ultimate_parent->object.type)) { struct unit_datum *parent_unit = unit_get(ultimate_parent_index); if (parent_unit->unit.active_camouflage > 0.0f && !TEST_FLAG( light_definition_get(light->definition_index)->flags, _light_definition_dont_fade_active_camouflage_bit)) { lens_flare_scale = 1.0f - parent_unit->unit.active_camouflage; light->color.red *= lens_flare_scale; light->color.green *= lens_flare_scale; light->color.blue *= lens_flare_scale; match_assert( "c:\\halo\\SOURCE\\objects\\object_lights.c", 0x1D1, light->color.red >=0.0f && light->color.red <=1.0f); match_assert( "c:\\halo\\SOURCE\\objects\\object_lights.c", 0x1D2, light->color.green>=0.0f && light->color.green<=1.0f); match_assert( "c:\\halo\\SOURCE\\objects\\object_lights.c", 0x1D3, light->color.blue >=0.0f && light->color.blue <=1.0f); } } } if (light->color.red != 0.0f || light->color.green != 0.0f || light->color.blue != 0.0f) { if (TEST_FLAG(light->flags, _point_light_dynamic_bit)) { light->radius = (definition->radius_modifier_lower_bound * inverse_intensity + definition->radius_modifier_upper_bound * intensity) * definition->radius; if (light->radius != 0.0f) { struct rasterizer_light_submit_parameters light_parameters; light_parameters.definition = light_definition_get( light->definition_index); light_parameters.position = light->position; light_parameters.forward = light->forward; light_parameters.up = light->up; light_parameters.radius = light->radius; light_parameters.color = light->color; match_assert( "c:\\halo\\SOURCE\\objects\\object_lights.c", 0x1EE, light->color.red >=0.0f && light->color.red <=1.0f); match_assert( "c:\\halo\\SOURCE\\objects\\object_lights.c", 0x1EF, light->color.green>=0.0f && light->color.green<=1.0f); match_assert( "c:\\halo\\SOURCE\\objects\\object_lights.c", 0x1F0, light->color.blue >=0.0f && light->color.blue <=1.0f); if (light->parent_light_index == NONE) { boolean adjusted = FALSE; if (TEST_FLAG( definition->flags, _light_definition_is_first_person_flashlight_bit)) { first_person_weapon_center_flashlight( light->object_index, &light_parameters.position, &light_parameters.forward, &light_parameters.up); adjusted = TRUE; } else if (object->object.type == _object_type_weapon && object->object.parent_object_index != NONE) { adjusted = first_person_weapon_adjust_light( light->object_index, object_get_attachment_marker_name( light->object_index, light->attachment_marker_index), &light_parameters.position, &light_parameters.forward, &light_parameters.up); } if (adjusted) { SET_FLAG( light->flags, _point_light_attached_to_first_person_weapon_bit, TRUE); } } light->rasterizer_light_index = rasterizer_light_submit( &light_parameters); debug_rasterizer_light_count = light->rasterizer_light_index + 1; } } else { light->radius = definition->radius; } if (definition->lens_flare.index != NONE) { struct rasterizer_lens_flare_submit_parameters lens_flare_parameters; lens_flare_parameters.definition = lens_flare_definition_get( definition->lens_flare.index); lens_flare_parameters.compressed_light_color = real_a_rgb_color_to_pixel32(lens_flare_scale, &light->color); lens_flare_parameters.compressed_light_scale = compress_real_to_int8(intensity); lens_flare_parameters.compressed_window_index = (byte)render.window_index; lens_flare_parameters.light_index = (short)DATUM_INDEX_TO_ABSOLUTE_INDEX(scene_light_handle); lens_flare_parameters.light_identifier = (short)DATUM_INDEX_TO_IDENTIFIER(scene_light_handle); match_assert( "c:\\halo\\SOURCE\\objects\\object_lights.c", 0x21C, lens_flare_parameters.light_identifier!=0); if (lens_flare_parameters.light_identifier == NONE) { lens_flare_parameters.light_identifier = 0; } if (light->parent_light_index == NONE) { char const *marker_name = object_get_attachment_marker_name( light->object_index, light->attachment_marker_index); struct object_marker markers[MAXIMUM_LENS_FLARES_PER_LIGHT]; short marker_count = 0; short marker_index; if (object->object.type == _object_type_weapon && object->object.parent_object_index != NONE) { marker_count = first_person_weapon_get_marker_by_name_render( light->object_index, marker_name, markers, MAXIMUM_LENS_FLARES_PER_LIGHT); if (marker_count > 0) { lens_flare_parameters.compressed_window_index |= LENS_FLARE_FIRST_PERSON_MARKER_FLAG; } } if (!marker_count) { marker_count = object_get_marker_by_name( light->object_index, marker_name, markers, MAXIMUM_LENS_FLARES_PER_LIGHT); } for (marker_index = 0; marker_index < marker_count; marker_index++) { lens_flare_parameters.position = markers[marker_index].matrix.position; lens_flare_parameters.compressed_direction = compress_real_vector3d_to_int32_clamp( &markers[marker_index].matrix.forward); lens_flare_parameters.compressed_up = compress_real_vector3d_to_int32_clamp( &markers[marker_index].matrix.up); lens_flare_parameters.lens_flare_index = marker_index; rasterizer_lens_flare_submit(&lens_flare_parameters); } } else { lens_flare_parameters.position = light->position; lens_flare_parameters.compressed_direction = compress_real_vector3d_to_int32_clamp(&light->forward); lens_flare_parameters.compressed_up = compress_real_vector3d_to_int32_clamp(&light->up); lens_flare_parameters.lens_flare_index = 0; rasterizer_lens_flare_submit(&lens_flare_parameters); } } } } for (queued_lens_flare_index = 0; queued_lens_flare_index < lights_globals.queued_lens_flare_count; queued_lens_flare_index++) { rasterizer_lens_flare_submit( &lights_globals.queued_lens_flares[queued_lens_flare_index]); } lights_globals.queued_lens_flare_count = 0; rasterizer_lights_end(); profile_exit(lights_section); return; } void light_delete( long light_index) { struct light_datum *light = light_get(light_index); cluster_partition_disconnect( &light_cluster_partition, light_index, &light->cluster_reference); datum_delete(light_data, light_index); return; } real object_get_self_illumination( long object_index) { struct object_datum *object = object_get(object_index); struct object_definition *definition = object_definition_get(object->definition_index); real illumination = 0.0f; short attachment_index = 0; if (definition->object.attachments.count > 0) { do { if (object->object.attachment_types[attachment_index] == _object_attachment_type_light && object->object.attachment_indices[attachment_index] != NONE) { struct light_datum *light = light_get(object->object.attachment_indices[attachment_index]); illumination += real_rgb_color_brightness(&light->color); } attachment_index++; } while (attachment_index < definition->object.attachments.count); } if (object->object.first_child_object_index != NONE) { illumination += object_get_self_illumination(object->object.first_child_object_index); } if (object->object.next_object_index != NONE) { illumination += object_get_self_illumination(object->object.next_object_index); } return illumination; } void lights_queue_lens_flare( long lens_flare_definition_index, real_point3d const *position, real_vector3d const *direction, real_vector3d const *up, real_rgb_color const *color, real scale) { if (lights_globals.queued_lens_flare_count < MAXIMUM_QUEUED_LENS_FLARES && (color->red != 0.0f || color->green != 0.0f || color->blue != 0.0f)) { struct rasterizer_lens_flare_submit_parameters *lens_flare_parameters = &lights_globals.queued_lens_flares[lights_globals.queued_lens_flare_count]; lens_flare_parameters->compressed_light_color = real_a_rgb_color_to_pixel32(1.0f, color); lens_flare_parameters->compressed_light_scale = compress_real_to_int8(scale); lens_flare_parameters->definition = lens_flare_definition_get(lens_flare_definition_index); lens_flare_parameters->position = *position; lens_flare_parameters->compressed_direction = compress_real_vector3d_to_int32_clamp(direction); lens_flare_parameters->compressed_up = compress_real_vector3d_to_int32_clamp(up); lens_flare_parameters->compressed_window_index = (byte)render.window_index; lens_flare_parameters->light_index = NONE; lens_flare_parameters->light_identifier = NONE; lens_flare_parameters->lens_flare_index = lights_globals.queued_lens_flare_count; lights_globals.queued_lens_flare_count++; } return; } void light_particle( real_point3d const *position, real_rgb_color *light, real_rgb_color *diffuse, boolean block) { short lightmap_index; short material_index; long surface_index; real s; real t; real_point3d collision_point; *light = *global_real_rgb_grey; *diffuse = *global_real_rgb_grey; if (structure_test_vector( position, &lightmap_sample_raycast_down, &collision_point, &lightmap_index, &material_index, &surface_index, &s, &t)) { struct structure_bsp *structure = global_structure_bsp_get(); struct structure_lightmap *lightmap = TAG_BLOCK_GET_ELEMENT( &structure->lightmaps, lightmap_index, struct structure_lightmap); struct structure_material *material = TAG_BLOCK_GET_ELEMENT( &lightmap->materials, material_index, struct structure_material); struct shader *shader = shader_definition_get(material->shader.index); if (shader->base.type == _shader_type_environment) { struct shader_environment_definition *shader_environment = shader_environment_definition_get(shader); if (structure->lightmap_group.index != NONE && shader_environment->base_map.index != NONE && lightmap->bitmap_index != NONE) { struct bitmap_data *lightmap_bitmap = bitmap_group_try_and_get_bitmap( structure->lightmap_group.index, lightmap->bitmap_index); struct bitmap_data *diffuse_bitmap = bitmap_group_try_and_get_bitmap( shader_environment->base_map.index, (short)(material->permutation_index % bitmap_group_get(shader_environment->base_map.index)->bitmaps.count)); struct structure_surface const *surface = NULL; if (lightmap_bitmap && ((block && texture_cache_bitmap_load(lightmap_bitmap)) || _texture_cache_bitmap_get_hardware_format(lightmap_bitmap, FALSE, FALSE))) { surface = TAG_BLOCK_GET_ELEMENT( &structure->surfaces, surface_index, struct structure_surface); sample_lightmap(material, lightmap_bitmap, surface, s, t, light); light->red = MIN(light->red + 0.1f, 1.0f); light->green = MIN(light->green + 0.1f, 1.0f); light->blue = MIN(light->blue + 0.1f, 1.0f); } if (diffuse_bitmap && ((block && texture_cache_bitmap_load(diffuse_bitmap)) || _texture_cache_bitmap_get_hardware_format(diffuse_bitmap, FALSE, FALSE))) { if (!surface) { surface = TAG_BLOCK_GET_ELEMENT( &structure->surfaces, surface_index, struct structure_surface); } sample_diffuse_texture(material, diffuse_bitmap, surface, s, t, diffuse); } } } } return; } void light_disconnect_from_map( long light_index) { struct light_datum *light = light_get(light_index); if (TEST_FLAG(light->flags, _point_light_connects_to_map_bit)) { match_assert( "c:\\halo\\SOURCE\\objects\\object_lights.c", 0x4D0, TEST_FLAG(light->flags, _point_light_connected_to_map_bit)); cluster_partition_disconnect( &light_cluster_partition, light_index, &light->cluster_reference); SET_FLAG(light->flags, _point_light_connected_to_map_bit, FALSE); } return; } void lights_disconnect_from_structure_bsp( void) { long light_index; for (light_index = data_next_index(light_data, NONE); light_index != NONE; light_index = data_next_index(light_data, light_index)) { struct light_datum *light = light_get(light_index); if (TEST_FLAG(light->flags, _point_light_connected_to_map_bit)) { light_disconnect_from_map(light_index); SET_FLAG(light->flags, _point_light_connected_to_map_bit, TRUE); } } return; } void lights_reconnect_to_structure_bsp( void) { long light_index; for (light_index = data_next_index(light_data, NONE); light_index != NONE; light_index = data_next_index(light_data, light_index)) { struct light_datum *light = light_get(light_index); if (TEST_FLAG(light->flags, _point_light_connected_to_map_bit)) { SET_FLAG(light->flags, _point_light_connected_to_map_bit, FALSE); light_reconnect_to_map(light_index); } } return; } static void light_marker_begin( void) { match_assert( "c:\\halo\\SOURCE\\objects\\object_lights.c", 0x664, !lights_globals.marker_initialized); lights_globals.marker++; lights_globals.marker_initialized = TRUE; return; } static boolean light_mark( long light_index) { struct light_datum *light = light_get(light_index); match_assert( "c:\\halo\\SOURCE\\objects\\object_lights.c", 0x67F, lights_globals.marker_initialized); if (light->marker != lights_globals.marker) { light->marker = lights_globals.marker; return TRUE; } return FALSE; } static boolean light_unmarked( long light_index) { struct light_datum *light = light_get(light_index); match_assert( "c:\\halo\\SOURCE\\objects\\object_lights.c", 0x66F, lights_globals.marker_initialized); if (light->marker != lights_globals.marker) { return TRUE; } return FALSE; } static void light_marker_end( void) { match_assert( "c:\\halo\\SOURCE\\objects\\object_lights.c", 0x68E, lights_globals.marker_initialized); lights_globals.marker_initialized = FALSE; return; } static void render_debug_light( long light_index) { if (debug_lights) { struct light_datum *light = light_get(light_index); struct point_light_definition *definition = light_definition_get(light->definition_index); real radius = definition->radius_modifier_upper_bound * definition->radius; real_argb_color color = *global_real_argb_orange; render_debug_sphere( TRUE, &light->position, definition->lens_flare_radius, global_real_argb_white); render_debug_sphere( TRUE, &light->position, light->radius, &color); color.red *= 0.8f; color.green *= 0.8f; color.blue *= 0.8f; if (!TEST_FLAG(definition->flags, _light_definition_no_specular_bit)) { radius *= definition->specular_radius_multiplier; render_debug_sphere( TRUE, &light->position, definition->specular_radius_multiplier * light->radius, &color); } color.red *= 0.8f; color.green *= 0.8f; color.blue *= 0.8f; render_debug_sphere( TRUE, &light->position, radius, &color); } return; } /* ---------- private code */ static real light_attenuation( real radius, real distance) { return 1.0f - (distance * distance) / (radius * radius); } static void brighten_real_rgb_color( real_rgb_color *color, real fraction) { real maximum = MAX(color->red, MAX(color->green, color->blue)); real scale = fraction + 1.0f; real scaled_maximum = scale * maximum; if (scaled_maximum > 1.0f) { scale = 1.0f / maximum; } else if (scaled_maximum < fraction) { scale = fraction / maximum; } color->red *= scale; color->green *= scale; color->blue *= scale; return; } static long cluster_get_first_light( long *reference_index, short cluster_index) { return cluster_partition_get_first_datum( &light_cluster_partition, reference_index, cluster_index); } static long cluster_get_next_light( long *reference_index) { return cluster_partition_get_next_datum( &light_cluster_partition, reference_index); } static void light_compute_bounding_sphere( long light_index, boolean maximum, boolean specular, boolean lens_flare_only, real_point3d *position, real *radius) { struct light_datum *light = light_get(light_index); struct point_light_definition *definition = light_definition_get(light->definition_index); real light_radius = maximum ? definition->radius_modifier_upper_bound * definition->radius : light->radius; if (!TEST_FLAG(definition->flags, _light_definition_no_specular_bit) && (specular || maximum)) { light_radius *= definition->specular_radius_multiplier; } if (lens_flare_only && light_radius < definition->lens_flare_radius) { *position = light->position; *radius = definition->lens_flare_radius; } else if (definition->cutoff_angle < _pi / 2) { if (definition->cutoff_angle < _pi / 4) { light_radius = *radius = light_radius / definition->runtime_cosine_cutoff_angle; position->x = light_radius * light->forward.i + light->position.x; position->y = light_radius * light->forward.j + light->position.y; position->z = light_radius * light->forward.k + light->position.z; } else { *radius = light_radius * definition->runtime_sine_cutoff_angle; light_radius *= definition->runtime_cosine_cutoff_angle; position->x = light_radius * light->forward.i + light->position.x; position->y = light_radius * light->forward.j + light->position.y; position->z = light_radius * light->forward.k + light->position.z; } } else { *position = light->position; *radius = light_radius; } return; } static short light_build_cluster_array( long light_index, short maximum_count, short *cluster_indices) { struct light_datum *light = light_get(light_index); short cluster_count = 0; short cluster_index; long reference_index; for (cluster_index = (short)cluster_partition_get_first_cluster( &light_cluster_partition, &reference_index, light->cluster_reference); cluster_count < maximum_count; cluster_index = (short)cluster_partition_get_next_cluster( &light_cluster_partition, &reference_index)) { if (cluster_index == NONE) { break; } cluster_indices[cluster_count++] = cluster_index; } return cluster_count; } static void light_get_bounding_sphere( long light_index, real_point3d *position, real *radius) { light_compute_bounding_sphere( light_index, TRUE, FALSE, TRUE, position, radius); return; } void lights_render_diffuse( void) { short cluster_indices[MAXIMUM_CLUSTERS_PER_LIGHT]; short light_index; rasterizer_environment_diffuse_lights_begin(); if (should_render_lights()) { for (light_index = 0; light_index < lights_globals.scene_point_light_count; light_index++) { struct light_datum *light = light_get( lights_globals.scene_point_lights[light_index]); if (TEST_FLAG(light->flags, _point_light_dynamic_bit) && light->rasterizer_light_index != NONE) { boolean skip_clusters = TEST_FLAG(light->flags, _point_light_attached_to_first_person_weapon_bit) && TEST_FLAG(light_definition_get(light->definition_index)->flags, _light_definition_supersize_in_first_person_bit); short cluster_count = 0; real_point3d center; real radius; if (!skip_clusters) { cluster_count = light_build_cluster_array( lights_globals.scene_point_lights[light_index], MAXIMUM_CLUSTERS_PER_LIGHT, cluster_indices); } light_compute_bounding_sphere( lights_globals.scene_point_lights[light_index], FALSE, FALSE, FALSE, ¢er, &radius); structure_render_diffuse_light( light->rasterizer_light_index, ¢er, radius, cluster_count, skip_clusters ? NULL : cluster_indices); } } } rasterizer_environment_diffuse_lights_end(); return; } void lights_render_specular( void) { short cluster_indices[MAXIMUM_CLUSTERS_PER_LIGHT]; short light_index; rasterizer_environment_specular_lights_begin(); if (should_render_lights()) { for (light_index = 0; light_index < lights_globals.scene_point_light_count; light_index++) { struct light_datum *light = light_get( lights_globals.scene_point_lights[light_index]); if (TEST_FLAG(light->flags, _point_light_dynamic_bit) && light->rasterizer_light_index != NONE && !TEST_FLAG(light_definition_get(light->definition_index)->flags, _light_definition_no_specular_bit)) { boolean skip_clusters = TEST_FLAG(light->flags, _point_light_attached_to_first_person_weapon_bit) && TEST_FLAG(light_definition_get(light->definition_index)->flags, _light_definition_supersize_in_first_person_bit); short cluster_count = 0; real_point3d center; real radius; if (!skip_clusters) { cluster_count = light_build_cluster_array( lights_globals.scene_point_lights[light_index], MAXIMUM_CLUSTERS_PER_LIGHT, cluster_indices); } light_compute_bounding_sphere( lights_globals.scene_point_lights[light_index], FALSE, TRUE, FALSE, ¢er, &radius); structure_render_specular_light( light->rasterizer_light_index, ¢er, radius, cluster_count, skip_clusters ? NULL : cluster_indices); } } } rasterizer_environment_specular_lights_end(); return; } void light_reconnect_to_map( long light_index) { struct light_datum *light = light_get(light_index); struct point_light_definition *definition = light_definition_get(light->definition_index); struct object_marker markers[1]; struct location location; real_point3d position; real radius; if (light->parent_light_index == NONE) { object_get_marker_by_name( light->object_index, object_get_attachment_marker_name(light->object_index, light->attachment_marker_index), markers, 1); light->position = markers[0].matrix.position; light->forward = markers[0].matrix.forward; light->up = markers[0].matrix.up; } else if (object_try_and_get(light->object_index)) { real_matrix4x3 *node_matrix = object_get_node_matrix(light->object_index, light->attachment_marker_index); matrix4x3_transform_point(node_matrix, &light->node.relative_position, &light->position); matrix4x3_transform_normal(node_matrix, &light->node.relative_forward, &light->forward); perpendicular3d(&light->forward, &light->up); normalize3d(&light->up); } if (TEST_FLAG(light->flags, _point_light_connects_to_map_bit)) { light_compute_bounding_sphere( light_index, TRUE, FALSE, TRUE, &position, &radius); match_assert( "c:\\halo\\SOURCE\\objects\\object_lights.c", 0x4F9, !TEST_FLAG(light->flags, _point_light_connected_to_map_bit)); if (light->object_index != NONE && object_try_and_get(light->object_index)) { object_get_location(light->object_index, &location); } else { scenario_location_from_point(&location, &position); } cluster_partition_reconnect( &light_cluster_partition, light_index, &light->cluster_reference, &position, radius, &location); SET_FLAG(light->flags, _point_light_connected_to_map_bit, TRUE); } return; } static void find_point_lights_for_object_in_cluster( long object_index, short cluster_index, real_point3d const *center, real radius, long *light_indices, real *light_intensities, real *light_attenuations, short *light_count, short maximum_light_count) { long light_index; long reference_index; match_assert( "c:\\halo\\SOURCE\\objects\\object_lights.c", 0x544, lights_globals.marker_initialized); for (light_index = cluster_partition_get_first_datum(&light_cluster_partition, &reference_index, cluster_index); light_index != NONE; light_index = cluster_partition_get_next_datum(&light_cluster_partition, &reference_index)) { if (light_unmarked(light_index)) { struct light_datum *light = light_get(light_index); if (light->rasterizer_light_index != NONE && (light->object_index != object_index || !TEST_FLAG(light_definition_get(light->definition_index)->flags, _light_definition_dont_light_own_object_bit))) { real distance = distance3d(&light->position, center); if (distance < radius + light->radius) { real attenuation = light_attenuation(light->radius, distance); real intensity = real_rgb_color_brightness(&light->color) * attenuation; short index; if (*light_count < maximum_light_count) { index = (*light_count)++; } else { real minimum_intensity = REAL_MAX; short dimmest_index = NONE; for (index = 0; index < *light_count; index++) { if (minimum_intensity > light_intensities[index]) { minimum_intensity = light_intensities[index]; dimmest_index = index; } } if (minimum_intensity < intensity) { index = dimmest_index; } } if (index < maximum_light_count) { light_indices[index] = light_index; light_intensities[index] = intensity; light_attenuations[index] = attenuation; } } } light_mark(light_index); } } return; } void lights_illumination_at_point( real_point3d const *point, struct location const *location, real_rgb_color *color) { *color = *global_real_rgb_black; { short lightmap_index; short material_index; long surface_index; real s; real t; real_point3d collision_point; if (structure_test_vector( point, &lightmap_sample_raycast_down, &collision_point, &lightmap_index, &material_index, &surface_index, &s, &t)) { struct structure_bsp *structure = global_structure_bsp_get(); struct structure_lightmap *lightmap = TAG_BLOCK_GET_ELEMENT( &structure->lightmaps, lightmap_index, struct structure_lightmap); struct structure_material *material = TAG_BLOCK_GET_ELEMENT( &lightmap->materials, material_index, struct structure_material); if (structure->lightmap_group.index != NONE && lightmap->bitmap_index != NONE) { struct bitmap_data *bitmap = bitmap_group_try_and_get_bitmap( structure->lightmap_group.index, lightmap->bitmap_index); struct structure_surface const *surface = TAG_BLOCK_GET_ELEMENT( &structure->surfaces, surface_index, struct structure_surface); match_assert( "c:\\halo\\SOURCE\\objects\\object_lights.c", 854, material->lightmap_vertices.type==_rasterizer_vertex_type_environment_lightmap_uncompressed || material->lightmap_vertices.type==_rasterizer_vertex_type_environment_lightmap_compressed); if (_texture_cache_bitmap_get_hardware_format(bitmap, FALSE, FALSE)) { sample_lightmap(material, bitmap, surface, s, t, color); } } } } if (location->cluster_index != NONE) { long light_indices[MAXIMUM_RENDERED_POINT_LIGHTS]; real light_intensities[MAXIMUM_RENDERED_POINT_LIGHTS]; real light_attenuations[MAXIMUM_RENDERED_POINT_LIGHTS]; short light_count = 0; short light_index; light_marker_begin(); find_point_lights_for_object_in_cluster( NONE, location->cluster_index, point, 0.0f, light_indices, light_intensities, light_attenuations, &light_count, MAXIMUM_RENDERED_POINT_LIGHTS); light_marker_end(); for (light_index = 0; light_index < light_count; light_index++) { struct light_datum *light = light_get(light_indices[light_index]); if (TEST_FLAG(light->flags, _point_light_dynamic_bit)) { color->red += light->color.red * light_attenuations[light_index]; color->green += light->color.green * light_attenuations[light_index]; color->blue += light->color.blue * light_attenuations[light_index]; } } } color->red = PIN(color->red, 0.0f, 1.0f); color->green = PIN(color->green, 0.0f, 1.0f); color->blue = PIN(color->blue, 0.0f, 1.0f); return; } void lights_prepare_for_object_dynamic( long object_index, struct render_lighting *lighting) { struct object_cluster_iterator iterator; real_point3d center; real radius; real light_intensities[MAXIMUM_RENDERED_POINT_LIGHTS]; real light_attenuations[MAXIMUM_RENDERED_POINT_LIGHTS]; short cluster_index; short light_index; object_get_bounding_sphere(object_index, ¢er, &radius); lighting->point_light_count = 0; light_marker_begin(); for (cluster_index = object_get_first_cluster(&iterator, object_index); cluster_index != NONE; cluster_index = object_get_next_cluster(&iterator, object_index)) { find_point_lights_for_object_in_cluster( object_index, cluster_index, ¢er, radius, lighting->point_light_indices, light_intensities, light_attenuations, &lighting->point_light_count, MAXIMUM_RENDERED_POINT_LIGHTS); } light_marker_end(); for (light_index = 0; light_index < lighting->point_light_count; light_index++) { lighting->point_light_indices[light_index] = light_get(lighting->point_light_indices[light_index])->rasterizer_light_index; } return; } static void build_distant_lights( long flags, real_vector3d const *surface_normal, real_rgb_color const *diffuse_color, real_vector3d const *radiosity_normal, real radiosity_accuracy, real_rgb_color const *lightmap_color, struct render_lighting *lighting) { real brightness = real_rgb_color_brightness(lightmap_color); real accuracy, horizontal_length, ambient; lighting->ambient_color.red = lightmap_color->red * object_light_ambient_scale + object_light_ambient_base; lighting->ambient_color.green = lightmap_color->green * object_light_ambient_scale + object_light_ambient_base; lighting->ambient_color.blue = lightmap_color->blue * object_light_ambient_scale + object_light_ambient_base; lighting->distant_light_count = 2; lighting->distant_lights[0].color = *lightmap_color; lighting->distant_lights[0].direction.i = -radiosity_normal->i; lighting->distant_lights[0].direction.j = -radiosity_normal->j; lighting->distant_lights[0].direction.k = -radiosity_normal->k; lighting->distant_lights[1].color.red = diffuse_color->red * object_light_secondary_scale * brightness; lighting->distant_lights[1].color.green = diffuse_color->green * object_light_secondary_scale * brightness; lighting->distant_lights[1].color.blue = diffuse_color->blue * object_light_secondary_scale * brightness; lighting->distant_lights[1].direction = *surface_normal; lighting->reflection_tint_color.alpha = PIN(brightness * 1.5f + 0.25f, 0.0f, 1.0f); lighting->reflection_tint_color.red = PIN(diffuse_color->red * 3.0f + 0.5f, 0.0f, 1.0f); lighting->reflection_tint_color.green = PIN(diffuse_color->green * 3.0f + 0.5f, 0.0f, 1.0f); lighting->reflection_tint_color.blue = PIN(diffuse_color->blue * 3.0f + 0.5f, 0.0f, 1.0f); lighting->reflection_tint_color.red *= PIN(lightmap_color->red * 2.0f + 0.25f, 0.0f, 1.0f); lighting->reflection_tint_color.green *= PIN(lightmap_color->green * 2.0f + 0.25f, 0.0f, 1.0f); lighting->reflection_tint_color.blue *= PIN(lightmap_color->blue * 2.0f + 0.25f, 0.0f, 1.0f); accuracy = power(radiosity_accuracy, 0.25f); lighting->shadow_vector.i = lighting->distant_lights[0].direction.i * accuracy; lighting->shadow_vector.j = lighting->distant_lights[0].direction.j * accuracy; horizontal_length = magnitude2d((real_vector2d *)&lighting->shadow_vector); if (horizontal_length < 0.707f) { lighting->shadow_vector.k = -square_root(1.0f - horizontal_length * horizontal_length); } else { lighting->shadow_vector.k = -0.707f; horizontal_length = 0.707f / horizontal_length; lighting->shadow_vector.i *= horizontal_length; lighting->shadow_vector.j *= horizontal_length; } ambient = (1.0f - radiosity_accuracy) * 0.5f; lighting->shadow_color.red = PIN(1.0f - lighting->distant_lights[0].color.red * 1.3f + ambient, object_light_ambient_base, 1.0f); lighting->shadow_color.green = PIN(1.0f - lighting->distant_lights[0].color.green * 1.3f + ambient, object_light_ambient_base, 1.0f); lighting->shadow_color.blue = PIN(1.0f - lighting->distant_lights[0].color.blue * 1.3f + ambient, object_light_ambient_base, 1.0f); if (TEST_FLAG(flags, _distant_lighting_brighten_bit)) { brighten_real_rgb_color(&lighting->ambient_color, 0.2f); brighten_real_rgb_color(&lighting->distant_lights[0].color, 0.3f); brighten_real_rgb_color(&lighting->distant_lights[1].color, 0.2f); brighten_real_rgb_color(&lighting->reflection_tint_color.rgb, 0.5f); lighting->reflection_tint_color.alpha = 1.0f; } return; } boolean lights_distant_lighting_at_point( long flags, real_point3d const *position, struct render_lighting *lighting) { boolean result = FALSE; real s; real t; short lightmap_index; short material_index; real lengths[3]; long surface_index; real_rgb_color lightmap_color; real_vector3d normals[3]; real_vector3d radiosity_normal; real_vector3d surface_normal; real_rgb_color diffuse_color; real_point3d collision_point; struct structure_bsp *structure_bsp = global_structure_bsp_get(); real_vector3d const *raycasts; short raycast_count; short raycast_index; if (structure_bsp->default_lighting.ambient_color.red != 0.0f) { *lighting = structure_bsp->default_lighting; lighting->distant_light_count = 2; } else { *lighting = default_object_lighting; } if (TEST_FLAG(flags, _distant_lighting_raycast_sideways_bit)) { raycasts = lightmap_sample_raycast_sideways; raycast_count = NUMBER_OF_LIGHTMAP_SAMPLE_SIDEWAYS_RAYCASTS; } else { raycasts = &lightmap_sample_raycast_down; raycast_count = 1; } for (raycast_index = 0; raycast_index < raycast_count; raycast_index++) { if (structure_test_vector( position, &raycasts[raycast_index], &collision_point, &lightmap_index, &material_index, &surface_index, &s, &t)) { struct structure_lightmap *lightmap; struct structure_material *material; struct shader *shader; structure_bsp = global_structure_bsp_get(); lightmap = TAG_BLOCK_GET_ELEMENT( &structure_bsp->lightmaps, lightmap_index, struct structure_lightmap); material = TAG_BLOCK_GET_ELEMENT( &lightmap->materials, material_index, struct structure_material); shader = shader_definition_get(material->shader.index); if (shader->base.type == _shader_type_environment) { struct shader_environment_definition *shader_environment = shader_environment_definition_get(shader); if (structure_bsp->lightmap_group.index != NONE && lightmap->bitmap_index != NONE && shader_environment->base_map.index != NONE) { struct structure_surface const *surface = TAG_BLOCK_GET_ELEMENT( &structure_bsp->surfaces, surface_index, struct structure_surface); struct bitmap_data *lightmap_bitmap = bitmap_group_try_and_get_bitmap( structure_bsp->lightmap_group.index, lightmap->bitmap_index); struct bitmap_data *diffuse_bitmap = bitmap_group_try_and_get_bitmap( shader_environment->base_map.index, (short)(material->permutation_index % bitmap_group_get(shader_environment->base_map.index)->bitmaps.count)); if (lightmap_bitmap != NULL && diffuse_bitmap != NULL && texture_cache_bitmap_load(lightmap_bitmap) != NULL && texture_cache_bitmap_load(diffuse_bitmap) != NULL) { real radiosity_accuracy; sample_diffuse_texture( material, diffuse_bitmap, surface, s, t, &diffuse_color); sample_lightmap( material, lightmap_bitmap, surface, s, t, &lightmap_color); environment_vertex_compressed_get_normal( structure_material_get_vertex(material, surface->vertex_indices[0]), &normals[0]); environment_vertex_compressed_get_normal( structure_material_get_vertex(material, surface->vertex_indices[1]), &normals[1]); environment_vertex_compressed_get_normal( structure_material_get_vertex(material, surface->vertex_indices[2]), &normals[2]); shade_vector3d( &normals[0], &normals[1], &normals[2], s, t, &surface_normal); normalize3d(&surface_normal); environment_lightmap_vertex_compressed_get_incident_radiosity( structure_material_get_lightmap_vertex(material, surface->vertex_indices[0]), &normals[0]); environment_lightmap_vertex_compressed_get_incident_radiosity( structure_material_get_lightmap_vertex(material, surface->vertex_indices[1]), &normals[1]); environment_lightmap_vertex_compressed_get_incident_radiosity( structure_material_get_lightmap_vertex(material, surface->vertex_indices[2]), &normals[2]); lengths[0] = normalize3d(&normals[0]); lengths[1] = normalize3d(&normals[1]); lengths[2] = normalize3d(&normals[2]); shade_vector3d( &normals[0], &normals[1], &normals[2], s, t, &radiosity_normal); radiosity_accuracy = shade_scalar(lengths[0], lengths[1], lengths[2], s, t); normalize3d(&radiosity_normal); if (debug_object_lights) { real_argb_color color; color.rgb = lightmap_color; color.alpha = 1.0f; render_debug_point( TRUE, position, 0.5f, &color); render_debug_vector( TRUE, position, &radiosity_normal, radiosity_accuracy, &color); } build_distant_lights( flags, &surface_normal, &diffuse_color, &radiosity_normal, radiosity_accuracy, &lightmap_color, lighting); result = TRUE; } } } break; } } return result; } void lights_prepare_for_object_static( long object_index, struct render_lighting *lighting) { struct object_datum *object = object_get(object_index); long flags = 0; struct render_lighting sample; short sample_count; short corner_index; boolean sampled; match_assert( "c:\\halo\\SOURCE\\objects\\object_lights.c", 970, lighting); if (TEST_FLAG(object->object.flags, _object_static_lighting_raycast_sideways_bit)) { SET_FLAG(flags, _distant_lighting_raycast_sideways_bit, TRUE); } if (TEST_FLAG(object_definition_get(object->definition_index)->object.flags, _object_artificially_bright_bit)) { SET_FLAG(flags, _distant_lighting_brighten_bit, TRUE); } sampled = lights_distant_lighting_at_point( flags, &object->object.bounding_sphere_center, lighting); if (TEST_FLAG(object->object.flags, _object_static_lighting_recompute_bit)) { return; } if (sampled) { sample_count = 1; } else { sample_count = 0; csmemset(lighting, 0, sizeof(struct render_lighting)); lighting->distant_light_count = 2; } for (corner_index = 0; corner_index < 4; corner_index++) { real_point3d point; point.x = (TEST_FLAG(corner_index, 0) ? 0.70710678f : -0.70710678f) * object->object.bounding_sphere_radius + object->object.bounding_sphere_center.x; point.y = (TEST_FLAG(corner_index, 1) ? 0.70710678f : -0.70710678f) * object->object.bounding_sphere_radius + object->object.bounding_sphere_center.y; point.z = object->object.bounding_sphere_center.z; if (lights_distant_lighting_at_point( flags, &point, &sample)) { sample_count++; lighting->ambient_color.red += sample.ambient_color.red; lighting->ambient_color.green += sample.ambient_color.green; lighting->ambient_color.blue += sample.ambient_color.blue; lighting->reflection_tint_color.alpha += sample.reflection_tint_color.alpha; lighting->reflection_tint_color.red += sample.reflection_tint_color.red; lighting->reflection_tint_color.green += sample.reflection_tint_color.green; lighting->reflection_tint_color.blue += sample.reflection_tint_color.blue; lighting->distant_lights[0].color.red += sample.distant_lights[0].color.red; lighting->distant_lights[0].color.green += sample.distant_lights[0].color.green; lighting->distant_lights[0].color.blue += sample.distant_lights[0].color.blue; lighting->distant_lights[0].direction.i += sample.distant_lights[0].direction.i; lighting->distant_lights[0].direction.j += sample.distant_lights[0].direction.j; lighting->distant_lights[0].direction.k += sample.distant_lights[0].direction.k; lighting->distant_lights[1].color.red += sample.distant_lights[1].color.red; lighting->distant_lights[1].color.green += sample.distant_lights[1].color.green; lighting->distant_lights[1].color.blue += sample.distant_lights[1].color.blue; lighting->distant_lights[1].direction.i += sample.distant_lights[1].direction.i; lighting->distant_lights[1].direction.j += sample.distant_lights[1].direction.j; lighting->distant_lights[1].direction.k += sample.distant_lights[1].direction.k; lighting->shadow_color.red += sample.shadow_color.red; lighting->shadow_color.green += sample.shadow_color.green; lighting->shadow_color.blue += sample.shadow_color.blue; lighting->shadow_vector.i += sample.shadow_vector.i; lighting->shadow_vector.j += sample.shadow_vector.j; lighting->shadow_vector.k += sample.shadow_vector.k; } } if (sample_count > 1) { real scale = 1.0f / sample_count; lighting->ambient_color.red *= scale; lighting->ambient_color.green *= scale; lighting->ambient_color.blue *= scale; lighting->reflection_tint_color.alpha *= scale; lighting->reflection_tint_color.red *= scale; lighting->reflection_tint_color.green *= scale; lighting->reflection_tint_color.blue *= scale; lighting->distant_lights[0].color.red *= scale; lighting->distant_lights[0].color.green *= scale; lighting->distant_lights[0].color.blue *= scale; scale_vector3d(&lighting->distant_lights[0].direction, scale, &lighting->distant_lights[0].direction); normalize3d(&lighting->distant_lights[0].direction); lighting->distant_lights[1].color.red *= scale; lighting->distant_lights[1].color.green *= scale; lighting->distant_lights[1].color.blue *= scale; scale_vector3d(&lighting->distant_lights[1].direction, scale, &lighting->distant_lights[1].direction); normalize3d(&lighting->distant_lights[1].direction); lighting->shadow_color.red *= scale; lighting->shadow_color.green *= scale; lighting->shadow_color.blue *= scale; scale_vector3d(&lighting->shadow_vector, scale, &lighting->shadow_vector); normalize3d(&lighting->shadow_vector); } else if (sample_count == 0) { *lighting = sample; } return; }