Switched to fixed point in gles triangle rasterization, and fixed wrong offset curve check collapsing the internal control points
This commit is contained in:
		
							parent
							
								
									e0300e9e3c
								
							
						
					
					
						commit
						0796b2cbcd
					
				| 
						 | 
				
			
			@ -41,7 +41,7 @@ int main()
 | 
			
		|||
	mp_window_bring_to_front(window);
 | 
			
		||||
	mp_window_focus(window);
 | 
			
		||||
 | 
			
		||||
	f32 dx = 17.000029, dy = 0;
 | 
			
		||||
	f32 dx = 0, dy = 0;
 | 
			
		||||
 | 
			
		||||
	while(!mp_should_quit())
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -67,30 +67,27 @@ int main()
 | 
			
		|||
 | 
			
		||||
				case MP_EVENT_KEYBOARD_KEY:
 | 
			
		||||
				{
 | 
			
		||||
					printf("key %i: %s\n",
 | 
			
		||||
					        event.key.code,
 | 
			
		||||
					        event.key.action == MP_KEY_PRESS ? "press" : (event.key.action == MP_KEY_RELEASE ? "release" : "repeat"));
 | 
			
		||||
					if(event.key.action == MP_KEY_PRESS || event.key.action == MP_KEY_REPEAT)
 | 
			
		||||
					{
 | 
			
		||||
						if(event.key.code == MP_KEY_LEFT)
 | 
			
		||||
						{
 | 
			
		||||
							printf("left\n");
 | 
			
		||||
							dx-=0.1;
 | 
			
		||||
							dx-=1.1;
 | 
			
		||||
						}
 | 
			
		||||
						else if(event.key.code == MP_KEY_RIGHT)
 | 
			
		||||
						{
 | 
			
		||||
							printf("right\n");
 | 
			
		||||
							dx+=0.1;
 | 
			
		||||
							dx+=1.1;
 | 
			
		||||
						}
 | 
			
		||||
						else if(event.key.code == MP_KEY_UP)
 | 
			
		||||
						{
 | 
			
		||||
							printf("up\n");
 | 
			
		||||
							dy+=0.1;
 | 
			
		||||
							dy+=1.1;
 | 
			
		||||
						}
 | 
			
		||||
						else if(event.key.code == MP_KEY_DOWN)
 | 
			
		||||
						{
 | 
			
		||||
							printf("down\n");
 | 
			
		||||
							dy-=0.1;
 | 
			
		||||
							dy-=1.1;
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				} break;
 | 
			
		||||
| 
						 | 
				
			
			@ -102,12 +99,10 @@ int main()
 | 
			
		|||
 | 
			
		||||
		mg_surface_prepare(surface);
 | 
			
		||||
 | 
			
		||||
			printf("dx = %f, dy = %f\n", dx, dy);
 | 
			
		||||
 | 
			
		||||
			// background
 | 
			
		||||
			mg_set_color_rgba(1, 0, 1, 1);
 | 
			
		||||
			mg_clear();
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
			// head
 | 
			
		||||
			mg_set_color_rgba(1, 1, 0, 1);
 | 
			
		||||
			mg_circle_fill(dx+400, dy+300, 200);
 | 
			
		||||
| 
						 | 
				
			
			@ -123,8 +118,6 @@ int main()
 | 
			
		|||
			// eyes
 | 
			
		||||
			mg_ellipse_fill(dx+330, dy+350, 30, 50);
 | 
			
		||||
			mg_ellipse_fill(dx+470, dy+350, 30, 50);
 | 
			
		||||
*/
 | 
			
		||||
			mg_rectangle_fill((int)(dx + 200), 200, (int)(dy+300), (int)(dy+300));
 | 
			
		||||
 | 
			
		||||
			mg_flush();
 | 
			
		||||
		mg_surface_present(surface);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
https://fgiesen.wordpress.com/2013/02/08/triangle-rasterization-in-practice/
 | 
			
		||||
 | 
			
		||||
https://github.com/rygorous/trirast/blob/master/main.cpp
 | 
			
		||||
 | 
			
		||||
https://joshbeam.com/articles/triangle_rasterization/
 | 
			
		||||
 | 
			
		||||
https://nlguillemot.wordpress.com/2016/07/10/rasterizer-notes/
 | 
			
		||||
 | 
			
		||||
https://web.archive.org/web/20120625103536/http://devmaster.net/forums/topic/1145-advanced-rasterization/
 | 
			
		||||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
*
 | 
			
		||||
*	file: gles_canvas_shaders.h
 | 
			
		||||
*	note: string literals auto-generated by embed_text.py
 | 
			
		||||
*	date: 01/022023
 | 
			
		||||
*	date: 02/022023
 | 
			
		||||
*
 | 
			
		||||
**********************************************************************/
 | 
			
		||||
#ifndef __GLES_CANVAS_SHADERS_H__
 | 
			
		||||
| 
						 | 
				
			
			@ -36,32 +36,25 @@ const char* gles_canvas_fragment =
 | 
			
		|||
"layout(location = 0) uniform int indexCount;\n"
 | 
			
		||||
"layout(location = 0) out vec4 fragColor;\n"
 | 
			
		||||
"\n"
 | 
			
		||||
"bool is_top_left(vec2 a, vec2 b)\n"
 | 
			
		||||
"bool is_top_left(ivec2 a, ivec2 b)\n"
 | 
			
		||||
"{\n"
 | 
			
		||||
"	return( (a.y == b.y && b.x < a.x)\n"
 | 
			
		||||
"	      ||(b.y < a.y));\n"
 | 
			
		||||
"}\n"
 | 
			
		||||
"\n"
 | 
			
		||||
"float orient2d(vec2 a, vec2 b, vec2 c)\n"
 | 
			
		||||
"int orient2d(ivec2 a, ivec2 b, ivec2 p)\n"
 | 
			
		||||
"{\n"
 | 
			
		||||
"	//////////////////////////////////////////////////////////////////////////////////////////\n"
 | 
			
		||||
"	//TODO(martin): FIX this. This is a **horrible** quick hack to fix the precision issues\n"
 | 
			
		||||
"	//              arising when a, b, and c are close. But it degrades when a, c, and c\n"
 | 
			
		||||
"	//              are big. The proper solution is to change the expression to avoid\n"
 | 
			
		||||
"	//              precision loss but I'm too busy/lazy to do it now.\n"
 | 
			
		||||
"	//////////////////////////////////////////////////////////////////////////////////////////\n"
 | 
			
		||||
"	a *= 10.;\n"
 | 
			
		||||
"	b *= 10.;\n"
 | 
			
		||||
"	c *= 10.;\n"
 | 
			
		||||
"	return((b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x));\n"
 | 
			
		||||
"	return((b.x-a.x)*(p.y-a.y) - (b.y-a.y)*(p.x-a.x));\n"
 | 
			
		||||
"}\n"
 | 
			
		||||
"\n"
 | 
			
		||||
"void main()\n"
 | 
			
		||||
"{\n"
 | 
			
		||||
"	float subPixelFactor = 16.;\n"
 | 
			
		||||
"\n"
 | 
			
		||||
"    vec4 pixelColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
 | 
			
		||||
"    vec4 currentColor = vec4(0., 0., 0., 1.0);\n"
 | 
			
		||||
"\n"
 | 
			
		||||
"	vec2 samplePoint = gl_FragCoord.xy;\n"
 | 
			
		||||
"	ivec2 samplePoint = ivec2(gl_FragCoord.xy * subPixelFactor + vec2(0.5, 0.5));\n"
 | 
			
		||||
"\n"
 | 
			
		||||
"    int currentZIndex = -1;\n"
 | 
			
		||||
"    int flipCount = 0;\n"
 | 
			
		||||
| 
						 | 
				
			
			@ -73,22 +66,22 @@ const char* gles_canvas_fragment =
 | 
			
		|||
"		uint i1 = indexBuffer.elements[i+1];\n"
 | 
			
		||||
"		uint i2 = indexBuffer.elements[i+2];\n"
 | 
			
		||||
"\n"
 | 
			
		||||
"		vec2 p0 = vertexBuffer.elements[i0].pos;\n"
 | 
			
		||||
"		vec2 p1 = vertexBuffer.elements[i1].pos;\n"
 | 
			
		||||
"		vec2 p2 = vertexBuffer.elements[i2].pos;\n"
 | 
			
		||||
"		ivec2 p0 = ivec2(vertexBuffer.elements[i0].pos * subPixelFactor + vec2(0.5, 0.5));\n"
 | 
			
		||||
"		ivec2 p1 = ivec2(vertexBuffer.elements[i1].pos * subPixelFactor + vec2(0.5, 0.5));\n"
 | 
			
		||||
"		ivec2 p2 = ivec2(vertexBuffer.elements[i2].pos * subPixelFactor + vec2(0.5, 0.5));\n"
 | 
			
		||||
"\n"
 | 
			
		||||
"		int zIndex = vertexBuffer.elements[i0].zIndex;\n"
 | 
			
		||||
"		vec4 color = vertexBuffer.elements[i0].color;\n"
 | 
			
		||||
"\n"
 | 
			
		||||
"		//NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge\n"
 | 
			
		||||
"		float cw = (p1 - p0).x*(p2 - p0).y - (p1 - p0).y*(p2 - p0).x;\n"
 | 
			
		||||
"		if(cw < 0.)\n"
 | 
			
		||||
"		int cw = (p1 - p0).x*(p2 - p0).y - (p1 - p0).y*(p2 - p0).x;\n"
 | 
			
		||||
"		if(cw < 0)\n"
 | 
			
		||||
"		{\n"
 | 
			
		||||
"			uint tmpIndex = i1;\n"
 | 
			
		||||
"			i1 = i2;\n"
 | 
			
		||||
"			i2 = tmpIndex;\n"
 | 
			
		||||
"\n"
 | 
			
		||||
"			vec2 tmpPoint = p1;\n"
 | 
			
		||||
"			ivec2 tmpPoint = p1;\n"
 | 
			
		||||
"			p1 = p2;\n"
 | 
			
		||||
"			p2 = tmpPoint;\n"
 | 
			
		||||
"		}\n"
 | 
			
		||||
| 
						 | 
				
			
			@ -101,14 +94,13 @@ const char* gles_canvas_fragment =
 | 
			
		|||
"		int bias1 = is_top_left(p2, p0) ? 0 : -1;\n"
 | 
			
		||||
"		int bias2 = is_top_left(p0, p1) ? 0 : -1;\n"
 | 
			
		||||
"\n"
 | 
			
		||||
"		float w0 = orient2d(p1, p2, samplePoint);\n"
 | 
			
		||||
"		float w1 = orient2d(p2, p0, samplePoint);\n"
 | 
			
		||||
"		float w2 = orient2d(p0, p1, samplePoint);\n"
 | 
			
		||||
"		int w0 = orient2d(p1, p2, samplePoint);\n"
 | 
			
		||||
"		int w1 = orient2d(p2, p0, samplePoint);\n"
 | 
			
		||||
"		int w2 = orient2d(p0, p1, samplePoint);\n"
 | 
			
		||||
"\n"
 | 
			
		||||
"		if((int(w0)+bias0) >= 0 && (int(w1)+bias1) >= 0 && (int(w2)+bias2) >= 0)\n"
 | 
			
		||||
"		if((w0+bias0) >= 0 && (w1+bias1) >= 0 && (w2+bias2) >= 0)\n"
 | 
			
		||||
"		{\n"
 | 
			
		||||
"			//TODO check cubic\n"
 | 
			
		||||
"			vec4 cubic = (cubic0*w0 + cubic1*w1 + cubic2*w2)/(w0+w1+w2);\n"
 | 
			
		||||
"			vec4 cubic = (cubic0*float(w0) + cubic1*float(w1) + cubic2*float(w2))/(float(w0)+float(w1)+float(w2));\n"
 | 
			
		||||
"\n"
 | 
			
		||||
"			float eps = 0.0001;\n"
 | 
			
		||||
"			if(cubic.w*(cubic.x*cubic.x*cubic.x - cubic.y*cubic.z) <= eps)\n"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,32 +23,25 @@ layout(binding = 1) buffer indexBufferSSBO {
 | 
			
		|||
layout(location = 0) uniform int indexCount;
 | 
			
		||||
layout(location = 0) out vec4 fragColor;
 | 
			
		||||
 | 
			
		||||
bool is_top_left(vec2 a, vec2 b)
 | 
			
		||||
bool is_top_left(ivec2 a, ivec2 b)
 | 
			
		||||
{
 | 
			
		||||
	return( (a.y == b.y && b.x < a.x)
 | 
			
		||||
	      ||(b.y < a.y));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float orient2d(vec2 a, vec2 b, vec2 c)
 | 
			
		||||
int orient2d(ivec2 a, ivec2 b, ivec2 p)
 | 
			
		||||
{
 | 
			
		||||
	//////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
	//TODO(martin): FIX this. This is a **horrible** quick hack to fix the precision issues
 | 
			
		||||
	//              arising when a, b, and c are close. But it degrades when a, c, and c
 | 
			
		||||
	//              are big. The proper solution is to change the expression to avoid
 | 
			
		||||
	//              precision loss but I'm too busy/lazy to do it now.
 | 
			
		||||
	//////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
	a *= 10.;
 | 
			
		||||
	b *= 10.;
 | 
			
		||||
	c *= 10.;
 | 
			
		||||
	return((b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x));
 | 
			
		||||
	return((b.x-a.x)*(p.y-a.y) - (b.y-a.y)*(p.x-a.x));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void main()
 | 
			
		||||
{
 | 
			
		||||
	float subPixelFactor = 16.;
 | 
			
		||||
 | 
			
		||||
    vec4 pixelColor = vec4(0.0, 1.0, 0.0, 1.0);
 | 
			
		||||
    vec4 currentColor = vec4(0., 0., 0., 1.0);
 | 
			
		||||
 | 
			
		||||
	vec2 samplePoint = gl_FragCoord.xy;
 | 
			
		||||
	ivec2 samplePoint = ivec2(gl_FragCoord.xy * subPixelFactor + vec2(0.5, 0.5));
 | 
			
		||||
 | 
			
		||||
    int currentZIndex = -1;
 | 
			
		||||
    int flipCount = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -60,22 +53,22 @@ void main()
 | 
			
		|||
		uint i1 = indexBuffer.elements[i+1];
 | 
			
		||||
		uint i2 = indexBuffer.elements[i+2];
 | 
			
		||||
 | 
			
		||||
		vec2 p0 = vertexBuffer.elements[i0].pos;
 | 
			
		||||
		vec2 p1 = vertexBuffer.elements[i1].pos;
 | 
			
		||||
		vec2 p2 = vertexBuffer.elements[i2].pos;
 | 
			
		||||
		ivec2 p0 = ivec2(vertexBuffer.elements[i0].pos * subPixelFactor + vec2(0.5, 0.5));
 | 
			
		||||
		ivec2 p1 = ivec2(vertexBuffer.elements[i1].pos * subPixelFactor + vec2(0.5, 0.5));
 | 
			
		||||
		ivec2 p2 = ivec2(vertexBuffer.elements[i2].pos * subPixelFactor + vec2(0.5, 0.5));
 | 
			
		||||
 | 
			
		||||
		int zIndex = vertexBuffer.elements[i0].zIndex;
 | 
			
		||||
		vec4 color = vertexBuffer.elements[i0].color;
 | 
			
		||||
 | 
			
		||||
		//NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge
 | 
			
		||||
		float cw = (p1 - p0).x*(p2 - p0).y - (p1 - p0).y*(p2 - p0).x;
 | 
			
		||||
		if(cw < 0.)
 | 
			
		||||
		int cw = (p1 - p0).x*(p2 - p0).y - (p1 - p0).y*(p2 - p0).x;
 | 
			
		||||
		if(cw < 0)
 | 
			
		||||
		{
 | 
			
		||||
			uint tmpIndex = i1;
 | 
			
		||||
			i1 = i2;
 | 
			
		||||
			i2 = tmpIndex;
 | 
			
		||||
 | 
			
		||||
			vec2 tmpPoint = p1;
 | 
			
		||||
			ivec2 tmpPoint = p1;
 | 
			
		||||
			p1 = p2;
 | 
			
		||||
			p2 = tmpPoint;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -88,14 +81,13 @@ void main()
 | 
			
		|||
		int bias1 = is_top_left(p2, p0) ? 0 : -1;
 | 
			
		||||
		int bias2 = is_top_left(p0, p1) ? 0 : -1;
 | 
			
		||||
 | 
			
		||||
		float w0 = orient2d(p1, p2, samplePoint);
 | 
			
		||||
		float w1 = orient2d(p2, p0, samplePoint);
 | 
			
		||||
		float w2 = orient2d(p0, p1, samplePoint);
 | 
			
		||||
		int w0 = orient2d(p1, p2, samplePoint);
 | 
			
		||||
		int w1 = orient2d(p2, p0, samplePoint);
 | 
			
		||||
		int w2 = orient2d(p0, p1, samplePoint);
 | 
			
		||||
 | 
			
		||||
		if((int(w0)+bias0) >= 0 && (int(w1)+bias1) >= 0 && (int(w2)+bias2) >= 0)
 | 
			
		||||
		if((w0+bias0) >= 0 && (w1+bias1) >= 0 && (w2+bias2) >= 0)
 | 
			
		||||
		{
 | 
			
		||||
			//TODO check cubic
 | 
			
		||||
			vec4 cubic = (cubic0*w0 + cubic1*w1 + cubic2*w2)/(w0+w1+w2);
 | 
			
		||||
			vec4 cubic = (cubic0*float(w0) + cubic1*float(w1) + cubic2*float(w2))/(float(w0)+float(w1)+float(w2));
 | 
			
		||||
 | 
			
		||||
			float eps = 0.0001;
 | 
			
		||||
			if(cubic.w*(cubic.x*cubic.x*cubic.x - cubic.y*cubic.z) <= eps)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1154,7 +1154,7 @@ void mg_offset_hull(int count, vec2* p, vec2* result, f32 offset)
 | 
			
		|||
{
 | 
			
		||||
//////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
//WARN: quick fix for coincident middle control points
 | 
			
		||||
	if(count == 4 && (p[1].x - p[2].x < 0.01) && (p[1].y - p[2].y < 0.01))
 | 
			
		||||
	if(count == 4 && (fabs(p[1].x - p[2].x) < 0.01) && (fabs(p[1].y - p[2].y) < 0.01))
 | 
			
		||||
	{
 | 
			
		||||
		vec2 hull3[3] = {p[0], p[1], p[3]};
 | 
			
		||||
		vec2 result3[3];
 | 
			
		||||
| 
						 | 
				
			
			@ -1284,6 +1284,7 @@ void mg_render_stroke_quadratic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, m
 | 
			
		|||
	//
 | 
			
		||||
	//		we compute the maximum overshoot outside these bounds and split the curve at the corresponding parameter
 | 
			
		||||
 | 
			
		||||
	//TODO: maybe refactor by using tolerance in the _check_, not in the computation of the overshoot
 | 
			
		||||
	f32 tolerance = minimum(attributes->tolerance, 0.5 * attributes->width);
 | 
			
		||||
	f32 d2LowBound = Square(0.5 * attributes->width - attributes->tolerance);
 | 
			
		||||
	f32 d2HighBound = Square(0.5 * attributes->width + attributes->tolerance);
 | 
			
		||||
| 
						 | 
				
			
			@ -1316,7 +1317,6 @@ void mg_render_stroke_quadratic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, m
 | 
			
		|||
 | 
			
		||||
	if(maxOvershoot > 0)
 | 
			
		||||
	{
 | 
			
		||||
		//TODO(martin): split at maxErrorParameter and recurse
 | 
			
		||||
		vec2 splitLeft[3];
 | 
			
		||||
		vec2 splitRight[3];
 | 
			
		||||
		mg_quadratic_split(p, maxOvershootParameter, splitLeft, splitRight);
 | 
			
		||||
| 
						 | 
				
			
			@ -1442,6 +1442,7 @@ void mg_render_stroke_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_at
 | 
			
		|||
	//
 | 
			
		||||
	//		we compute the maximum overshoot outside these bounds and split the curve at the corresponding parameter
 | 
			
		||||
 | 
			
		||||
	//TODO: maybe refactor by using tolerance in the _check_, not in the computation of the overshoot
 | 
			
		||||
	f32 tolerance = minimum(attributes->tolerance, 0.5 * attributes->width);
 | 
			
		||||
	f32 d2LowBound = Square(0.5 * attributes->width - attributes->tolerance);
 | 
			
		||||
	f32 d2HighBound = Square(0.5 * attributes->width + attributes->tolerance);
 | 
			
		||||
| 
						 | 
				
			
			@ -1474,17 +1475,17 @@ void mg_render_stroke_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_at
 | 
			
		|||
 | 
			
		||||
	if(maxOvershoot > 0)
 | 
			
		||||
	{
 | 
			
		||||
		//TODO(martin): split at maxErrorParameter and recurse
 | 
			
		||||
		vec2 splitLeft[4];
 | 
			
		||||
		vec2 splitRight[4];
 | 
			
		||||
		mg_cubic_split(p, maxOvershootParameter, splitLeft, splitRight);
 | 
			
		||||
		mg_render_stroke_cubic(canvas, splitLeft, zIndex, attributes);
 | 
			
		||||
		mg_render_stroke_cubic(canvas, splitRight, zIndex, attributes);
 | 
			
		||||
 | 
			
		||||
		//TODO: render joint between the split curves
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		//NOTE(martin): push the actual fill commands for the offset contour
 | 
			
		||||
 | 
			
		||||
		u32 zIndex = mg_get_next_z_index(canvas);
 | 
			
		||||
 | 
			
		||||
		mg_render_fill_cubic(canvas, positiveOffsetHull, zIndex, attributes->color);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										408
									
								
								todo.txt
								
								
								
								
							
							
						
						
									
										408
									
								
								todo.txt
								
								
								
								
							| 
						 | 
				
			
			@ -1,198 +1,210 @@
 | 
			
		|||
 | 
			
		||||
[.] Check changes in macos version
 | 
			
		||||
	[x] Restructure macos version to use mp_app_internal.h/mp_app.c
 | 
			
		||||
	[x] test new run loop structure on macos
 | 
			
		||||
	[x] Fix resize crash when there's no surface
 | 
			
		||||
	[>] separate data for key and mouse event?
 | 
			
		||||
	[>] Simplify event structs
 | 
			
		||||
		[ ] use isARepeat in macos keyDown event and simplify update key state
 | 
			
		||||
 | 
			
		||||
	[x] use surfaces to define restricted drawing locations
 | 
			
		||||
		[x] Implement with NSView subviews on osx
 | 
			
		||||
			[/] Maybe switch to just using CALayers?
 | 
			
		||||
 | 
			
		||||
	[ ] Cleanup graphics backend compile-time/runtime selection
 | 
			
		||||
	[ ] Cleanup graphics resource handles
 | 
			
		||||
 | 
			
		||||
[>>] OpenGL surface on OSX
 | 
			
		||||
[>>] Port vector graphics to OpenGL on OSX
 | 
			
		||||
[>] Check OpenGL vector graphics on win32
 | 
			
		||||
[ ] Implement surfaces with child windows on win32
 | 
			
		||||
	[/] Maybe implement compositing directly in d3d and opengl compat extension...
 | 
			
		||||
 | 
			
		||||
Windows port
 | 
			
		||||
------------
 | 
			
		||||
[.] Finish events handling
 | 
			
		||||
	[x] window
 | 
			
		||||
	[x] mouse move/buttons/enter/leave
 | 
			
		||||
	[x] mouse wheel
 | 
			
		||||
	[.] keys
 | 
			
		||||
		[!] set key label
 | 
			
		||||
	[x] text input
 | 
			
		||||
	[/] pathdrop
 | 
			
		||||
 | 
			
		||||
[x] Unify app struct and window structs for different platforms?
 | 
			
		||||
	> define common app and window struct in mp_app_internal.h
 | 
			
		||||
	> this file conditionally includes platform specific headers, win32_app.h, osx_app.h, etc...
 | 
			
		||||
	> these define a macro to fill the common app and window structures with platform specific stuff.
 | 
			
		||||
	> Common app/window proc are defined in mp_app.c
 | 
			
		||||
	> Platform specific stuff is defined in platform specific files win32_app.c, osx_app.m, etc...
 | 
			
		||||
	(mp_app.c can 'see' platform specific stuff, so ObjectiveC defs pose a problem, but we can define id as void*
 | 
			
		||||
	when not in ObjC...)
 | 
			
		||||
 | 
			
		||||
[.] Implement input polling
 | 
			
		||||
	[ ] Simplify input polling API names
 | 
			
		||||
	[/] Try to simplify input state and polling once we have UI usage code
 | 
			
		||||
 | 
			
		||||
[ ] Finish win32 window create flags and properties query/setting
 | 
			
		||||
 | 
			
		||||
[ ] Implement clipboard
 | 
			
		||||
[ ] Implement file dialogs
 | 
			
		||||
[ ] Impement resource path... -> maybe in abstracted file handling
 | 
			
		||||
 | 
			
		||||
[ ] Clean backend selection (compile time and runtime)
 | 
			
		||||
[ ] Finish OpenGL loader
 | 
			
		||||
[ ] Test compute shaders
 | 
			
		||||
[ ] Initial version of vector graphics backend
 | 
			
		||||
[ ] Check integration of UI.
 | 
			
		||||
 | 
			
		||||
[ ] Remove unused APIs
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Misc
 | 
			
		||||
----
 | 
			
		||||
[ ] Clean-up file structure
 | 
			
		||||
	[ ] Move stb libs to ext/
 | 
			
		||||
 | 
			
		||||
[ ] Renaming/clean-up pass
 | 
			
		||||
	[ ] Separate Internal/API functions in mp_app.c
 | 
			
		||||
	[ ] Remove MP_EVENT_KEYBOARD_MODS
 | 
			
		||||
	[ ] Rename MP_EVENT_HIDE/SHOW to MINMIZE/UNMINIMIZE
 | 
			
		||||
	[ ] Remove frame
 | 
			
		||||
	[ ] Remove sequence from char event?
 | 
			
		||||
	[ ] Replace frame_event with mp_rect
 | 
			
		||||
	[ ] Document/unify quit/request_quit etc
 | 
			
		||||
	[ ] Document/unify close/request_close etc
 | 
			
		||||
	[ ] Cleanup window management
 | 
			
		||||
	[ ] Remove unused run loop constructs
 | 
			
		||||
	[ ]
 | 
			
		||||
 | 
			
		||||
Shortlist
 | 
			
		||||
---------
 | 
			
		||||
[x] let pass flat args in ui_size_push() and ui_box_set_size()
 | 
			
		||||
[x] separate style stacks
 | 
			
		||||
[x] animation time stack
 | 
			
		||||
[>] margins? as part of size, or different styling stack?
 | 
			
		||||
 | 
			
		||||
[ ] Let build code set target style directly, and animate from current to target
 | 
			
		||||
[ ] filter styles stack by tag
 | 
			
		||||
[ ] image backgrounds/gradients?
 | 
			
		||||
[ ] animating open/close widgets?
 | 
			
		||||
 | 
			
		||||
[.] Text box widget
 | 
			
		||||
	[ ] Draw selection
 | 
			
		||||
	[ ] Set cursor on click
 | 
			
		||||
	[ ] Scroll to cursor
 | 
			
		||||
 | 
			
		||||
Canvas Drawing
 | 
			
		||||
--------------
 | 
			
		||||
[.] Correctly handle resizing / viewport
 | 
			
		||||
	[x] associate surfaces with mp_windows
 | 
			
		||||
	[x] window resize resizes surface. Surface always renders to whole mp_window
 | 
			
		||||
	[x] Add ability to create sub-views, and create surfaces for these
 | 
			
		||||
		- window comes with a main view, so we can get a surface for the whole window
 | 
			
		||||
	[>] Clean native mp_window_data struct (don't need to cache a lot of stuff here)
 | 
			
		||||
 | 
			
		||||
[.] Add images bliting
 | 
			
		||||
	[x] Clean, rename uv vs texUV stuff
 | 
			
		||||
	[>] Destroy stuff
 | 
			
		||||
	[>] More unified handle system
 | 
			
		||||
	[.] Rounded images (sortof)
 | 
			
		||||
	[ ] path clipped images
 | 
			
		||||
 | 
			
		||||
[ ] Add color gradients?
 | 
			
		||||
[ ] Make canvas implicit?
 | 
			
		||||
[/] Handle based error signaling
 | 
			
		||||
[/] Allow polling events in main thread, and updating/rendering in background thread.
 | 
			
		||||
 | 
			
		||||
[x] font metrics shouldn't depend on surface, & font
 | 
			
		||||
    shouldn't really depend on canvas either???
 | 
			
		||||
	> meaning we should be able to pass fonts without canvas in ui
 | 
			
		||||
	> and only pass canvas when drawing at the end...
 | 
			
		||||
 | 
			
		||||
UI
 | 
			
		||||
--
 | 
			
		||||
[x] Make gui context implicit?
 | 
			
		||||
[x] Uniform ui_box struct + cache widgets
 | 
			
		||||
[x] Prune unused boxes
 | 
			
		||||
[.] Layout boxes
 | 
			
		||||
	[x] basic two pass layout
 | 
			
		||||
	[x] Layout from start or end
 | 
			
		||||
	[>] Add overflow flags to layout, & solve conflicts
 | 
			
		||||
 | 
			
		||||
[x] Temporarily push transform and text flip when rendering UI, so that the coord system is y down, origin at top left
 | 
			
		||||
[x] Canvas render the same size on a high-dpi surface
 | 
			
		||||
	> it works with abstract 'pixel' units, which are transformed to pixels in the shader, according to backing store scaling
 | 
			
		||||
 | 
			
		||||
[.] Style struct and style stack
 | 
			
		||||
	[ ] Maybe use individual stack for different style attributes
 | 
			
		||||
[x] Pass initial style in ui_begin_frame()
 | 
			
		||||
 | 
			
		||||
[.] Draw boxes
 | 
			
		||||
	[x] use flags to enable/disable drawing each feature
 | 
			
		||||
	[ ] active/hovered transitions
 | 
			
		||||
 | 
			
		||||
[x] Change input state handling a move it to app layer
 | 
			
		||||
[x] Compute signals for ui_box
 | 
			
		||||
[x] Use ui_size_push() and pass axis instead of ui_width/height_push()
 | 
			
		||||
[>] Use value is ui_size as margin when kind == text or == children?
 | 
			
		||||
 | 
			
		||||
[ ] Allow animating sizes according to hot/active?
 | 
			
		||||
 | 
			
		||||
[ ] Basic helpers
 | 
			
		||||
	[.] button
 | 
			
		||||
	[.] slider (or rather, scroll bar)
 | 
			
		||||
	[.] simple spacers
 | 
			
		||||
		[ ] have a flag for non-cached stuff
 | 
			
		||||
	[.] scrolling panel
 | 
			
		||||
		[ ] Allow/disallow scrolling in x/y
 | 
			
		||||
		[ ] Scroll with mousewheel
 | 
			
		||||
		[/] add margins to scrollbars (disallow scrollbars crossing)
 | 
			
		||||
 | 
			
		||||
[?] Maybe let builder code handle "active"/"hot" state, since it
 | 
			
		||||
    depends on the widgets
 | 
			
		||||
    [ ] On the other hand, this state must be set before layouting, in
 | 
			
		||||
        particular font/fontSize -> maybe do a pass for static layout,
 | 
			
		||||
        instead of doing it in box creation...
 | 
			
		||||
    [ ] this way we can compute styling after user has set active/hot, but before layout
 | 
			
		||||
	> Maybe just let user set style selector, and provide persistent state bits that can
 | 
			
		||||
	> be used in any way? (to replace eg active/hot?) or perhaps not needed if we have just
 | 
			
		||||
	> 'dragging' state
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[x] Mask mouse outside of parent rects -> maintain clip stack and clip mouse against it
 | 
			
		||||
[x] Mask mouse below panels/other widgets
 | 
			
		||||
[x] popups and tooltips
 | 
			
		||||
	[x] allow pushing/popping boxes irrespective of parent/child relation
 | 
			
		||||
	[x] ui_begin_frame() prepares two containers, user ui goes in the first one
 | 
			
		||||
	[x] tooltips and menus go to the second one
 | 
			
		||||
	[x] Add menus
 | 
			
		||||
[ ] line editing widget
 | 
			
		||||
 | 
			
		||||
Misc
 | 
			
		||||
----
 | 
			
		||||
[x] Split metal surface and metal painter (but put them in the same compilation unit?)
 | 
			
		||||
[x] Have only one rect struct
 | 
			
		||||
[x] Shorten mp_string to str8
 | 
			
		||||
 | 
			
		||||
[ ] Better/Simpler time API
 | 
			
		||||
 | 
			
		||||
[/] Frame throttling
 | 
			
		||||
	[x] For now, we always wait on vblank during mg_surface_present(), regardless of target fps
 | 
			
		||||
	[ ] Then actually get the correct display interval from the surface's current monitor
 | 
			
		||||
	[ ] Allow waiting for more display interval than one? (ie allow throttling at 30fps for a 60fps display)
 | 
			
		||||
 | 
			
		||||
[/] split osx_app and move all platform independant stuff outside
 | 
			
		||||
 | 
			
		||||
[ ] Sort out mg_matrix_push/pop() -> transform vs. set...
 | 
			
		||||
 | 
			
		||||
[.] Check changes in macos version
 | 
			
		||||
	[x] Restructure macos version to use mp_app_internal.h/mp_app.c
 | 
			
		||||
	[x] test new run loop structure on macos
 | 
			
		||||
	[x] Fix resize crash when there's no surface
 | 
			
		||||
	[>] separate data for key and mouse event?
 | 
			
		||||
	[>] Simplify event structs
 | 
			
		||||
		[ ] use isARepeat in macos keyDown event and simplify update key state
 | 
			
		||||
 | 
			
		||||
	[x] use surfaces to define restricted drawing locations
 | 
			
		||||
		[x] Implement with NSView subviews on osx
 | 
			
		||||
			[/] Maybe switch to just using CALayers?
 | 
			
		||||
 | 
			
		||||
	[ ] Cleanup graphics backend compile-time/runtime selection
 | 
			
		||||
	[ ] Cleanup graphics resource handles
 | 
			
		||||
 | 
			
		||||
[.] GLES 3.0 surface on OSX
 | 
			
		||||
[x] GLES 3.1 surface on Win32
 | 
			
		||||
[.] GLES vector graphics on win32
 | 
			
		||||
	[x] Fix triangle rasterization precision issues
 | 
			
		||||
		-> we do not want to snap vertex coordinates to integers though, but use fixed point with 4 or 8 bits of subpixel precision
 | 
			
		||||
		-> convert verts pos to fixed point
 | 
			
		||||
		-> do orient2d in fixed point
 | 
			
		||||
	[!] Check precision/possible overflow when using barycentric coords
 | 
			
		||||
 | 
			
		||||
	[>>] Investigate cubics flipping when curves are disabled
 | 
			
		||||
	[>>] Investigate bad curve splitting on the right?
 | 
			
		||||
	[ ] Multi-sampling
 | 
			
		||||
 | 
			
		||||
	[>] Avoid first useless (degenerate) triangle on every path
 | 
			
		||||
 | 
			
		||||
[ ] Implement surfaces with child windows on win32
 | 
			
		||||
	[/] Maybe implement compositing directly in d3d and opengl compat extension...
 | 
			
		||||
 | 
			
		||||
Windows port
 | 
			
		||||
------------
 | 
			
		||||
[.] Finish events handling
 | 
			
		||||
	[x] window
 | 
			
		||||
	[x] mouse move/buttons/enter/leave
 | 
			
		||||
	[x] mouse wheel
 | 
			
		||||
	[.] keys
 | 
			
		||||
		[!] set key label
 | 
			
		||||
	[x] text input
 | 
			
		||||
	[/] pathdrop
 | 
			
		||||
 | 
			
		||||
[x] Unify app struct and window structs for different platforms?
 | 
			
		||||
	> define common app and window struct in mp_app_internal.h
 | 
			
		||||
	> this file conditionally includes platform specific headers, win32_app.h, osx_app.h, etc...
 | 
			
		||||
	> these define a macro to fill the common app and window structures with platform specific stuff.
 | 
			
		||||
	> Common app/window proc are defined in mp_app.c
 | 
			
		||||
	> Platform specific stuff is defined in platform specific files win32_app.c, osx_app.m, etc...
 | 
			
		||||
	(mp_app.c can 'see' platform specific stuff, so ObjectiveC defs pose a problem, but we can define id as void*
 | 
			
		||||
	when not in ObjC...)
 | 
			
		||||
 | 
			
		||||
[.] Implement input polling
 | 
			
		||||
	[ ] Simplify input polling API names
 | 
			
		||||
	[/] Try to simplify input state and polling once we have UI usage code
 | 
			
		||||
 | 
			
		||||
[ ] Finish win32 window create flags and properties query/setting
 | 
			
		||||
 | 
			
		||||
[ ] Implement clipboard
 | 
			
		||||
[ ] Implement file dialogs
 | 
			
		||||
[ ] Impement resource path... -> maybe in abstracted file handling
 | 
			
		||||
 | 
			
		||||
[ ] Clean backend selection (compile time and runtime)
 | 
			
		||||
[ ] Finish OpenGL loader
 | 
			
		||||
[ ] Test compute shaders
 | 
			
		||||
[ ] Initial version of vector graphics backend
 | 
			
		||||
[ ] Check integration of UI.
 | 
			
		||||
 | 
			
		||||
[ ] Remove unused APIs
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Misc
 | 
			
		||||
----
 | 
			
		||||
[ ] Clean-up file structure
 | 
			
		||||
	[ ] Move stb libs to ext/
 | 
			
		||||
 | 
			
		||||
[ ] Renaming/clean-up pass
 | 
			
		||||
	[ ] Separate Internal/API functions in mp_app.c
 | 
			
		||||
	[ ] Remove MP_EVENT_KEYBOARD_MODS
 | 
			
		||||
	[ ] Rename MP_EVENT_HIDE/SHOW to MINMIZE/UNMINIMIZE
 | 
			
		||||
	[ ] Remove frame
 | 
			
		||||
	[ ] Remove sequence from char event?
 | 
			
		||||
	[ ] Replace frame_event with mp_rect
 | 
			
		||||
	[ ] Document/unify quit/request_quit etc
 | 
			
		||||
	[ ] Document/unify close/request_close etc
 | 
			
		||||
	[ ] Cleanup window management
 | 
			
		||||
	[ ] Remove unused run loop constructs
 | 
			
		||||
	[ ]
 | 
			
		||||
 | 
			
		||||
Shortlist
 | 
			
		||||
---------
 | 
			
		||||
[x] let pass flat args in ui_size_push() and ui_box_set_size()
 | 
			
		||||
[x] separate style stacks
 | 
			
		||||
[x] animation time stack
 | 
			
		||||
[>] margins? as part of size, or different styling stack?
 | 
			
		||||
 | 
			
		||||
[ ] Let build code set target style directly, and animate from current to target
 | 
			
		||||
[ ] filter styles stack by tag
 | 
			
		||||
[ ] image backgrounds/gradients?
 | 
			
		||||
[ ] animating open/close widgets?
 | 
			
		||||
 | 
			
		||||
[.] Text box widget
 | 
			
		||||
	[ ] Draw selection
 | 
			
		||||
	[ ] Set cursor on click
 | 
			
		||||
	[ ] Scroll to cursor
 | 
			
		||||
 | 
			
		||||
Canvas Drawing
 | 
			
		||||
--------------
 | 
			
		||||
[.] Correctly handle resizing / viewport
 | 
			
		||||
	[x] associate surfaces with mp_windows
 | 
			
		||||
	[x] window resize resizes surface. Surface always renders to whole mp_window
 | 
			
		||||
	[x] Add ability to create sub-views, and create surfaces for these
 | 
			
		||||
		- window comes with a main view, so we can get a surface for the whole window
 | 
			
		||||
	[>] Clean native mp_window_data struct (don't need to cache a lot of stuff here)
 | 
			
		||||
 | 
			
		||||
[.] Add images bliting
 | 
			
		||||
	[x] Clean, rename uv vs texUV stuff
 | 
			
		||||
	[>] Destroy stuff
 | 
			
		||||
	[>] More unified handle system
 | 
			
		||||
	[.] Rounded images (sortof)
 | 
			
		||||
	[ ] path clipped images
 | 
			
		||||
 | 
			
		||||
[ ] Add color gradients?
 | 
			
		||||
[ ] Make canvas implicit?
 | 
			
		||||
[/] Handle based error signaling
 | 
			
		||||
[/] Allow polling events in main thread, and updating/rendering in background thread.
 | 
			
		||||
 | 
			
		||||
[x] font metrics shouldn't depend on surface, & font
 | 
			
		||||
    shouldn't really depend on canvas either???
 | 
			
		||||
	> meaning we should be able to pass fonts without canvas in ui
 | 
			
		||||
	> and only pass canvas when drawing at the end...
 | 
			
		||||
 | 
			
		||||
UI
 | 
			
		||||
--
 | 
			
		||||
[x] Make gui context implicit?
 | 
			
		||||
[x] Uniform ui_box struct + cache widgets
 | 
			
		||||
[x] Prune unused boxes
 | 
			
		||||
[.] Layout boxes
 | 
			
		||||
	[x] basic two pass layout
 | 
			
		||||
	[x] Layout from start or end
 | 
			
		||||
	[>] Add overflow flags to layout, & solve conflicts
 | 
			
		||||
 | 
			
		||||
[x] Temporarily push transform and text flip when rendering UI, so that the coord system is y down, origin at top left
 | 
			
		||||
[x] Canvas render the same size on a high-dpi surface
 | 
			
		||||
	> it works with abstract 'pixel' units, which are transformed to pixels in the shader, according to backing store scaling
 | 
			
		||||
 | 
			
		||||
[.] Style struct and style stack
 | 
			
		||||
	[ ] Maybe use individual stack for different style attributes
 | 
			
		||||
[x] Pass initial style in ui_begin_frame()
 | 
			
		||||
 | 
			
		||||
[.] Draw boxes
 | 
			
		||||
	[x] use flags to enable/disable drawing each feature
 | 
			
		||||
	[ ] active/hovered transitions
 | 
			
		||||
 | 
			
		||||
[x] Change input state handling a move it to app layer
 | 
			
		||||
[x] Compute signals for ui_box
 | 
			
		||||
[x] Use ui_size_push() and pass axis instead of ui_width/height_push()
 | 
			
		||||
[>] Use value is ui_size as margin when kind == text or == children?
 | 
			
		||||
 | 
			
		||||
[ ] Allow animating sizes according to hot/active?
 | 
			
		||||
 | 
			
		||||
[ ] Basic helpers
 | 
			
		||||
	[.] button
 | 
			
		||||
	[.] slider (or rather, scroll bar)
 | 
			
		||||
	[.] simple spacers
 | 
			
		||||
		[ ] have a flag for non-cached stuff
 | 
			
		||||
	[.] scrolling panel
 | 
			
		||||
		[ ] Allow/disallow scrolling in x/y
 | 
			
		||||
		[ ] Scroll with mousewheel
 | 
			
		||||
		[/] add margins to scrollbars (disallow scrollbars crossing)
 | 
			
		||||
 | 
			
		||||
[?] Maybe let builder code handle "active"/"hot" state, since it
 | 
			
		||||
    depends on the widgets
 | 
			
		||||
    [ ] On the other hand, this state must be set before layouting, in
 | 
			
		||||
        particular font/fontSize -> maybe do a pass for static layout,
 | 
			
		||||
        instead of doing it in box creation...
 | 
			
		||||
    [ ] this way we can compute styling after user has set active/hot, but before layout
 | 
			
		||||
	> Maybe just let user set style selector, and provide persistent state bits that can
 | 
			
		||||
	> be used in any way? (to replace eg active/hot?) or perhaps not needed if we have just
 | 
			
		||||
	> 'dragging' state
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[x] Mask mouse outside of parent rects -> maintain clip stack and clip mouse against it
 | 
			
		||||
[x] Mask mouse below panels/other widgets
 | 
			
		||||
[x] popups and tooltips
 | 
			
		||||
	[x] allow pushing/popping boxes irrespective of parent/child relation
 | 
			
		||||
	[x] ui_begin_frame() prepares two containers, user ui goes in the first one
 | 
			
		||||
	[x] tooltips and menus go to the second one
 | 
			
		||||
	[x] Add menus
 | 
			
		||||
[ ] line editing widget
 | 
			
		||||
 | 
			
		||||
Misc
 | 
			
		||||
----
 | 
			
		||||
[x] Split metal surface and metal painter (but put them in the same compilation unit?)
 | 
			
		||||
[x] Have only one rect struct
 | 
			
		||||
[x] Shorten mp_string to str8
 | 
			
		||||
 | 
			
		||||
[ ] Better/Simpler time API
 | 
			
		||||
 | 
			
		||||
[/] Frame throttling
 | 
			
		||||
	[x] For now, we always wait on vblank during mg_surface_present(), regardless of target fps
 | 
			
		||||
	[ ] Then actually get the correct display interval from the surface's current monitor
 | 
			
		||||
	[ ] Allow waiting for more display interval than one? (ie allow throttling at 30fps for a 60fps display)
 | 
			
		||||
 | 
			
		||||
[/] split osx_app and move all platform independant stuff outside
 | 
			
		||||
 | 
			
		||||
[ ] Sort out mg_matrix_push/pop() -> transform vs. set...
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue