opengl32: Implement wglUseFontOutlines curve smoothing.
This commit is contained in:
parent
9d4fcaf2bb
commit
2a208bd2ad
|
@ -1311,6 +1311,74 @@ static void WINAPI tess_callback_end(void)
|
||||||
funcs->gl.p_glEnd();
|
funcs->gl.p_glEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct _bezier_vector {
|
||||||
|
GLdouble x;
|
||||||
|
GLdouble y;
|
||||||
|
} bezier_vector;
|
||||||
|
|
||||||
|
static double bezier_deviation_squared(const bezier_vector *p)
|
||||||
|
{
|
||||||
|
bezier_vector deviation;
|
||||||
|
bezier_vector vertex;
|
||||||
|
bezier_vector base;
|
||||||
|
double base_length;
|
||||||
|
double dot;
|
||||||
|
|
||||||
|
vertex.x = (p[0].x + p[1].x*2 + p[2].x)/4 - p[0].x;
|
||||||
|
vertex.y = (p[0].y + p[1].y*2 + p[2].y)/4 - p[0].y;
|
||||||
|
|
||||||
|
base.x = p[2].x - p[0].x;
|
||||||
|
base.y = p[2].y - p[0].y;
|
||||||
|
|
||||||
|
base_length = sqrt(base.x*base.x + base.y*base.y);
|
||||||
|
base.x /= base_length;
|
||||||
|
base.y /= base_length;
|
||||||
|
|
||||||
|
dot = base.x*vertex.x + base.y*vertex.y;
|
||||||
|
dot = min(max(dot, 0.0), base_length);
|
||||||
|
base.x *= dot;
|
||||||
|
base.y *= dot;
|
||||||
|
|
||||||
|
deviation.x = vertex.x-base.x;
|
||||||
|
deviation.y = vertex.y-base.y;
|
||||||
|
|
||||||
|
return deviation.x*deviation.x + deviation.y*deviation.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bezier_approximate(const bezier_vector *p, bezier_vector *points, FLOAT deviation)
|
||||||
|
{
|
||||||
|
bezier_vector first_curve[3];
|
||||||
|
bezier_vector second_curve[3];
|
||||||
|
bezier_vector vertex;
|
||||||
|
int total_vertices;
|
||||||
|
|
||||||
|
if(bezier_deviation_squared(p) <= deviation*deviation)
|
||||||
|
{
|
||||||
|
if(points)
|
||||||
|
*points = p[2];
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
vertex.x = (p[0].x + p[1].x*2 + p[2].x)/4;
|
||||||
|
vertex.y = (p[0].y + p[1].y*2 + p[2].y)/4;
|
||||||
|
|
||||||
|
first_curve[0] = p[0];
|
||||||
|
first_curve[1].x = (p[0].x + p[1].x)/2;
|
||||||
|
first_curve[1].y = (p[0].y + p[1].y)/2;
|
||||||
|
first_curve[2] = vertex;
|
||||||
|
|
||||||
|
second_curve[0] = vertex;
|
||||||
|
second_curve[1].x = (p[2].x + p[1].x)/2;
|
||||||
|
second_curve[1].y = (p[2].y + p[1].y)/2;
|
||||||
|
second_curve[2] = p[2];
|
||||||
|
|
||||||
|
total_vertices = bezier_approximate(first_curve, points, deviation);
|
||||||
|
if(points)
|
||||||
|
points += total_vertices;
|
||||||
|
total_vertices += bezier_approximate(second_curve, points, deviation);
|
||||||
|
return total_vertices;
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* wglUseFontOutlines_common
|
* wglUseFontOutlines_common
|
||||||
*/
|
*/
|
||||||
|
@ -1336,6 +1404,9 @@ static BOOL wglUseFontOutlines_common(HDC hdc,
|
||||||
TRACE("(%p, %d, %d, %d, %f, %f, %d, %p, %s)\n", hdc, first, count,
|
TRACE("(%p, %d, %d, %d, %f, %f, %d, %p, %s)\n", hdc, first, count,
|
||||||
listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
|
listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
|
||||||
|
|
||||||
|
if(deviation <= 0.0)
|
||||||
|
deviation = 1.0/em_size;
|
||||||
|
|
||||||
if (!load_libglu())
|
if (!load_libglu())
|
||||||
{
|
{
|
||||||
ERR("glu32 is required for this function but isn't available\n");
|
ERR("glu32 is required for this function but isn't available\n");
|
||||||
|
@ -1364,7 +1435,8 @@ static BOOL wglUseFontOutlines_common(HDC hdc,
|
||||||
BYTE *buf;
|
BYTE *buf;
|
||||||
TTPOLYGONHEADER *pph;
|
TTPOLYGONHEADER *pph;
|
||||||
TTPOLYCURVE *ppc;
|
TTPOLYCURVE *ppc;
|
||||||
GLdouble *vertices;
|
GLdouble *vertices = NULL;
|
||||||
|
int vertex_total = -1;
|
||||||
|
|
||||||
if(unicode)
|
if(unicode)
|
||||||
needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
|
needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
|
||||||
|
@ -1375,7 +1447,6 @@ static BOOL wglUseFontOutlines_common(HDC hdc,
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
buf = HeapAlloc(GetProcessHeap(), 0, needed);
|
buf = HeapAlloc(GetProcessHeap(), 0, needed);
|
||||||
vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
|
|
||||||
|
|
||||||
if(unicode)
|
if(unicode)
|
||||||
GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
|
GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
|
||||||
|
@ -1398,63 +1469,116 @@ static BOOL wglUseFontOutlines_common(HDC hdc,
|
||||||
lpgmf++;
|
lpgmf++;
|
||||||
}
|
}
|
||||||
|
|
||||||
funcs->gl.p_glNewList(listBase++, GL_COMPILE);
|
funcs->gl.p_glNewList(listBase++, GL_COMPILE);
|
||||||
funcs->gl.p_glFrontFace(GL_CW);
|
funcs->gl.p_glFrontFace(GL_CW);
|
||||||
pgluTessBeginPolygon(tess, NULL);
|
pgluTessBeginPolygon(tess, NULL);
|
||||||
|
|
||||||
pph = (TTPOLYGONHEADER*)buf;
|
while(!vertices)
|
||||||
while((BYTE*)pph < buf + needed)
|
|
||||||
{
|
{
|
||||||
TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
|
if(vertex_total != -1)
|
||||||
|
vertices = HeapAlloc(GetProcessHeap(), 0, vertex_total * 3 * sizeof(GLdouble));
|
||||||
|
vertex_total = 0;
|
||||||
|
|
||||||
pgluTessBeginContour(tess);
|
pph = (TTPOLYGONHEADER*)buf;
|
||||||
|
while((BYTE*)pph < buf + needed)
|
||||||
fixed_to_double(pph->pfxStart, em_size, vertices);
|
|
||||||
pgluTessVertex(tess, vertices, vertices);
|
|
||||||
vertices += 3;
|
|
||||||
|
|
||||||
ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
|
|
||||||
while((char*)ppc < (char*)pph + pph->cb)
|
|
||||||
{
|
{
|
||||||
int i;
|
GLdouble previous[3];
|
||||||
|
fixed_to_double(pph->pfxStart, em_size, previous);
|
||||||
|
|
||||||
switch(ppc->wType) {
|
if(vertices)
|
||||||
case TT_PRIM_LINE:
|
TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
|
||||||
for(i = 0; i < ppc->cpfx; i++)
|
|
||||||
{
|
|
||||||
TRACE("\t\tline to %d, %d\n", ppc->apfx[i].x.value, ppc->apfx[i].y.value);
|
|
||||||
fixed_to_double(ppc->apfx[i], em_size, vertices);
|
|
||||||
pgluTessVertex(tess, vertices, vertices);
|
|
||||||
vertices += 3;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TT_PRIM_QSPLINE:
|
pgluTessBeginContour(tess);
|
||||||
for(i = 0; i < ppc->cpfx/2; i++)
|
|
||||||
{
|
if(vertices)
|
||||||
/* FIXME: just connecting the control points for now */
|
{
|
||||||
TRACE("\t\tcurve %d,%d %d,%d\n",
|
fixed_to_double(pph->pfxStart, em_size, vertices);
|
||||||
ppc->apfx[i * 2].x.value, ppc->apfx[i * 3].y.value,
|
pgluTessVertex(tess, vertices, vertices);
|
||||||
ppc->apfx[i * 2 + 1].x.value, ppc->apfx[i * 3 + 1].y.value);
|
vertices += 3;
|
||||||
fixed_to_double(ppc->apfx[i * 2], em_size, vertices);
|
|
||||||
pgluTessVertex(tess, vertices, vertices);
|
|
||||||
vertices += 3;
|
|
||||||
fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices);
|
|
||||||
pgluTessVertex(tess, vertices, vertices);
|
|
||||||
vertices += 3;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ERR("\t\tcurve type = %d\n", ppc->wType);
|
|
||||||
pgluTessEndContour(tess);
|
|
||||||
goto error_in_list;
|
|
||||||
}
|
}
|
||||||
|
vertex_total++;
|
||||||
|
|
||||||
ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
|
ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
|
||||||
(ppc->cpfx - 1) * sizeof(POINTFX));
|
while((char*)ppc < (char*)pph + pph->cb)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
int num;
|
||||||
|
|
||||||
|
switch(ppc->wType) {
|
||||||
|
case TT_PRIM_LINE:
|
||||||
|
for(i = 0; i < ppc->cpfx; i++)
|
||||||
|
{
|
||||||
|
if(vertices)
|
||||||
|
{
|
||||||
|
TRACE("\t\tline to %d, %d\n",
|
||||||
|
ppc->apfx[i].x.value, ppc->apfx[i].y.value);
|
||||||
|
fixed_to_double(ppc->apfx[i], em_size, vertices);
|
||||||
|
pgluTessVertex(tess, vertices, vertices);
|
||||||
|
vertices += 3;
|
||||||
|
}
|
||||||
|
fixed_to_double(ppc->apfx[i], em_size, previous);
|
||||||
|
vertex_total++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TT_PRIM_QSPLINE:
|
||||||
|
for(i = 0; i < ppc->cpfx-1; i++)
|
||||||
|
{
|
||||||
|
bezier_vector curve[3];
|
||||||
|
bezier_vector *points;
|
||||||
|
GLdouble curve_vertex[3];
|
||||||
|
|
||||||
|
if(vertices)
|
||||||
|
TRACE("\t\tcurve %d,%d %d,%d\n",
|
||||||
|
ppc->apfx[i].x.value, ppc->apfx[i].y.value,
|
||||||
|
ppc->apfx[i + 1].x.value, ppc->apfx[i + 1].y.value);
|
||||||
|
|
||||||
|
curve[0].x = previous[0];
|
||||||
|
curve[0].y = previous[1];
|
||||||
|
fixed_to_double(ppc->apfx[i], em_size, curve_vertex);
|
||||||
|
curve[1].x = curve_vertex[0];
|
||||||
|
curve[1].y = curve_vertex[1];
|
||||||
|
fixed_to_double(ppc->apfx[i + 1], em_size, curve_vertex);
|
||||||
|
curve[2].x = curve_vertex[0];
|
||||||
|
curve[2].y = curve_vertex[1];
|
||||||
|
if(i < ppc->cpfx-2)
|
||||||
|
{
|
||||||
|
curve[2].x = (curve[1].x + curve[2].x)/2;
|
||||||
|
curve[2].y = (curve[1].y + curve[2].y)/2;
|
||||||
|
}
|
||||||
|
num = bezier_approximate(curve, NULL, deviation);
|
||||||
|
points = HeapAlloc(GetProcessHeap(), 0, num*sizeof(bezier_vector));
|
||||||
|
num = bezier_approximate(curve, points, deviation);
|
||||||
|
vertex_total += num;
|
||||||
|
if(vertices)
|
||||||
|
{
|
||||||
|
for(j=0; j<num; j++)
|
||||||
|
{
|
||||||
|
TRACE("\t\t\tvertex at %f,%f\n", points[j].x, points[j].y);
|
||||||
|
vertices[0] = points[j].x;
|
||||||
|
vertices[1] = points[j].y;
|
||||||
|
vertices[2] = 0.0;
|
||||||
|
pgluTessVertex(tess, vertices, vertices);
|
||||||
|
vertices += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HeapFree(GetProcessHeap(), 0, points);
|
||||||
|
previous[0] = curve[2].x;
|
||||||
|
previous[1] = curve[2].y;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERR("\t\tcurve type = %d\n", ppc->wType);
|
||||||
|
pgluTessEndContour(tess);
|
||||||
|
goto error_in_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
|
||||||
|
(ppc->cpfx - 1) * sizeof(POINTFX));
|
||||||
|
}
|
||||||
|
pgluTessEndContour(tess);
|
||||||
|
pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
|
||||||
}
|
}
|
||||||
pgluTessEndContour(tess);
|
|
||||||
pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
error_in_list:
|
error_in_list:
|
||||||
|
|
Loading…
Reference in New Issue