/* Mega Bezel - Creates a graphic treatment for the game play area to give a retro feel Copyright (C) 2019-2022 HyperspaceMadness - HyperspaceMadness@outlook.com Incorporates much great feedback from the libretro forum, and thanks to Hunterk who helped me get started See more at the libretro forum https://forums.libretro.com/t/hsm-mega-bezel-reflection-shader-feedback-and-updates This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see [http://www.gnu.org/licenses/]. */ #pragma format R32G32B32A32_SFLOAT #pragma stage vertex layout(location = 0) in vec4 Position; layout(location = 1) in vec2 TexCoord; layout(location = 0) out vec2 vTexCoord; void main() { gl_Position = global.MVP * Position; vTexCoord = TexCoord; } #pragma stage fragment layout(location = 0) in vec2 vTexCoord; layout(location = 0) out vec4 FragColor; layout(set = 0, binding = 1) uniform sampler2D Source; layout(set = 0, binding = 2) uniform sampler2D InfoCachePassFeedback; layout(set = 0, binding = 3) uniform sampler2D ScreenPlacementImage; // Get the original size with split area added vec2 HSM_GetScreenCorePreppedSize(float screen_index) { vec2 core_prepped_size = global.NegativeCropAddedPassSize.xy; if (HSM_DUALSCREEN_MODE > 0) if (HSM_GetCoreImageSplitDirection() == 1) core_prepped_size.y *= 0.5; else core_prepped_size.x *= 0.5; return core_prepped_size; } vec2 HSM_GetRotatedScreenCorePreppedSize(float screen_index) { vec2 original_size = HSM_GetScreenCorePreppedSize(screen_index); return HSM_ROTATE_CORE_IMAGE * original_size.yx + (1 - HSM_ROTATE_CORE_IMAGE) * original_size.xy; } vec2 HSM_GetRotatedScreenDerezedSize() { vec2 pass_size = global.DerezedPassSize.xy; if (HSM_DUALSCREEN_MODE > 0) if (HSM_GetCoreImageSplitDirection() == 1) pass_size.y *= 0.5; else pass_size.x *= 0.5; return HSM_ROTATE_CORE_IMAGE * pass_size.yx + (1 - HSM_ROTATE_CORE_IMAGE) * pass_size.xy; } float HSM_GetUseVerticalScanlines(float screen_aspect) { float auto_use_vert_scanlines = screen_aspect < 1 ? 1 : 0; float out_scanline_direction = 0; if (HSM_SCANLINE_DIRECTION < 1) out_scanline_direction = screen_aspect < 1 ? 1 : 0; else if (HSM_SCANLINE_DIRECTION > 1.5) out_scanline_direction = 1; return out_scanline_direction; } vec2 HSM_GetScreenScaleWithEdgeHeight(vec2 edge_thickness, vec2 screen_scale) // Edge thickness is a 0 to 1 percentage of the screen height { float output_aspect_ratio = global.FinalViewportSize.x / global.FinalViewportSize.y; float aspect_ratio = screen_scale.x / screen_scale.y; vec2 edge_width_height_as_scale = vec2(0, 0); edge_width_height_as_scale.x = 1 + (edge_thickness.x / screen_scale.y) / aspect_ratio / output_aspect_ratio; edge_width_height_as_scale.y = 1 + edge_thickness.y / screen_scale.y; return screen_scale * edge_width_height_as_scale; } // Same as the HSM_GetScreenScale, but adds the width of the black edge // Used for adding thickness around the screen like the black edge vec2 HSM_GetTubeScale(vec2 screen_scale, float image_placement_screen_height, vec2 edge_thickness) { // Add switch for independent scale if (HSM_BZL_USE_INDEPENDENT_SCALE == 1) { if (HSM_USE_IMAGE_FOR_PLACEMENT == 0) screen_scale = screen_scale / screen_scale.y * HSM_BZL_INDEPENDENT_SCALE; else screen_scale = screen_scale / screen_scale.y * image_placement_screen_height; } float normalized_screen_height = screen_scale.y / DEFAULT_UNCORRECTED_SCREEN_SCALE.y; return HSM_GetScreenScaleWithEdgeHeight(edge_thickness * vec2(1.2 / 100.0 * normalized_screen_height), screen_scale * HSM_BZL_SCALE_OFFSET); } // TODO need to get the screen scale before integer scale so we can derive automatic scanlines from it // HSM_SNAP_TO_CLOSEST_INT_SCALE_TOLERANCE vec2 HSM_GetScreenScale(float screen_aspect, float screen_height_from_image, vec2 cropped_size) { if (HSM_ASPECT_RATIO_MODE > 5.5) { return vec2(1, 1); } else { float output_aspect_ratio = global.FinalViewportSize.x / global.FinalViewportSize.y; bool viewport_is_vertical = (global.FinalViewportSize.x < global.FinalViewportSize.y); float vertical_preset_scale_mult = HSM_VERTICAL_PRESET > 0.5 || viewport_is_vertical ? DEFAULT_SCREEN_HEIGHT_PORTRAIT_MULTIPLIER : 1; float screen_height = HSM_NON_INTEGER_SCALE * vertical_preset_scale_mult; if (HSM_DUALSCREEN_MODE > 0) screen_height *= 0.5; if (HSM_INT_SCALE_MODE == 0) { if (HSM_USE_PHYSICAL_SIZE_FOR_NON_INTEGER == 1) { float monitor_aspect_with_rotation = HSM_VERTICAL_PRESET > 0.5 || viewport_is_vertical ? 1 / HSM_PHYSICAL_MONITOR_ASPECT_RATIO : HSM_PHYSICAL_MONITOR_ASPECT_RATIO; float monitor_height = HSM_PHYSICAL_MONITOR_DIAGONAL_SIZE / sqrt(monitor_aspect_with_rotation * monitor_aspect_with_rotation + 1); float sim_screen_height = HSM_PHYSICAL_SIM_TUBE_DIAGONAL_SIZE / sqrt(screen_aspect * screen_aspect + 1); screen_height = 0.012 + sim_screen_height / monitor_height; } if (HSM_USE_IMAGE_FOR_PLACEMENT == 1) screen_height = screen_height_from_image; screen_height *= HSM_NON_INTEGER_SCALE_OFFSET; // If the integer tolerance is greater than zero see if we can snap to the nearest integer multiple if (HSM_SNAP_TO_CLOSEST_INT_SCALE_TOLERANCE > 0) { float integer_scale_multiple_vert = screen_height * global.FinalViewportSize.y / cropped_size.y; float int_scale_remainder = fract(integer_scale_multiple_vert); int_scale_remainder = (int_scale_remainder < 1 - int_scale_remainder) ? int_scale_remainder : 1 - int_scale_remainder; float remainder_percent_of_screen_height = (int_scale_remainder * cropped_size.y) / (screen_height * global.FinalViewportSize.y); if (remainder_percent_of_screen_height < HSM_SNAP_TO_CLOSEST_INT_SCALE_TOLERANCE) { integer_scale_multiple_vert = round(integer_scale_multiple_vert); screen_height = integer_scale_multiple_vert * cropped_size.y / global.FinalViewportSize.y; } } return vec2(screen_aspect / output_aspect_ratio, 1) * screen_height; } // Get the maximum height that the integer scale needs to fit into float viewport_res_y_without_border = global.FinalViewportSize.y - (1 - HSM_INT_SCALE_MAX_HEIGHT) * global.FinalViewportSize.y; float viewport_res_x_without_border = global.FinalViewportSize.x - (1 - HSM_INT_SCALE_MAX_HEIGHT) * global.FinalViewportSize.x; if (HSM_DUALSCREEN_MODE == 1) viewport_res_y_without_border = global.FinalViewportSize.y / 2 - 0.5 * (1 - HSM_INT_SCALE_MAX_HEIGHT) * global.FinalViewportSize.y; if (HSM_DUALSCREEN_MODE == 2) viewport_res_x_without_border *= global.FinalViewportSize.x / 2 - 0.5 * (1 - HSM_INT_SCALE_MAX_HEIGHT) * global.FinalViewportSize.x; // If the viewport is taller than it is wide then get the height from the corresponding available width if (viewport_is_vertical) viewport_res_y_without_border = viewport_res_x_without_border / screen_aspect; // If the screen is too high if ((viewport_res_y_without_border * screen_aspect) > global.FinalViewportSize.x) { viewport_res_y_without_border = (1 - 2 * (1 - HSM_INT_SCALE_MAX_HEIGHT)) * global.FinalViewportSize.x / screen_aspect; } float integer_scale_multiple_vert = clamp(floor(viewport_res_y_without_border / cropped_size.y) + HSM_INT_SCALE_MULTIPLE_OFFSET, 1, 100); float integer_scale_vert = integer_scale_multiple_vert * cropped_size.y / global.FinalViewportSize.y; // Get the horizontal scale from the vertical scale and aspect ratio float integer_scale_horz_from_aspect = screen_aspect / output_aspect_ratio * integer_scale_vert; // Get the scale as a multiple of the original x-size float integer_scale_multiple_horz = integer_scale_horz_from_aspect * global.FinalViewportSize.x / cropped_size.x; // If we are using vertical scanlines or integer scale is set to both directions make the horizontal multiple an integer float final_int_scale_mode = HSM_INT_SCALE_MODE; if (HSM_INT_SCALE_MODE > 0.5) { if (HSM_GetUseVerticalScanlines(screen_aspect) == 1 || HSM_INT_SCALE_MODE == 2) { integer_scale_multiple_horz = round(integer_scale_multiple_horz); final_int_scale_mode = 2; } } float both_axes = clamp((final_int_scale_mode - 1) * 10000, 0, 1); integer_scale_multiple_vert += both_axes * abs(clamp((screen_aspect - 1) * 10000, -1, 0)) * HSM_INT_SCALE_MULTIPLE_OFFSET_LONG; integer_scale_multiple_horz += both_axes * abs(clamp((screen_aspect - 1) * 10000, 0, 1)) * HSM_INT_SCALE_MULTIPLE_OFFSET_LONG; integer_scale_vert = integer_scale_multiple_vert * cropped_size.y / global.FinalViewportSize.y; float integer_scale_horz = integer_scale_multiple_horz * cropped_size.x / global.FinalViewportSize.x; return vec2(integer_scale_horz, integer_scale_vert); } } vec2 HSM_GetScreenScaleFor2ndScreen(vec2 screen_scale, float screen_aspect) { vec2 out_screen_scale = screen_scale; float output_aspect = global.FinalViewportSize.x / global.FinalViewportSize.y; if (HSM_2ND_SCREEN_INDEPENDENT_SCALE == 1) out_screen_scale = DEFAULT_UNCORRECTED_SCREEN_SCALE.y * 0.5 * vec2(screen_aspect / output_aspect, 1); else out_screen_scale = screen_scale.y * vec2(screen_aspect / output_aspect, 1); out_screen_scale *= HSM_2ND_SCREEN_SCALE_OFFSET; return out_screen_scale; } float HSM_GetIsCorePreppedSizeVertical(float screen_index) { vec2 rotated_original_size = HSM_GetRotatedScreenCorePreppedSize(screen_index); float aspect_ratio = rotated_original_size.x / rotated_original_size.y; return aspect_ratio < 1 ? 1 : 0; } vec2 HSM_GetResMult(float use_vert_scanlines) { vec2 sampling_mult = vec2(HSM_CORE_RES_SAMPLING_MULT_SCANLINE_DIR, HSM_CORE_RES_SAMPLING_MULT_OPPOSITE_DIR); if (use_vert_scanlines == 1 && HSM_ROTATE_CORE_IMAGE == 0 || use_vert_scanlines == 0 && HSM_ROTATE_CORE_IMAGE == 1) sampling_mult = sampling_mult.yx; return sampling_mult; } bool HSM_ResolutionIsEqual(vec2 in_res, vec2 match_res) { return (in_res == match_res); } // if return_rough_aspect is on we only get a rough aspect which doesn't // require the cropped_size (which implicates the use_vertical_scanlines) float HSM_GetScreenAspect(float screen_index, vec2 cropped_size) { vec2 original_size = HSM_GetRotatedCoreOriginalSize(); vec2 rotated_original_size = HSM_GetRotatedCoreOriginalSize(); float core_aspect_ratio = rotated_original_size.x / rotated_original_size.y; float core_aspect_horizontal = (core_aspect_ratio < 1) ? 1 / core_aspect_ratio : core_aspect_ratio; float horizontal_aspect = 0; vec2 atari_lynx_res = vec2(160, 102); vec2 atari_2600_res = vec2(160, 228); vec2 atari_2600_crop_res = vec2(152, 228); vec2 nintendo_gameboy_advance_res = vec2(240, 160); vec2 nintendo_gameboy_res = vec2(160, 144); vec2 nintendo_ds_res = vec2(256, 192); vec2 nintendo_ds_top_bottom_res = vec2(256, 384); vec2 nintendo_ds_side_by_side_res = vec2(512, 192); vec2 nintendo_3ds_top_res = vec2(400, 240); vec2 nintendo_3ds_bottom_res = vec2(320, 240); vec2 nintendo_3ds_top_bottom_res = vec2(400, 480); vec2 nintendo_3ds_side_by_side_res = vec2(720, 240); vec2 sega_saturn_fmv_res = vec2(352, 480); vec2 sony_psp = vec2(480, 272); vec2 sony_ps_fmv_res = vec2(320, 480); vec2 sony_ps_fmv_res_2 = vec2(512, 480); // This should handle some PS games with weird resolutions like Tekken and Driver float sony_ps_height = 448; if (HSM_ASPECT_RATIO_MODE == 0) { // If the vertical res is larger than 580 is is probably a modern square pixel resolution // 576 seems to be PAL vertical resolution used sometimes if (original_size.y > 580) horizontal_aspect = core_aspect_horizontal; else if (HSM_ResolutionIsEqual(sony_psp, original_size)) horizontal_aspect = core_aspect_horizontal; else if (HSM_ResolutionIsEqual(nintendo_gameboy_advance_res, original_size)) horizontal_aspect = core_aspect_horizontal; else if (HSM_ResolutionIsEqual(nintendo_gameboy_res, original_size)) horizontal_aspect = core_aspect_horizontal; else if (HSM_ResolutionIsEqual(nintendo_ds_res, original_size)) horizontal_aspect = core_aspect_horizontal; else if (HSM_ResolutionIsEqual(nintendo_ds_top_bottom_res, original_size)) horizontal_aspect = core_aspect_horizontal; else if (HSM_ResolutionIsEqual(nintendo_ds_side_by_side_res, original_size)) horizontal_aspect = core_aspect_horizontal; else if (HSM_ResolutionIsEqual(nintendo_3ds_top_res, original_size)) horizontal_aspect = core_aspect_horizontal; else if (HSM_ResolutionIsEqual(nintendo_3ds_bottom_res, original_size)) horizontal_aspect = core_aspect_horizontal; else if (HSM_ResolutionIsEqual(nintendo_3ds_top_bottom_res, original_size)) horizontal_aspect = core_aspect_horizontal; else if (HSM_ResolutionIsEqual(nintendo_3ds_side_by_side_res, original_size)) horizontal_aspect = core_aspect_horizontal; else if (HSM_ResolutionIsEqual(atari_lynx_res, original_size)) horizontal_aspect = core_aspect_horizontal; else if (HSM_ResolutionIsEqual(atari_2600_res, original_size)) horizontal_aspect = 1.333; else if (HSM_ResolutionIsEqual(atari_2600_crop_res, original_size)) horizontal_aspect = 1.333; else if (HSM_ResolutionIsEqual(sony_ps_fmv_res, original_size)) horizontal_aspect = 1.333; else if (HSM_ResolutionIsEqual(sony_ps_fmv_res_2, original_size)) horizontal_aspect = 1.333; else if (original_size.y == sony_ps_height) horizontal_aspect = 1.333; // Fall back to the explicit ratio else horizontal_aspect = HSM_ASPECT_RATIO_EXPLICIT; } else if (HSM_ASPECT_RATIO_MODE == 1) horizontal_aspect = HSM_ASPECT_RATIO_EXPLICIT; else if (HSM_ASPECT_RATIO_MODE == 2) horizontal_aspect = 1.3333; else if (HSM_ASPECT_RATIO_MODE == 3) horizontal_aspect = 1.5; else if (HSM_ASPECT_RATIO_MODE == 4) horizontal_aspect = 1.7777; else if (HSM_ASPECT_RATIO_MODE == 5) horizontal_aspect = cropped_size.x / cropped_size.y; else if (HSM_ASPECT_RATIO_MODE == 6) horizontal_aspect = global.FinalViewportSize.x / global.FinalViewportSize.y; else horizontal_aspect = 1.333; // Find what the vertical aspect would be, either the current horizontal_aspect (if it's already vertical) // Or changing the horizontal aspect to vertical by taking the reciprocal float vertical_aspect = 1 / horizontal_aspect; float final_orientation = HSM_ASPECT_RATIO_ORIENTATION; if (HSM_ASPECT_RATIO_ORIENTATION < 0.5) { // Catch for Atari 2600 - Stella Emulator which would otherwise show up as a vertical aspect ratio if ( HSM_ResolutionIsEqual(atari_2600_res, original_size) || HSM_ResolutionIsEqual(atari_2600_crop_res, original_size) || HSM_ResolutionIsEqual(sega_saturn_fmv_res, original_size) || HSM_ResolutionIsEqual(sony_ps_fmv_res, original_size) || HSM_ResolutionIsEqual(sony_ps_fmv_res_2, original_size) || original_size.y == sony_ps_height ) { final_orientation = 1; } else { final_orientation = (HSM_GetIsCorePreppedSizeVertical(screen_index) > 0.5) ? 2 : 1; } } float final_aspect_ratio = (final_orientation < 1.5) ? horizontal_aspect : vertical_aspect; return final_aspect_ratio; } int HSM_IsCoordIn2DRange(vec2 in_coord, vec4 in_2d_range) { return (in_coord.x > in_2d_range.x && in_coord.y > in_2d_range.y && in_coord.x < in_2d_range.z && in_coord.y < in_2d_range.w ) ? 1 : 0; } // HSM_CROP_BLACK_ONLY vec4 HSM_GetBlackOnlyCropInPixels(sampler2D in_sampler_2D, vec2 sample_start_pixel_coord, vec2 window_size, float num_samples, vec4 max_crop) { // HSM_GetTexSampleFromSampleStartAndSize(sampler2D in_sampler, vec2 in_screen_coord, vec2 sample_start_pixel_coord, vec2 window_size) // Working except Bottom and Right edges jump back and forth and are not very accurate vec4 tex_sample = vec4(0); float brightness = 0; float test_crop = 0; float crop_left_px = max_crop.x; float crop_top_px = max_crop.y; float crop_right_px = max_crop.z; float crop_bottom_px = max_crop.w; // Should use as many samples as crop pixels float final_crop_left_px = crop_left_px; test_crop = crop_left_px; for (int i=0; i < crop_left_px; i++) { tex_sample = HSM_GetTexSampleFromSampleStartAndSize(in_sampler_2D, vec2((test_crop - 0.5) / window_size.x, 0.5), sample_start_pixel_coord, window_size); brightness = tex_sample.r + tex_sample.g + tex_sample.b; if (brightness > HSM_CROP_BLACK_THRESHOLD) { final_crop_left_px = min(final_crop_left_px, test_crop); } test_crop -= 1; } final_crop_left_px -= 1; float final_crop_top_px = crop_top_px; test_crop = crop_top_px; for (int i=0; i < crop_top_px; i++) { tex_sample = HSM_GetTexSampleFromSampleStartAndSize(in_sampler_2D, vec2(0.5, (test_crop - 0.5) / window_size.y), sample_start_pixel_coord, window_size); brightness = tex_sample.r + tex_sample.g + tex_sample.b; if (brightness > HSM_CROP_BLACK_THRESHOLD) { final_crop_top_px = test_crop; } test_crop -= 1; } final_crop_top_px -= 1; float final_crop_right_px = crop_right_px; test_crop = crop_right_px; for (int i=0; i < crop_right_px; i++) { tex_sample = HSM_GetTexSampleFromSampleStartAndSize(in_sampler_2D, vec2((window_size.x - test_crop + 0.5) / window_size.x, 0.5), sample_start_pixel_coord, window_size); brightness = tex_sample.r + tex_sample.g + tex_sample.b; if (brightness > HSM_CROP_BLACK_THRESHOLD) { final_crop_right_px = test_crop; } test_crop -= 1; } final_crop_right_px -= 2; float final_crop_bottom_px = crop_bottom_px; test_crop = crop_bottom_px; for (int i=0; i < crop_bottom_px; i++) { tex_sample = HSM_GetTexSampleFromSampleStartAndSize(in_sampler_2D, vec2(0.5, (window_size.y - test_crop + 0.5) / window_size.y), sample_start_pixel_coord, window_size); brightness = tex_sample.r + tex_sample.g + tex_sample.b; if (brightness > 0) { final_crop_bottom_px = test_crop; } test_crop -= 1; } final_crop_bottom_px -= 2; return clamp(vec4(final_crop_left_px, final_crop_top_px, final_crop_right_px, final_crop_bottom_px), 0, 512); } void HSM_GetCroppedRotatedSizeAndPixelSampleAreaStart(float screen_index, sampler2D original_pass, inout vec2 cropped_rotated_size, inout vec2 cropped_sample_area_start) { screen_index = HSM_GetSwappedScreenIndex(screen_index); vec2 rotated_negative_crop_added_size = HSM_GetRotatedNegativeCropAddedSize(); float default_crop_left_px = floor(MAX_NEGATIVE_CROP * rotated_negative_crop_added_size.x); float default_crop_top_px = floor(MAX_NEGATIVE_CROP * rotated_negative_crop_added_size.y); float default_crop_right_px = floor(MAX_NEGATIVE_CROP * rotated_negative_crop_added_size.x); float default_crop_bottom_px = floor(MAX_NEGATIVE_CROP * rotated_negative_crop_added_size.y); float zoom_crop_left_px = floor(HSM_CROP_PERCENT_ZOOM * rotated_negative_crop_added_size.x); float zoom_crop_top_px = floor(HSM_CROP_PERCENT_ZOOM * rotated_negative_crop_added_size.y); float zoom_crop_right_px = floor(HSM_CROP_PERCENT_ZOOM * rotated_negative_crop_added_size.x); float zoom_crop_bottom_px = floor(HSM_CROP_PERCENT_ZOOM * rotated_negative_crop_added_size.y); float crop_left_px = floor(HSM_CROP_PERCENT_LEFT * rotated_negative_crop_added_size.x); float crop_top_px = floor(HSM_CROP_PERCENT_TOP * rotated_negative_crop_added_size.y); float crop_right_px = floor(HSM_CROP_PERCENT_RIGHT * rotated_negative_crop_added_size.x); float crop_bottom_px = floor(HSM_CROP_PERCENT_BOTTOM * rotated_negative_crop_added_size.y); float final_crop_left_px = 0; float final_crop_top_px = 0; float final_crop_right_px = 0; float final_crop_bottom_px = 0; if (HSM_DUALSCREEN_MODE > 0) { float zoom_crop = 0; if (screen_index == 2) { crop_left_px = floor(HSM_2ND_SCREEN_CROP_PERCENT_LEFT * rotated_negative_crop_added_size.x); crop_top_px = floor(HSM_2ND_SCREEN_CROP_PERCENT_TOP * rotated_negative_crop_added_size.y); crop_right_px = floor(HSM_2ND_SCREEN_CROP_PERCENT_RIGHT * rotated_negative_crop_added_size.x); crop_bottom_px = floor(HSM_2ND_SCREEN_CROP_PERCENT_BOTTOM * rotated_negative_crop_added_size.y); zoom_crop = HSM_2ND_SCREEN_CROP_PERCENT_ZOOM; if (HSM_GetCoreImageSplitDirection() == 1) { default_crop_top_px = floor(rotated_negative_crop_added_size.y * (0.5 - HSM_DUALSCREEN_CORE_IMAGE_SPLIT_OFFSET)); crop_top_px = floor(crop_top_px / 2); crop_bottom_px = floor(crop_bottom_px / 2); } else { default_crop_left_px = floor(rotated_negative_crop_added_size.x * (0.5 - HSM_DUALSCREEN_CORE_IMAGE_SPLIT_OFFSET)); crop_left_px = floor(crop_left_px / 2); crop_right_px = floor(crop_right_px / 2); } } else { zoom_crop = HSM_CROP_PERCENT_ZOOM; if (HSM_GetCoreImageSplitDirection() == 1) { default_crop_bottom_px = floor(rotated_negative_crop_added_size.y * (0.5 + HSM_DUALSCREEN_CORE_IMAGE_SPLIT_OFFSET)); crop_top_px = floor(crop_top_px / 2); crop_bottom_px = floor(crop_bottom_px / 2); } else { default_crop_right_px = floor(rotated_negative_crop_added_size.x * (0.5 + HSM_DUALSCREEN_CORE_IMAGE_SPLIT_OFFSET)); crop_left_px = floor(crop_left_px / 2); crop_right_px = floor(crop_right_px / 2); } } vec2 base_cropped_size = rotated_negative_crop_added_size - vec2(final_crop_left_px + final_crop_right_px, final_crop_top_px + final_crop_bottom_px); if (HSM_GetCoreImageSplitDirection() == 1) { zoom_crop_top_px = floor(base_cropped_size.x * zoom_crop / 2); } else { zoom_crop_left_px = floor(base_cropped_size.y * zoom_crop / 2); } zoom_crop_right_px = zoom_crop_left_px; zoom_crop_bottom_px = zoom_crop_top_px; // TODO currently overwriting split screen final_crop_top_px += default_crop_top_px + crop_top_px + zoom_crop_top_px; final_crop_left_px += default_crop_left_px + crop_left_px + zoom_crop_left_px; final_crop_right_px += default_crop_right_px + crop_right_px + zoom_crop_right_px; final_crop_bottom_px += default_crop_bottom_px + crop_bottom_px + zoom_crop_bottom_px; } else { // No Cropping if (HSM_CROP_MODE == 0) { final_crop_left_px = default_crop_left_px; final_crop_top_px = default_crop_top_px; final_crop_right_px = default_crop_right_px; final_crop_bottom_px = default_crop_bottom_px; } // Crop Only Black else if (HSM_CROP_MODE == 1) { // vec4 max_crop = vec4(crop_left_px + zoom_crop_left_px, crop_top_px + zoom_crop_top_px, crop_right_px + zoom_crop_right_px, crop_bottom_px + zoom_crop_bottom_px); vec4 max_crop = vec4(default_crop_left_px + crop_left_px + zoom_crop_left_px, default_crop_top_px + crop_top_px + zoom_crop_top_px, default_crop_right_px + crop_right_px + zoom_crop_right_px, default_crop_bottom_px + crop_bottom_px + zoom_crop_bottom_px); // Start and window where we are going to test for the black area // vec2 black_sample_start_coord_px = vec2(default_crop_left_px, default_crop_top_px); // vec2 black_sample_window = rotated_negative_crop_added_size - vec2(default_crop_left_px + default_crop_right_px, default_crop_top_px + default_crop_bottom_px); vec2 black_sample_start_coord_px = vec2(0); vec2 black_sample_window = rotated_negative_crop_added_size; vec4 cropping = HSM_GetBlackOnlyCropInPixels(original_pass, black_sample_start_coord_px, black_sample_window, 100, max_crop); final_crop_left_px = cropping.x; final_crop_top_px = cropping.y; final_crop_right_px = cropping.z; final_crop_bottom_px = cropping.w; } else { final_crop_top_px = default_crop_top_px + crop_top_px + zoom_crop_top_px; final_crop_left_px = default_crop_left_px + crop_left_px + zoom_crop_left_px; final_crop_bottom_px = default_crop_bottom_px + crop_bottom_px + zoom_crop_bottom_px; final_crop_right_px = default_crop_right_px + crop_right_px + zoom_crop_right_px; } } // Make sure we don't actually negatively crop final_crop_top_px = clamp(final_crop_top_px, 0, 20000); final_crop_bottom_px = clamp(final_crop_bottom_px, 0, 20000); final_crop_left_px = clamp(final_crop_left_px, 0, 20000); final_crop_right_px = clamp(final_crop_right_px, 0, 20000); cropped_rotated_size = rotated_negative_crop_added_size - vec2(final_crop_left_px + final_crop_right_px, final_crop_top_px + final_crop_bottom_px); cropped_sample_area_start = vec2(final_crop_left_px, final_crop_top_px); } vec2 HSM_GetCroppedRotatedSizeWithResMult(vec2 cropped_rotated_size, vec2 sampling_mult) { sampling_mult = HSM_ROTATE_CORE_IMAGE == 1 ? sampling_mult.yx : sampling_mult.xy; return ceil(cropped_rotated_size * sampling_mult.xy); } float HSM_GetParameterSum() { float out_sum = (0 + global.FinalViewportSize.x + global.FinalViewportSize.y + HSM_GLOBAL_GRAPHICS_BRIGHTNESS * 100 + HSM_STATIC_LAYERS_GAMMA + HSM_CACHE_GRAPHICS_ON // Night Lighting + HSM_AMBIENT_LIGHTING_OPACITY * 100 + HSM_AMBIENT1_OPACITY * 100 + HSM_AMBIENT2_OPACITY * 100 + HSM_AMBIENT_LIGHTING_SWAP_IMAGE_MODE // Zoom & Pan + HSM_VIEWPORT_ZOOM * 100 + HSM_VIEWPORT_POSITION_X * 1000 + HSM_VIEWPORT_POSITION_Y * 1000 // FLIP & ROTATE + HSM_FLIP_VIEWPORT_VERTICAL + HSM_FLIP_VIEWPORT_HORIZONTAL // + HSM_FLIP_CORE_VERTICAL // + HSM_FLIP_CORE_HORIZONTAL + HSM_ROTATE_CORE_IMAGE // ASPECT RATIO + HSM_ASPECT_RATIO_ORIENTATION + HSM_ASPECT_RATIO_MODE + HSM_ASPECT_RATIO_EXPLICIT // SCALING + HSM_INT_SCALE_MODE + HSM_VERTICAL_PRESET // Integer Scale + HSM_INT_SCALE_MAX_HEIGHT + HSM_INT_SCALE_MULTIPLE_OFFSET + HSM_INT_SCALE_MULTIPLE_OFFSET_LONG // Non Integer Scale + HSM_NON_INTEGER_SCALE + HSM_USE_PHYSICAL_SIZE_FOR_NON_INTEGER + HSM_PHYSICAL_MONITOR_ASPECT_RATIO + HSM_PHYSICAL_MONITOR_DIAGONAL_SIZE + HSM_PHYSICAL_SIM_TUBE_DIAGONAL_SIZE // Extended Scale + HSM_USE_IMAGE_FOR_PLACEMENT + HSM_PLACEMENT_IMAGE_USE_HORIZONTAL + HSM_PLACEMENT_IMAGE_MODE // Non Integer Scale Offset + HSM_NON_INTEGER_SCALE_OFFSET * 100 // Snap to Integer Scale + HSM_USE_SNAP_TO_CLOSEST_INT_SCALE + HSM_SNAP_TO_CLOSEST_INT_SCALE_TOLERANCE // Position + HSM_SCREEN_POSITION_X * 1000 + HSM_SCREEN_POSITION_Y * 1000 // CROPPING + HSM_CROP_MODE + HSM_CROP_PERCENT_ZOOM * 100 + HSM_CROP_PERCENT_TOP * 100 + HSM_CROP_PERCENT_BOTTOM * 100 + HSM_CROP_PERCENT_LEFT * 100 + HSM_CROP_PERCENT_RIGHT * 100 + HSM_CROP_BLACK_THRESHOLD * 100 // + HSM_CORE_RES_SAMPLING_MULT_SCANLINE_DIR // + HSM_CORE_RES_SAMPLING_MULT_OPPOSITE_DIR // CURVATURE + HSM_CURVATURE_MODE + HSM_CURVATURE_2D_SCALE_LONG_AXIS * 100 + HSM_CURVATURE_2D_SCALE_SHORT_AXIS * 100 + HSM_CURVATURE_3D_RADIUS * 100 + HSM_CURVATURE_3D_VIEW_DIST * 100 + HSM_CURVATURE_3D_TILT_ANGLE_X * 100 + HSM_CURVATURE_3D_TILT_ANGLE_Y * 100 // + HSM_AB_COMPARE_SHOW_MODE + HSM_AB_COMPARE_AREA + HSM_AB_COMPARE_SPLIT_POSITION + HSM_AB_COMPARE_FREEZE_GRAPHICS // // TUBE DIFFUSE // + HSM_TUBE_OPACITY // + HSM_TUBE_DIFFUSE_MODE // + HSM_TUBE_DIFFUSE_IMAGE_DUALSCREEN_VIS_MODE // + HSM_TUBE_DIFFUSE_IMAGE_COLORIZE_ON // + HSM_TUBE_DIFFUSE_IMAGE_HUE // + HSM_TUBE_DIFFUSE_IMAGE_SATURATION // + HSM_TUBE_DIFFUSE_IMAGE_BRIGHTNESS // + HSM_TUBE_DIFFUSE_IMAGE_GAMMA + HSM_TUBE_EMPTY_THICKNESS + HSM_TUBE_EMPTY_THICKNESS_X_SCALE + HSM_TUBE_DIFFUSE_FORCE_ASPECT + HSM_TUBE_EXPLICIT_ASPECT // SCREEN BLACK EDGE + HSM_GLOBAL_CORNER_RADIUS + HSM_TUBE_BLACK_EDGE_CORNER_RADIUS_SCALE * 100 + HSM_TUBE_BLACK_EDGE_SHARPNESS * 100 + HSM_TUBE_BLACK_EDGE_CURVATURE_SCALE * 100 + HSM_TUBE_BLACK_EDGE_THICKNESS * 100 + HSM_TUBE_BLACK_EDGE_THICKNESS_X_SCALE * 100 // // DUAL SCREEN + HSM_DUALSCREEN_MODE + HSM_DUALSCREEN_CORE_IMAGE_SPLIT_MODE + HSM_DUALSCREEN_CORE_IMAGE_SWAP_SCREENS + HSM_DUALSCREEN_CORE_IMAGE_SPLIT_OFFSET * 1000 + HSM_DUALSCREEN_VIEWPORT_SPLIT_LOCATION * 1000 + HSM_DUALSCREEN_SHIFT_POSITION_WITH_SCALE + HSM_DUALSCREEN_POSITION_OFFSET_BETWEEN_SCREENS * 1000 + HSM_2ND_SCREEN_ASPECT_RATIO_MODE + HSM_2ND_SCREEN_INDEPENDENT_SCALE + HSM_2ND_SCREEN_SCALE_OFFSET * 100 + HSM_2ND_SCREEN_POS_X * 1000 + HSM_2ND_SCREEN_POS_Y * 1000 + HSM_2ND_SCREEN_CROP_PERCENT_ZOOM * 100 + HSM_2ND_SCREEN_CROP_PERCENT_TOP * 100 + HSM_2ND_SCREEN_CROP_PERCENT_BOTTOM * 100 + HSM_2ND_SCREEN_CROP_PERCENT_LEFT * 100 + HSM_2ND_SCREEN_CROP_PERCENT_RIGHT * 100 // AMBIENT LIGHTING 1 + HSM_AMBIENT1_HUE * 360 + HSM_AMBIENT1_SATURATION * 100 + HSM_AMBIENT1_VALUE * 100 + HSM_AMBIENT1_CONTRAST + HSM_AMBIENT1_SCALE_INHERIT_MODE + HSM_AMBIENT1_SCALE * 100 + HSM_AMBIENT1_SCALE_X * 100 + HSM_AMBIENT1_ROTATE + HSM_AMBIENT1_MIRROR_HORZ + HSM_AMBIENT1_POS_INHERIT_MODE + HSM_AMBIENT1_POSITION_X * 1000 + HSM_AMBIENT1_POSITION_Y * 1000 + HSM_AMBIENT1_DITHERING_SAMPLES // AMBIENT LIGHTING 2 + HSM_AMBIENT2_HUE * 360 + HSM_AMBIENT2_SATURATION * 100 + HSM_AMBIENT2_VALUE * 100 + HSM_AMBIENT2_CONTRAST + HSM_AMBIENT2_SCALE_INHERIT_MODE + HSM_AMBIENT2_SCALE * 100 + HSM_AMBIENT2_SCALE_X * 100 + HSM_AMBIENT2_ROTATE + HSM_AMBIENT2_MIRROR_HORZ + HSM_AMBIENT2_POS_INHERIT_MODE + HSM_AMBIENT2_POSITION_X * 1000 + HSM_AMBIENT2_POSITION_Y * 1000 // BEZEL INDEPENDENT SCALE + HSM_BZL_USE_INDEPENDENT_SCALE + HSM_BZL_INDEPENDENT_SCALE * 100 + HSM_BZL_USE_INDEPENDENT_CURVATURE + HSM_BZL_INDEPENDENT_CURVATURE_SCALE_LONG_AXIS * 100 + HSM_BZL_INDEPENDENT_CURVATURE_SCALE_SHORT_AXIS * 100 // BEZEL GENERAL + HSM_BZL_OPACITY * 100 + HSM_BZL_BLEND_MODE + HSM_BZL_WIDTH / 0.0008624 + HSM_BZL_HEIGHT / 0.0008732 + HSM_BZL_SCALE_OFFSET * 100 + HSM_BZL_INNER_CURVATURE_SCALE * 100 + HSM_BZL_INNER_CORNER_RADIUS_SCALE * 100 #ifdef HAS_BEZEL_PARAMS // Bezel Params not in Screen Scale + HSM_BZL_INNER_EDGE_THICKNESS / 0.00007 + HSM_BZL_INNER_EDGE_SHARPNESS * 100 + HSM_BZL_OUTER_POSITION_Y * 2000 + HSM_BZL_OUTER_CURVATURE_SCALE * 100 + HSM_BZL_OUTER_CORNER_RADIUS_SCALE * 100 + HSM_BZL_BRIGHTNESS * 100 + HSM_BZL_BRIGHTNESS_MULT_TOP * 100 + HSM_BZL_BRIGHTNESS_MULT_BOTTOM * 100 + HSM_BZL_BRIGHTNESS_MULT_SIDES * 100 + HSM_BZL_BRIGHTNESS_MULT_SIDE_LEFT * 100 + HSM_BZL_BRIGHTNESS_MULT_SIDE_RIGHT * 100 + HSM_BZL_HIGHLIGHT * 100 + HSM_BZL_NOISE * 100 + HSM_BZL_INNER_EDGE_SHADOW * 100 // Bezel Color + HSM_BZL_COLOR_HUE * 360 + HSM_BZL_COLOR_SATURATION * 100 + HSM_BZL_COLOR_VALUE * 100 + HSM_BZL_AMBIENT_LIGHTING_MULTIPLIER * 100 + HSM_BZL_AMBIENT2_LIGHTING_MULTIPLIER * 100 // Frame Color + HSM_FRM_USE_INDEPENDENT_COLOR + HSM_FRM_COLOR_HUE * 360 + HSM_FRM_COLOR_SATURATION * 100 + HSM_FRM_COLOR_VALUE * 100 // Generated Frame + HSM_FRM_OPACITY * 100 + HSM_FRM_BLEND_MODE + HSM_FRM_TEXTURE_OPACITY * 100 + HSM_FRM_TEXTURE_BLEND_MODE + HSM_FRM_NOISE * 100 + HSM_FRM_INNER_EDGE_THICKNESS / 0.00003 + HSM_FRM_THICKNESS / 0.0007 + HSM_FRM_THICKNESS_SCALE_X * 100 + HSM_FRM_OUTER_POS_Y * 100 + HSM_FRM_OUTER_CURVATURE_SCALE * 100 + HSM_FRM_OUTER_CORNER_RADIUS + HSM_FRM_OUTER_EDGE_THICKNESS / 0.00006 + HSM_FRM_OUTER_EDGE_SHADING * 100 + HSM_FRM_SHADOW_OPACITY * 100 + HSM_FRM_SHADOW_WIDTH * 1000 // Corner + HSM_REFLECT_CORNER_FADE * 100 + HSM_REFLECT_CORNER_FADE_DISTANCE * 100 + HSM_REFLECT_CORNER_INNER_SPREAD * 100 + HSM_REFLECT_CORNER_OUTER_SPREAD * 100 + HSM_REFLECT_CORNER_ROTATION_OFFSET_TOP + HSM_REFLECT_CORNER_ROTATION_OFFSET_BOTTOM + HSM_REFLECT_CORNER_SPREAD_FALLOFF #endif #ifdef HAS_IMAGE_LAYER_PARAMS // Layer Order + HSM_BG_LAYER_ORDER + HSM_VIEWPORT_VIGNETTE_LAYER_ORDER + HSM_CRT_LAYER_ORDER + HSM_DEVICE_LAYER_ORDER + HSM_DEVICELED_LAYER_ORDER + HSM_CAB_GLASS_LAYER_ORDER + HSM_DECAL_LAYER_ORDER + HSM_LED_LAYER_ORDER + HSM_TOP_LAYER_ORDER // Background + HSM_BG_OPACITY + HSM_BG_COLORIZE_ON + HSM_BG_HUE * 360 + HSM_BG_SATURATION * 100 + HSM_BG_BRIGHTNESS * 100 + HSM_BG_GAMMA + HSM_BG_AMBIENT_LIGHTING_MULTIPLIER * 100 + HSM_BG_AMBIENT2_LIGHTING_MULTIPLIER * 100 + HSM_BG_APPLY_AMBIENT_IN_ADD_MODE + HSM_BG_BLEND_MODE + HSM_BG_SOURCE_MATTE_TYPE + HSM_BG_MASK_MODE + HSM_BG_CUTOUT_MODE + HSM_BG_DUALSCREEN_VIS_MODE + HSM_BG_FOLLOW_LAYER + HSM_BG_FOLLOW_MODE + HSM_BG_FOLLOW_FULL_USES_ZOOM + HSM_BG_FILL_MODE + HSM_BG_SPLIT_PRESERVE_CENTER * 1000 + HSM_BG_SPLIT_REPEAT_WIDTH * 1000 + HSM_BG_SCALE * 100 + HSM_BG_SCALE_X * 100 + HSM_BG_POS_X * 100 + HSM_BG_POS_Y * 100 + HSM_BG_MIRROR_WRAP + HSM_BG_MIPMAPPING_BLEND_BIAS // Background Vignette + HSM_VIEWPORT_VIGNETTE_OPACITY * 100 + HSM_VIEWPORT_VIGNETTE_MASK_MODE + HSM_VIEWPORT_VIGNETTE_CUTOUT_MODE + HSM_VIEWPORT_VIGNETTE_FOLLOW_LAYER + HSM_VIEWPORT_VIGNETTE_SCALE * 100 + HSM_VIEWPORT_VIGNETTE_SCALE_X * 100 + HSM_VIEWPORT_VIGNETTE_POS_X * 100 + HSM_VIEWPORT_VIGNETTE_POS_Y * 100 // Cutout + HSM_CUTOUT_ASPECT_MODE + HSM_CUTOUT_EXPLICIT_ASPECT + HSM_CUTOUT_FOLLOW_LAYER + HSM_CUTOUT_FOLLOW_FULL_USES_ZOOM + HSM_CUTOUT_SCALE * 100 + HSM_CUTOUT_SCALE_X * 100 + HSM_CUTOUT_POS_X * 400 + HSM_CUTOUT_POS_Y * 400 + HSM_CUTOUT_CORNER_RADIUS // LED + HSM_LED_OPACITY * 100 + HSM_LED_COLORIZE_ON + HSM_LED_HUE * 360 + HSM_LED_SATURATION * 100 + HSM_LED_BRIGHTNESS * 100 + HSM_LED_GAMMA + HSM_LED_AMBIENT_LIGHTING_MULTIPLIER * 100 + HSM_LED_AMBIENT2_LIGHTING_MULTIPLIER * 100 + HSM_LED_APPLY_AMBIENT_IN_ADD_MODE + HSM_LED_BLEND_MODE + HSM_LED_SOURCE_MATTE_TYPE + HSM_LED_MASK_MODE + HSM_LED_CUTOUT_MODE + HSM_LED_DUALSCREEN_VIS_MODE + HSM_LED_FOLLOW_LAYER + HSM_LED_FOLLOW_MODE + HSM_LED_FOLLOW_FULL_USES_ZOOM + HSM_LED_FILL_MODE + HSM_LED_SPLIT_PRESERVE_CENTER * 1000 + HSM_LED_SPLIT_REPEAT_WIDTH * 1000 + HSM_LED_SCALE * 100 + HSM_LED_SCALE_X * 100 + HSM_LED_POS_X * 100 + HSM_LED_POS_Y * 100 + HSM_LED_MIPMAPPING_BLEND_BIAS // Device + HSM_DEVICE_OPACITY * 100 + HSM_DEVICE_COLORIZE_ON + HSM_DEVICE_HUE * 360 + HSM_DEVICE_SATURATION * 100 + HSM_DEVICE_BRIGHTNESS * 100 + HSM_DEVICE_GAMMA + HSM_DEVICE_AMBIENT_LIGHTING_MULTIPLIER * 100 + HSM_DEVICE_AMBIENT2_LIGHTING_MULTIPLIER * 100 + HSM_DEVICE_APPLY_AMBIENT_IN_ADD_MODE + HSM_DEVICE_BLEND_MODE + HSM_DEVICE_SOURCE_MATTE_TYPE + HSM_DEVICE_MASK_MODE + HSM_DEVICE_CUTOUT_MODE + HSM_DEVICE_DUALSCREEN_VIS_MODE + HSM_DEVICE_FOLLOW_LAYER + HSM_DEVICE_FOLLOW_MODE + HSM_DEVICE_FOLLOW_FULL_USES_ZOOM + HSM_DEVICE_FILL_MODE + HSM_DEVICE_SPLIT_PRESERVE_CENTER * 1000 + HSM_DEVICE_SPLIT_REPEAT_WIDTH * 1000 + HSM_DEVICE_SCALE * 100 + HSM_DEVICE_SCALE_X * 100 + HSM_DEVICE_POS_X * 100 + HSM_DEVICE_POS_Y * 100 + HSM_DEVICE_MIPMAPPING_BLEND_BIAS // Device LED + HSM_DEVICELED_OPACITY * 100 + HSM_DEVICELED_COLORIZE_ON + HSM_DEVICELED_HUE * 360 + HSM_DEVICELED_SATURATION * 100 + HSM_DEVICELED_BRIGHTNESS * 100 + HSM_DEVICELED_GAMMA + HSM_DEVICELED_AMBIENT_LIGHTING_MULTIPLIER * 100 + HSM_DEVICELED_AMBIENT2_LIGHTING_MULTIPLIER * 100 + HSM_DEVICELED_APPLY_AMBIENT_IN_ADD_MODE + HSM_DEVICELED_BLEND_MODE + HSM_DEVICELED_SOURCE_MATTE_TYPE + HSM_DEVICELED_MASK_MODE + HSM_DEVICELED_CUTOUT_MODE + HSM_DEVICELED_DUALSCREEN_VIS_MODE + HSM_DEVICELED_FOLLOW_LAYER + HSM_DEVICELED_FOLLOW_MODE + HSM_DEVICELED_FOLLOW_FULL_USES_ZOOM + HSM_DEVICELED_FILL_MODE + HSM_DEVICELED_SPLIT_PRESERVE_CENTER * 1000 + HSM_DEVICELED_SPLIT_REPEAT_WIDTH * 1000 + HSM_DEVICELED_SCALE * 100 + HSM_DEVICELED_SCALE_X * 100 + HSM_DEVICELED_POS_X * 100 + HSM_DEVICELED_POS_Y * 100 + HSM_DEVICELED_MIPMAPPING_BLEND_BIAS // Decal + HSM_DECAL_OPACITY * 100 + HSM_DECAL_COLORIZE_ON + HSM_DECAL_HUE * 360 + HSM_DECAL_SATURATION * 100 + HSM_DECAL_BRIGHTNESS * 100 + HSM_DECAL_GAMMA + HSM_DECAL_AMBIENT_LIGHTING_MULTIPLIER * 100 + HSM_DECAL_AMBIENT2_LIGHTING_MULTIPLIER * 100 + HSM_DECAL_APPLY_AMBIENT_IN_ADD_MODE + HSM_DECAL_BLEND_MODE + HSM_DECAL_SOURCE_MATTE_TYPE + HSM_DECAL_MASK_MODE + HSM_DECAL_CUTOUT_MODE + HSM_DECAL_DUALSCREEN_VIS_MODE + HSM_DECAL_FOLLOW_LAYER + HSM_DECAL_FOLLOW_MODE + HSM_DECAL_FOLLOW_FULL_USES_ZOOM + HSM_DECAL_FILL_MODE + HSM_DECAL_SPLIT_PRESERVE_CENTER * 1000 + HSM_DECAL_SPLIT_REPEAT_WIDTH * 1000 + HSM_DECAL_SCALE * 100 + HSM_DECAL_SCALE_X * 100 + HSM_DECAL_POS_X * 100 + HSM_DECAL_POS_Y * 100 + HSM_DECAL_MIPMAPPING_BLEND_BIAS // // Cab Glass + HSM_CAB_GLASS_OPACITY * 100 + HSM_CAB_GLASS_COLORIZE_ON + HSM_CAB_GLASS_HUE * 360 + HSM_CAB_GLASS_SATURATION * 100 + HSM_CAB_GLASS_BRIGHTNESS * 100 + HSM_CAB_GLASS_GAMMA + HSM_CAB_GLASS_AMBIENT_LIGHTING_MULTIPLIER * 100 + HSM_CAB_GLASS_AMBIENT2_LIGHTING_MULTIPLIER * 100 + HSM_CAB_GLASS_APPLY_AMBIENT_IN_ADD_MODE + HSM_CAB_GLASS_BLEND_MODE + HSM_CAB_GLASS_SOURCE_MATTE_TYPE + HSM_CAB_GLASS_MASK_MODE + HSM_CAB_GLASS_CUTOUT_MODE + HSM_CAB_GLASS_DUALSCREEN_VIS_MODE + HSM_CAB_GLASS_FOLLOW_LAYER + HSM_CAB_GLASS_FOLLOW_MODE + HSM_CAB_GLASS_FOLLOW_FULL_USES_ZOOM + HSM_CAB_GLASS_FILL_MODE + HSM_CAB_GLASS_SPLIT_PRESERVE_CENTER * 1000 + HSM_CAB_GLASS_SPLIT_REPEAT_WIDTH * 1000 + HSM_CAB_GLASS_SCALE * 100 + HSM_CAB_GLASS_SCALE_X * 100 + HSM_CAB_GLASS_POS_X * 100 + HSM_CAB_GLASS_POS_Y * 100 + HSM_CAB_GLASS_MIPMAPPING_BLEND_BIAS // Top Image + HSM_TOP_OPACITY * 100 + HSM_TOP_COLORIZE_ON + HSM_TOP_HUE * 360 + HSM_TOP_SATURATION * 100 + HSM_TOP_BRIGHTNESS * 100 + HSM_TOP_GAMMA + HSM_TOP_AMBIENT_LIGHTING_MULTIPLIER * 100 + HSM_TOP_AMBIENT2_LIGHTING_MULTIPLIER * 100 + HSM_TOP_APPLY_AMBIENT_IN_ADD_MODE + HSM_TOP_BLEND_MODE + HSM_TOP_SOURCE_MATTE_TYPE + HSM_TOP_MASK_MODE + HSM_TOP_CUTOUT_MODE + HSM_TOP_DUALSCREEN_VIS_MODE + HSM_TOP_FOLLOW_LAYER + HSM_TOP_FOLLOW_MODE + HSM_TOP_FOLLOW_FULL_USES_ZOOM + HSM_TOP_FILL_MODE + HSM_TOP_SPLIT_PRESERVE_CENTER * 1000 + HSM_TOP_SPLIT_REPEAT_WIDTH * 1000 + HSM_TOP_SCALE * 100 + HSM_TOP_SCALE_X * 100 + HSM_TOP_POS_X * 100 + HSM_TOP_POS_Y * 100 + HSM_TOP_MIRROR_WRAP + HSM_TOP_MIPMAPPING_BLEND_BIAS + HSM_RENDER_SIMPLE_MODE + HSM_LAYERING_DEBUG_MASK_MODE #endif ); return out_sum; } vec2 GetScreenSizeWithZoom(vec2 screen_scale) { vec2 screen_size = global.FinalViewportSize.xy * screen_scale * HSM_VIEWPORT_ZOOM; // Round this so we get proper integers // TODO try + eps and floor screen_size = vec2(ceil(screen_size.x), ceil(screen_size.y)); return screen_size; } vec4 HSM_GetColorForScreenInfoCache(vec2 viewport_coord, sampler2D feedback_pass, sampler2D original_pass, sampler2D screen_placement_image) { NEGATIVE_CROP_EXPAND_MULTIPLIER = global.NegativeCropAddedPassSize.y / global.DerezedPassSize.y; MAX_NEGATIVE_CROP = ((1 - (1 / NEGATIVE_CROP_EXPAND_MULTIPLIER)) / 2); vec4 out_color = vec4(0); float output_aspect = global.FinalViewportSize.x / global.FinalViewportSize.y; vec2 rotated_derezed_size = HSM_GetRotatedScreenDerezedSize(); vec2 cropped_rotated_size = vec2(100); vec2 cropped_sample_area_start_pixel_coord = vec2(100); HSM_GetCroppedRotatedSizeAndPixelSampleAreaStart(1, original_pass, cropped_rotated_size, cropped_sample_area_start_pixel_coord); float screen_aspect = HSM_GetScreenAspect(1, cropped_rotated_size); float use_vertical_scanlines = HSM_GetUseVerticalScanlines(screen_aspect); vec2 sampling_dir_mult = HSM_GetResMult(use_vertical_scanlines); vec2 cropped_rotated_size_with_res_mult = HSM_GetCroppedRotatedSizeWithResMult(cropped_rotated_size, sampling_dir_mult); // First Screen vec3 screen_pos_and_height = HSM_GetScreenPlacementAndHeight(screen_placement_image, 60); vec2 screen_scale = HSM_GetScreenScale(screen_aspect, screen_pos_and_height.z, cropped_rotated_size); vec2 screen_size = GetScreenSizeWithZoom(screen_scale); vec2 tube_diffuse_scale = HSM_GetTubeScale(screen_scale, screen_pos_and_height.z, vec2(HSM_TUBE_EMPTY_THICKNESS * HSM_TUBE_EMPTY_THICKNESS_X_SCALE, HSM_TUBE_EMPTY_THICKNESS)); float tube_diffuse_aspect = tube_diffuse_scale.x / tube_diffuse_scale.y * output_aspect; // TODO need to adjust height in screen_pos_and_height with the tube extra thickness if (HSM_TUBE_DIFFUSE_FORCE_ASPECT > 0) { if ( HSM_TUBE_DIFFUSE_FORCE_ASPECT == 1) tube_diffuse_aspect = screen_aspect; if ( HSM_TUBE_DIFFUSE_FORCE_ASPECT == 2) tube_diffuse_aspect = screen_aspect > 1 ? HSM_TUBE_EXPLICIT_ASPECT : 1.0 / HSM_TUBE_EXPLICIT_ASPECT; tube_diffuse_scale = vec2( tube_diffuse_scale.y * tube_diffuse_aspect / output_aspect, tube_diffuse_scale.y ); } vec2 tube_scale = HSM_GetTubeScale(tube_diffuse_scale, screen_pos_and_height.z, vec2(HSM_TUBE_BLACK_EDGE_THICKNESS * HSM_TUBE_BLACK_EDGE_THICKNESS_X_SCALE, HSM_TUBE_BLACK_EDGE_THICKNESS)); vec2 pos_offset = HSM_GetScreenPositionOffset(screen_pos_and_height.xy, screen_scale, 1); vec2 rotated_core_preppezd_size = HSM_GetRotatedScreenCorePreppedSize(1); vec2 cropped_size_2nd_screen = vec2(100); vec2 sample_area_start_pixel_coord_2nd_screen = vec2(100); HSM_GetCroppedRotatedSizeAndPixelSampleAreaStart(2, original_pass, cropped_size_2nd_screen, sample_area_start_pixel_coord_2nd_screen); float screen_aspect_2nd_screen = HSM_2ND_SCREEN_ASPECT_RATIO_MODE == 1 ? cropped_size_2nd_screen.x/cropped_size_2nd_screen.y : screen_aspect; vec2 screen_scale_2nd_screen = HSM_GetScreenScaleFor2ndScreen(screen_scale, screen_aspect_2nd_screen); vec2 screen_size_2nd_screen = GetScreenSizeWithZoom(screen_scale_2nd_screen); vec2 cropped_size_with_res_mult_2nd_screen = HSM_GetCroppedRotatedSizeWithResMult(cropped_size_2nd_screen, sampling_dir_mult); vec2 tube_diffuse_scale_2nd_screen = HSM_GetTubeScale(screen_scale_2nd_screen, DEFAULT_UNCORRECTED_SCREEN_SCALE.y, vec2(HSM_TUBE_EMPTY_THICKNESS * HSM_TUBE_EMPTY_THICKNESS_X_SCALE, HSM_TUBE_EMPTY_THICKNESS)); vec2 tube_scale_2nd_screen = HSM_GetTubeScale(tube_diffuse_scale_2nd_screen, DEFAULT_UNCORRECTED_SCREEN_SCALE.y, vec2(HSM_TUBE_BLACK_EDGE_THICKNESS * HSM_TUBE_BLACK_EDGE_THICKNESS_X_SCALE, HSM_TUBE_BLACK_EDGE_THICKNESS)); float tube_aspect_2nd_screen = tube_scale_2nd_screen.x / tube_scale_2nd_screen.y * output_aspect; // TODO need to add tube diffuse aspect to cache data vec2 pos_offset_2nd_screen = HSM_GetScreenPositionOffset(vec2(0.5, 0.5), screen_scale_2nd_screen, 2); vec4 sample_2d_range = vec4(0); float parameter_sum = HSM_GetParameterSum(); // Sample 1, 1 // r AVERAGE_LUMA sample_2d_range = HSM_GetCacheSampleRange(1, 1); if (HSM_IsCoordIn2DRange(viewport_coord, sample_2d_range) == 1) { out_color.rg = sampling_dir_mult; out_color.a = HSM_GetAverageLuma(original_pass, global.NegativeCropAddedPassSize.xy); } // Sample 2, 1 // r SCREEN_ASPECT // ba SCREEN_SCALE sample_2d_range = HSM_GetCacheSampleRange(2, 1); if (HSM_IsCoordIn2DRange(viewport_coord, sample_2d_range) == 1) { out_color.r = screen_aspect; out_color.ba = screen_scale; } // Sample 3, 1 // rg TUBE_SCALE // ba SCREEN_POS_OFFSET sample_2d_range = HSM_GetCacheSampleRange(3, 1); if (HSM_IsCoordIn2DRange(viewport_coord, sample_2d_range) == 1) { out_color.rg = tube_scale; out_color.ba = pos_offset; } // Sample 4, 1 // rg CROPPED_ROTATED_SIZE_WITH_RES_MULT sample_2d_range = HSM_GetCacheSampleRange(4, 1); if (HSM_IsCoordIn2DRange(viewport_coord, sample_2d_range) == 1) { out_color.rg = cropped_rotated_size_with_res_mult; out_color.ba = HSM_GetRotatedNegativeCropAddedSize(); } // Sample 1, 2 // rg CROPPED_ROTATED_SIZE // ba SAMPLE_AREA_START_PIXEL_COORD sample_2d_range = HSM_GetCacheSampleRange(1, 2); if (HSM_IsCoordIn2DRange(viewport_coord, sample_2d_range) == 1) { out_color.rg = cropped_rotated_size; out_color.ba = cropped_sample_area_start_pixel_coord; } // Sample 2, 2 // r SCREEN_ASPECT_2ND_SCREEN // g PARAMETER_SUM_SCREEN_SCALE // ba SCREEN_SCALE_2ND_SCREEN sample_2d_range = HSM_GetCacheSampleRange(2, 2); if (HSM_IsCoordIn2DRange(viewport_coord, sample_2d_range) == 1) { out_color.r = screen_aspect_2nd_screen; out_color.gb = screen_scale_2nd_screen; } // Sample 3, 2 // rg TUBE_SCALE // ba SCREEN_POS_OFFSET sample_2d_range = HSM_GetCacheSampleRange(3, 2); if (HSM_IsCoordIn2DRange(viewport_coord, sample_2d_range) == 1) { out_color.rg = tube_scale_2nd_screen; out_color.ba = pos_offset_2nd_screen; } // Sample 4, 2 // rg CROPPED_ROTATED_SIZE_WITH_RES_MULT 2nd screen sample_2d_range = HSM_GetCacheSampleRange(4, 2); if (HSM_IsCoordIn2DRange(viewport_coord, sample_2d_range) == 1) { out_color.rg = cropped_size_with_res_mult_2nd_screen; } // Sample 1, 3 // rg CROPPED_ROTATED_SIZE 2nd screen // ba SAMPLE_AREA_START_PIXEL_COORD 2nd screen sample_2d_range = HSM_GetCacheSampleRange(1, 3); if (HSM_IsCoordIn2DRange(viewport_coord, sample_2d_range) == 1) { out_color.rg = cropped_size_2nd_screen; out_color.ba = sample_area_start_pixel_coord_2nd_screen; } // Sample 2, 3 // rg CORE_SIZE sample_2d_range = HSM_GetCacheSampleRange(2, 3); if (HSM_IsCoordIn2DRange(viewport_coord, sample_2d_range) == 1) { out_color.rg = global.CorePassSize.xy; out_color.ba = HSM_GetRotatedCoreOriginalSize(); } // Sample 3, 3 // rg VIEWPORT_SCALE // ba VIEWPORT_POS sample_2d_range = HSM_GetCacheSampleRange(3, 3); if (HSM_IsCoordIn2DRange(viewport_coord, sample_2d_range) == 1) { out_color.rg = vec2(HSM_VIEWPORT_ZOOM, HSM_VIEWPORT_ZOOM); out_color.ba = vec2(HSM_VIEWPORT_POSITION_X, HSM_VIEWPORT_POSITION_Y); } // Sample 4, 3 // rg SCREEN_SCALE_2ND_SCREEN // ba SCREEN_POS_OFFSET_2ND_SCREEN sample_2d_range = HSM_GetCacheSampleRange(4, 3); if (HSM_IsCoordIn2DRange(viewport_coord, sample_2d_range) == 1) { out_color.rg = screen_scale_2nd_screen; out_color.ba = pos_offset_2nd_screen; } // Sample 1, 4 sample_2d_range = HSM_GetCacheSampleRange(1, 4); if (HSM_IsCoordIn2DRange(viewport_coord, sample_2d_range) == 1) { out_color.r = parameter_sum; vec2 sample_coord = HSM_GetCacheSampleCoord(1, 4); vec4 texture_sample = texture(feedback_pass, sample_coord); float last_frame = floor(texture_sample.g); out_color.g = last_frame + global.FrameDirection * 1; out_color.ba = rotated_derezed_size; } // Sample 2, 4 // r = NEGATIVE_CROP_EXPAND_MULTIPLIER // g = MAX_NEGATIVE_CROP; sample_2d_range = HSM_GetCacheSampleRange(2, 4); if (HSM_IsCoordIn2DRange(viewport_coord, sample_2d_range) == 1) { out_color.r = NEGATIVE_CROP_EXPAND_MULTIPLIER; out_color.g = MAX_NEGATIVE_CROP; out_color.b = use_vertical_scanlines; } // TODO need to add TUBE_DIFFUSE_ASPECT & deal with 2nd Screen // Sample 3, 4 // rg TUBE_DIFFUSE_SCALE // ba TUBE_DIFFUSE_SCALE_2ND_SCREEN sample_2d_range = HSM_GetCacheSampleRange(3, 4); if (HSM_IsCoordIn2DRange(viewport_coord, sample_2d_range) == 1) { out_color.rg = tube_diffuse_scale; out_color.ba = tube_diffuse_scale_2nd_screen; } // Sample 4, 4 // rg SCREEN_SIZE // ba SCREEN_SIZE_2ND_SCREEN sample_2d_range = HSM_GetCacheSampleRange(4, 4); if (HSM_IsCoordIn2DRange(viewport_coord, sample_2d_range) == 1) { out_color.rg = screen_size; out_color.ba = screen_size_2nd_screen; } vec2 sample_coord = vec2(0); vec4 texture_sample = vec4(0); // Check the difference in parameter sum values to see if the cache has changed // Sample 1, 4 Feedback // r parameter_sum_feedback sample_coord = HSM_GetCacheSampleCoord(1, 4); texture_sample = texture(feedback_pass, sample_coord); float parameter_sum_feedback = texture_sample.r; //----------------------------------------------------- // Screen 1 resolution float res_mult_size_sum = cropped_rotated_size_with_res_mult.x + cropped_rotated_size_with_res_mult.y; // Sample 4, 1 Feedback // rg parameter_sum_feedback sample_coord = HSM_GetCacheSampleCoord(4, 1); texture_sample = texture(feedback_pass, sample_coord); CROPPED_ROTATED_SIZE_WITH_RES_MULT_FEEDBACK = texture_sample.rg; float res_mult_size_sum_feedback = CROPPED_ROTATED_SIZE_WITH_RES_MULT_FEEDBACK.x + CROPPED_ROTATED_SIZE_WITH_RES_MULT_FEEDBACK.y; //----------------------------------------------------- // Screen 2 resolution // r res_mult_size2_sum float res_mult_size2_sum = cropped_size_with_res_mult_2nd_screen.x + cropped_size_with_res_mult_2nd_screen.y; sample_coord = HSM_GetCacheSampleCoord(4, 2); texture_sample = texture(feedback_pass, sample_coord); CROPPED_ROTATED_SIZE_WITH_RES_MULT_FEEDBACK = texture_sample.rg; float res_mult_size2_sum_feedback = CROPPED_ROTATED_SIZE_WITH_RES_MULT_FEEDBACK.x + CROPPED_ROTATED_SIZE_WITH_RES_MULT_FEEDBACK.y; // Need to check croped sample resolutions of both screens bool cache_changed = res_mult_size_sum != res_mult_size_sum_feedback || res_mult_size2_sum != res_mult_size2_sum_feedback || abs((parameter_sum) - (parameter_sum_feedback)) > 0.0000001 ? true : false || HSM_CACHE_GRAPHICS_ON < 0.5; //----------------------------------------------------- // Store if the cache has changed since last frame // Sample 8, 8 // r CACHE_INFO_CHANGED sample_2d_range = HSM_GetCacheSampleRange(8, 8); if (HSM_IsCoordIn2DRange(viewport_coord, sample_2d_range) == 1) { out_color.r = cache_changed ? 1 : 0; } return out_color; } void main() { FragColor = HSM_GetColorForScreenInfoCache(vTexCoord, InfoCachePassFeedback, Source, ScreenPlacementImage); }