/* RENDER.C symbols in this file: 001743B0 0020: _render_effects (0000) 001743D0 0010: _render_initialize (0000) 001743E0 0010: _render_initialize_for_new_map (0000) 001743F0 0010: _render_dispose_from_old_map (0000) 00174400 0010: _render_dispose (0000) 00174410 0110: _render_nonplayer_frame (0000) 00174520 00f0: _render_frame_pregame (0000) 00174610 0020: _render_frame_present (0000) 00174630 0070: _render_location_visible (0000) 001746A0 0050: _rendered_cluster_get (0000) 001746F0 03f0: _render_window (0000) 00174AE0 03f0: _render_player_frame (0000) 00174ED0 00f0: _render_frame (0000) 0029F44C 001f: ??_C@_0BP@JNDFGHKA@c?3?2halo?2SOURCE?2render?2render?4c?$AA@ (0000) 0029F470 0061: ??_C@_0GB@NHJDHKGO@location?9?$DOcluster_index?$DO?$DN0?5?$CG?$CG?5lo@ (0000) 0029F4D8 0052: ??_C@_0FC@DLFICDJP@rendered_cluster_index?$DO?$DN0?5?$CG?$CG?5ren@ (0000) 0029F530 0052: ??_C@_0FC@NBMIPGBN@window?9?$DOrender_camera?4viewport_b@ (0000) 0029F588 0051: ??_C@_0FB@IDPOBHAJ@window?9?$DOrender_camera?4viewport_b@ (0000) 0029F5DC 002c: ??_C@_0CM@LKHLGDKF@window?9?$DOrender_camera?4viewport_b@ (0000) 0029F608 002c: ??_C@_0CM@HBCHLAAA@window?9?$DOrender_camera?4viewport_b@ (0000) 0029F638 006d: ??_C@_0GN@PKELCNNH@?$CBmemcmp?$CI?$CGwindow?9?$DOrender_camera?4w@ (0000) 0029F6A8 0071: ??_C@_0HB@BCLIBPGM@?$CBmemcmp?$CI?$CGwindow?9?$DOrender_camera?4v@ (0000) 0029F720 0048: ??_C@_0EI@NGOLLMDP@?$CD?$CD?$CD?5ERROR?5something?5is?5wrong?5wit@ (0000) 0030D4D2 0004: _render_contrails_enabled (0000) _render_particles_enabled (0001) _render_particle_systems_enabled (0002) _render_weather_particle_systems_enabled (0003) 004B8B22 0001: _render_invalid_fog_warning_displayed (0000) */ /* ---------- headers */ #include "cseries.h" #include "render.h" #include "render_cameras_internal.h" #include "render_particles.h" #include "objects.h" #include "scenario.h" #include "structure_bsp_definitions.h" #include "structures/structure_visibility.h" #include "rasterizer.h" #include "rasterizer/rasterizer_lights.h" #include "profile.h" #include "progress_bar.h" #include "ui_widget.h" #include "bink_playback.h" #include "game.h" #include "game_engine.h" #include "interface/first_person_weapons.h" #include "editor_stubs.h" #include "render_debug.h" #include "objects/object_lights_rendering.h" #include "effects/particle_systems.h" #include "effects/weather_particle_systems.h" #ifdef HALO_ANDROID #include "cutscene/cinematics.h" #include "game/players.h" #include "game/player_control.h" #include "interface/hud.h" #include "physics/collisions.h" #include "units/units.h" #include "halo_vr.h" #endif /* ---------- constants */ enum { _render_target_primary = 0, _render_target_secondary, }; enum { _decal_layer_primary = 0, _decal_layer_secondary, _decal_layer_light, _decal_layer_alpha_tested, _decal_layer_water, }; enum { _render_planar_fog_mode_fully_fogged = 2, }; /* ---------- macros */ #ifdef HALO_LINUX #define RASTERIZER_TARGET_RENDER_PRIMARY_WIDTH halo_screen_width() #else #define RASTERIZER_TARGET_RENDER_PRIMARY_WIDTH 640 #endif #define RASTERIZER_TARGET_RENDER_PRIMARY_HEIGHT 480 /* ---------- structures */ /* ---------- prototypes */ static void render_nonplayer_frame( const struct render_window *window, long window_type); static void render_window( short local_player_index, const struct render_camera *camera, const struct render_frustum *frustum, const struct render_camera *rasterizer_camera, const struct render_frustum *rasterizer_frustum, short rasterizer_target, boolean has_mirror); static void render_player_frame( struct render_window *window, const point2d *screenshot_combined_index); #ifdef HALO_ANDROID static void render_vr_player_frame( struct render_window *window); static void render_vr_overlay( const struct render_window *window); static void render_vr_laser( short local_player_index); static void render_vr_scope( struct render_window *window); #endif void structure_get_planar_fog( short cluster_index, struct render_fog *fog); void player_effect_get_screen_flash( short local_player_index, struct render_screen_flash *screen_flash); void build_sprite_prepare_for_window( void); void render_sky( void); void render_objects( void); void render_object_shadows( void); void rasterizer_transparent_geometry_stop( void); void interface_draw_fullscreen_overlays( void); void rasterizer_debug_draw( void); void render_debug( void); void progress_bar_eachframe( void); short main_get_window_count( void); /* ---------- globals */ struct render_globals render; static boolean render_invalid_fog_warning_displayed; extern short global_screenshot_count; extern short global_screenshot_size; boolean render_contrails_enabled = TRUE; boolean render_particles_enabled = TRUE; boolean render_particle_systems_enabled = TRUE; boolean render_weather_particle_systems_enabled = TRUE; #ifdef HALO_ANDROID /* VR (render_vr_player_frame): drawing an eye, which leaves out the HUD and the menus, and that eye's frustum bounds */ static boolean render_vr_eye_pass = FALSE; static const real_rectangle2d *render_vr_frustum_bounds = NULL; #endif /* ---------- public code */ void render_effects( boolean enable) { render_weather_particle_systems_enabled = enable; render_particle_systems_enabled = enable; render_particles_enabled = enable; render_contrails_enabled = enable; } void render_initialize( void) { render_objects_initialize(); } void render_initialize_for_new_map( void) { render_objects_initialize_for_new_map(); } void render_dispose_from_old_map( void) { render_objects_dispose_from_old_map(); } void render_dispose( void) { render_objects_dispose(); } static void render_nonplayer_frame( const struct render_window *window, long window_type) { struct rasterizer_window_begin_parameters parameters; profile_render_window_start(FALSE); memset(¶meters, 0, sizeof(parameters)); render.camera = window->render_camera; render_camera_build_frustum(&render.camera, NULL, &render.frustum, TRUE); parameters.camera = window->rasterizer_camera; render_camera_build_frustum(¶meters.camera, NULL, ¶meters.frustum, TRUE); parameters.rasterizer_target = _render_target_primary; parameters.suppress_clear = window_type == 0; parameters.window_index = NONE; rasterizer_window_begin(¶meters); switch (window_type) { case 0: /* letterbox bars and split screen dividers: laid out from the viewport, so not centered like the menus on a wide screen */ interface_draw_fullscreen_overlays(); rasterizer_debug_draw(); break; case 1: #ifdef HALO_LINUX halo_screen_ui_offset(TRUE); game_engine_nonplayer_post_rasterize(); halo_screen_ui_offset(FALSE); #else game_engine_nonplayer_post_rasterize(); #endif break; default: match_assert("c:\\halo\\SOURCE\\render\\render.c", 287, !"unreachable"); break; } rasterizer_window_end(); profile_render_window_end(); return; } void render_frame_pregame( struct render_window const *window, struct bitmap_data *bitmap) { struct rasterizer_frame_begin_parameters parameters; struct rasterizer_window_begin_parameters rasterizer_parameters; render.frame_index++; rasterizer_frame_begin(¶meters); rasterizer_windows_begin(); profile_render_window_start(FALSE); memset(&rasterizer_parameters, 0, sizeof(rasterizer_parameters)); render.camera = window->render_camera; render_camera_build_frustum(&render.camera, NULL, &render.frustum, TRUE); rasterizer_parameters.camera = window->rasterizer_camera; render_camera_build_frustum(&rasterizer_parameters.camera, NULL, &rasterizer_parameters.frustum, TRUE); rasterizer_parameters.rasterizer_target = 0; rasterizer_window_begin(&rasterizer_parameters); #ifdef HALO_LINUX halo_screen_ui_offset(TRUE); render_ui_widgets(0, &window->rasterizer_camera.viewport_bounds); halo_screen_ui_offset(FALSE); #else render_ui_widgets(0, &window->rasterizer_camera.viewport_bounds); #endif bink_playback_render(); { real progress; if (game_map_loading_in_progress(&progress)) { progress_bar_display(progress); } } rasterizer_window_end(); profile_render_window_end(); rasterizer_windows_end(); rasterizer_frame_end(); return; } void render_frame_present( const point2d *screenshot_index, struct bitmap_data *bitmap) { rasterizer_present(bitmap, screenshot_index); return; } boolean render_location_visible( struct location *location) { match_assert("c:\\halo\\SOURCE\\render\\render.c", 584, location->cluster_index>=0 && location->cluster_indexclusters.count); return TEST_FLAG(render.visible_cluster_flags[location->cluster_index>>5], location->cluster_index&31); } struct rendered_cluster *rendered_cluster_get( short rendered_cluster_index) { match_assert("c:\\halo\\SOURCE\\render\\render.c", 592, rendered_cluster_index>=0 && rendered_cluster_indexcluster_index); } rasterizer_decals_end(); rasterizer_decals_begin(_decal_layer_alpha_tested); for (rendered_cluster_index = 0; rendered_cluster_index < render.rendered_cluster_count; rendered_cluster_index++) { rasterizer_decals_draw(rendered_cluster_get(rendered_cluster_index)->cluster_index); } rasterizer_decals_end(); structure_render_diffuse_texture(); rasterizer_decals_begin(_decal_layer_primary); for (rendered_cluster_index = 0; rendered_cluster_index < render.rendered_cluster_count; rendered_cluster_index++) { rasterizer_decals_draw(rendered_cluster_get(rendered_cluster_index)->cluster_index); } rasterizer_decals_end(); rasterizer_decals_begin(_decal_layer_secondary); for (rendered_cluster_index = 0; rendered_cluster_index < render.rendered_cluster_count; rendered_cluster_index++) { rasterizer_decals_draw(rendered_cluster_get(rendered_cluster_index)->cluster_index); } rasterizer_decals_end(); lights_render_specular(); structure_render_specular_lightmaps(); structure_render_reflection_lightmap_masks(); structure_render_reflection_mirrors(); structure_render_reflections(); structure_render_transparent_geometry(); structure_render_fog(); game_engine_post_rasterize_objects(); weather_particle_systems_render(); render_particles(); particle_systems_render(); render_contrails_normal(); rasterizer_transparent_geometry_draw(TRUE); rasterizer_decals_begin(_decal_layer_water); for (rendered_cluster_index = 0; rendered_cluster_index < render.rendered_cluster_count; rendered_cluster_index++) { rasterizer_decals_draw(rendered_cluster_get(rendered_cluster_index)->cluster_index); } rasterizer_decals_end(); structure_render_detail_objects(); rasterizer_transparent_geometry_draw(FALSE); rasterizer_transparent_geometry_stop(); structure_render_fog_screen(); rasterizer_lens_flares_draw(); #ifdef HALO_ANDROID if (render_vr_eye_pass) { /* the HUD and the menus go on the overlay (render_vr_overlay) */ rasterizer_screen_flash(); } else #endif { interface_draw_screen(); rasterizer_screen_flash(); #ifdef HALO_LINUX halo_screen_ui_offset(TRUE); render_ui_widgets(local_player_index, &rasterizer_camera->viewport_bounds); halo_screen_ui_offset(FALSE); #else render_ui_widgets(local_player_index, &rasterizer_camera->viewport_bounds); #endif } } bink_playback_render(); #ifdef HALO_ANDROID if (render_vr_eye_pass) render_vr_laser(local_player_index); #endif render_camera_debug_frustum(&render.camera, &render.frustum); render_debug(); editor_render(); rasterizer_debug_draw(); rasterizer_window_end(); profile_render_window_end(); return; } static void render_player_frame( struct render_window *window, const point2d *screenshot_combined_index) { struct render_camera *camera; boolean has_mirror; real_rectangle2d frustum_bounds; struct render_frustum frustum; struct render_frustum rasterizer_frustum; struct render_mirror mirror; camera = &window->render_camera; has_mirror = FALSE; structure_visibility_find_camera(camera); render.fog.runtime_flags = 0; scenario_get_atmospheric_fog( window->local_player_index, (word)render.visible_sky_index, &camera->position, &render.fog); structure_get_planar_fog((short)render.cluster_index, &render.fog); if (render.fog.atmospheric_maximum_distance != 0.0f && render.visible_sky_index == NONE && render.fog.planar_maximum_distance > render.fog.atmospheric_maximum_distance) { render.fog.planar_maximum_distance = render.fog.atmospheric_maximum_distance; } if (render.fog.atmospheric_maximum_density == 1.0f && render.fog.atmospheric_maximum_distance != 0.0f) { window->render_camera.z_far = MIN( window->render_camera.z_far, render.fog.atmospheric_maximum_distance); } if (render.fog.planar_mode == _render_planar_fog_mode_fully_fogged && render.fog.planar_maximum_distance != 0.0f) { window->render_camera.z_far = MIN( window->render_camera.z_far, render.fog.planar_maximum_distance); } if (window->render_camera.z_far <= window->render_camera.z_near) { if (!render_invalid_fog_warning_displayed) { error(2, "### ERROR something is wrong with the fog in the sky tag or the fog tag"); render_invalid_fog_warning_displayed = TRUE; } window->render_camera.z_far = window->render_camera.z_near + 0.01f; } match_assert( "c:\\halo\\SOURCE\\render\\render.c", 187, !memcmp(&window->render_camera.viewport_bounds, &window->rasterizer_camera.viewport_bounds, sizeof(rectangle2d))); match_assert( "c:\\halo\\SOURCE\\render\\render.c", 188, !memcmp(&window->render_camera.window_bounds, &window->rasterizer_camera.window_bounds, sizeof(rectangle2d))); render_camera_build_frustum_bounds(camera, &frustum_bounds); #ifdef HALO_ANDROID if (render_vr_frustum_bounds) frustum_bounds = *render_vr_frustum_bounds; #endif if (screenshot_combined_index != NULL) { long tile_count; tile_count = global_screenshot_count * global_screenshot_size; if (tile_count > 0) { real tile_width; real tile_height; real_rectangle2d adjusted_bounds; tile_width = (frustum_bounds.x1 - frustum_bounds.x0) / (real)tile_count; tile_height = (frustum_bounds.y1 - frustum_bounds.y0) / (real)tile_count; adjusted_bounds.x0 = (real)screenshot_combined_index->x * tile_width + frustum_bounds.x0; adjusted_bounds.y0 = (real)(tile_count - screenshot_combined_index->y - 1) * tile_height + frustum_bounds.y0; adjusted_bounds.x1 = adjusted_bounds.x0 + tile_width; adjusted_bounds.y1 = adjusted_bounds.y0 + tile_height; frustum_bounds = adjusted_bounds; } } render_camera_build_frustum(camera, &frustum_bounds, &frustum, TRUE); render_camera_build_frustum( &window->rasterizer_camera, &frustum_bounds, &rasterizer_frustum, TRUE); if (main_get_window_count() == 1) { if (structure_visibility_find_mirror(camera, &frustum, &mirror)) { short saved_cluster_index; struct render_camera mirror_camera; struct render_frustum mirror_frustum; saved_cluster_index = (short)render.cluster_index; match_assert("c:\\halo\\SOURCE\\render\\render.c", 225, window->render_camera.viewport_bounds.x0==0); match_assert("c:\\halo\\SOURCE\\render\\render.c", 226, window->render_camera.viewport_bounds.y0==0); match_assert("c:\\halo\\SOURCE\\render\\render.c", 227, window->render_camera.viewport_bounds.x1==RASTERIZER_TARGET_RENDER_PRIMARY_WIDTH); match_assert("c:\\halo\\SOURCE\\render\\render.c", 228, window->render_camera.viewport_bounds.y1==RASTERIZER_TARGET_RENDER_PRIMARY_HEIGHT); render_camera_mirror(camera, &mirror, &mirror_camera); render_camera_build_frustum( &mirror_camera, &frustum_bounds, &mirror_frustum, TRUE); rasterizer_profile_enable(FALSE); render.cluster_index = mirror.cluster_index; render_window( NONE, &mirror_camera, &mirror_frustum, &mirror_camera, &mirror_frustum, _render_target_secondary, FALSE); render.cluster_index = saved_cluster_index; rasterizer_profile_enable(TRUE); has_mirror = TRUE; } } render_window( window->local_player_index, camera, &frustum, &window->rasterizer_camera, &rasterizer_frustum, _render_target_primary, has_mirror); return; } #ifdef HALO_ANDROID static void render_vr_camera_set( struct render_camera *camera, const float position[3], const float forward[3], const float up[3], real vertical_field_of_view) { camera->position.x = position[0]; camera->position.y = position[1]; camera->position.z = position[2]; camera->forward.i = forward[0]; camera->forward.j = forward[1]; camera->forward.k = forward[2]; camera->up.i = up[0]; camera->up.j = up[1]; camera->up.k = up[2]; camera->vertical_field_of_view = vertical_field_of_view; } /* A player's view in VR (port/linux/include/halo_vr.h): drawn once per eye from the headset's eye poses, placed at the game's camera, each copied to its eye image; then the HUD and the menus, over nothing, for the overlay the headset shows in front of the eyes. */ static void render_vr_player_frame( struct render_window *window) { float game_position[3]; short eye; game_position[0] = window->render_camera.position.x; game_position[1] = window->render_camera.position.y; game_position[2] = window->render_camera.position.z; { /* seated, the vehicle's heading as this frame draws it (between ticks): the view turns with it smoothly */ long player_index = local_player_get_player_index(window->local_player_index); long unit_index = player_index == NONE ? NONE : player_get(player_index)->unit_index; long vehicle_index = unit_index == NONE ? NONE : object_get(unit_index)->object.parent_object_index; real_matrix4x3 *nodes = vehicle_index == NONE ? NULL : render_interpolation_object_node_matrices(vehicle_index); if (nodes) halo_vr_set_seat_frame(window->local_player_index, (float)atan2(nodes[0].forward.j, nodes[0].forward.i)); } if (halo_vr_multiview()) { /* both eyes at once, from between them */ struct render_window eye_window = *window; float position[3], forward[3], up[3], bounds[4]; float vertical_field_of_view; real_rectangle2d frustum_bounds; halo_vr_center_camera(game_position, position, forward, up, &vertical_field_of_view, bounds); render_vr_camera_set(&eye_window.render_camera, position, forward, up, vertical_field_of_view); render_vr_camera_set(&eye_window.rasterizer_camera, position, forward, up, vertical_field_of_view); frustum_bounds.x0 = bounds[0]; frustum_bounds.x1 = bounds[1]; frustum_bounds.y0 = bounds[2]; frustum_bounds.y1 = bounds[3]; { /* the depth of what the game projects itself (its sprites) */ struct render_frustum frustum; render_camera_build_frustum(&eye_window.rasterizer_camera, &frustum_bounds, &frustum, TRUE); halo_vr_multiview_projection(frustum.projection_matrix[2][2], frustum.projection_matrix[3][2]); } render_vr_eye_pass = TRUE; render_vr_frustum_bounds = &frustum_bounds; render_player_frame(&eye_window, NULL); render_vr_frustum_bounds = NULL; render_vr_eye_pass = FALSE; halo_vr_capture_multiview(); } else for (eye = 0; eye < 2; eye++) { struct render_window eye_window = *window; float position[3], forward[3], up[3], bounds[4]; float vertical_field_of_view; real_rectangle2d frustum_bounds; halo_vr_eye_camera(eye, game_position, position, forward, up, &vertical_field_of_view, bounds); render_vr_camera_set(&eye_window.render_camera, position, forward, up, vertical_field_of_view); render_vr_camera_set(&eye_window.rasterizer_camera, position, forward, up, vertical_field_of_view); frustum_bounds.x0 = bounds[0]; frustum_bounds.x1 = bounds[1]; frustum_bounds.y0 = bounds[2]; frustum_bounds.y1 = bounds[3]; render_vr_eye_pass = TRUE; render_vr_frustum_bounds = &frustum_bounds; render_player_frame(&eye_window, NULL); render_vr_frustum_bounds = NULL; render_vr_eye_pass = FALSE; halo_vr_capture_eye(eye); } render_vr_scope(window); render_vr_overlay(window); return; } /* The scope's view (halo_vr_scope): zoomed in, the player's view once more, from the weapon along its aim through the zoom's field of view, into a small square at the back buffer's top left (a sixteenth of it: the disc is a few centimetres across), which becomes the disc over the weapon. */ #define RENDER_VR_SCOPE_SIZE 120 static void render_vr_scope( struct render_window *window) { short zoom_level = player_control_get_zoom_level(window->local_player_index); long player_index = local_player_get_player_index(window->local_player_index); float position[3], forward[3], up[3]; float vertical_field_of_view; real magnification; struct render_window scope_window; if (zoom_level == NONE || player_index == NONE || player_get(player_index)->unit_index == NONE) return; magnification = unit_get_zoom_magnification(player_get(player_index)->unit_index, zoom_level); if (!halo_vr_scope(window->local_player_index, magnification, position, forward, up, &vertical_field_of_view)) return; scope_window = *window; render_vr_camera_set(&scope_window.render_camera, position, forward, up, vertical_field_of_view); render_vr_camera_set(&scope_window.rasterizer_camera, position, forward, up, vertical_field_of_view); scope_window.render_camera.viewport_bounds.x0 = scope_window.render_camera.viewport_bounds.y0 = 0; scope_window.render_camera.viewport_bounds.x1 = scope_window.render_camera.viewport_bounds.y1 = RENDER_VR_SCOPE_SIZE; scope_window.render_camera.window_bounds = scope_window.render_camera.viewport_bounds; scope_window.rasterizer_camera.viewport_bounds = scope_window.render_camera.viewport_bounds; scope_window.rasterizer_camera.window_bounds = scope_window.render_camera.viewport_bounds; render_vr_eye_pass = TRUE; render_player_frame(&scope_window, NULL); render_vr_eye_pass = FALSE; halo_vr_capture_scope(0.f, 0.f, (float)RENDER_VR_SCOPE_SIZE / RASTERIZER_TARGET_RENDER_PRIMARY_WIDTH, (float)RENDER_VR_SCOPE_SIZE / RASTERIZER_TARGET_RENDER_PRIMARY_HEIGHT); return; } /* where a ray from the weapon, as far as the longest-ranged weapons reach, hits something, or its end */ static void render_vr_ray_end( float const start[3], float const direction[3], long unit_index, real_point3d *origin, real_point3d *end) { real_vector3d ray; struct collision_result collision; origin->x = start[0]; origin->y = start[1]; origin->z = start[2]; ray.i = direction[0] * 100.f; ray.j = direction[1] * 100.f; ray.k = direction[2] * 100.f; if (collision_test_vector(_collision_test_for_projectiles_flags, origin, &ray, unit_index, &collision)) *end = collision.point; else point_from_line3d(origin, &ray, 1.f, end); } /* how far the weapon in the right hand aims before it hits something (the crosshair floats there, halo_vr_set_aim_distance), and its laser up to there, along the barrel as a reload turns it (halo_vr_laser), if vr.laser is on, but not over the menus */ static void render_vr_laser( short local_player_index) { static real_argb_color const laser_color = { 1.f, 1.f, 0.15f, 0.1f }; float start[3], direction[3]; real_point3d origin, end; long player_index; long unit_index = NONE; player_index = local_player_get_player_index(local_player_index); if (player_index != NONE) unit_index = player_get(player_index)->unit_index; if (!halo_vr_ready_laser(local_player_index, start, direction)) return; /* seated, the aim passes through the player's own vehicle (a gun's barrel and shield are in front of the hand) */ if (unit_index != NONE && object_get(unit_index)->object.parent_object_index != NONE) unit_index = object_get(unit_index)->object.parent_object_index; render_vr_ray_end(start, direction, unit_index, &origin, &end); halo_vr_set_aim_distance(distance3d(&origin, &end)); if (!halo_vr_laser(local_player_index, start, direction) || ui_widgets_menus_active()) return; render_vr_ray_end(start, direction, unit_index, &origin, &end); render_debug_line(TRUE, &origin, &end, &laser_color); render_debug_point(TRUE, &end, 0.02f, &laser_color); return; } /* the HUD and the menus of a player's view, on the cleared back buffer */ static void render_vr_overlay( const struct render_window *window) { struct rasterizer_window_begin_parameters parameters; boolean menus_active = ui_widgets_menus_active(); halo_vr_begin_overlay(menus_active); profile_render_window_start(FALSE); memset(¶meters, 0, sizeof(parameters)); render.local_player_index = window->local_player_index; render.camera = window->render_camera; render_camera_build_frustum(&render.camera, NULL, &render.frustum, TRUE); parameters.camera = window->rasterizer_camera; render_camera_build_frustum(¶meters.camera, NULL, ¶meters.frustum, TRUE); parameters.rasterizer_target = _render_target_primary; parameters.suppress_clear = TRUE; parameters.window_index = render.window_index; if (!menus_active && halo_vr_crosshair_apart()) { /* the weapon's crosshair alone, taken to where the weapon aims */ rasterizer_window_begin(¶meters); hud_draw_crosshair(); rasterizer_window_end(); halo_vr_capture_crosshair(); } rasterizer_window_begin(¶meters); interface_draw_screen(); halo_screen_ui_offset(TRUE); render_ui_widgets(window->local_player_index, &window->rasterizer_camera.viewport_bounds); halo_screen_ui_offset(FALSE); rasterizer_window_end(); profile_render_window_end(); return; } #endif void render_frame( struct render_window *windoze, short window_count, const point2d *screenshot_page_index, const point2d *screenshot_index, struct bitmap_data *screenshot_bitmap, real time_delta_since_tick_sec) { struct rasterizer_frame_begin_parameters parameters; short window_index; struct render_window *window; point2d screenshot_combined_index; render.frame_index++; render.time_delta_since_tick_sec = time_delta_since_tick_sec; memset(¶meters, 0, sizeof(parameters)); #ifdef HALO_LINUX /* continuous between ticks (render_interpolation.c) */ parameters.game_time_sec = render_interpolation_game_time_sec(game_time_get()); #else parameters.game_time_sec = (real)game_time_get() * (1.0f / TICKS_PER_SECOND); #endif rasterizer_frame_begin(¶meters); rasterizer_windows_begin(); for (window_index = 0; window_index < window_count; window_index++) { long window_type; window = &windoze[window_index]; render.window_index = window_index; if (window->console_window) { window_type = 0; } #ifdef HALO_ANDROID else if (window->local_player_index != NONE && screenshot_index == NULL && halo_vr_stereo_player(window->local_player_index, cinematic_in_progress())) { render_vr_player_frame(window); continue; } #endif else if (window->local_player_index != NONE) { if (screenshot_index != NULL && screenshot_page_index != NULL) { screenshot_combined_index.x = screenshot_page_index->x * global_screenshot_size + screenshot_index->x; screenshot_combined_index.y = screenshot_page_index->y * global_screenshot_size + screenshot_index->y; } render_player_frame( window, screenshot_index != NULL ? &screenshot_combined_index : NULL); continue; } else { window_type = 1; } render_nonplayer_frame(window, window_type); } #ifdef HALO_LINUX halo_screen_ui_offset(TRUE); progress_bar_eachframe(); halo_screen_ui_offset(FALSE); #else progress_bar_eachframe(); #endif rasterizer_windows_end(); rasterizer_frame_end(); return; } /* ---------- private code */