﻿// Upgrade NOTE: replaced '_CameraToWorld' with 'unity_CameraToWorld'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'


Shader "Error.mdl/EHUD"
{
    Properties
    {
		[Header(Main Textures)]
		[NoScaleOffset] _HudTex ("HUD Texture", 2D) = "white" {}
		_TintMain ("HUD Tint", Color) = (1,1,1,1)
		[NoScaleOffset] _HudTex2 ("Secondary HUD Texture", 2D) = "white" {}
		_TintScnd ("Secondary HUD Tint", Color) = (1,1,1,1)
		
		[Header(Compass)]
		[NoScaleOffset] _CompTex ("Compass Texture (RGB)", 2D) = "white" {}
		_TintComp ("Compass Tint", Color) = (1,1,1,1)
		_CompRad ("Compass Radius", float) = 0.25
		
		[Header(Flip Book)]
		[NoScaleOffset] _FlipTex ("Flip-book Texture", 2D) = "white" {}
		_TintFlip ("Flip-book Tint", Color) = (1,1,1,1)
		_xtiles ("Flip-book Columns", float) = 1
		_ytiles ("Flip-book Rows", float) = 1
		_frame ("Flip-book Frame", float) = 0
		
		[Header(Digits)]
		[NoScaleOffset] _DigitTex ("Digits (RGB)", 2D) = "white" {}
		_TintColor ("FPS Color", Color) = (1,1,1,1)
		_TintColor2 ("Clock Color", Color) = (1,1,1,1)
		_TintColorX ("X-axis Color", Color) = (1,0,0,1)
		_TintColorY ("Y-axis Color", Color) = (0,1,0,1)
		_TintColorZ ("Z-axis Color", Color) = (0,0,1,1)
		
		[Header(Axis Gizmo)]
		_TintGiz ("Axis Gizmo Tint", Color) = (1,1,1,1)
		_aoffset ("Axis Pos (W=Scale)", Vector) = (-0.46307, -0.36493, 1.12914, 1.0)
		
		[Header(Global Settings)]
		_offset ("Hud offset", Vector) = (0.0, 0.0, 0.0, 0.0)
		_range ("Range (radius from center)", Range (0.0, 1.0)) = 0.35
		_convergence ("Stereo Convergence", float) = 0.07648
		_clip ("alpha clip", float) = 0.001
		
		[Header(Burn in Prevention)]
		_HoloWidth ("Hologram Effect Band Width", Range (0.001, 0.5)) = 0.7
		_HoloDepth ("Hologram Effect Min Alpha", Range (0.0, 1.0)) = 0.4
		_HoloScroll ("Hologram Scroll Speed", float) = 1
		_NoiseTex ("Noise Texture", 2D) = "black" {}
		_NoiseAlpha ("Noise Alpha", range(0.0,1.0)) = 1.0
		_NoiseThresh ("Noise Alpha Threshold", range(0.0,10.0)) = 0.0
		_JitterX ("Horizonal Jitter", float) = 0.002
		_JitterY ("Vertical Jitter", float) = 0.002
		_JitterS ("Jitter Speed", float) = 0.05
		
		//This allows you to hide your hud from other players, needs to be attached to your head to work.
		//WARNING: You'll need to scale up the hud by around 10,000 so the bounding box is large enough to be seen by you.
		//For everybody else, your bounding box will be huge and your IK will never be culled. Not a good idea to use this.
		
		//[Header(Object must be attached to your head for this to work)]
		[HideInInspector][Toggle] _Hide ("Hide from other players", int) = 0
		[HideInInspector] _scale ("Hud's scale in the transform tab", float) = 1.0
		
    }
    SubShader
    {
        Tags { "Queue"="Overlay" "RenderType"="Transparent" }
        LOD 100
        
        Cull off
        Zwrite Off
        
        Ztest Always
        
        Blend SrcAlpha OneMinusSrcAlpha
        
        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            struct v2f
            {
                float2 uv : TEXCOORD0;
				int3x4 digits : TEXCOORD1;
				//int4 digits[1] : TEXCOORD2;
				//int3 digits[2] : TEXCOORD3;
				int type : TEXCOORD5;
				float2 ang: TEXCOORD6;
				float4 pos : SV_POSITION;
				float4 color : COLOR;
				//float ang : ANGLE;
            };
			

			sampler2D _DigitTex;
			sampler2D _HudTex;
			sampler2D _HudTex2;
			sampler2D _FlipTex;
			sampler2D _CompTex;
			//sampler2D_float _vel;
			half4 _DigitTex_ST;
			fixed4 _TintMain;
			fixed4 _TintScnd;
			fixed4 _TintComp;
			fixed4 _TintFlip;
			fixed4 _TintGiz;
			fixed4 _TintColor;
			fixed4 _TintColor2;
			fixed4 _TintColorX;
			fixed4 _TintColorY;
			fixed4 _TintColorZ;
			half _convergence;
			half _range;
			half _CompRad;
			half4 _offset;
			half4 _aoffset;
			float _clip;
			half _xtiles;
			half _ytiles;
			half _frame;
			int  _Hide;
			half _scale;
			
			float _HoloWidth;
			float _HoloDepth;
			float _HoloScroll;
			float _JitterX;
			float _JitterY;
			float _JitterS;
			
			sampler2D _NoiseTex;
			float4 _NoiseTex_TexelSize;
			float _NoiseAlpha;
			float _NoiseThresh;
			
			//sampler2D _sep;
			//half4 _sep_ST;
			
			float is_eq(float num, float comp)
			{
				return step(comp-0.01, num)*step(num,comp+0.01);
			}
			
			int display_type(float4 color)
			{
				//---------------------------------------------------------
				// Display type					Vertex Color
				// 0: normal texture			Not one of the below
				// 1: world coordinates			pure red, green, or blue
				// 2: Axis Gizmo				(0,0,0.5)
				// 3: compass					(0,0.5,0)
				// 4: fps						(0,0,0)
				// 5: clock						(0.5,0,0)
				// 6: Secondary Texture			(0.5, 0.5, 0)
				// 7: Flip-Book Texture			(0.5, 0, 0.5)
				//----------------------------------------------------------
				int type = 0;
				
				type += step(0.99, color.r)*step(color.g,0.01)*step(color.b,0.01)
						+ step(0.99, color.b)*step(color.r,0.01)*step(color.g,0.01)
						+ step(0.99, color.g)*step(color.r,0.01)*step(color.b,0.01);
						
				type += 2*step(color.r + color.g, 0.01)*step(color.b, 0.55)*step(0.45,color.b);
				type += 3*step(color.r + color.b, 0.01)*step(color.g, 0.55)*step(0.45,color.g);
				type += 4*step(color.r + color.g + color.b, 0.01);	
				type += 5*step(color.b + color.g, 0.01)*step(color.r, 0.55)*step(0.45,color.r);
				type += 6*is_eq(color.r, 0.5)*is_eq(color.g, 0.5)*step(color.b, 0.01);
				type += 7*is_eq(color.r, 0.5)*is_eq(color.b, 0.5)*step(color.g, 0.01);
				return type;
			}
			
			int3x4 display_digits(float displayValue, int type, int3x4 digits)
			{
				
				//sign of the coordinate number
				digits[2][1] = sign(displayValue + 0.00001);
				displayValue = abs(displayValue);
				
				
				// Are we displaying a normal number, or time?
				int isTime = (type == 5);
				
				
				// Normal digit display -----------------------------------------------------
				
				//Number of digits in the number above the decimal place
				digits[2][2] = 1 + step(10.0,displayValue) + step(100.0,displayValue) + step(1000.0,displayValue) + step(10000.0,displayValue)
								+ step(100000.0,displayValue) + step(1000000.0,displayValue);
				
				
				digits[2][0] += (1 - isTime)*round(frac(round(displayValue*100.0)/10.0)*10.0);
				// Tenths place
				digits[1][3] += (1 - isTime)*round(frac(floor(displayValue*10.0)/10.0)*10.0);
				// Single Digits
				digits[1][2] += (1 - isTime)*round(frac(floor(displayValue)/10.0)*10.0);
				// 10^1
				digits[1][1] += (1 - isTime)*round(frac(floor(displayValue/10.0)/10.0)*10.0);
				//10^2
				digits[1][0] += (1 - isTime)*round(frac(floor(displayValue/100.0)/10.0)*10.0);
				//10^3
				digits[0][3] += (1 - isTime)*round(frac(floor(displayValue/1000.0)/10.0)*10.0);
				//10^4
				digits[0][2] += (1 - isTime)*round(frac(floor(displayValue/10000)/10.0)*10);
				//10^5
				digits[0][1] += (1 - isTime)*round(frac(floor(displayValue/100000)/10.0)*10);
				//10^6
				digits[0][0] += (1 - isTime)*round(frac(floor(displayValue/1000000)/10.0)*10);
				
				// Time Display ----------------------------------------------------------------
				digits[1][0] += (isTime)*round(frac(floor(displayValue)/60.0)*60.0);
				//tens of seconds
				digits[1][1] += (isTime)*round(frac(floor(displayValue/10)/6.0)*6.0);
				//minutes
				digits[1][2] += (isTime)*round(frac(floor(displayValue/60.0)/60.0)*60.0);
				//tens of minutes
				digits[0][0] += (isTime)*round(frac(floor(displayValue/600.0)/6.0)*6);
				//hours
				digits[0][1] += (isTime)*round(frac(floor(displayValue/3600)/10)*10);
				//tens of hours
				digits[0][2] += (isTime)*round(frac(floor(displayValue/36000)/10)*10);
				
				return digits;
			}
			
            v2f vert(float4 pos : POSITION, float2 uv : TEXCOORD0, float4 color : COLOR)
            {
                v2f o;
				
				o.type = display_type(color);
				
				float3 WPos = mul(unity_ObjectToWorld, float4(0,0,0,1)).xyz;
				
				float3 coords = WPos*color.rgb;
				
				//Number to be displayed
				float displayValue = 0;
				
				// If world coordinates, set display value to coords
				displayValue += (o.type == 1)*(coords.x + coords.y + coords.z);
				// If framerate, set display value to smoothed delta-time
				displayValue += (o.type == 4)*unity_DeltaTime[3];
				// If time, set value to number of seconds
				displayValue += (o.type == 5)*_Time[1];
				
				
				
				
				//-----------------------------------------------------------------------------------------------------
				// Move verticies to the camera's position
				//-----------------------------------------------------------------------------------------------------
				
				
				
				// offset the mesh position in each eye to give a sense of depth
				#if UNITY_SINGLE_PASS_STEREO
					
					// Original code for getting the actual IPD of the player. This leads to problems with the perceived hud size
					// changing with avatar height, so I use a fixed value for consistency now.
					
					// float ipd = length(mul(unity_WorldToObject, 
					//				  float4(unity_StereoWorldSpaceCameraPos[0].xyz - unity_StereoWorldSpaceCameraPos[1].xyz, 0)));
					
					// Offset the verticies in each eye along the x axis, moving them toward the other eye.
					float ipd = _convergence;
					float4 abspos = pos + float4(ipd*(0.5-unity_StereoEyeIndex), 0, 0, 0);
					float4 camPos = mul(unity_CameraToWorld, float4(_aoffset.xyz,1) + float4(ipd*(0.5-unity_StereoEyeIndex), 0, 0, 0));
				
				#else
					float ipd = 0.0;
					float4 abspos = pos;
					float4 camPos = mul(unity_CameraToWorld, float4(_aoffset.xyz,1) );
				
				#endif
	
				float2 jitter = float2(_JitterX*sin(-1.3*_Time[1]*_JitterS),
										_JitterY*sin(_Time[1]*_JitterS));
				abspos.xyz += _offset.xyz;
				abspos.xy += jitter;
				
				//Transform the verticies to the players camera. Consider the fact that the positions of the vertices
				//are referenced with respect to the center of the object. We want to move them to be centered on the
				//camera. If we assume that the vertices are in fact referenced with respect to the camera, our job is
				//already done. We just need to transform them from camera space to clip space instead of object to clip.
				//In most cases, you can assume the coordinates are directly in clip space and you do not even need to
				//convert anything. However, that doesn't seem to work in this case for some reason. I transform
				//from camera to world to object to clip, which is extremely round-about and ideally you shouldn't do
				//it this way for screen-space shaders. I'm too lazy to figure out what's wrong though, so I'm keeping it.
				
				float4 worldPos  = mul(unity_CameraToWorld, abspos);   // Transform View to World
				float4 objectPos = mul(unity_WorldToObject, worldPos); // Transform World To Object
				
				// Transform the axis to the correct position on the screen
				// The w component of the offset is used as a scale factor for the axis
				float4 axisPos = mul(UNITY_MATRIX_V, float4(pos.xyz*_aoffset.w,0) + float4(camPos.xyz,1));
				axisPos = mul(UNITY_MATRIX_P,axisPos);
				
				o.pos = UnityObjectToClipPos(objectPos)*(step(o.type,1.9) + step(2.9,o.type)) + (o.type == 2)*axisPos;
				
				// Snap all the verticies to 0,0,0 if the camera is too far from the HUD's center so other players cannot see it
				float4 dist = distance(_WorldSpaceCameraPos, mul(unity_ObjectToWorld, float4(0,0,0,1)));
				o.pos = o.pos - o.pos*step(_range, dist);
				
				//Snap the vertices to 0,0,0 if hide from other players is checked, and the scaling is normal
				//(i.e. the object was not shrunk to a tiny scale with the local headbone)
				half LocalScale = length(mul(unity_ObjectToWorld, float4(0,0,1/_scale,0)));
				o.pos = o.pos - o.pos*step(0.02, LocalScale)*(_Hide == 1);
				
				//------------------------------------------------------------------------------------------
				// Set vertex colors
				//------------------------------------------------------------------------------------------
				
				o.color = float4(0,0,0,0);
				o.color += (o.type == 1)*(color.r*_TintColorX + color.g*_TintColorY + color.b*_TintColorZ);
				o.color += _TintColor*(o.type == 4);
				o.color += _TintColor2*(o.type == 5);
				
				//---------------------------------------------------------------------------------------------
				//Set Value to Display
				//---------------------------------------------------------------------------------------------
				
				o.digits = int3x4(0,0,0,0, 0,0,0,0, 0,0,0,0);
				
				o.digits = display_digits(displayValue, o.type, o.digits);
				
				//----------------------------------------------------------------------------------------------
				// Get the camera's angle with z+ and get the angle to the origin
				//----------------------------------------------------------------------------------------------
				
				#if UNITY_SINGLE_PASS_STEREO
					float3 p1 =  mul(unity_StereoCameraToWorld[0], float4(0,0,1,1));
					float3 p2 =  mul(unity_StereoCameraToWorld[0], float4(0,0,0,1));
				#else
					float3 p1 =  mul(unity_CameraToWorld, float4(0,0,1,1));
					float3 p2 =  mul(unity_CameraToWorld, float4(0,0,0,1));
				#endif
					
				float3 forward = p2-p1;
				forward.xz = normalize(forward.xz);
				o.ang[0] = sign(forward.x)*acos(forward.z) ;
				
				float2 origin_dir = normalize(p2.xz);
				o.ang[1] = sign(origin_dir.x)*acos(origin_dir.y);
				
				
				//-----------------------------------------------------------------------------------------------
				// Flip-Book UVs
				//-----------------------------------------------------------------------------------------------
				o.uv = TRANSFORM_TEX(uv, _DigitTex);
				half2 frame = half2(floor(fmod(_frame, _xtiles)), floor(fmod((_frame/float(_xtiles)), _ytiles)));	
				o.uv += (o.type==7)*(-o.uv + float2((o.uv.x + frame[0])/_xtiles, ((o.uv.y - frame[1])/_ytiles) + (_ytiles - 1.0)/_ytiles));
					
                return o;
            }

           
			// Total number of digits that can be displayed
			static const half numDigits = 9.0;
			
            fixed4 frag(v2f i) : SV_Target
            {                
			
				//----------------------------------------------------------------------------------------
				//Digit UVs
				//----------------------------------------------------------------------------------------
				
				
				
				// Display Width. How many segments we need to divide the display into.
				// Include an extra segment for the negative sign and half a segment for the decimal point
				half dpw = numDigits + 1.5;
				
				// Digit Width. How wide each digit needs to be on the UV Map.
				half dw = 1.0/(dpw);
				
				int digit = -1;
				digit += step(dw, i.uv.x)*step(i.uv.x, 2.0*dw)*(i.digits[0][0] + step(6.9,i.digits[2][2]));
				digit += step(2.0*dw, i.uv.x)*step(i.uv.x, 3.0*dw)*(i.digits[0][1] + step(5.9,i.digits[2][2]));
				digit += step(3.0*dw, i.uv.x)*step(i.uv.x, 4.0*dw)*(i.digits[0][2] + step(4.9,i.digits[2][2]));
				digit += step(4.0*dw, i.uv.x)*step(i.uv.x, 5.0*dw)*(i.digits[0][3] + step(3.9,i.digits[2][2]));
				digit += step(5.0*dw, i.uv.x)*step(i.uv.x, 6.0*dw)*(i.digits[1][0] + step(2.9,i.digits[2][2]));
				digit += step(6.0*dw, i.uv.x)*step(i.uv.x, 7.0*dw)*(i.digits[1][1] + step(1.9,i.digits[2][2]));
				digit += step(7.0*dw, i.uv.x)*step(i.uv.x, 8.0*dw)*(i.digits[1][2] + 1);
				digit += step(8.5*dw, i.uv.x)*step(i.uv.x, 9.5*dw)*(i.digits[1][3] + 1);
				digit += step(9.5*dw, i.uv.x)*step(i.uv.x, 1.0)*(i.digits[2][0] + 1);
				
				float digitUvX = frac((i.uv.x - 0.5*dw*step(8.0*dw,i.uv.x))*dpw)*0.1 + 0.1*digit;
				fixed4 digitColor = step(-0.1, digit)*tex2D(_DigitTex, float2(digitUvX, i.uv.y*0.5 + 0.5))* i.color;
				
				float minusUvX = frac(i.uv.x*dpw)*0.1;
				fixed4 minusColor = step(7.0-i.digits[2][2],i.uv.x*dpw)*step(i.uv.x*dpw, 8-i.digits[2][2])*step(0.5,1-i.digits[2][1])
									*tex2D(_DigitTex, float2(minusUvX, i.uv.y*0.5))* i.color;
				
				float decUvX = frac(i.uv.x*dpw)*0.1+dw;
				fixed4 decColor = tex2D(_DigitTex, float2(decUvX, i.uv.y*0.5))* i.color;
				
				//----------------------------------------------------------------------------------------
				// Clock UVs
				//----------------------------------------------------------------------------------------
				
				//digit widths are hard coded to be 2/7 (6 digits plus two half-width colons)
				
				float clock_uv = step(0, i.uv.x)*step(i.uv.x, 0.142857)*(i.uv.x*0.7 + 0.1*i.digits[0][2])
					   + step(0.142857, i.uv.x)*step(i.uv.x, 0.285714)*((i.uv.x-0.142857)*0.7 + 0.1*i.digits[0][1])
					   + step(0.285714, i.uv.x)*step(i.uv.x, 0.357142)*((i.uv.x-0.285714)*0.7)
					   + step(0.357142, i.uv.x)*step(i.uv.x, 0.500)*((i.uv.x-0.357142)*0.7 + 0.1*i.digits[0][0])
					   + step(0.500, i.uv.x)*step(i.uv.x, 0.642857)*((i.uv.x-0.500)*0.7 + 0.1*i.digits[1][2])
					   + step(0.642857, i.uv.x)*step(i.uv.x, 0.714286)*((i.uv.x-0.642857)*0.7)
					   + step(0.714286, i.uv.x)*step(i.uv.x, 0.857143)*((i.uv.x-0.714286)*0.7 + 0.1*i.digits[1][1])
					   + step(0.857143, i.uv.x)*step(i.uv.x, 1.000)*((i.uv.x-0.857143)*0.7 + 0.1*i.digits[1][0]);
				fixed4 clock_color = tex2D(_DigitTex, float2(clock_uv, i.uv.y*0.5+0.5));
				fixed4 clock_colon = tex2D(_DigitTex, float2(clock_uv + 1.5*dw, i.uv.y*0.5));
				clock_color = (step(0,i.uv.x)*step(i.uv.x, 0.285714)*clock_color
					 + step(0.285714, i.uv.x)*step(i.uv.x, 0.357142)*clock_colon
					 + step(0.357142, i.uv.x)*step(i.uv.x, 0.642857)*clock_color
					 + step(0.642857, i.uv.x)*step(i.uv.x, 0.714286)*clock_colon
					 + step(0.714286, i.uv.x)*step(i.uv.x, 1.000)*clock_color)
					 * _TintColor2;
				
				//----------------------------------------------------------------------------------------
				// Compass UVs and Color
				//----------------------------------------------------------------------------------------
				
				//Main portion of the compass
				float2 compassUVs = float2((i.uv.x-0.5)*_CompRad + i.ang[0]*0.1591549431, i.uv.y);
				
				//Add + or - 2pi to the origin angle to compensate for the fact that acos only gives values in the range +pi to -pi.
				//If we don't do this, the origin marker will disappear when looking certain directions
				float sng = step(i.ang[0],0.0)*step(1.570796327,i.ang[1]) - step(i.ang[1],-1.570796327)*step(0.0,sign(i.ang[0])) ;  
				
				//Quest marker pointing toward the origin
				float2 WaypointUVs = float2((i.uv.x-0.5)*_CompRad +
									clamp((i.ang[0]-i.ang[1] + sng*6.283185)*0.1591549431,-0.47*_CompRad,0.47*_CompRad), i.uv.y);
				//quest marker is located on the digits texture, so shift and scale the uv's so the texture is centered properly
				WaypointUVs.x = 5.0*WaypointUVs.x + 0.25;
				WaypointUVs.y = 0.5*WaypointUVs.y;
				
				//Get final compass color.
				fixed4 waypointColor = step(0.2,WaypointUVs.x)*step(WaypointUVs.x,0.3)*tex2D(_DigitTex, WaypointUVs);
				fixed4 compassColor = tex2D(_CompTex, compassUVs);
				compassColor = lerp(compassColor, waypointColor, pow(waypointColor.a,0.5));
				
				//fade out the alpha towards the edges of the compass
				compassColor.a *= smoothstep(0,0.1,i.uv.x)*smoothstep(1,0.9,i.uv.x);
				 
				
				//--------------------------------------------------------------------------------------------
				// Add all the color values for each type to the final result
				//--------------------------------------------------------------------------------------------
				
				fixed4 hud = tex2D(_HudTex,i.uv);
				fixed4 hud2 = tex2D(_HudTex2,i.uv);
				fixed4 flipbook = tex2D(_FlipTex,i.uv);
				
				fixed4 finalcolor = fixed4(0,0,0,0);
				finalcolor += (i.type == 1 || i.type == 4)*minusColor;
				finalcolor += (i.type == 1 || i.type == 4)*digitColor;
				finalcolor += (i.type == 1 || i.type == 4)*step(8.0*dw, i.uv.x)*step(i.uv.x,8.5*dw)*decColor;
				finalcolor += (i.type == 0)*hud*_TintMain;
				finalcolor += (i.type == 2)*hud*_TintGiz;
				finalcolor += (i.type == 3)*compassColor*_TintComp;
				finalcolor += (i.type == 5)*clock_color;
				finalcolor += (i.type == 6)*hud2*_TintScnd;
				finalcolor += (i.type == 7)*flipbook*_TintFlip;
				clip(finalcolor.a - _clip);
				float holoAlpha = (0.5*sin(3.14159*(i.pos.y/_HoloWidth + _Time[1]*_HoloScroll)) + 0.5)*(1-_HoloDepth) + _HoloDepth;
				float4 noiseUvs = UNITY_PROJ_COORD(ComputeGrabScreenPos(i.pos));
				noiseUvs.xy = noiseUvs.xy*float2(_ScreenParams.xy*_NoiseTex_TexelSize.xy) / noiseUvs.w;
				noiseUvs.xy += float2(sin(_Time[1]*5.4),sin(_Time[1]*7.1));
				float4 noiseRGBA = tex2Dlod(_NoiseTex, float4(noiseUvs.x, noiseUvs.y,0.0,0.0));
				float noise = (1.0-_NoiseAlpha)*saturate(pow(1-noiseRGBA.r,_NoiseThresh)) + _NoiseAlpha;
				finalcolor.a = i.type != 6 ? finalcolor.a * holoAlpha * noise : finalcolor.a;

				return finalcolor;
            }
            ENDCG
        }
    }
}