#version 150 compatibility
#extension GL_EXT_geometry_shader4 : enable

layout(points) in;
layout(triangle_strip, max_vertices = 4) out;

uniform bool measure_point_size_in_pixel;
uniform float reference_point_size;

uniform bool orient_splats;
uniform float outline_width_from_pixel;
uniform float percentual_outline_width;
uniform float percentual_halo;
uniform float pixel_extent_per_depth;

in vec3 normal_gs[];
in vec4 color_gs[];

out vec3 normal;
out vec2 uv;
out vec4 color;
out vec3 position;

out float percentual_outline_start;
out float percentual_halo_start;
out float percentual_pixel_extent;
out float percentual_splat_size;
flat out int   side; // 0 is back facing and 1 is front facing

int surface_side_handling(in vec3 position, inout vec3 normal, inout vec4 color);

void emit_corner(in vec3 corner, in float u, in float v)
{
	position = corner;

	uv = vec2(u,v);

	// compute position in clip space
	gl_Position	   = gl_ProjectionMatrix * vec4(position,1.0);

	EmitVertex();
}

void main()
{
	// set color to color attribute
	color = color_gs[0];
	// transform normal to eye space
	normal = normalize(gl_NormalMatrix*(normal_gs[0]));
	// transform position to eye space
	vec3 position_eye = (gl_ModelViewMatrix*gl_PositionIn[0]).xyz;
	// sign of dot product between normal and view vector tells us side that we see
	float sign_indicator = dot(normal, position_eye);

	// determine side in eye space
	side = surface_side_handling(position_eye, normal, color);
	if (side == -1)
		return;

	// compute percentual size of splat and its radius
	float depth = abs(position_eye.z);
	float point_radius = 0.5 * gl_PointSizeIn[0];
	if (measure_point_size_in_pixel) {
		point_radius *= pixel_extent_per_depth * depth;
	}
	else {
		point_radius *= reference_point_size;
	}
	// compute percentage of one pixel with respect to point radius
	percentual_pixel_extent = pixel_extent_per_depth * depth / point_radius;
	float percentual_outline_width_final = max(percentual_outline_width, outline_width_from_pixel * percentual_pixel_extent);
	float percentual_halo_width_final = max(percentual_halo, outline_width_from_pixel * percentual_pixel_extent);
	// compute splat size to be one pixel larger than point plus outline
	percentual_splat_size    = 1.0 + 0.5 * (percentual_outline_width_final + percentual_pixel_extent);
	percentual_outline_start = 1.0 - 0.5 * (percentual_outline_width_final + percentual_pixel_extent);
	percentual_halo_start = 2.0;
	if (percentual_halo > 0.0)
		percentual_halo_start = 1.0 - 0.5 * (percentual_halo_width_final + percentual_pixel_extent);
	float splat_radius = point_radius * percentual_splat_size;

	// compute splat base vectors and scale by splat radius
	vec3 dx = vec3(1.0 ,0.0, 0.0);
	vec3 dy = vec3(0.0, 1.0, 0.0);

	if (orient_splats) {
		dx = normalize(cross(dy, normal));
		dy = cross(normal, dx);
	}
	dx *= splat_radius;
	dy *= splat_radius;

	// generate splat vertices
	emit_corner(position_eye + dx - dy,  percentual_splat_size, -percentual_splat_size);
	emit_corner(position_eye + dx + dy,  percentual_splat_size,  percentual_splat_size);
	emit_corner(position_eye - dx - dy, -percentual_splat_size, -percentual_splat_size);
	emit_corner(position_eye - dx + dy, -percentual_splat_size,  percentual_splat_size);
}
