Code:
#ifndef NVG_MOD_H
#define NVG_MOD_H
// Center of the circle used to represent the NVGs.
//
// Now let's imagine we use 1000x1000 Pixels as In-game Resolution:
// And lets say we want the center at 300px from the left and 650px from the bottom.
//
// 1000px=1 so 300px = 0.3
//
// The Values are starting to count from the Bottom-Left corner of your Res, first is for for
// Horizontal position and the second for Vertical:
//
//
const float2 EYE_CENTER = float2(0.50000f,0.55000f);
const float2 MASK_CENTER = float2(0.50000f,0.55000f);
// In precent of screen size. Since most monitors are not 1:1 aspect ratio most often you will
// choose your height was the percent value then you take the pixel value of that percentage and
// divide that by your screen width.
//
// Example: Resolution = 1920x1080
// You want the eye to be 85% the size of 1080. You take 1080*.85=918, now to figure out same
// size width take 918/1920=0.4781. Now your circle will be the same width and height.
//
// Here are the some numbers for different common aspect-ratios:
// 4:3 = 1.333 -> Triplehead 4:3 = 4
// 5:4 = 1.25 -> Triplehead 5:4 = 3.75
// 16:10 = 1.6 -> Triplehead 16:10 = 4.8
// 16:9 = 1.78 -> riplehead 16:9 = 5.333
//
// First value is for width second for height:
//
//const float2 EYE_SIZE = float2(0.5344f, 0.95f);
const float2 EYE_SIZE = float2(0.17763f,0.94737f);
const float2 MASK_SIZE = float2(0.53289f,0.94737f);
// How much to scale the image in RENDER_MODE=1. Anything greater then 20% is a bit crazy!
const float EYE_SCALE = 0.19f;
// Min value to multiply noise.
const float NOISE_MIN[2] =
{
0.5f, // A-10C
0.75f // KA-50
};
// Max value to multiply noise.
const float NOISE_MAX[2] =
{
0.5f, // A-10C
0.75f // KA-50
};
// Color to use for NVGs.
const float2x3 COLORIZE_COLOR =
{
{0.65f, 1.00f, 0.35f}, // A-10C
{0.2f, 0.46f, 0.22f} // KA-50
};
// Based on the NVG magnification the image is lifted by this.
// (COLORIZE_COLOR * nvgmag) * this
const float NVG_COLOR_LIFT[2] =
{
0.175f, // A-10C
0.175f // KA-50
};
// Changes the Circle rendering mode.
//
// 0 = Circle without zoom
// 1 = Circle with zoom
// 2 = Fullscreen without zoom.
//
const int RENDER_MODE = 0;
// Enables a slight distortion along the edges of the NVG glass.
const bool ENABLE_RIM_DISTORT = false;
// Changes the blur rendering mode.
//
// 0 = Use default game blur
//
// Not yet implemented
//
const int NVG_INNER_BLUR_MODE = 0;
////
// STATIC VARS
////
//
// NVG Type
//
// 0 = A-10C.
// 1 = KA-50.
//
static const int NVG_A10 = 0;
static const int NVG_KA50 = 1;
const float INNER_RANGE_MIN = 0.950f;
const float INNER_RANGE_MAX = 0.967f;
const float OUTTER_RANGE_MIN = 0.979f;
const float OUTTER_RANGE_MAX = 1.000f;
const float INNER_RANGE_DIST_MIN = 0.963f;
const float INNER_RANGE_DIST_MAX = 0.979f;
float pertween(const float start, const float end, const float value)
{
const float range = max(start, end) - min(start, end);
const float a = range - (end - value);
return a / range;
}
float3 RGBtoHSL(const float3 rgb): COLOR0
{
float r = clamp(rgb.r, 0.0f, 1.0f);
float g = clamp(rgb.g, 0.0f, 1.0f);
float b = clamp(rgb.b, 0.0f, 1.0f);
float maxV = max(max(r, g), b);
float minV = min(min(r, g), b);
float h = (maxV + minV) / 2.0f;
float s = h;
float l = h;
if (maxV == minV)
{
h = 0.0f;
s = 0.0f;
}
else
{
float d = maxV - minV;
if (l > 0.5f)
{
s = d / (2.0f - maxV - minV);
}
else
{
s = d / (maxV + minV);
}
if (maxV == r)
{
h = (g - b) / d;
}
else
{
if (maxV = g)
{
h = ((b - r) / d) + 2.0f;
}
else
{
h = ((r - g) / d) + 4.0f;
}
}
h /= 6.0f;
}
return float3(h, s, l);
}
float hue2rgb(const float p, const float q, const float t)
{
float T = t;
if (t < 0.0f)
{
T += 1.0f;
}
if (t > 1.0f)
{
T -= 1.0f;
}
if (T < 1.0f / 6.0f)
{
return p + (q - p) * 6.0f * T;
}
if (T < 1.0f / 2.0f)
{
return q;
}
if (T < 2.0f / 3.0f)
{
return p + (q - p) * (2.0 / 3.0f - T) * 6.0f;
}
return p;
}
float3 HSLtoRGB(const float3 hsl): COLOR0
{
const float h = hsl.r;
const float s = hsl.g;
const float l = hsl.b;
float r = 0.0f;
float g = 0.0f;
float b = 0.0f;
if (s == 0.0f)
{
r = 1.0f;
g = 1.0f;
b = 1.0f;
}
else
{
float q = l < 0.5f ? l * (1 + s) : l + s - l * s;
float p = 2 * l - q;
r = hue2rgb(p, q, h + (1.0f / 3.0f));
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - (1.0f / 3.0f));
}
return float3(r, g, b);
}
float3 colorize(const float3 rgb, const float3 to_color): COLOR0
{
const float3 hsl = RGBtoHSL(to_color);
const float maxV = max(max(rgb.r, rgb.g), rgb.b);
const float minV = min(min(rgb.r, rgb.g), rgb.b);
const float lum = (maxV + minV) / 2.0f;
if (lum > 1.0f)
{
return float3(1.0f, 1.0f, 1.0f);
}
return HSLtoRGB(float3(hsl.r, hsl.g, lum));
}
/*
float keyHudNVG(const float3 rgb, const float3 krgb)
{
const float3 hsl = RGBtoHSL(rgb);
const float3 khsl = RGBtoHSL(krgb);
const float satscale = 0.41f;
const float maxk = 0.0f;
const float mink = 0.05f;
float2 delta = hsl.xy - khsl.xy;
delta.y *= satscale;
float d2 = dot(delta, delta);
d2 = smoothstep(maxk, mink, d2);
return d2.x;
}
*/
float3 maskNVGEye(const float2 uv, const float2 center, const float2 size, const float2 res): COLOR0
{
float2 pos = float2(res.x * uv.x, res.y * (1.0f - uv.y));
float2 eye_center = float2(res.x * center.x, res.y * center.y);
float2 eye_size = float2(res.x, res.y) * size;
float2 tmp = eye_size * 0.5f;
float4x2 eye_bbox = {
eye_center.x - tmp.x, eye_center.y - tmp.y,
eye_center.x + tmp.x, eye_center.y - tmp.y,
eye_center.x + tmp.x, eye_center.y + tmp.y,
eye_center.x - tmp.x, eye_center.y + tmp.y
};
if (pos.x < eye_bbox[0][0] || pos.x > eye_bbox[1][0] || pos.y < eye_bbox[0][1] || pos.y > eye_bbox[2][1])
{
return float3(0.0f, 0.0f, 0.0f);
}
const float radius = eye_size.x > eye_size.y ? max(eye_size.x, eye_size.y) * 0.5f : min(eye_size.x, eye_size.y) * 0.5f;
const float aspect = eye_size.x / eye_size.y;
const float dx = pos.x - eye_center.x;
const float dy = pos.y * aspect - eye_center.y * aspect;
const float distance = sqrt((dx * dx) + (dy * dy)) / radius;
float3 mask = float3(0.0f, 0.0f, 0.0f);
if (distance <= INNER_RANGE_MAX)
{
if (distance >= INNER_RANGE_MIN)
{
float v = 1.0f - pertween(INNER_RANGE_MIN, INNER_RANGE_MAX, distance);
v = smoothstep(1.0f, 0.0f, v);
mask = float3(v, 1.0f, distance);
}
else
{
mask = float3(0.0f, 1.0f, distance);
}
}
else
{
if (distance <= OUTTER_RANGE_MAX)
{
float v = 1.0f - pertween(OUTTER_RANGE_MIN, OUTTER_RANGE_MAX, distance);
v = smoothstep(0.0f, 1.0f, v);
mask = float3(v, 0.0f, distance);
}
}
return mask;
}
#endif