HLSL Color Transforms and 3D LUT (#4043)

* Remove broken scanline uniform from post_pass

* Add 3D LUT to HLSL

* Allow individual LUTs for screen and UI

* WIP: Port 3D LUT to BGFX

* Finish porting LUT to BGFX

* Add individual phosphor color conversion for HLSL
	new file:   hlsl/chroma.fx
		Shader for converting xyY3 to sRGB
	modified:   hlsl/phosphor.fx
		Minor changes to emphasize idea that phosphors are color
agnostic
	modified:   hlsl/post.fx
		Conversion from signal RGB to xyY3
	modified:   src/osd/modules/render/d3d/d3dhlsl.cpp
	modified:   src/osd/modules/render/d3d/d3dhlsl.h
	modified:   src/osd/windows/winmain.cpp
	modified:   src/osd/windows/winmain.h

* Add phosphor examples and update presets

* Port phosphor color shaders to BGFX

* Fix missing newlines at EOF
This commit is contained in:
Westley M. Martinez 2018-10-07 08:42:30 -07:00 committed by R. Belmont
parent 7b42e2f799
commit b5a54b761c
61 changed files with 1025 additions and 171 deletions

View File

@ -21,13 +21,13 @@
"sliders": [
// type (required): The sliders's conceptual type. Is it a list of string selections? Is it a single floating-point value? Does it require RGB values, or XY values?
// values: "intenum", "int", "float", "vec2", "color"
//
//
// name (required): The internal name of the slider, used to attach it to entry uniforms.
// value: Any valid ASCII string.
//
//
// text (required): The description of the slider, to which "X" or "Y" is appended for the "vec2" type, and to which "Red", "Green" or "Blue" will be appended for the "color" type.
// value: Any valid user-understandable ASCII string.
//
//
// default (required): The value that this slider should have upon creation.
// type: Either a single integer value or an array of integer values corresponding to the size of the slider type:
// "intenum": Single integer value
@ -35,23 +35,23 @@
// "float": Single integer value
// "vec2": Array of two integer values
// "color": Array of three integer values
//
//
// max (required): The upper limit to which the slider can be adjusted by a user.
// type: See type for "default"
//
//
// min (required): The lower limit to which the slider can be adjusted by a user.
// type: See type for "default"
//
//
// step (required): How much does a single left/right adjustment adjust the slider?
// type: Integer value
//
//
// format (required): A C-style formatting string to use when displaying the slider's value.
// type: Any standard C-style formatting string (%s, %d, %1.2f, and so on)
//
//
// screen (required): The type of screens for which we should populate this slider [NOT YET IMPLEMENTED]
// values: "none", "raster", "vector", "crt", "vectorraster", "lcd", "nonvector", "lcdraster", "lcdvector", "any", "all"
// "crt", "nonvector", and "all" are provided as aliases for "vectorraster", "lcdraster", and "any"
//
//
// strings (optional): A list of strings to use with the "intenum" type, to select from a list of text options instead of simply numbers.
// value: An array of 2 or more entries, with one entry per possible slider setting from "min" to "max" inclusive.
@ -86,8 +86,6 @@
{ "type": "vec2", "name": "defocus", "text": "Defocus, ", "default": [ 0.5, 0.5 ], "max": [ 2.0, 2.0 ], "min": [ 0.0, 0.0 ], "step": 0.1, "format": "%1.1f", "screen": "crt" },
{ "type": "color", "name": "phosphor", "text": "Phosphor Persistence, ", "default": [ 0.45, 0.45, 0.45 ], "max": [ 1.00, 1.00, 1.00 ], "min": [ 0.00, 0.00, 0.00 ], "step": 0.01, "format": "%1.2f", "screen": "crt" },
{ "type": "float", "name": "scanline_alpha", "text": "Scanline Amount", "default": 0.50, "max": 1.00, "min": 0.0, "step": 0.01, "format": "%1.2f", "screen": "crt" },
{ "type": "float", "name": "scanline_scale", "text": "Overall Scanline Scale", "default": 1.00, "max": 4.00, "min": 0.0, "step": 0.01, "format": "%1.2f", "screen": "crt" },
{ "type": "float", "name": "scanline_height", "text": "Individual Scanline Scale", "default": 1.00, "max": 4.00, "min": 0.0, "step": 0.01, "format": "%1.2f", "screen": "crt" },
@ -96,7 +94,7 @@
{ "type": "float", "name": "scanline_bright_offset", "text": "Scanline Brightness Offset", "default": 1.50, "max": 4.00, "min": 0.0, "step": 0.01, "format": "%1.2f", "screen": "crt" },
{ "type": "float", "name": "scanline_jitter_amount", "text": "Scanline Jitter Amount", "default": 0.00, "max": 4.00, "min": 0.0, "step": 0.01, "format": "%1.2f", "screen": "crt" },
{ "type": "float", "name": "scanline_variation", "text": "Scanline Variation", "default": 1.00, "max": 4.00, "min": 0.0, "step": 0.01, "format": "%1.2f", "screen": "crt" },
{ "type": "intenum", "name": "shadow_tile_mode", "text": "Shadow Mask Tile Mode", "default": 0, "max": 1, "min": 0, "step": 1, "format": "%s", "screen": "any", "strings": [ "Screen", "Source" ] },
{ "type": "float", "name": "shadow_alpha", "text": "Shadow Mask Amount", "default": 0.50, "max": 1.00, "min": 0.00, "step": 0.01, "format": "%1.2f", "screen": "crt" },
{ "type": "vec2", "name": "shadow_uv_count", "text": "Shadow Mask Pixel Count ", "default": [ 12, 12 ], "max": [ 128, 128 ], "min": [ 1, 1 ], "step": 1, "format": "%3f", "screen": "crt" },
@ -109,29 +107,40 @@
{ "type": "color", "name": "floor", "text": "Signal Floor, ", "default": [ 0.05, 0.05, 0.05 ], "max": [ 1.00, 1.00, 1.00 ], "min": [ 0.00, 0.00, 0.00 ], "step": 0.01, "format": "%1.2f", "screen": "crt" },
{ "type": "color", "name": "power", "text": "Signal Exponent, ", "default": [ 1.00, 1.00, 1.00 ], "max": [ 4.00, 4.00, 4.00 ], "min": [ 0.00, 0.00, 0.00 ], "step": 0.01, "format": "%1.2f", "screen": "crt" },
{ "type": "intenum", "name": "chroma_mode", "text": "Color Mode", "default": 3, "max": 3, "min": 1, "step": 1, "format": "%s", "screen": "any", "strings": [ " ", "Monochrome", "Dichrome", "Trichrome" ] },
{ "type": "color", "name": "chroma_conversion_gain", "text": "Chroma Conversion Gain, ", "default": [ 0.299, 0.587, 0.114 ], "max": [ 1.0, 1.0, 1.0 ], "min": [ 0.0, 0.0, 0.0 ], "step": 0.0001, "format": "%1.4f", "screen": "any" },
{ "type": "vec2", "name": "chroma_a", "text": "Phosphor A Chromaticity ", "default": [ 0.630, 0.340 ], "max": [ 1.0, 1.0 ], "min": [ 0.0, 0.0 ], "step": 0.001, "format": "%1.3f", "screen": "any" },
{ "type": "vec2", "name": "chroma_b", "text": "Phosphor B Chromaticity ", "default": [ 0.310, 0.595 ], "max": [ 1.0, 1.0 ], "min": [ 0.0, 0.0 ], "step": 0.001, "format": "%1.3f", "screen": "any" },
{ "type": "vec2", "name": "chroma_c", "text": "Phosphor C Chromaticity ", "default": [ 0.155, 0.070 ], "max": [ 1.0, 1.0 ], "min": [ 0.0, 0.0 ], "step": 0.001, "format": "%1.3f", "screen": "any" },
{ "type": "color", "name": "chroma_y_gain", "text": "Phosphor Gain, ", "default": [ 0.2124, 0.7011, 0.0866 ], "max": [ 1.0, 1.0, 1.0 ], "min": [ 0.0, 0.0, 0.0 ], "step": 0.0001, "format": "%1.4f", "screen": "any" },
{ "type": "color", "name": "phosphor", "text": "Phosphor Persistence, ", "default": [ 0.45, 0.45, 0.45 ], "max": [ 1.00, 1.00, 1.00 ], "min": [ 0.00, 0.00, 0.00 ], "step": 0.01, "format": "%1.2f", "screen": "crt" },
{ "type": "float", "name": "distortion", "text": "Quadric Distortion Amount", "default": 0.05, "max": 2.00, "min": -2.00, "step": 0.01, "format": "%1.2f", "screen": "crt" },
{ "type": "float", "name": "cubic_distortion", "text": "Cubic Distortion Amount", "default": 0.00, "max": 2.00, "min": -2.00, "step": 0.01, "format": "%1.2f", "screen": "crt" },
{ "type": "float", "name": "distort_corner", "text": "Distorted Corner Amount", "default": 0.05, "max": 2.00, "min": 0.00, "step": 0.01, "format": "%1.2f", "screen": "crt" },
{ "type": "float", "name": "round_corner", "text": "Rounded Corner Amount", "default": 0.05, "max": 2.00, "min": 0.00, "step": 0.01, "format": "%1.2f", "screen": "crt" },
{ "type": "float", "name": "smooth_border", "text": "Smooth Border Amount", "default": 0.03, "max": 2.00, "min": 0.00, "step": 0.01, "format": "%1.2f", "screen": "crt" },
{ "type": "float", "name": "vignetting", "text": "Vignetting Amount", "default": 0.08, "max": 2.00, "min": 0.00, "step": 0.01, "format": "%1.2f", "screen": "crt" },
{ "type": "float", "name": "reflection", "text": "Reflection Amount", "default": 0.05, "max": 2.00, "min": 0.00, "step": 0.01, "format": "%1.2f", "screen": "crt" }
{ "type": "float", "name": "reflection", "text": "Reflection Amount", "default": 0.05, "max": 2.00, "min": 0.00, "step": 0.01, "format": "%1.2f", "screen": "crt" },
{ "type": "intenum", "name": "lut_enable", "text": "3D LUT", "default": 0, "max": 1, "min": 0, "step": 1, "format": "%s", "screen": "any", "strings": [ "Off", "On" ] }
],
// parameters (optional): A list of procedurally-generated parameters that can be bound to entry uniforms.
"parameters": [
// name (required): The internal name of the parameter that will be used when binding to an entry uniform.
// value: Any valid ASCII string.
//
//
// type (required): The type of the parameter.
// values:
// "frame": Increment by 1 for each rendered frame. Limited to a given value range. Can be use for A/B field jitter and such.
// "window": Contains the index of the window to which this screen belongs.
// "time": The current time, in milliseconds. Can be limited to a given value range.
//
//
// period (required by type "frame"): The range of frames across which to count. A value of 20 will make the value loop from 0-19.
// value: Any integer value.
//
//
// limit (required by type "time"): The range of time across which to loop. 0.0 means run indefinitely.
// value: Any numeric value.
@ -143,21 +152,21 @@
"targets": [
// name (required): The name of the target. Will be used to bind it as a texture and as an output in chain entries.
// value: Any valid ASCII string.
//
//
// mode (required): The mode of the target. Can be used for different implicit and explicit sizing options.
// values:
// "guest": Use the size of the emulated screen that is being processed (e.g. 256x256 when running "targ")
// "native": Use the size of the displayed screen inside the window that is being displayed (the same size as the window size, for single-screen games with no artwork)
// "custom": Use a custom size.
//
//
// bilinear (optional): Whether or not to apply bilinear filtering to this render target.
// values: true, false
// default: true
//
//
// doublebuffer (optional): Whether or not this render target will be needed as a source texture. If you don't know what this means, omit it or set it to true.
// values: true, false
// default: true
//
//
// scale (optional): Multiply the internal size of this render target by this amount. Certain effects benefit from operating at a higher internal resolution. If you're not sure, omit it.
// values: Any integer value
// default: 1
@ -225,19 +234,19 @@
"disablewhen": [
// type (optional): Reserved for future expansion. Currently only "slider" is supported.
// value: "slider"
//
//
// condition (optional): The disabler is active when the named slider is either equal or not equal to the reference value.
// values: "equal", "notequal"
// default: "equal"
//
//
// combine (optional): All "and" conditions are ANDed together, all "or" conditions are OR'd together, then these two
// values are OR'd together to finally determine whether this pass should run or not.
// values: "or", "and"
// default: "or"
//
//
// name (required): The name of the slider to use for this condition.
// value: Any valid ASCII string.
//
//
// value (required): The value against which we are comparing to determine whether this disabler is active.
// type: Either a single integer value or an array of integer values corresponding to the size of the slider's type:
// "intenum": Single integer value
@ -253,15 +262,15 @@
"uniforms": [
// uniform (required): The name of the uniform, as it is referenced in the shader source code itself.
// value: Any valid ASCII string.
//
//
// The remaining options can be one of either "slider", "parameter", or "value":
//
//
// slider (optional): The name of the slider to bind to this uniform.
// value: Any valid ASCII string that corresponds to the name of a slider.
//
// parameter (optional): The name of the dynamic parameter to bind to this uniform.
// value: Any valid ASCII string that corresponds to the name of a parameter.
//
//
// value (optional): An array of numeric values that should be loaded into this uniform.
// values: Should be an array containing anywhere from 1-16 numeric values, corresponding to the size of the uniform's type.
@ -278,28 +287,28 @@
"input": [
// sampler (required): The name of the sampler, as it is referenced in the shader source code itself.
// value: Any valid ASCII string.
//
//
// The remaining options can be one of either "texture", "target", or "option".
//
//
// texture (optional): Either "screen" for the texture that MAME provided for this chain's screen, or the name of a texture file in the artwork directory.
// value: Any valid ASCII string.
//
//
// target (optioanl): Any target from the "targets" list, or "previous" or "output" for two native-sized automatically-generated targets.
// value: Any valid ASCII string that names a target.
//
//
// option (optional): The name of any MAME option, which will have its value fetched and used as the name of a PNG to load from the artwork directory.
// value: Any valid MAME INI option name.
//
//
// bilinear (optional, texture and target only): Whether to apply bilinear filtering to the sampler.
// values: true, false
// default: true
//
//
// selection (optional, option and texture only): Determines the name of the selection and alowes to select other textures in the same directory as the specified texture file.
// values: Any valid ASCII string.
{ "sampler": "s_tex", "target": "ntsc" }
],
// output (required): The target to use as the output for this pass. Can be one of the named targets in "targets", or "output"
// output (required): The target to use as the output for this pass. Can be one of the named targets in "targets", or "output"
// or "previous" for one of two automatically-generated targets.
// value: Any valid ASCII string that names a target.
"output": "ntsc"
@ -427,6 +436,36 @@
],
"output": "internal"
},
{ "effect": "hlsl/post",
"name": "Non-Bloom Post Pass",
"disablewhen": [
{ "type": "slider", "condition": "equal", "combine": "or", "name": "adjustments", "value": 0 },
{ "type": "slider", "condition": "equal", "combine": "and", "name": "shadow_alpha", "value": 0.0 },
{ "type": "slider", "condition": "equal", "combine": "and", "name": "humbar_alpha", "value": 0.0 },
{ "type": "slider", "condition": "equal", "combine": "and", "name": "floor", "value": [ 0, 0, 0 ] },
{ "type": "slider", "condition": "equal", "combine": "and", "name": "power", "value": [ 0, 0, 0 ] },
{ "type": "slider", "condition": "equal", "combine": "and", "name": "chroma_mode", "value": 3 }
],
"uniforms": [
{ "uniform": "u_shadow_tile_mode", "slider": "shadow_tile_mode" },
{ "uniform": "u_shadow_alpha", "slider": "shadow_alpha" },
{ "uniform": "u_shadow_count", "slider": "shadow_uv_count" },
{ "uniform": "u_shadow_uv", "slider": "shadow_uv_size" },
{ "uniform": "u_shadow_uv_offset", "slider": "shadow_uv_offset" },
{ "uniform": "u_humbar_alpha", "slider": "humbar_alpha" },
{ "uniform": "u_humbar_hertz_rate", "slider": "humbar_hertz_rate" },
{ "uniform": "u_floor", "slider": "floor" },
{ "uniform": "u_power", "slider": "power" },
{ "uniform": "u_chroma_mode", "slider": "chroma_mode" },
{ "uniform": "u_conversion_gain", "slider": "chroma_conversion_gain" },
{ "uniform": "u_time", "parameter": "time" }
],
"input": [
{ "sampler": "s_tex", "target": "internal" },
{ "sampler": "s_shadow", "option": "bgfx_shadow_mask", "selection": "Shadow Mask" }
],
"output": "internal"
},
{ "effect": "hlsl/phosphor",
"name": "Phosphor Decay",
"disablewhen": [
@ -459,32 +498,22 @@
],
"output": "previous"
},
{ "effect": "hlsl/post",
"name": "Non-Bloom Post Pass",
"disablewhen": [
{ "type": "slider", "condition": "equal", "combine": "or", "name": "adjustments", "value": 0 },
{ "type": "slider", "condition": "equal", "combine": "and", "name": "shadow_alpha", "value": 0.0 },
{ "type": "slider", "condition": "equal", "combine": "and", "name": "humbar_alpha", "value": 0.0 },
{ "type": "slider", "condition": "equal", "combine": "and", "name": "floor", "value": [ 0, 0, 0 ] },
{ "type": "slider", "condition": "equal", "combine": "and", "name": "power", "value": [ 0, 0, 0 ] }
],
"uniforms": [
{ "uniform": "u_shadow_tile_mode", "slider": "shadow_tile_mode" },
{ "uniform": "u_shadow_alpha", "slider": "shadow_alpha" },
{ "uniform": "u_shadow_count", "slider": "shadow_uv_count" },
{ "uniform": "u_shadow_uv", "slider": "shadow_uv_size" },
{ "uniform": "u_shadow_uv_offset", "slider": "shadow_uv_offset" },
{ "uniform": "u_humbar_alpha", "slider": "humbar_alpha" },
{ "uniform": "u_humbar_hertz_rate", "slider": "humbar_hertz_rate" },
{ "uniform": "u_floor", "slider": "floor" },
{ "uniform": "u_power", "slider": "power" },
{ "uniform": "u_time", "parameter": "time" }
],
"input": [
{ "sampler": "s_tex", "target": "internal" },
{ "sampler": "s_shadow", "option": "bgfx_shadow_mask", "selection": "Shadow Mask" }
],
"output": "internal"
{
"effect": "hlsl/chroma",
"name": "Phosphor Chromaticity Conversion",
"disablewhen": [
{ "type": "slider", "condition": "equal", "name": "adjustments", "value": 0 }
],
"uniforms": [
{ "uniform": "u_y_gain", "slider": "chroma_y_gain" },
{ "uniform": "u_chroma_a", "slider": "chroma_a" },
{ "uniform": "u_chroma_b", "slider": "chroma_b" },
{ "uniform": "u_chroma_c", "slider": "chroma_c" }
],
"input": [
{ "sampler": "s_tex", "target": "internal" }
],
"output": "internal"
},
{ "effect": "hlsl/distortion",
"name": "Distortion Pass",
@ -512,6 +541,40 @@
],
"output": "internal"
},
{
"effect": "misc/lut",
"name": "Apply LUT",
"disablewhen": [
{
"type": "slider",
"condition": "equal",
"combine": "or",
"name": "adjustments",
"value": 0
},
{
"type": "slider",
"condition": "equal",
"combine": "or",
"name": "lut_enable",
"value": 0
}
],
"input": [
{
"sampler": "s_tex",
"target": "internal"
},
{
"sampler": "s_3dlut",
"option": "bgfx_lut",
"bilinear": false,
"clamp": true,
"selection": "LUT Texture"
}
],
"output": "internal"
},
{ "effect": "misc/blit",
"name": "Final Blit",
"input": [

36
bgfx/chains/lut.json Normal file
View File

@ -0,0 +1,36 @@
{
"name": "3D LUT",
"author": "W. M. Martinez",
"targets": [
{
"name": "temp",
"mode": "guest"
}
],
"passes": [
{
"effect": "misc/blit",
"name": "Copy To Filtered Texture",
"input": [
{ "sampler": "s_tex", "texture": "screen" }
],
"output": "temp"
}, {
"effect": "misc/lut",
"name": "Apply LUT",
"input": [
{
"sampler": "s_tex",
"target": "temp"
}, {
"sampler": "s_3dlut",
"option": "bgfx_lut",
"bilinear": false,
"clamp": true,
"selection": "LUT Texture"
}
],
"output": "output"
}
]
}

View File

@ -0,0 +1,33 @@
// license:BSD-3-Clause
// copyright-holders:W. M. Martinez
//============================================================
//
// chroma.json: Phosphor chromaticity conversion
//
//============================================================
{
"blend": {
"equation": "add",
"srcColor": "srcalpha",
"dstColor": "1-srcalpha",
"srcAlpha": "srcalpha",
"dstAlpha": "1-srcalpha"
},
"depth": {
"function": "always"
},
"cull": { "mode": "none" },
"write": {
"rgb": true,
"alpha": true
},
"vertex": "chains/hlsl/vs_chroma",
"fragment": "chains/hlsl/fs_chroma",
"uniforms": [
{ "name": "s_tex", "type": "int", "values": [ 0.0 ] },
{ "name": "u_y_gain", "type": "vec4", "values": [ 0.2124, 0.7011, 0.0866, 0.0 ] },
{ "name": "u_chroma_a", "type": "vec4", "values": [ 0.630, 0.340, 0.0, 0.0 ] },
{ "name": "u_chroma_b", "type": "vec4", "values": [ 0.310, 0.595, 0.0, 0.0 ] },
{ "name": "u_chroma_c", "type": "vec4", "values": [ 0.155, 0.070, 0.0, 0.0 ] }
]
}

View File

@ -42,6 +42,8 @@
{ "name": "u_shadow_uv", "type": "vec4", "values": [ 0.25, 0.25, 0.0, 0.0 ] },
{ "name": "u_shadow_uv_offset", "type": "vec4", "values": [ 0.0, 0.0, 0.0, 0.0 ] },
{ "name": "u_power", "type": "vec4", "values": [ 1.0, 1.0, 1.0, 0.0 ] },
{ "name": "u_floor", "type": "vec4", "values": [ 0.0, 0.0, 0.0, 0.0 ] }
{ "name": "u_floor", "type": "vec4", "values": [ 0.0, 0.0, 0.0, 0.0 ] },
{ "name": "u_chroma_mode", "type": "vec4", "values": [ 3.0, 0.0, 0.0, 0.0 ] },
{ "name": "u_conversion_gain", "type": "vec4", "values": [ 0.299, 0.587, 0.114, 0.0 ] }
]
}
}

View File

@ -0,0 +1,32 @@
{
"blend": {
"equation": "add",
"srcColor": "srcalpha",
"dstColor": "1-srcalpha",
"srcAlpha": "srcalpha",
"dstAlpha": "1-srcalpha"
},
"depth": {
"function": "always"
},
"cull": {
"mode": "none"
},
"write": {
"rgb": true,
"alpha": true
},
"vertex": "chains/misc/vs_lut",
"fragment": "chains/misc/fs_lut",
"uniforms": [
{
"name": "s_tex",
"type": "int",
"values": [ 1.0 ]
}, {
"name": "s_3dlut",
"type": "int",
"values": [ 1.0 ]
}
]
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

122
hlsl/chroma.fx Normal file
View File

@ -0,0 +1,122 @@
// license:BSD-3-Clause
// copyright-holders:W. M. Martinez
//-----------------------------------------------------------------------------
// Phosphor Chromaticity to sRGB Transform Effect
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Sampler Definitions
//-----------------------------------------------------------------------------
texture Diffuse;
sampler DiffuseSampler = sampler_state
{
Texture = <Diffuse>;
MipFilter = LINEAR;
MinFilter = LINEAR;
MagFilter = LINEAR;
AddressU = CLAMP;
AddressV = CLAMP;
AddressW = CLAMP;
};
//-----------------------------------------------------------------------------
// Vertex Definitions
//-----------------------------------------------------------------------------
struct VS_OUTPUT
{
float4 Position : POSITION;
float4 Color : COLOR0;
float2 TexCoord : TEXCOORD0;
float2 PrevCoord : TEXCOORD1;
};
struct VS_INPUT
{
float3 Position : POSITION;
float4 Color : COLOR0;
float2 TexCoord : TEXCOORD0;
};
struct PS_INPUT
{
float4 Color : COLOR0;
float2 TexCoord : TEXCOORD0;
float2 PrevCoord : TEXCOORD1;
};
//-----------------------------------------------------------------------------
// Chroma Vertex Shader
//-----------------------------------------------------------------------------
uniform float2 ScreenDims;
uniform float2 TargetDims;
uniform bool Passthrough;
VS_OUTPUT vs_main(VS_INPUT Input)
{
VS_OUTPUT Output = (VS_OUTPUT)0.0;
Output.Position = float4(Input.Position.xyz, 1.0);
Output.Position.xy /= ScreenDims;
Output.Position.y = 1.0 - Output.Position.y; // flip y
Output.Position.xy -= 0.5; // center
Output.Position.xy *= 2.0; // zoom
Output.TexCoord = Input.TexCoord;
Output.TexCoord += 0.5 / TargetDims; // half texel offset correction (DX9)
Output.PrevCoord = Output.TexCoord;
Output.Color = Input.Color;
return Output;
}
//-----------------------------------------------------------------------------
// Chroma Pixel Shader
//-----------------------------------------------------------------------------
uniform float3 YGain = float3(0.2126, 0.7152, 0.0722);
uniform float2 ChromaA = float2(0.630, 0.340);
uniform float2 ChromaB = float2(0.310, 0.595);
uniform float2 ChromaC = float2(0.155, 0.070);
static const float3x3 XYZ_TO_sRGB = {
3.2406, -1.5372, -0.4986,
-0.9689, 1.8758, 0.0415,
0.0557, -0.2040, 1.0570
};
float4 ps_main(PS_INPUT Input) : COLOR
{
const float4 cin = tex2D(DiffuseSampler, Input.TexCoord);
float4 cout = float4(0.0, 0.0, 0.0, cin.a);
const float3x2 xy = { ChromaA, ChromaB, ChromaC };
for (int i = 0; i < 3; ++i) {
const float Y = YGain[i] * cin[i];
const float X = xy[i].x * (Y / xy[i].y);
const float Z = (1.0 - xy[i].x - xy[i].y) * (Y / xy[i].y);
cout.rgb += mul(XYZ_TO_sRGB, float3(X, Y, Z));
}
return cout;
}
//-----------------------------------------------------------------------------
// Phosphor Technique
//-----------------------------------------------------------------------------
technique DefaultTechnique
{
pass Pass0
{
Lighting = FALSE;
VertexShader = compile vs_2_0 vs_main();
PixelShader = compile ps_2_0 ps_main();
}
}

View File

@ -71,16 +71,16 @@ uniform bool Passthrough;
VS_OUTPUT vs_main(VS_INPUT Input)
{
VS_OUTPUT Output = (VS_OUTPUT)0;
VS_OUTPUT Output = (VS_OUTPUT)0.0;
Output.Position = float4(Input.Position.xyz, 1.0f);
Output.Position = float4(Input.Position.xyz, 1.0);
Output.Position.xy /= ScreenDims;
Output.Position.y = 1.0f - Output.Position.y; // flip y
Output.Position.xy -= 0.5f; // center
Output.Position.xy *= 2.0f; // zoom
Output.Position.y = 1.0 - Output.Position.y; // flip y
Output.Position.xy -= 0.5; // center
Output.Position.xy *= 2.0; // zoom
Output.TexCoord = Input.TexCoord;
Output.TexCoord += 0.5f / TargetDims; // half texel offset correction (DX9)
Output.TexCoord += 0.5 / TargetDims; // half texel offset correction (DX9)
Output.PrevCoord = Output.TexCoord;
@ -93,24 +93,23 @@ VS_OUTPUT vs_main(VS_INPUT Input)
// Phosphor Pixel Shader
//-----------------------------------------------------------------------------
uniform float3 Phosphor = float3(0.0f, 0.0f, 0.0f);
uniform float DeltaTime = 0.0f;
static const float F = 30.0f;
uniform float DeltaTime = 0.0;
uniform float3 Phosphor = float3(0.0, 0.0, 0.0);
static const float F = 30.0;
float4 ps_main(PS_INPUT Input) : COLOR
{
float4 CurrPix = tex2D(DiffuseSampler, Input.TexCoord);
float3 PrevPix = tex2D(PreviousSampler, Input.PrevCoord).rgb;
float4 CurrY = tex2D(DiffuseSampler, Input.TexCoord);
float3 PrevY = tex2D(PreviousSampler, Input.PrevCoord).rgb;
PrevPix.r *= Phosphor.r == 0 ? 0 : pow(Phosphor.r, F * DeltaTime);
PrevPix.g *= Phosphor.g == 0 ? 0 : pow(Phosphor.g, F * DeltaTime);
PrevPix.b *= Phosphor.b == 0 ? 0 : pow(Phosphor.b, F * DeltaTime);
float RedMax = max(CurrPix.r, PrevPix.r);
float GreenMax = max(CurrPix.g, PrevPix.g);
float BlueMax = max(CurrPix.b, PrevPix.b);
return Passthrough ?
CurrPix : float4(RedMax, GreenMax, BlueMax, CurrPix.a);
PrevY[0] *= Phosphor[0] == 0.0 ? 0.0 : pow(Phosphor[0], F * DeltaTime);
PrevY[1] *= Phosphor[1] == 0.0 ? 0.0 : pow(Phosphor[1], F * DeltaTime);
PrevY[2] *= Phosphor[2] == 0.0 ? 0.0 : pow(Phosphor[2], F * DeltaTime);
float a = max(PrevY[0], CurrY[0]);
float b = max(PrevY[1], CurrY[1]);
float c = max(PrevY[2], CurrY[2]);
return Passthrough ? CurrY : float4(a, b, c, CurrY.a);
}
//-----------------------------------------------------------------------------

View File

@ -4,6 +4,10 @@
// Shadowmask Effect
//-----------------------------------------------------------------------------
#define MONOCHROME 1
#define DICHROME 2
#define TRICHROME 3
//-----------------------------------------------------------------------------
// Sampler Definitions
//-----------------------------------------------------------------------------
@ -64,8 +68,8 @@ struct PS_INPUT
// Constants
//-----------------------------------------------------------------------------
static const float PI = 3.1415927f;
static const float HalfPI = PI * 0.5f;
static const float PI = 3.1415927;
static const float HalfPI = PI * 0.5;
//-----------------------------------------------------------------------------
// Shadowmask Vertex Shader
@ -77,8 +81,8 @@ uniform float2 TargetDims;
uniform float2 TargetScale;
uniform float2 QuadDims;
uniform float2 ShadowDims = float2(32.0f, 32.0f); // size of the shadow texture (extended to power-of-two size)
uniform float2 ShadowUVOffset = float2(0.0f, 0.0f);
uniform float2 ShadowDims = float2(32.0, 32.0); // size of the shadow texture (extended to power-of-two size)
uniform float2 ShadowUVOffset = float2(0.0, 0.0);
uniform bool SwapXY = false;
@ -89,16 +93,16 @@ VS_OUTPUT vs_main(VS_INPUT Input)
{
VS_OUTPUT Output = (VS_OUTPUT)0;
Output.Position = float4(Input.Position.xyz, 1.0f);
Output.Position = float4(Input.Position.xyz, 1.0);
Output.Position.xy /= ScreenDims;
Output.Position.y = 1.0f - Output.Position.y; // flip y
Output.Position.xy -= 0.5f; // center
Output.Position.xy *= 2.0f; // zoom
Output.Position.y = 1.0 - Output.Position.y; // flip y
Output.Position.xy -= 0.5; // center
Output.Position.xy *= 2.0; // zoom
Output.TexCoord = Input.TexCoord;
Output.TexCoord += PrepareBloom
? 0.0f // use half texel offset (DX9) to do the blur for first bloom layer
: 0.5f / TargetDims; // fix half texel offset (DX9)
? 0.0 // use half texel offset (DX9) to do the blur for first bloom layer
: 0.5 / TargetDims; // fix half texel offset (DX9)
Output.ScreenCoord = Input.Position.xy / ScreenDims;
@ -111,34 +115,37 @@ VS_OUTPUT vs_main(VS_INPUT Input)
// Shadowmask Pixel Shader
//-----------------------------------------------------------------------------
uniform float HumBarDesync = 60.0f / 59.94f - 1.0f; // difference between the 59.94 Hz field rate and 60 Hz line frequency (NTSC)
uniform float HumBarAlpha = 0.0f;
uniform float HumBarDesync = 60.0 / 59.94 - 1.0; // difference between the 59.94 Hz field rate and 60 Hz line frequency (NTSC)
uniform float HumBarAlpha = 0.0;
uniform float TimeMilliseconds = 0.0f;
uniform float TimeMilliseconds = 0.0;
uniform float2 ScreenScale = float2(1.0f, 1.0f);
uniform float2 ScreenOffset = float2(0.0f, 0.0f);
uniform float2 ScreenScale = float2(1.0, 1.0);
uniform float2 ScreenOffset = float2(0.0, 0.0);
uniform float3 BackColor = float3(0.0f, 0.0f, 0.0f);
uniform float3 BackColor = float3(0.0, 0.0, 0.0);
uniform int ShadowTileMode = 0; // 0 based on screen (quad) dimension, 1 based on source dimension
uniform float ShadowAlpha = 0.0f;
uniform float2 ShadowCount = float2(6.0f, 6.0f);
uniform float2 ShadowUV = float2(0.25f, 0.25f);
uniform float ShadowAlpha = 0.0;
uniform float2 ShadowCount = float2(6.0, 6.0);
uniform float2 ShadowUV = float2(0.25, 0.25);
uniform float3 Power = float3(1.0f, 1.0f, 1.0f);
uniform float3 Floor = float3(0.0f, 0.0f, 0.0f);
uniform float3 Power = float3(1.0, 1.0, 1.0);
uniform float3 Floor = float3(0.0, 0.0, 0.0);
uniform int ChromaMode = 3;
uniform float3 ConversionGain = float3(0.0, 0.0, 0.0);
float2 GetAdjustedCoords(float2 coord)
{
// center coordinates
coord -= 0.5f;
coord -= 0.5;
// apply screen scale
coord *= ScreenScale;
// un-center coordinates
coord += 0.5f;
coord += 0.5;
// apply screen offset
coord += ScreenOffset;
@ -158,8 +165,8 @@ float2 GetShadowCoord(float2 TargetCoord, float2 SourceCoord)
? TargetCoord + ShadowUVOffset / BaseTargetDims
: SourceCoord + ShadowUVOffset / SourceDims;
float2 canvasTexelDims = ShadowTileMode == 0
? 1.0f / BaseTargetDims
: 1.0f / SourceDims;
? 1.0 / BaseTargetDims
: 1.0 / SourceDims;
float2 shadowDims = ShadowDims;
float2 shadowUV = ShadowUV;
@ -186,8 +193,8 @@ float2 GetShadowCoord(float2 TargetCoord, float2 SourceCoord)
float2 shadowCoord = (shadowFrac * shadowUV);
shadowCoord += ShadowTileMode == 0
? 0.5f / shadowDims // fix half texel offset (DX9)
: 0.0f;
? 0.5 / shadowDims // fix half texel offset (DX9)
: 0.0;
return shadowCoord;
}
@ -199,29 +206,14 @@ float4 ps_main(PS_INPUT Input) : COLOR
// Color
float4 BaseColor = tex2D(DiffuseSampler, BaseCoord);
BaseColor.a = 1.0f;
BaseColor.a = 1.0;
// clip border
if (BaseCoord.x < 0.0f || BaseCoord.y < 0.0f ||
BaseCoord.x > 1.0f || BaseCoord.y > 1.0f)
if (BaseCoord.x < 0.0 || BaseCoord.y < 0.0 ||
BaseCoord.x > 1.0 || BaseCoord.y > 1.0)
{
// we don't use the clip function, because we don't clear the render target before
return float4(0.0f, 0.0f, 0.0f, 1.0f);
}
// Mask Simulation (may not affect bloom)
if (!PrepareBloom && ShadowAlpha > 0.0f)
{
float2 ShadowCoord = GetShadowCoord(ScreenCoord, BaseCoord);
float4 ShadowColor = tex2D(ShadowSampler, ShadowCoord);
float3 ShadowMaskColor = lerp(1.0f, ShadowColor.rgb, ShadowAlpha);
float ShadowMaskClear = (1.0f - ShadowColor.a) * ShadowAlpha;
// apply shadow mask color
BaseColor.rgb *= ShadowMaskColor;
// clear shadow mask by background color
BaseColor.rgb = lerp(BaseColor.rgb, BackColor, ShadowMaskClear);
return float4(0.0, 0.0, 0.0, 1.0);
}
// Color Compression (may not affect bloom)
@ -236,16 +228,36 @@ float4 ps_main(PS_INPUT Input) : COLOR
BaseColor.g = pow(BaseColor.g, Power.g);
BaseColor.b = pow(BaseColor.b, Power.b);
// Scanline Simulation (may not affect bloom)
if (!PrepareBloom)
// Hum Bar Simulation (may not affect vector screen)
if (!PrepareBloom && !VectorScreen && HumBarAlpha > 0.0)
{
// Hum Bar Simulation (may not affect vector screen)
if (!VectorScreen && HumBarAlpha > 0.0f)
{
float HumBarStep = frac(TimeMilliseconds * HumBarDesync);
float HumBarBrightness = 1.0 - frac(BaseCoord.y + HumBarStep) * HumBarAlpha;
BaseColor.rgb *= HumBarBrightness;
}
float HumBarStep = frac(TimeMilliseconds * HumBarDesync);
float HumBarBrightness = 1.0 - frac(BaseCoord.y + HumBarStep) * HumBarAlpha;
BaseColor.rgb *= HumBarBrightness;
}
// Mask Simulation (may not affect bloom)
if (!PrepareBloom && ShadowAlpha > 0.0)
{
float2 ShadowCoord = GetShadowCoord(ScreenCoord, BaseCoord);
float4 ShadowColor = tex2D(ShadowSampler, ShadowCoord);
float3 ShadowMaskColor = lerp(1.0, ShadowColor.rgb, ShadowAlpha);
float ShadowMaskClear = (1.0 - ShadowColor.a) * ShadowAlpha;
// apply shadow mask color
BaseColor.rgb *= ShadowMaskColor;
// clear shadow mask by background color
BaseColor.rgb = lerp(BaseColor.rgb, BackColor, ShadowMaskClear);
}
// Preparation for phosphor color conversion
if (ChromaMode == MONOCHROME) {
BaseColor.r = dot(ConversionGain, BaseColor.rgb);
BaseColor.gb = float2(BaseColor.r, BaseColor.r);
} else if (ChromaMode == DICHROME) {
BaseColor.r = dot(ConversionGain.rg, BaseColor.rg);
BaseColor.g = BaseColor.r;
}
return BaseColor;

View File

@ -1,14 +1,23 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
// copyright-holders:Ryan Holtz, W. M. Martinez
//-----------------------------------------------------------------------------
// Primary Effect
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Macros
//-----------------------------------------------------------------------------
#define LUT_TEXTURE_WIDTH 4096.0f
#define LUT_SIZE 64.0f
#define LUT_SCALE float2(1.0f / LUT_TEXTURE_WIDTH, 1.0f / LUT_SIZE)
//-----------------------------------------------------------------------------
// Sampler Definitions
//-----------------------------------------------------------------------------
texture Diffuse;
texture LutTexture;
sampler DiffuseSampler = sampler_state
{
@ -21,6 +30,35 @@ sampler DiffuseSampler = sampler_state
AddressW = CLAMP;
};
sampler2D LutSampler = sampler_state
{
Texture = <LutTexture>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = CLAMP;
AddressV = CLAMP;
AddressW = CLAMP;
};
//-----------------------------------------------------------------------------
// Utilities
//-----------------------------------------------------------------------------
float3 apply_lut(float3 color)
{
// NOTE: Do not change the order of parameters here.
float3 lutcoord = float3((color.rg * (LUT_SIZE - 1.0f) + 0.5f) *
LUT_SCALE, color.b * (LUT_SIZE - 1.0f));
float shift = floor(lutcoord.z);
lutcoord.x += shift * LUT_SCALE.y;
color.rgb = lerp(tex2D(LutSampler, lutcoord.xy).rgb, tex2D(LutSampler,
float2(lutcoord.x + LUT_SCALE.y, lutcoord.y)).rgb,
lutcoord.z - shift);
return color;
}
//-----------------------------------------------------------------------------
// Vertex Definitions
//-----------------------------------------------------------------------------
@ -49,7 +87,7 @@ struct PS_INPUT
// Primary Vertex Shaders
//-----------------------------------------------------------------------------
static const float Epsilon = 1.0e-7f;
//static const float Epsilon = 1.0e-7f;
uniform float2 ScreenDims;
uniform float2 TargetDims;
@ -112,10 +150,15 @@ VS_OUTPUT vs_ui_main(VS_INPUT Input)
// Primary Pixel Shaders
//-----------------------------------------------------------------------------
uniform bool LutEnable;
uniform bool UiLutEnable;
float4 ps_screen_main(PS_INPUT Input) : COLOR
{
float4 BaseTexel = tex2D(DiffuseSampler, Input.TexCoord);
if (LutEnable)
BaseTexel.rgb = apply_lut(BaseTexel.rgb);
return BaseTexel;
}
@ -123,6 +166,8 @@ float4 ps_vector_buffer_main(PS_INPUT Input) : COLOR
{
float4 BaseTexel = tex2D(DiffuseSampler, Input.TexCoord);
if (LutEnable)
BaseTexel.rgb = apply_lut(BaseTexel.rgb);
return BaseTexel;
}
@ -131,6 +176,8 @@ float4 ps_ui_main(PS_INPUT Input) : COLOR
float4 BaseTexel = tex2D(DiffuseSampler, Input.TexCoord);
BaseTexel *= Input.Color;
if (UiLutEnable)
BaseTexel.rgb = apply_lut(BaseTexel.rgb);
return BaseTexel;
}

View File

@ -0,0 +1,21 @@
# Example for BT.601 525-line Color Space
#
# BT.601 is a standard for converting analog video into the digital domain,
# and serves as a reference for the color space of analog video, but the color
# spaces defined existed before the standard.
#
# Due to historical differences, there are two color spaces in BT.601: one for
# 525-line television (developed in the U.S.), and one for 625-line television
# (developed in Europe). The color spaces, along with NTSC-J, converged upon
# the development of HD television with the BT.709 standard.
#
# This color space should be used for most 60 Hz arcade systems, consoles, and
# computer systems.
#
# DIRECT3D POST-PROCESSING OPTIONS
#
chroma_mode 3
chroma_a 0.630,0.340
chroma_b 0.310,0.595
chroma_c 0.155,0.070
chroma_y_gain 0.2124,0.7011,0.0866

View File

@ -0,0 +1,21 @@
# Example for BT.601 625-line Color Space
#
# BT.601 is a standard for converting analog video into the digital domain,
# and serves as a reference for the color space of analog video, but the color
# spaces defined existed before the standard.
#
# Due to historical differences, there are two color spaces in BT.601: one for
# 525-line television (developed in the U.S.), and one for 625-line television
# (developed in Europe). The color spaces, along with NTSC-J, converged upon
# the development of HD television with the BT.709 standard.
#
# This color space should be used for most 50 Hz arcade systems, consoles, and
# computer systems.
#
# DIRECT3D POST-PROCESSING OPTIONS
#
chroma_mode 3
chroma_a 0.64,0.33
chroma_b 0.29,0.60
chroma_c 0.15,0.06
chroma_y_gain 0.2220,0.7067,0.0713

16
ini/examples/bt709.ini Normal file
View File

@ -0,0 +1,16 @@
# Example for BT.709 Color Space
#
# BT.709 was standardized in 1990 for HD television. The color space for
# BT.709 would later be used for sRGB, the color space used for modern
# operating systems.
#
# This color space should be used for post-1995 computer systems and HD game
# systems.
#
# DIRECT3D POST-PROCESSING OPTIONS
#
chroma_mode 3
chroma_a 0.64,0.33
chroma_b 0.30,0.60
chroma_c 0.15,0.06
chroma_y_gain 0.2126,0.7152,0.0722

16
ini/examples/ntscj.ini Normal file
View File

@ -0,0 +1,16 @@
# Example for NTSC-J Color Space
#
# NTSC-J has identical colorimetry to the BT.601 525-line standard, but uses a
# 9300K white-point 'D93'. Note that this white point is not necessarily
# definitive for all Japanese works.
#
# This color space may be used for 60 Hz arcade systems and consoles as an
# alternative to BT.601 525-line.
#
# DIRECT3D POST-PROCESSING OPTIONS
#
chroma_mode 3
chroma_a 0.630,0.340
chroma_b 0.310,0.595
chroma_c 0.155,0.070
chroma_gain 0.1875,0.6940,0.1185

12
ini/examples/p1.ini Normal file
View File

@ -0,0 +1,12 @@
# P1 Phosphor
#
# Multipurpose green phosphor
#
# Perhaps the most well-known phosphor, it has medium persistence.
#
# DIRECT3D POST-PROCESSING OPTIONS
#
chroma_mode 1
chroma_a 0.218,0.712
chroma_conversion_gain 0.30,0.59,0.11
chroma_y_gain 1.0,0.0,0.0

15
ini/examples/p14.ini Normal file
View File

@ -0,0 +1,15 @@
# P14 Phosphor
#
# Dual-color phosphor for military RADAR
#
# Red channel should be set to medium-short persistence. Green
# channel should be set to medium.
#
# DIRECT3D POST-PROCESSING OPTIONS
#
phosphor_life 0.2,0.6,0.0
chroma_mode 1
chroma_a 0.150,0.093
chroma_b 0.504,0.443
chroma_conversion_gain 0.30,0.59,0.11
chroma_y_gain 0.50,0.50,0.0

12
ini/examples/p2.ini Normal file
View File

@ -0,0 +1,12 @@
# P2 Phosphor
#
# Green phosphor for oscilloscopes
#
# This phosphor was developed as a fast response alternative to P1.
#
# DIRECT3D POST-PROCESSING OPTIONS
#
chroma_mode 1
chroma_a 0.279,0.534
chroma_conversion_gain 0.30,0.59,0.11
chroma_y_gain 1.0,0.0,0.0

12
ini/examples/p3.ini Normal file
View File

@ -0,0 +1,12 @@
# P3 Phosphor
#
# Amber phosphor for monochrome monitors
#
# Medium persistence
#
# DIRECT3D POST-PROCESSING OPTIONS
#
chroma_mode 1
chroma_a 0.523,0.469
chroma_conversion_gain 0.30,0.59,0.11
chroma_y_gain 1.0,0.0,0.0

12
ini/examples/p35.ini Normal file
View File

@ -0,0 +1,12 @@
# P35 Phosphor
#
# Blue-green phosphor used for oscilloscopes.
#
# Medium-short persistence.
#
# DIRECT3D POST-PROCESSING OPTIONS
#
chroma_mode 1
chroma_a 0.200,0.245
chroma_conversion_gain 0.30,0.59,0.11
chroma_y_gain 1.0,0.0,0.0

19
ini/examples/p4.ini Normal file
View File

@ -0,0 +1,19 @@
# P4 Phosphor
#
# White phosphor for black & white televisions
#
# This phosphor presents a clear white appearance that is perceptually similar
# to a black and white photograph on highly reflective paper when the viewing
# environment is sufficiently dim, and makes D65 look fairly dull and yellowish
# in comparison, that said, next to saturated colors the blueish tint becomes
# more apparent. This might explain why this white point was abandoned in
# favor of the more neutral Illuminant C (and later D65) for color television.
#
# Medium-short persistence
#
# DIRECT3D POST-PROCESSING OPTIONS
#
chroma_mode 1
chroma_a 0.265,0.285
chroma_conversion_gain 0.30,0.59,0.11
chroma_y_gain 1.0,0.0,0.0

13
ini/examples/p55.ini Normal file
View File

@ -0,0 +1,13 @@
# P55 Phosphor
#
# Trichromatic phosphors for CRT projectors
#
# Red and green have medium persistence, blue has medium-short.
#
# DIRECT3D POST-PROCESSING OPTIONS
#
chroma_mode 3
chroma_a 0.615,0.360
chroma_b 0.300,0.600
chroma_c 0.150,0.070
chroma_y_gain 0.2555,0.6582,0.0863

15
ini/examples/p7.ini Normal file
View File

@ -0,0 +1,15 @@
# P7 Phosphor
#
# Dual-color phosphor for military RADAR
#
# Red channel should be set to medium-short persistence. Green
# channel should be set to long.
#
# DIRECT3D POST-PROCESSING OPTIONS
#
phosphor_life 0.2,0.8,0.0
chroma_mode 1
chroma_a 0.151,0.032
chroma_b 0.357,0.537
chroma_conversion_gain 0.30,0.59,0.11
chroma_y_gain 0.50,0.50,0.0

View File

@ -38,6 +38,11 @@ scale 1.15,1.05,0.90
power 0.90,0.90,1.15
floor 0.025,0.025,0.025
phosphor_life 0.25,0.25,0.25
chroma_mode 3
chroma_a 0.630,0.340
chroma_b 0.310,0.595
chroma_c 0.155,0.070
chroma_y_gain 0.2124,0.7011,0.0866
#
# NTSC POST-PROCESSING OPTIONS

View File

@ -38,6 +38,10 @@ scale 1.0,1.0,1.0
power 1.0,1.0,1.0
floor 0.0,0.0,0.0
phosphor_life 0.5,0.5,0.5
chroma_mode 1
chroma_a 0.265,0.285
chroma_conversion_gain 0.30,0.59,0.11
chroma_y_gain 1.0,0.0,0.0
#
# NTSC POST-PROCESSING OPTIONS

View File

@ -41,6 +41,11 @@ scale 1.0,1.0,1.0
power 1.0,1.0,1.0
floor 0.0,0.0,0.0
phosphor_life 0.5,0.5,0.5
chroma_mode 3
chroma_a 0.630,0.340
chroma_b 0.310,0.595
chroma_c 0.155,0.070
chroma_y_gain 0.2124,0.7011,0.0866
#
# NTSC POST-PROCESSING OPTIONS

View File

@ -155,6 +155,7 @@ const options_entry osd_options::s_option_entries[] =
{ OSDOPTION_BGFX_DEBUG, "0", OPTION_BOOLEAN, "enable BGFX debugging statistics" },
{ OSDOPTION_BGFX_SCREEN_CHAINS, "default", OPTION_STRING, "comma-delimited list of screen chain JSON names, colon-delimited per-window" },
{ OSDOPTION_BGFX_SHADOW_MASK, "slot-mask.png", OPTION_STRING, "shadow mask texture name" },
{ OSDOPTION_BGFX_LUT, "", OPTION_STRING, "LUT texture name" },
{ OSDOPTION_BGFX_AVI_NAME, OSDOPTVAL_AUTO, OPTION_STRING, "filename for BGFX output logging" },
// End of list

View File

@ -88,6 +88,7 @@
#define OSDOPTION_BGFX_DEBUG "bgfx_debug"
#define OSDOPTION_BGFX_SCREEN_CHAINS "bgfx_screen_chains"
#define OSDOPTION_BGFX_SHADOW_MASK "bgfx_shadow_mask"
#define OSDOPTION_BGFX_LUT "bgfx_lut"
#define OSDOPTION_BGFX_AVI_NAME "bgfx_avi_name"
//============================================================
@ -162,6 +163,7 @@ public:
bool bgfx_debug() const { return bool_value(OSDOPTION_BGFX_DEBUG); }
const char *bgfx_screen_chains() const { return value(OSDOPTION_BGFX_SCREEN_CHAINS); }
const char *bgfx_shadow_mask() const { return value(OSDOPTION_BGFX_SHADOW_MASK); }
const char *bgfx_lut() const { return value(OSDOPTION_BGFX_LUT); }
const char *bgfx_avi_name() const { return value(OSDOPTION_BGFX_AVI_NAME); }
// PortAudio options

View File

@ -63,8 +63,10 @@ bgfx_chain_entry* chain_entry_reader::read_from_value(const Value& value, std::s
if (!READER_CHECK(!has_target || input["target"].IsString(), (prefix + "input[" + std::to_string(i) + ": Value 'target' must be a string\n").c_str())) return nullptr;
if (!READER_CHECK(!has_option || input["option"].IsString(), (prefix + "input[" + std::to_string(i) + ": Value 'option' must be a string\n").c_str())) return nullptr;
if (!READER_CHECK(has_target || !input.HasMember("bilinear") || input["bilinear"].IsBool(), (prefix + "input[" + std::to_string(i) + ": Value 'bilinear' must be a boolean\n").c_str())) return nullptr;
if (!READER_CHECK(has_target || !input.HasMember("clamp") || input["clamp"].IsBool(), (prefix + "input[" + std::to_string(i) + ": Value 'clamp' must be a boolean\n").c_str())) return nullptr;
if (!READER_CHECK(has_texture || has_option || !input.HasMember("selection") || input["selection"].IsString(), (prefix + "input[" + std::to_string(i) + ": Value 'selection' must be a string\n").c_str())) return nullptr;
bool bilinear = get_bool(input, "bilinear", true);
bool clamp = get_bool(input, "clamp", false);
std::string selection = get_string(input, "selection", "");
std::vector<std::string> texture_names;
@ -87,7 +89,8 @@ bgfx_chain_entry* chain_entry_reader::read_from_value(const Value& value, std::s
if (selection == "")
{
// create texture for specified file name
uint32_t flags = bilinear ? 0 : (BGFX_TEXTURE_MIN_POINT | BGFX_TEXTURE_MAG_POINT | BGFX_TEXTURE_MIP_POINT);
uint32_t flags = bilinear ? 0u : (BGFX_TEXTURE_MIN_POINT | BGFX_TEXTURE_MAG_POINT | BGFX_TEXTURE_MIP_POINT);
flags |= clamp ? (BGFX_TEXTURE_U_CLAMP | BGFX_TEXTURE_V_CLAMP | BGFX_TEXTURE_W_CLAMP) : 0u;
bgfx_texture* texture = chains.textures().create_png_texture(chains.options().art_path(), texture_name, texture_name, flags, screen_index);
if (texture == nullptr)
{
@ -97,7 +100,8 @@ bgfx_chain_entry* chain_entry_reader::read_from_value(const Value& value, std::s
else
{
// create texture for specified file name
uint32_t flags = bilinear ? 0 : (BGFX_TEXTURE_MIN_POINT | BGFX_TEXTURE_MAG_POINT | BGFX_TEXTURE_MIP_POINT);
uint32_t flags = bilinear ? 0u : (BGFX_TEXTURE_MIN_POINT | BGFX_TEXTURE_MAG_POINT | BGFX_TEXTURE_MIP_POINT);
flags |= clamp ? (BGFX_TEXTURE_U_CLAMP | BGFX_TEXTURE_V_CLAMP | BGFX_TEXTURE_W_CLAMP) : 0u;
bgfx_texture* texture = chains.textures().create_png_texture(chains.options().art_path(), texture_name, texture_name, flags, screen_index);
if (texture == nullptr)
{
@ -149,7 +153,8 @@ bgfx_chain_entry* chain_entry_reader::read_from_value(const Value& value, std::s
if (file_extension == extension)
{
// create textures for all files containd in the path of the specified file name
uint32_t flags = bilinear ? 0 : (BGFX_TEXTURE_MIN_POINT | BGFX_TEXTURE_MAG_POINT | BGFX_TEXTURE_MIP_POINT);
uint32_t flags = bilinear ? 0u : (BGFX_TEXTURE_MIN_POINT | BGFX_TEXTURE_MAG_POINT | BGFX_TEXTURE_MIP_POINT);
flags |= clamp ? (BGFX_TEXTURE_U_CLAMP | BGFX_TEXTURE_V_CLAMP | BGFX_TEXTURE_W_CLAMP) : 0u;
bgfx_texture* texture = chains.textures().create_png_texture(chains.options().art_path(), file_path, file_path, flags, screen_index);
if (texture == nullptr)
{

View File

@ -0,0 +1,38 @@
$input v_color0, v_texcoord0
// license: BSD-3-Clause
// copyright-holders: W. M. Martinez
//-----------------------------------------------------------------------------
// Phosphor Chromaticity to sRGB Transform Effect
//-----------------------------------------------------------------------------
#include "common.sh"
// User-supplied
uniform vec4 u_y_gain;
uniform vec4 u_chroma_a;
uniform vec4 u_chroma_b;
uniform vec4 u_chroma_c;
// Samplers
SAMPLER2D(s_tex, 0);
void main()
{
vec4 cin = texture2D(s_tex, v_texcoord0);
vec4 cout = vec4(0.0, 0.0, 0.0, cin.a);
mat3 xy = mat3(u_chroma_a.xyz, u_chroma_b.xyz, u_chroma_c.xyz);
const mat3 XYZ_TO_sRGB = mat3(
3.2406, -1.5372, -0.4986,
-0.9689, 1.8758, 0.0415,
0.0557, -0.2040, 1.0570
);
for (int i = 0; i < 3; ++i) {
float Y = u_y_gain[i] * cin[i];
float X = xy[i].x / xy[i].y * Y;
float Z = (1.0 - xy[i].x - xy[i].y) / xy[i].y * Y;
cout.rgb += mul(XYZ_TO_sRGB, vec3(X, Y, Z));
}
gl_FragColor = cout * v_color0;
}

View File

@ -3,11 +3,15 @@ $input v_color0, v_texcoord0
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz,ImJezze
//-----------------------------------------------------------------------------
// Scanline & Shadowmask Effect
// Shadowmask Effect
//-----------------------------------------------------------------------------
#include "common.sh"
#define MONOCHROME 1.0
#define DICHROME 2.0
#define TRICHROME 3.0
// Autos
uniform vec4 u_swap_xy;
uniform vec4 u_source_dims; // size of the guest machine
@ -27,6 +31,8 @@ uniform vec4 u_humbar_hertz_rate; // difference between the 59.94 Hz field rate
uniform vec4 u_humbar_alpha;
uniform vec4 u_power;
uniform vec4 u_floor;
uniform vec4 u_chroma_mode;
uniform vec4 u_conversion_gain;
// Parametric
uniform vec4 u_time; // milliseconds
@ -112,6 +118,14 @@ void main()
}
else
{
// Hum Bar Simulation
if (u_humbar_alpha.x > 0.0f)
{
float HumTimeStep = fract(u_time.x * u_humbar_hertz_rate.x);
float HumBrightness = 1.0 - fract(BaseCoord.y + HumTimeStep) * u_humbar_alpha.x;
BaseColor.rgb *= HumBrightness;
}
// Mask Simulation
if (u_shadow_alpha.x > 0.0)
{
@ -139,14 +153,15 @@ void main()
BaseColor.g = pow(BaseColor.g, u_power.g);
BaseColor.b = pow(BaseColor.b, u_power.b);
// Hum Bar Simulation
if (u_humbar_alpha.x > 0.0f)
{
float HumTimeStep = fract(u_time.x * u_humbar_hertz_rate.x);
float HumBrightness = 1.0 - fract(BaseCoord.y + HumTimeStep) * u_humbar_alpha.x;
BaseColor.rgb *= HumBrightness;
BaseColor.rgb *= v_color0.rgb;
if (u_chroma_mode.x == MONOCHROME) {
BaseColor.r = dot(u_conversion_gain.rgb, BaseColor.rgb);
BaseColor.gb = vec2(BaseColor.r, BaseColor.r);
} else if (u_chroma_mode.x == DICHROME) {
BaseColor.r = dot(u_conversion_gain.rg, BaseColor.rg);
BaseColor.g = BaseColor.r;
}
gl_FragColor = vec4(BaseColor.rgb * v_color0.rgb, BaseColor.a);
gl_FragColor = BaseColor;
}
}

View File

@ -0,0 +1,14 @@
$input a_position, a_texcoord0, a_color0
$output v_texcoord0, v_color0
// license:BSD-3-Clause
// copyright-holders:Dario Manesku
#include "common.sh"
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}

View File

@ -0,0 +1,29 @@
$input v_color0, v_texcoord0
// license: BSD-3-Clause
// copyright-holders: W. M. Martinez
#include "common.sh"
#define LUT_TEXTURE_WIDTH 4096.0f
#define LUT_SIZE 64.0f
#define LUT_SCALE vec2(1.0f / LUT_TEXTURE_WIDTH, 1.0f / LUT_SIZE)
SAMPLER2D(s_tex, 0);
SAMPLER2D(s_3dlut, 1);
void main()
{
vec4 bp = texture2D(s_tex, v_texcoord0);
vec3 color = bp.rgb;
// NOTE: Do not change the order of parameters here.
vec3 lutcoord = vec3(color.rg * ((LUT_SIZE - 1.0f) + 0.5f) *
LUT_SCALE, (LUT_SIZE - 1.0f) * color.b);
float shift = floor(lutcoord.z);
lutcoord.x += shift * LUT_SCALE.y;
color.rgb = mix(texture2D(s_3dlut, lutcoord.xy).rgb,
texture2D(s_3dlut, vec2(lutcoord.x + LUT_SCALE.y,
lutcoord.y)).rgb, lutcoord.z - shift);
gl_FragColor = vec4(color, bp.a) * v_color0;
}

View File

@ -0,0 +1,14 @@
$input a_position, a_texcoord0, a_color0
$output v_texcoord0, v_color0
// license:BSD-3-Clause
// copyright-holders:Dario Manesku
#include "common.sh"
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}

View File

@ -25,6 +25,7 @@
#include "strconv.h"
#include "d3dhlsl.h"
#include "../frontend/mame/ui/slider.h"
#include <array>
#include <utility>
//============================================================
@ -171,6 +172,8 @@ shaders::shaders() :
acc_t(0),
delta_t(0),
shadow_texture(nullptr),
lut_texture(nullptr),
ui_lut_texture(nullptr),
options(nullptr),
black_surface(nullptr),
black_texture(nullptr),
@ -198,6 +201,7 @@ shaders::shaders() :
bloom_effect(nullptr),
downsample_effect(nullptr),
vector_effect(nullptr),
chroma_effect(nullptr),
curr_texture(nullptr),
curr_render_target(nullptr),
curr_poly(nullptr),
@ -546,6 +550,12 @@ bool shaders::init(d3d_base *d3dintf, running_machine *machine, renderer_d3d9 *r
get_vector(winoptions.screen_floor(), 3, options->floor, true);
get_vector(winoptions.screen_phosphor(), 3, options->phosphor, true);
options->saturation = winoptions.screen_saturation();
options->chroma_mode = winoptions.screen_chroma_mode();
get_vector(winoptions.screen_chroma_a(), 2, options->chroma_a, true);
get_vector(winoptions.screen_chroma_b(), 2, options->chroma_b, true);
get_vector(winoptions.screen_chroma_c(), 2, options->chroma_c, true);
get_vector(winoptions.screen_chroma_conversion_gain(), 3, options->chroma_conversion_gain, true);
get_vector(winoptions.screen_chroma_y_gain(), 3, options->chroma_y_gain, true);
options->yiq_enable = winoptions.screen_yiq_enable();
options->yiq_jitter = winoptions.screen_yiq_jitter();
options->yiq_cc = winoptions.screen_yiq_cc();
@ -574,6 +584,10 @@ bool shaders::init(d3d_base *d3dintf, running_machine *machine, renderer_d3d9 *r
options->bloom_level6_weight = winoptions.screen_bloom_lvl6_weight();
options->bloom_level7_weight = winoptions.screen_bloom_lvl7_weight();
options->bloom_level8_weight = winoptions.screen_bloom_lvl8_weight();
strncpy(options->lut_texture, winoptions.screen_lut_texture(), sizeof(options->lut_texture));
options->lut_enable = winoptions.screen_lut_enable();
strncpy(options->ui_lut_texture, winoptions.ui_lut_texture(), sizeof(options->ui_lut_texture));
options->ui_lut_enable = winoptions.ui_lut_enable();
options->params_init = true;
@ -728,6 +742,44 @@ int shaders::create_resources()
d3d->get_texture_manager()->m_texture_list.push_back(std::move(tex));
}
render_load_png(lut_bitmap, file, nullptr, options->lut_texture);
if (lut_bitmap.valid())
{
render_texinfo texture;
// fake in the basic data so it looks like it came from render.c
texture.base = lut_bitmap.raw_pixptr(0);
texture.rowpixels = lut_bitmap.rowpixels();
texture.width = lut_bitmap.width();
texture.height = lut_bitmap.height();
texture.palette = nullptr;
texture.seqid = 0;
// now create it (no prescale, no wrap)
auto tex = std::make_unique<texture_info>(d3d->get_texture_manager(), &texture, 1, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32));
lut_texture = tex.get();
d3d->get_texture_manager()->m_texture_list.push_back(std::move(tex));
}
render_load_png(ui_lut_bitmap, file, nullptr, options->ui_lut_texture);
if (ui_lut_bitmap.valid())
{
render_texinfo texture;
// fake in the basic data so it looks like it came from render.c
texture.base = ui_lut_bitmap.raw_pixptr(0);
texture.rowpixels = ui_lut_bitmap.rowpixels();
texture.width = ui_lut_bitmap.width();
texture.height = ui_lut_bitmap.height();
texture.palette = nullptr;
texture.seqid = 0;
// now create it (no prescale, no wrap)
auto tex = std::make_unique<texture_info>(d3d->get_texture_manager(), &texture, 1, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32));
ui_lut_texture = tex.get();
d3d->get_texture_manager()->m_texture_list.push_back(std::move(tex));
}
const char *fx_dir = downcast<windows_options &>(machine->options()).screen_post_fx_dir();
default_effect = new effect(this, d3d->get_device(), "primary.fx", fx_dir);
@ -743,6 +795,7 @@ int shaders::create_resources()
bloom_effect = new effect(this, d3d->get_device(), "bloom.fx", fx_dir);
downsample_effect = new effect(this, d3d->get_device(), "downsample.fx", fx_dir);
vector_effect = new effect(this, d3d->get_device(), "vector.fx", fx_dir);
chroma_effect = new effect(this, d3d->get_device(), "chroma.fx", fx_dir);
if (!default_effect->is_valid() ||
!post_effect->is_valid() ||
@ -756,14 +809,13 @@ int shaders::create_resources()
!ntsc_effect->is_valid() ||
!bloom_effect->is_valid() ||
!downsample_effect->is_valid() ||
!vector_effect->is_valid())
!vector_effect->is_valid() ||
!chroma_effect->is_valid())
{
return 1;
}
const int EFFECT_COUNT = 14;
effect *effects[EFFECT_COUNT] = {
std::array<effect*, 15> effects = {
default_effect,
post_effect,
distortion_effect,
@ -777,10 +829,11 @@ int shaders::create_resources()
color_effect,
bloom_effect,
downsample_effect,
vector_effect
vector_effect,
chroma_effect
};
for (int i = 0; i < EFFECT_COUNT; i++)
for (int i = 0; i < effects.size(); i++)
{
effects[i]->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS);
effects[i]->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS);
@ -824,15 +877,22 @@ int shaders::create_resources()
focus_effect->add_uniform("Defocus", uniform::UT_VEC2, uniform::CU_FOCUS_SIZE);
phosphor_effect->add_uniform("Phosphor", uniform::UT_VEC3, uniform::CU_PHOSPHOR_LIFE);
post_effect->add_uniform("ShadowAlpha", uniform::UT_FLOAT, uniform::CU_POST_SHADOW_ALPHA);
post_effect->add_uniform("ShadowAlpha", uniform::UT_FLOAT, uniform::CU_POST_SHADOW_ALPHA);
post_effect->add_uniform("ShadowCount", uniform::UT_VEC2, uniform::CU_POST_SHADOW_COUNT);
post_effect->add_uniform("ShadowUV", uniform::UT_VEC2, uniform::CU_POST_SHADOW_UV);
post_effect->add_uniform("ShadowUVOffset", uniform::UT_VEC2, uniform::CU_POST_SHADOW_UV_OFFSET);
post_effect->add_uniform("ShadowDims", uniform::UT_VEC2, uniform::CU_POST_SHADOW_DIMS);
post_effect->add_uniform("Power", uniform::UT_VEC3, uniform::CU_POST_POWER);
post_effect->add_uniform("Floor", uniform::UT_VEC3, uniform::CU_POST_FLOOR);
post_effect->add_uniform("ChomaMode", uniform::UT_INT, uniform::CU_CHROMA_MODE);
post_effect->add_uniform("ConversionGain", uniform::UT_VEC3, uniform::CU_CHROMA_CONVERSION_GAIN);
phosphor_effect->add_uniform("Phosphor", uniform::UT_VEC3, uniform::CU_PHOSPHOR_LIFE);
chroma_effect->add_uniform("YGain", uniform::UT_VEC3, uniform::CU_CHROMA_Y_GAIN);
chroma_effect->add_uniform("ChromaA", uniform::UT_VEC2, uniform::CU_CHROMA_A);
chroma_effect->add_uniform("ChromaB", uniform::UT_VEC2, uniform::CU_CHROMA_B);
chroma_effect->add_uniform("ChromaC", uniform::UT_VEC2, uniform::CU_CHROMA_C);
distortion_effect->add_uniform("VignettingAmount", uniform::UT_FLOAT, uniform::CU_POST_VIGNETTING);
distortion_effect->add_uniform("DistortionAmount", uniform::UT_FLOAT, uniform::CU_POST_DISTORTION);
@ -842,6 +902,9 @@ int shaders::create_resources()
distortion_effect->add_uniform("SmoothBorderAmount", uniform::UT_FLOAT, uniform::CU_POST_SMOOTH_BORDER);
distortion_effect->add_uniform("ReflectionAmount", uniform::UT_FLOAT, uniform::CU_POST_REFLECTION);
default_effect->add_uniform("LutEnable", uniform::UT_BOOL, uniform::CU_LUT_ENABLE);
default_effect->add_uniform("UiLutEnable", uniform::UT_BOOL, uniform::CU_UI_LUT_ENABLE);
return 0;
}
@ -880,6 +943,7 @@ void shaders::begin_draw()
bloom_effect->set_technique("DefaultTechnique");
downsample_effect->set_technique("DefaultTechnique");
vector_effect->set_technique("DefaultTechnique");
chroma_effect->set_technique("DefaultTechnique");
HRESULT result = d3d->get_device()->SetRenderTarget(0, backbuffer);
if (FAILED(result))
@ -1190,13 +1254,11 @@ int shaders::post_pass(d3d_render_target *rt, int source_index, poly_info *poly,
curr_effect = post_effect;
curr_effect->update_uniforms();
curr_effect->set_texture("ShadowTexture", shadow_texture == nullptr ? nullptr : shadow_texture->get_finaltex());
curr_effect->set_int("ShadowTileMode", options->shadow_mask_tile_mode);
curr_effect->set_texture("ShadowTexture", shadow_texture == nullptr ? nullptr : shadow_texture->get_finaltex()); curr_effect->set_int("ShadowTileMode", options->shadow_mask_tile_mode);
curr_effect->set_texture("DiffuseTexture", rt->target_texture[next_index]);
curr_effect->set_vector("BackColor", 3, back_color);
curr_effect->set_vector("ScreenScale", 2, screen_scale);
curr_effect->set_vector("ScreenOffset", 2, screen_offset);
curr_effect->set_float("ScanlineOffset", curr_texture->get_cur_frame() == 0 ? 0.0f : options->scanline_jitter);
curr_effect->set_float("TimeMilliseconds", (float)machine->time().as_double() * 1000.0f);
curr_effect->set_float("HumBarAlpha", options->hum_bar_alpha);
curr_effect->set_bool("PrepareBloom", prepare_bloom);
@ -1207,6 +1269,18 @@ int shaders::post_pass(d3d_render_target *rt, int source_index, poly_info *poly,
return next_index;
}
int shaders::chroma_pass(d3d_render_target *rt, int source_index, poly_info *poly, int vertnum)
{
int next_index = source_index;
curr_effect = chroma_effect;
curr_effect->update_uniforms();
curr_effect->set_texture("Diffuse", rt->target_texture[next_index]);
next_index = rt->next_index(next_index);
blit(rt->target_surface[next_index], false, D3DPT_TRIANGLELIST, 0, 2);
return next_index;
}
int shaders::downsample_pass(d3d_render_target *rt, int source_index, poly_info *poly, int vertnum)
{
int next_index = source_index;
@ -1332,6 +1406,8 @@ int shaders::vector_buffer_pass(d3d_render_target *rt, int source_index, poly_in
curr_effect->set_technique("VectorBufferTechnique");
curr_effect->set_texture("Diffuse", rt->target_texture[next_index]);
curr_effect->set_texture("LutTexture", lut_texture == nullptr ? nullptr : lut_texture->get_finaltex());
// we need to clear the vector render target here
next_index = rt->next_index(next_index);
@ -1351,6 +1427,7 @@ int shaders::screen_pass(d3d_render_target *rt, int source_index, poly_info *pol
curr_effect->set_technique("ScreenTechnique");
curr_effect->set_texture("Diffuse", rt->target_texture[next_index]);
curr_effect->set_texture("LutTexture", lut_texture == nullptr ? nullptr : lut_texture->get_finaltex());
blit(backbuffer, false, poly->type(), vertnum, poly->count());
@ -1382,6 +1459,8 @@ void shaders::ui_pass(poly_info *poly, int vertnum)
curr_effect->update_uniforms();
curr_effect->set_technique("UiTechnique");
curr_effect->set_texture("LutTexture", lut_texture == nullptr ? nullptr : ui_lut_texture->get_finaltex());
blit(nullptr, false, poly->type(), vertnum, poly->count());
}
@ -1429,17 +1508,19 @@ void shaders::render_quad(poly_info *poly, int vertnum)
next_index = deconverge_pass(rt, next_index, poly, vertnum);
next_index = scanline_pass(rt, next_index, poly, vertnum);
next_index = defocus_pass(rt, next_index, poly, vertnum);
next_index = phosphor_pass(rt, next_index, poly, vertnum);
//next_index = phosphor_pass(rt, next_index, poly, vertnum);
// create bloom textures
int phosphor_index = next_index;
int old_index = next_index;
next_index = post_pass(rt, next_index, poly, vertnum, true);
next_index = downsample_pass(rt, next_index, poly, vertnum);
// apply bloom textures
next_index = phosphor_index;
next_index = old_index;
next_index = post_pass(rt, next_index, poly, vertnum, false);
next_index = bloom_pass(rt, next_index, poly, vertnum);
next_index = phosphor_pass(rt, next_index, poly, vertnum);
next_index = chroma_pass(rt, next_index, poly, vertnum);
next_index = distortion_pass(rt, next_index, poly, vertnum);
@ -1508,17 +1589,19 @@ void shaders::render_quad(poly_info *poly, int vertnum)
next_index = vector_buffer_pass(rt, next_index, poly, vertnum);
next_index = deconverge_pass(rt, next_index, poly, vertnum);
next_index = defocus_pass(rt, next_index, poly, vertnum);
next_index = phosphor_pass(rt, next_index, poly, vertnum);
//next_index = phosphor_pass(rt, next_index, poly, vertnum);
// create bloom textures
int phosphor_index = next_index;
int old_index = next_index;
next_index = post_pass(rt, next_index, poly, vertnum, true);
next_index = downsample_pass(rt, next_index, poly, vertnum);
// apply bloom textures
next_index = phosphor_index;
next_index = old_index;
next_index = post_pass(rt, next_index, poly, vertnum, false);
next_index = bloom_pass(rt, next_index, poly, vertnum);
next_index = phosphor_pass(rt, next_index, poly, vertnum);
next_index = chroma_pass(rt, next_index, poly, vertnum);
next_index = distortion_pass(rt, next_index, poly, vertnum);
@ -1826,6 +1909,11 @@ void shaders::delete_resources()
delete ntsc_effect;
ntsc_effect = nullptr;
}
if (chroma_effect != nullptr)
{
delete chroma_effect;
chroma_effect = nullptr;
}
if (backbuffer != nullptr)
{
@ -1845,6 +1933,8 @@ void shaders::delete_resources()
}
shadow_bitmap.reset();
lut_bitmap.reset();
ui_lut_bitmap.reset();
}
@ -1980,7 +2070,8 @@ hlsl_options shaders::last_options = { false };
enum slider_option
{
SLIDER_VECTOR_BEAM_SMOOTH = 0,
SLIDER_UI_LUT_ENABLE = 0,
SLIDER_VECTOR_BEAM_SMOOTH,
SLIDER_VECTOR_ATT_MAX,
SLIDER_VECTOR_ATT_LEN_MIN,
SLIDER_SHADOW_MASK_TILE_MODE,
@ -2019,6 +2110,12 @@ enum slider_option
SLIDER_SCALE,
SLIDER_POWER,
SLIDER_FLOOR,
SLIDER_CHROMA_MODE,
SLIDER_CHROMA_A,
SLIDER_CHROMA_B,
SLIDER_CHROMA_C,
SLIDER_CHROMA_CONVERSION_GAIN,
SLIDER_Y_GAIN,
SLIDER_PHOSPHOR,
SLIDER_BLOOM_BLEND_MODE,
SLIDER_BLOOM_SCALE,
@ -2043,7 +2140,8 @@ enum slider_option
SLIDER_NTSC_Y_VALUE,
SLIDER_NTSC_I_VALUE,
SLIDER_NTSC_Q_VALUE,
SLIDER_NTSC_SCAN_TIME
SLIDER_NTSC_SCAN_TIME,
SLIDER_LUT_ENABLE,
};
enum slider_screen_type
@ -2058,6 +2156,7 @@ enum slider_screen_type
slider_desc shaders::s_sliders[] =
{
{ "3D LUT (UI/Artwork)", 0, 0, 1, 1, SLIDER_INT_ENUM, SLIDER_SCREEN_TYPE_ANY, SLIDER_UI_LUT_ENABLE, 0, "%s", { "Off", "On" } },
{ "Vector Beam Smooth Amount", 0, 0, 100, 1, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_VECTOR, SLIDER_VECTOR_BEAM_SMOOTH, 0.01f, "%1.2f", {} },
{ "Vector Attenuation Maximum", 0, 50, 100, 1, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_VECTOR, SLIDER_VECTOR_ATT_MAX, 0.01f, "%1.2f", {} },
{ "Vector Attenuation Length Minimum", 1, 500, 1000, 1, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_VECTOR, SLIDER_VECTOR_ATT_LEN_MIN, 0.001f, "%1.3f", {} },
@ -2097,6 +2196,12 @@ slider_desc shaders::s_sliders[] =
{ "Signal Scale,", -200, 100, 200, 1, SLIDER_COLOR, SLIDER_SCREEN_TYPE_ANY, SLIDER_SCALE, 0.01f, "%2.2f", {} },
{ "Signal Exponent,", -800, 0, 800, 1, SLIDER_COLOR, SLIDER_SCREEN_TYPE_ANY, SLIDER_POWER, 0.01f, "%2.2f", {} },
{ "Signal Floor,", 0, 0, 100, 1, SLIDER_COLOR, SLIDER_SCREEN_TYPE_ANY, SLIDER_FLOOR, 0.01f, "%2.2f", {} },
{ "Color Mode,", 1, 3, 3, 1, SLIDER_INT_ENUM, SLIDER_SCREEN_TYPE_ANY, SLIDER_CHROMA_MODE, 0, "%s", { "", "Monochrome", "Dichrome", "Trichrome" } },
{ "Chroma Conversion Gain,", 0, 0, 10000,10, SLIDER_COLOR, SLIDER_SCREEN_TYPE_ANY, SLIDER_CHROMA_CONVERSION_GAIN, 0.0001f, "%1.4f", {} },
{ "Phosphor A Chromaticity,", 0, 0, 1000,10, SLIDER_VEC2, SLIDER_SCREEN_TYPE_ANY, SLIDER_CHROMA_A, 0.001f, "%1.3f", {} },
{ "Phosphor B Chromaticity,", 0, 0, 1000,10, SLIDER_VEC2, SLIDER_SCREEN_TYPE_ANY, SLIDER_CHROMA_B, 0.001f, "%1.3f", {} },
{ "Phosphor C Chromaticity,", 0, 0, 1000,10, SLIDER_VEC2, SLIDER_SCREEN_TYPE_ANY, SLIDER_CHROMA_C, 0.001f, "%1.3f", {} },
{ "Phosphor Gain,", 0, 0, 10000,10, SLIDER_COLOR, SLIDER_SCREEN_TYPE_ANY, SLIDER_Y_GAIN, 0.0001f, "%1.4f", {} },
{ "Phosphor Persistence,", 0, 0, 100, 1, SLIDER_COLOR, SLIDER_SCREEN_TYPE_ANY, SLIDER_PHOSPHOR, 0.01f, "%2.2f", {} },
{ "Bloom Blend Mode", 0, 0, 1, 1, SLIDER_INT_ENUM, SLIDER_SCREEN_TYPE_ANY, SLIDER_BLOOM_BLEND_MODE, 0, "%s", { "Brighten", "Darken" } },
{ "Bloom Scale", 0, 0, 2000, 5, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_ANY, SLIDER_BLOOM_SCALE, 0.001f, "%1.3f", {} },
@ -2122,6 +2227,7 @@ slider_desc shaders::s_sliders[] =
{ "NTSC I Signal Bandwidth (Hz)", 0, 120, 600, 5, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_LCD_OR_RASTER, SLIDER_NTSC_I_VALUE, 0.01f, "%1.4f", {} },
{ "NTSC Q Signal Bandwidth (Hz)", 0, 60, 600, 5, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_LCD_OR_RASTER, SLIDER_NTSC_Q_VALUE, 0.01f, "%1.4f", {} },
{ "NTSC Scanline Duration (uSec)", 0, 5260, 10000, 1, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_LCD_OR_RASTER, SLIDER_NTSC_SCAN_TIME, 0.01f, "%1.2f", {} },
{ "3D LUT (Screen)", 0, 0, 1, 1, SLIDER_INT_ENUM, SLIDER_SCREEN_TYPE_ANY, SLIDER_LUT_ENABLE, 0, "%s", { "Off", "On" } },
{ nullptr, 0, 0, 0, 0, 0, 0, -1, 0, nullptr, {} }
};
@ -2169,6 +2275,12 @@ void *shaders::get_slider_option(int id, int index)
case SLIDER_SCALE: return &(options->scale[index]);
case SLIDER_POWER: return &(options->power[index]);
case SLIDER_FLOOR: return &(options->floor[index]);
case SLIDER_CHROMA_MODE: return &(options->chroma_mode);
case SLIDER_CHROMA_A: return &(options->chroma_a[index]);
case SLIDER_CHROMA_B: return &(options->chroma_b[index]);
case SLIDER_CHROMA_C: return &(options->chroma_c[index]);
case SLIDER_CHROMA_CONVERSION_GAIN: return &(options->chroma_conversion_gain[index]);
case SLIDER_Y_GAIN: return &(options->chroma_y_gain[index]);
case SLIDER_PHOSPHOR: return &(options->phosphor[index]);
case SLIDER_BLOOM_BLEND_MODE: return &(options->bloom_blend_mode);
case SLIDER_BLOOM_SCALE: return &(options->bloom_scale);
@ -2194,6 +2306,8 @@ void *shaders::get_slider_option(int id, int index)
case SLIDER_NTSC_I_VALUE: return &(options->yiq_i);
case SLIDER_NTSC_Q_VALUE: return &(options->yiq_q);
case SLIDER_NTSC_SCAN_TIME: return &(options->yiq_scan_time);
case SLIDER_LUT_ENABLE: return &(options->lut_enable);
case SLIDER_UI_LUT_ENABLE: return &(options->ui_lut_enable);
}
return nullptr;
}
@ -2458,6 +2572,24 @@ void uniform::update()
m_shader->set_vector("Defocus", 2, &options->defocus[0]);
break;
case CU_CHROMA_MODE:
m_shader->set_int("ChromaMode", options->chroma_mode);
break;
case CU_CHROMA_A:
m_shader->set_vector("ChromaA", 2, &options->chroma_a[0]);
break;
case CU_CHROMA_B:
m_shader->set_vector("ChromaB", 2, &options->chroma_b[0]);
break;
case CU_CHROMA_C:
m_shader->set_vector("ChromaC", 2, &options->chroma_c[0]);
break;
case CU_CHROMA_CONVERSION_GAIN:
m_shader->set_vector("ConversionGain", 3, &options->chroma_conversion_gain[0]);
case CU_CHROMA_Y_GAIN:
m_shader->set_vector("YGain", 3, &options->chroma_y_gain[0]);
break;
case CU_PHOSPHOR_LIFE:
m_shader->set_vector("Phosphor", 3, options->phosphor);
break;
@ -2545,6 +2677,11 @@ void uniform::update()
case CU_POST_FLOOR:
m_shader->set_vector("Floor", 3, options->floor);
break;
case CU_LUT_ENABLE:
m_shader->set_bool("LutEnable", options->lut_enable ? true : false);
break;
case CU_UI_LUT_ENABLE:
m_shader->set_bool("UiLutEnable", options->ui_lut_enable ? true : false);
}
}

View File

@ -101,6 +101,14 @@ public:
CU_POST_SCANLINE_BRIGHT_OFFSET,
CU_POST_POWER,
CU_POST_FLOOR,
CU_CHROMA_MODE,
CU_CHROMA_A,
CU_CHROMA_B,
CU_CHROMA_C,
CU_CHROMA_CONVERSION_GAIN,
CU_CHROMA_Y_GAIN,
CU_LUT_ENABLE,
CU_UI_LUT_ENABLE,
CU_COUNT
};
@ -207,6 +215,12 @@ struct hlsl_options
float floor[3];
float phosphor[3];
float saturation;
int chroma_mode;
float chroma_a[2];
float chroma_b[2];
float chroma_c[2];
float chroma_conversion_gain[3];
float chroma_y_gain[3];
// NTSC
int yiq_enable;
@ -241,6 +255,12 @@ struct hlsl_options
float bloom_level6_weight;
float bloom_level7_weight;
float bloom_level8_weight;
// Final
char lut_texture[1024];
int lut_enable;
char ui_lut_texture[1024];
int ui_lut_enable;
};
struct slider_desc
@ -338,6 +358,7 @@ private:
int post_pass(d3d_render_target *rt, int source_index, poly_info *poly, int vertnum, bool prepare_bloom);
int downsample_pass(d3d_render_target *rt, int source_index, poly_info *poly, int vertnum);
int bloom_pass(d3d_render_target *rt, int source_index, poly_info *poly, int vertnum);
int chroma_pass(d3d_render_target *rt, int source_index, poly_info *poly, int vertnum);
int distortion_pass(d3d_render_target *rt, int source_index, poly_info *poly, int vertnum);
int vector_pass(d3d_render_target *rt, int source_index, poly_info *poly, int vertnum);
int vector_buffer_pass(d3d_render_target *rt, int source_index, poly_info *poly, int vertnum);
@ -357,6 +378,10 @@ private:
double delta_t; // data for delta_time
bitmap_argb32 shadow_bitmap; // shadow mask bitmap for post-processing shader
texture_info * shadow_texture; // shadow mask texture for post-processing shader
bitmap_argb32 lut_bitmap;
texture_info * lut_texture;
bitmap_argb32 ui_lut_bitmap;
texture_info * ui_lut_texture;
hlsl_options * options; // current options
IDirect3DSurface9 * black_surface; // black dummy surface
@ -391,6 +416,7 @@ private:
effect * bloom_effect; // pointer to the bloom composite effect
effect * downsample_effect; // pointer to the bloom downsample effect
effect * vector_effect; // pointer to the vector-effect object
effect * chroma_effect;
texture_info * curr_texture;
d3d_render_target * curr_render_target;

View File

@ -216,6 +216,12 @@ const options_entry windows_options::s_option_entries[] =
{ WINOPTION_POWER";fs_power", "1.0,1.0,1.0", OPTION_STRING, "signal power value (exponential)" },
{ WINOPTION_FLOOR";fs_floor", "0.0,0.0,0.0", OPTION_STRING, "signal floor level" },
{ WINOPTION_PHOSPHOR";fs_phosphor", "0.0,0.0,0.0", OPTION_STRING, "phosphorescence decay rate (0.0 is instant, 1.0 is forever)" },
{ WINOPTION_CHROMA_MODE, "3", OPTION_INTEGER, "Number of phosphors to use: 1 - monochrome, 2 - dichrome, 3 - trichrome (color)" },
{ WINOPTION_CHROMA_CONVERSION_GAIN, "0.299,0.587,0.114", OPTION_STRING, "Gain to be applied when summing RGB signal for monochrome and dichrome modes" },
{ WINOPTION_CHROMA_A, "0.64,0.33", OPTION_STRING, "Chromaticity coordinate for first phosphor" },
{ WINOPTION_CHROMA_B, "0.30,0.60", OPTION_STRING, "Chromaticity coordinate for second phosphor" },
{ WINOPTION_CHROMA_C, "0.15,0.06", OPTION_STRING, "Chromaticity coordinate for third phosphor" },
{ WINOPTION_CHROMA_Y_GAIN, "0.2126,0.7152,0.0722", OPTION_STRING, "Gain to be applied for each phosphor" },
/* NTSC simulation below this line */
{ nullptr, nullptr, OPTION_HEADER, "NTSC POST-PROCESSING OPTIONS" },
{ WINOPTION_YIQ_ENABLE";yiq", "0", OPTION_BOOLEAN, "enables YIQ-space HLSL post-processing" },
@ -250,6 +256,10 @@ const options_entry windows_options::s_option_entries[] =
{ WINOPTION_BLOOM_LEVEL6_WEIGHT, "0.04", OPTION_FLOAT, "Bloom level 6 weight (1/4 smaller that level 5 target)" },
{ WINOPTION_BLOOM_LEVEL7_WEIGHT, "0.02", OPTION_FLOAT, "Bloom level 7 weight (1/4 smaller that level 6 target)" },
{ WINOPTION_BLOOM_LEVEL8_WEIGHT, "0.01", OPTION_FLOAT, "Bloom level 8 weight (1/4 smaller that level 7 target)" },
{ WINOPTION_LUT_TEXTURE, "", OPTION_STRING, "3D LUT texture filename for screen, PNG format" },
{ WINOPTION_LUT_ENABLE, "0", OPTION_BOOLEAN, "Enables 3D LUT to be applied to screen after post-processing" },
{ WINOPTION_UI_LUT_TEXTURE, "", OPTION_STRING, "3D LUT texture filename of UI, PNG format" },
{ WINOPTION_UI_LUT_ENABLE, "0", OPTION_BOOLEAN, "Enables 3D LUT to be applied to UI and artwork after post-processing" },
// full screen options
{ nullptr, nullptr, OPTION_HEADER, "FULL SCREEN OPTIONS" },
@ -648,4 +658,3 @@ static int is_double_click_start(int argc)
}
#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)

View File

@ -70,6 +70,12 @@
#define WINOPTION_FLOOR "floor"
#define WINOPTION_PHOSPHOR "phosphor_life"
#define WINOPTION_SATURATION "saturation"
#define WINOPTION_CHROMA_MODE "chroma_mode"
#define WINOPTION_CHROMA_CONVERSION_GAIN "chroma_conversion_gain"
#define WINOPTION_CHROMA_A "chroma_a"
#define WINOPTION_CHROMA_B "chroma_b"
#define WINOPTION_CHROMA_C "chroma_c"
#define WINOPTION_CHROMA_Y_GAIN "chroma_y_gain"
#define WINOPTION_YIQ_ENABLE "yiq_enable"
#define WINOPTION_YIQ_JITTER "yiq_jitter"
#define WINOPTION_YIQ_CCVALUE "yiq_cc"
@ -98,6 +104,10 @@
#define WINOPTION_BLOOM_LEVEL6_WEIGHT "bloom_lvl6_weight"
#define WINOPTION_BLOOM_LEVEL7_WEIGHT "bloom_lvl7_weight"
#define WINOPTION_BLOOM_LEVEL8_WEIGHT "bloom_lvl8_weight"
#define WINOPTION_LUT_TEXTURE "lut_texture"
#define WINOPTION_LUT_ENABLE "lut_enable"
#define WINOPTION_UI_LUT_TEXTURE "ui_lut_texture"
#define WINOPTION_UI_LUT_ENABLE "ui_lut_enable"
// full screen options
#define WINOPTION_TRIPLEBUFFER "triplebuffer"
@ -199,6 +209,16 @@ public:
const char *screen_floor() const { return value(WINOPTION_FLOOR); }
const char *screen_phosphor() const { return value(WINOPTION_PHOSPHOR); }
float screen_saturation() const { return float_value(WINOPTION_SATURATION); }
int screen_chroma_mode() const { return int_value(WINOPTION_CHROMA_MODE); }
const char *screen_chroma_a() const { return value(WINOPTION_CHROMA_A); }
const char *screen_chroma_b() const { return value(WINOPTION_CHROMA_B); }
const char *screen_chroma_c() const { return value(WINOPTION_CHROMA_C); }
const char *screen_chroma_conversion_gain() const { return value(WINOPTION_CHROMA_CONVERSION_GAIN); }
const char *screen_chroma_y_gain() const { return value(WINOPTION_CHROMA_Y_GAIN); }
const char *screen_lut_texture() const { return value(WINOPTION_LUT_TEXTURE); }
bool screen_lut_enable() const { return bool_value(WINOPTION_LUT_ENABLE); }
const char *ui_lut_texture() const { return value(WINOPTION_UI_LUT_TEXTURE); }
bool ui_lut_enable() const { return bool_value(WINOPTION_UI_LUT_ENABLE); }
// full screen options
bool triple_buffer() const { return bool_value(WINOPTION_TRIPLEBUFFER); }