Files
Cesarus85--ringfall-mjolnir-vr/source/render/render.c
T
MrBruh 94882796b7 Anti-aliasing
display.anti_aliasing, off by default: "fxaa" or "smaa" (a pass over the
3D view before the HUD and menus; SMAA vendored from port/third_party/smaa,
MIT), "ssaa2x" (the screen's targets at twice the resolution, at most the
GPU's largest target) and "msaa2x" to "msaa8x". Multisampled framebuffers
have every attachment multisampled, so the mirror's view with the back
buffer's depth buffer is too, and a target's texture and renderbuffer stay
coherent. The setting is read again between frames. Android has FXAA for
SMAA and no supersampling.

Based on #38 and #39 by Tyberious.
2026-10-06 15:24:59 +13:00

654 lines
18 KiB
C

/*
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 "cseries/errors.h"
#include "render.h"
#include "render_cameras_internal.h"
#include "render_particles.h"
#include "objects.h"
#include "render_sprite.h"
#include "scenario.h"
#include "structure_bsp_definitions.h"
#include "effects/player_effects.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 "interface/interface.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"
#include "main/main.h"
#include "structures/structures.h"
/* ---------- 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 */
#define RASTERIZER_TARGET_RENDER_PRIMARY_WIDTH halo_screen_width()
#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);
void render_sky(
void);
/* ---------- globals */
struct render_globals render;
static boolean render_invalid_fog_warning_displayed;
extern short global_screenshot_count;
boolean render_contrails_enabled = TRUE;
boolean render_particles_enabled = TRUE;
boolean render_particle_systems_enabled = TRUE;
boolean render_weather_particle_systems_enabled = TRUE;
/* ---------- 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(&parameters, 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(&parameters.camera, NULL, &parameters.frustum, TRUE);
parameters.rasterizer_target = _render_target_primary;
parameters.suppress_clear = window_type == 0;
parameters.window_index = NONE;
rasterizer_window_begin(&parameters);
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:
halo_screen_ui_offset(TRUE);
game_engine_nonplayer_post_rasterize();
halo_screen_ui_offset(FALSE);
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(&parameters);
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);
halo_screen_ui_offset(TRUE);
render_ui_widgets(0, &window->rasterizer_camera.viewport_bounds);
halo_screen_ui_offset(FALSE);
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_index<global_structure_bsp_get()->clusters.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_index<render.rendered_cluster_count);
return &render.rendered_clusters[rendered_cluster_index];
}
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)
{
struct rasterizer_window_begin_parameters parameters;
short rendered_cluster_index;
profile_render_window_start(TRUE);
render.scene_index++;
memset(&parameters, 0, sizeof(parameters));
render.local_player_index = local_player_index;
render.camera = *camera;
render.frustum = *frustum;
parameters.camera = *rasterizer_camera;
parameters.frustum = *rasterizer_frustum;
parameters.rasterizer_target = rasterizer_target;
parameters.has_mirror = has_mirror;
parameters.window_index = render.window_index;
parameters.fog = render.fog;
structure_visibility_compute();
player_effect_get_screen_flash(local_player_index, &parameters.screen_flash);
rasterizer_window_begin(&parameters);
if (!bink_playback_in_progress())
{
build_sprite_prepare_for_window();
render_sky();
first_person_weapon_render_update();
lights_preprocess_scene();
render_objects();
structure_render_preprocess();
structure_render_lightmaps();
rasterizer_lens_flares_submit_occlusion_tests();
render_object_shadows();
lights_render_diffuse();
rasterizer_decals_begin(_decal_layer_light);
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_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();
/* port: the 3D view antialiased (display.anti_aliasing), before the
HUD and menus are drawn over it */
if (rasterizer_target == _render_target_primary)
{
halo_screen_anti_alias(
rasterizer_camera->viewport_bounds.x0,
rasterizer_camera->viewport_bounds.y0,
rasterizer_camera->viewport_bounds.x1,
rasterizer_camera->viewport_bounds.y1);
}
interface_draw_screen();
rasterizer_screen_flash();
halo_screen_ui_offset(TRUE);
render_ui_widgets(local_player_index, &rasterizer_camera->viewport_bounds);
halo_screen_ui_offset(FALSE);
}
bink_playback_render();
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);
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;
}
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(&parameters, 0, sizeof(parameters));
/* continuous between ticks (render_interpolation.c) */
parameters.game_time_sec = render_interpolation_game_time_sec(game_time_get());
rasterizer_frame_begin(&parameters);
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;
}
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);
}
halo_screen_ui_offset(TRUE);
progress_bar_eachframe();
halo_screen_ui_offset(FALSE);
rasterizer_windows_end();
rasterizer_frame_end();
return;
}
/* ---------- private code */