d3dx9/tests: Added outline comparison tests for D3DXCreateText.

This commit is contained in:
Dylan Smith 2011-03-09 08:26:42 -05:00 committed by Alexandre Julliard
parent eec288a4c5
commit b06a6c84ac
1 changed files with 759 additions and 0 deletions

View File

@ -2012,10 +2012,756 @@ static void D3DXCreateCylinderTest(void)
DestroyWindow(wnd); DestroyWindow(wnd);
} }
struct dynamic_array
{
int count, capacity;
void *items;
};
enum pointtype {
POINTTYPE_CURVE = 0,
POINTTYPE_CORNER,
POINTTYPE_CURVE_START,
POINTTYPE_CURVE_END,
POINTTYPE_CURVE_MIDDLE,
};
struct point2d
{
D3DXVECTOR2 pos;
enum pointtype corner;
};
/* is a dynamic_array */
struct outline
{
int count, capacity;
struct point2d *items;
};
/* is a dynamic_array */
struct outline_array
{
int count, capacity;
struct outline *items;
};
struct glyphinfo
{
struct outline_array outlines;
float offset_x;
};
static BOOL reserve(struct dynamic_array *array, int count, int itemsize)
{
if (count > array->capacity) {
void *new_buffer;
int new_capacity;
if (array->items && array->capacity) {
new_capacity = max(array->capacity * 2, count);
new_buffer = HeapReAlloc(GetProcessHeap(), 0, array->items, new_capacity * itemsize);
} else {
new_capacity = max(16, count);
new_buffer = HeapAlloc(GetProcessHeap(), 0, new_capacity * itemsize);
}
if (!new_buffer)
return FALSE;
array->items = new_buffer;
array->capacity = new_capacity;
}
return TRUE;
}
static struct point2d *add_point(struct outline *array)
{
struct point2d *item;
if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
return NULL;
item = &array->items[array->count++];
ZeroMemory(item, sizeof(*item));
return item;
}
static struct outline *add_outline(struct outline_array *array)
{
struct outline *item;
if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
return NULL;
item = &array->items[array->count++];
ZeroMemory(item, sizeof(*item));
return item;
}
static inline D3DXVECTOR2 *convert_fixed_to_float(POINTFX *pt, int count, float emsquare)
{
D3DXVECTOR2 *ret = (D3DXVECTOR2*)pt;
while (count--) {
D3DXVECTOR2 *pt_flt = (D3DXVECTOR2*)pt;
pt_flt->x = (pt->x.value + pt->x.fract / (float)0x10000) / emsquare;
pt_flt->y = (pt->y.value + pt->y.fract / (float)0x10000) / emsquare;
pt++;
}
return ret;
}
static HRESULT add_bezier_points(struct outline *outline, const D3DXVECTOR2 *p1,
const D3DXVECTOR2 *p2, const D3DXVECTOR2 *p3,
float max_deviation)
{
D3DXVECTOR2 split1 = {0, 0}, split2 = {0, 0}, middle, vec;
float deviation;
D3DXVec2Scale(&split1, D3DXVec2Add(&split1, p1, p2), 0.5f);
D3DXVec2Scale(&split2, D3DXVec2Add(&split2, p2, p3), 0.5f);
D3DXVec2Scale(&middle, D3DXVec2Add(&middle, &split1, &split2), 0.5f);
deviation = D3DXVec2Length(D3DXVec2Subtract(&vec, &middle, p2));
if (deviation < max_deviation) {
struct point2d *pt = add_point(outline);
if (!pt) return E_OUTOFMEMORY;
pt->pos = *p2;
pt->corner = POINTTYPE_CURVE;
/* the end point is omitted because the end line merges into the next segment of
* the split bezier curve, and the end of the split bezier curve is added outside
* this recursive function. */
} else {
HRESULT hr = add_bezier_points(outline, p1, &split1, &middle, max_deviation);
if (hr != S_OK) return hr;
hr = add_bezier_points(outline, &middle, &split2, p3, max_deviation);
if (hr != S_OK) return hr;
}
return S_OK;
}
static inline BOOL is_direction_similar(D3DXVECTOR2 *dir1, D3DXVECTOR2 *dir2, float cos_theta)
{
/* dot product = cos(theta) */
return D3DXVec2Dot(dir1, dir2) > cos_theta;
}
static inline D3DXVECTOR2 *unit_vec2(D3DXVECTOR2 *dir, const D3DXVECTOR2 *pt1, const D3DXVECTOR2 *pt2)
{
return D3DXVec2Normalize(D3DXVec2Subtract(dir, pt2, pt1), dir);
}
static BOOL attempt_line_merge(struct outline *outline,
int pt_index,
const D3DXVECTOR2 *nextpt,
BOOL to_curve)
{
D3DXVECTOR2 curdir, lastdir;
struct point2d *prevpt, *pt;
BOOL ret = FALSE;
const float cos_half = cos(D3DXToRadian(0.5f));
pt = &outline->items[pt_index];
pt_index = (pt_index - 1 + outline->count) % outline->count;
prevpt = &outline->items[pt_index];
if (to_curve)
pt->corner = pt->corner != POINTTYPE_CORNER ? POINTTYPE_CURVE_MIDDLE : POINTTYPE_CURVE_START;
if (outline->count < 2)
return FALSE;
/* remove last point if the next line continues the last line */
unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
unit_vec2(&curdir, &pt->pos, nextpt);
if (is_direction_similar(&lastdir, &curdir, cos_half))
{
outline->count--;
if (pt->corner == POINTTYPE_CURVE_END)
prevpt->corner = pt->corner;
if (prevpt->corner == POINTTYPE_CURVE_END && to_curve)
prevpt->corner = POINTTYPE_CURVE_MIDDLE;
pt = prevpt;
ret = TRUE;
if (outline->count < 2)
return ret;
pt_index = (pt_index - 1 + outline->count) % outline->count;
prevpt = &outline->items[pt_index];
unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
unit_vec2(&curdir, &pt->pos, nextpt);
}
return ret;
}
static HRESULT create_outline(struct glyphinfo *glyph, void *raw_outline, int datasize,
float max_deviation, float emsquare)
{
const float cos_45 = cos(D3DXToRadian(45.0f));
const float cos_90 = cos(D3DXToRadian(90.0f));
TTPOLYGONHEADER *header = (TTPOLYGONHEADER *)raw_outline;
while ((char *)header < (char *)raw_outline + datasize)
{
TTPOLYCURVE *curve = (TTPOLYCURVE *)(header + 1);
struct point2d *lastpt, *pt;
D3DXVECTOR2 lastdir;
D3DXVECTOR2 *pt_flt;
int j;
struct outline *outline = add_outline(&glyph->outlines);
if (!outline)
return E_OUTOFMEMORY;
pt = add_point(outline);
if (!pt)
return E_OUTOFMEMORY;
pt_flt = convert_fixed_to_float(&header->pfxStart, 1, emsquare);
pt->pos = *pt_flt;
pt->corner = POINTTYPE_CORNER;
if (header->dwType != TT_POLYGON_TYPE)
trace("Unknown header type %d\n", header->dwType);
while ((char *)curve < (char *)header + header->cb)
{
D3DXVECTOR2 bezier_start = outline->items[outline->count - 1].pos;
BOOL to_curve = curve->wType != TT_PRIM_LINE && curve->cpfx > 1;
if (!curve->cpfx) {
curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
continue;
}
pt_flt = convert_fixed_to_float(curve->apfx, curve->cpfx, emsquare);
attempt_line_merge(outline, outline->count - 1, &pt_flt[0], to_curve);
if (to_curve)
{
HRESULT hr;
int count = curve->cpfx;
j = 0;
while (count > 2)
{
D3DXVECTOR2 bezier_end;
D3DXVec2Scale(&bezier_end, D3DXVec2Add(&bezier_end, &pt_flt[j], &pt_flt[j+1]), 0.5f);
hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &bezier_end, max_deviation);
if (hr != S_OK)
return hr;
bezier_start = bezier_end;
count--;
j++;
}
hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &pt_flt[j+1], max_deviation);
if (hr != S_OK)
return hr;
pt = add_point(outline);
if (!pt)
return E_OUTOFMEMORY;
j++;
pt->pos = pt_flt[j];
pt->corner = POINTTYPE_CURVE_END;
} else {
for (j = 0; j < curve->cpfx; j++)
{
pt = add_point(outline);
if (!pt)
return E_OUTOFMEMORY;
pt->pos = pt_flt[j];
pt->corner = POINTTYPE_CORNER;
}
}
curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
}
/* remove last point if the next line continues the last line */
if (outline->count >= 3) {
BOOL to_curve;
lastpt = &outline->items[outline->count - 1];
pt = &outline->items[0];
if (pt->pos.x == lastpt->pos.x && pt->pos.y == lastpt->pos.y) {
if (lastpt->corner == POINTTYPE_CURVE_END)
{
if (pt->corner == POINTTYPE_CURVE_START)
pt->corner = POINTTYPE_CURVE_MIDDLE;
else
pt->corner = POINTTYPE_CURVE_END;
}
outline->count--;
lastpt = &outline->items[outline->count - 1];
} else {
/* outline closed with a line from end to start point */
attempt_line_merge(outline, outline->count - 1, &pt->pos, FALSE);
}
lastpt = &outline->items[0];
to_curve = lastpt->corner != POINTTYPE_CORNER && lastpt->corner != POINTTYPE_CURVE_END;
if (lastpt->corner == POINTTYPE_CURVE_START)
lastpt->corner = POINTTYPE_CORNER;
pt = &outline->items[1];
if (attempt_line_merge(outline, 0, &pt->pos, to_curve))
*lastpt = outline->items[outline->count];
}
lastpt = &outline->items[outline->count - 1];
pt = &outline->items[0];
unit_vec2(&lastdir, &lastpt->pos, &pt->pos);
for (j = 0; j < outline->count; j++)
{
D3DXVECTOR2 curdir;
lastpt = pt;
pt = &outline->items[(j + 1) % outline->count];
unit_vec2(&curdir, &lastpt->pos, &pt->pos);
switch (lastpt->corner)
{
case POINTTYPE_CURVE_START:
case POINTTYPE_CURVE_END:
if (!is_direction_similar(&lastdir, &curdir, cos_45))
lastpt->corner = POINTTYPE_CORNER;
break;
case POINTTYPE_CURVE_MIDDLE:
if (!is_direction_similar(&lastdir, &curdir, cos_90))
lastpt->corner = POINTTYPE_CORNER;
else
lastpt->corner = POINTTYPE_CURVE;
break;
default:
break;
}
lastdir = curdir;
}
header = (TTPOLYGONHEADER *)((char *)header + header->cb);
}
return S_OK;
}
static BOOL compute_text_mesh(struct mesh *mesh, HDC hdc, LPCSTR text, FLOAT deviation, FLOAT extrusion, FLOAT otmEMSquare)
{
HRESULT hr = E_FAIL;
DWORD nb_vertices, nb_faces;
DWORD nb_corners, nb_outline_points;
int textlen = 0;
float offset_x;
char *raw_outline = NULL;
struct glyphinfo *glyphs = NULL;
GLYPHMETRICS gm;
int i;
struct vertex *vertex_ptr;
face *face_ptr;
if (deviation == 0.0f)
deviation = 1.0f / otmEMSquare;
textlen = strlen(text);
glyphs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, textlen * sizeof(*glyphs));
if (!glyphs) {
hr = E_OUTOFMEMORY;
goto error;
}
offset_x = 0.0f;
for (i = 0; i < textlen; i++)
{
/* get outline points from data returned from GetGlyphOutline */
const MAT2 identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
int datasize;
glyphs[i].offset_x = offset_x;
datasize = GetGlyphOutline(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
if (datasize < 0) {
hr = E_FAIL;
goto error;
}
HeapFree(GetProcessHeap(), 0, raw_outline);
raw_outline = HeapAlloc(GetProcessHeap(), 0, datasize);
if (!glyphs) {
hr = E_OUTOFMEMORY;
goto error;
}
datasize = GetGlyphOutline(hdc, text[i], GGO_NATIVE, &gm, datasize, raw_outline, &identity);
create_outline(&glyphs[i], raw_outline, datasize, deviation, otmEMSquare);
offset_x += gm.gmCellIncX / (float)otmEMSquare;
}
/* corner points need an extra vertex for the different side faces normals */
nb_corners = 0;
nb_outline_points = 0;
for (i = 0; i < textlen; i++)
{
int j;
for (j = 0; j < glyphs[i].outlines.count; j++)
{
int k;
struct outline *outline = &glyphs[i].outlines.items[j];
nb_outline_points += outline->count;
nb_corners++; /* first outline point always repeated as a corner */
for (k = 1; k < outline->count; k++)
if (outline->items[k].corner)
nb_corners++;
}
}
nb_vertices = (nb_outline_points + nb_corners) * 2 + textlen;
nb_faces = nb_outline_points * 2;
if (!new_mesh(mesh, nb_vertices, nb_faces))
goto error;
/* convert 2D vertices and faces into 3D mesh */
vertex_ptr = mesh->vertices;
face_ptr = mesh->faces;
for (i = 0; i < textlen; i++)
{
int j;
/* side vertices and faces */
for (j = 0; j < glyphs[i].outlines.count; j++)
{
struct vertex *outline_vertices = vertex_ptr;
struct outline *outline = &glyphs[i].outlines.items[j];
int k;
struct point2d *prevpt = &outline->items[outline->count - 1];
struct point2d *pt = &outline->items[0];
for (k = 1; k <= outline->count; k++)
{
struct vertex vtx;
struct point2d *nextpt = &outline->items[k % outline->count];
WORD vtx_idx = vertex_ptr - mesh->vertices;
D3DXVECTOR2 vec;
if (pt->corner == POINTTYPE_CURVE_START)
D3DXVec2Subtract(&vec, &pt->pos, &prevpt->pos);
else if (pt->corner)
D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
else
D3DXVec2Subtract(&vec, &nextpt->pos, &prevpt->pos);
D3DXVec2Normalize(&vec, &vec);
vtx.normal.x = -vec.y;
vtx.normal.y = vec.x;
vtx.normal.z = 0;
vtx.position.x = pt->pos.x + glyphs[i].offset_x;
vtx.position.y = pt->pos.y;
vtx.position.z = 0;
*vertex_ptr++ = vtx;
vtx.position.z = -extrusion;
*vertex_ptr++ = vtx;
vtx.position.x = nextpt->pos.x + glyphs[i].offset_x;
vtx.position.y = nextpt->pos.y;
if (pt->corner && nextpt->corner && nextpt->corner != POINTTYPE_CURVE_END) {
vtx.position.z = -extrusion;
*vertex_ptr++ = vtx;
vtx.position.z = 0;
*vertex_ptr++ = vtx;
(*face_ptr)[0] = vtx_idx;
(*face_ptr)[1] = vtx_idx + 2;
(*face_ptr)[2] = vtx_idx + 1;
face_ptr++;
(*face_ptr)[0] = vtx_idx;
(*face_ptr)[1] = vtx_idx + 3;
(*face_ptr)[2] = vtx_idx + 2;
face_ptr++;
} else {
if (nextpt->corner) {
if (nextpt->corner == POINTTYPE_CURVE_END) {
struct point2d *nextpt2 = &outline->items[(k + 1) % outline->count];
D3DXVec2Subtract(&vec, &nextpt2->pos, &nextpt->pos);
} else {
D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
}
D3DXVec2Normalize(&vec, &vec);
vtx.normal.x = -vec.y;
vtx.normal.y = vec.x;
vtx.position.z = 0;
*vertex_ptr++ = vtx;
vtx.position.z = -extrusion;
*vertex_ptr++ = vtx;
}
(*face_ptr)[0] = vtx_idx;
(*face_ptr)[1] = vtx_idx + 3;
(*face_ptr)[2] = vtx_idx + 1;
face_ptr++;
(*face_ptr)[0] = vtx_idx;
(*face_ptr)[1] = vtx_idx + 2;
(*face_ptr)[2] = vtx_idx + 3;
face_ptr++;
}
prevpt = pt;
pt = nextpt;
}
if (!pt->corner) {
*vertex_ptr++ = *outline_vertices++;
*vertex_ptr++ = *outline_vertices++;
}
}
/* FIXME: compute expected faces */
/* Add placeholder to seperate glyph outlines */
vertex_ptr->position.x = 0;
vertex_ptr->position.y = 0;
vertex_ptr->position.z = 0;
vertex_ptr->normal.x = 0;
vertex_ptr->normal.y = 0;
vertex_ptr->normal.z = 1;
vertex_ptr++;
}
hr = D3D_OK;
error:
if (glyphs) {
for (i = 0; i < textlen; i++)
{
int j;
for (j = 0; j < glyphs[i].outlines.count; j++)
HeapFree(GetProcessHeap(), 0, glyphs[i].outlines.items[j].items);
HeapFree(GetProcessHeap(), 0, glyphs[i].outlines.items);
}
HeapFree(GetProcessHeap(), 0, glyphs);
}
HeapFree(GetProcessHeap(), 0, raw_outline);
return hr == D3D_OK;
}
static void compare_text_outline_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh, int textlen)
{
HRESULT hr;
DWORD number_of_vertices, number_of_faces;
IDirect3DVertexBuffer9 *vertex_buffer = NULL;
IDirect3DIndexBuffer9 *index_buffer = NULL;
D3DVERTEXBUFFER_DESC vertex_buffer_description;
D3DINDEXBUFFER_DESC index_buffer_description;
struct vertex *vertices = NULL;
face *faces = NULL;
int expected, i;
int vtx_idx1, face_idx1, vtx_idx2, face_idx2;
number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
/* vertex buffer */
hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
if (hr != D3D_OK)
{
skip("Couldn't get vertex buffers\n");
goto error;
}
hr = IDirect3DVertexBuffer9_GetDesc(vertex_buffer, &vertex_buffer_description);
ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
if (hr != D3D_OK)
{
skip("Couldn't get vertex buffer description\n");
}
else
{
ok(vertex_buffer_description.Format == D3DFMT_VERTEXDATA, "Test %s, result %x, expected %x (D3DFMT_VERTEXDATA)\n",
name, vertex_buffer_description.Format, D3DFMT_VERTEXDATA);
ok(vertex_buffer_description.Type == D3DRTYPE_VERTEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_VERTEXBUFFER)\n",
name, vertex_buffer_description.Type, D3DRTYPE_VERTEXBUFFER);
ok(vertex_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, vertex_buffer_description.Usage, 0);
ok(vertex_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_DEFAULT)\n",
name, vertex_buffer_description.Pool, D3DPOOL_DEFAULT);
ok(vertex_buffer_description.FVF == mesh->fvf, "Test %s, result %x, expected %x\n",
name, vertex_buffer_description.FVF, mesh->fvf);
if (mesh->fvf == 0)
{
expected = number_of_vertices * mesh->vertex_size;
}
else
{
expected = number_of_vertices * D3DXGetFVFVertexSize(mesh->fvf);
}
ok(vertex_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
name, vertex_buffer_description.Size, expected);
}
hr = d3dxmesh->lpVtbl->GetIndexBuffer(d3dxmesh, &index_buffer);
ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
if (hr != D3D_OK)
{
skip("Couldn't get index buffer\n");
goto error;
}
hr = IDirect3DIndexBuffer9_GetDesc(index_buffer, &index_buffer_description);
ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
if (hr != D3D_OK)
{
skip("Couldn't get index buffer description\n");
}
else
{
ok(index_buffer_description.Format == D3DFMT_INDEX16, "Test %s, result %x, expected %x (D3DFMT_INDEX16)\n",
name, index_buffer_description.Format, D3DFMT_INDEX16);
ok(index_buffer_description.Type == D3DRTYPE_INDEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_INDEXBUFFER)\n",
name, index_buffer_description.Type, D3DRTYPE_INDEXBUFFER);
todo_wine ok(index_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, index_buffer_description.Usage, 0);
ok(index_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_DEFAULT)\n",
name, index_buffer_description.Pool, D3DPOOL_DEFAULT);
expected = number_of_faces * sizeof(WORD) * 3;
ok(index_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
name, index_buffer_description.Size, expected);
}
/* specify offset and size to avoid potential overruns */
hr = IDirect3DVertexBuffer9_Lock(vertex_buffer, 0, number_of_vertices * sizeof(D3DXVECTOR3) * 2,
(LPVOID *)&vertices, D3DLOCK_DISCARD);
ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
if (hr != D3D_OK)
{
skip("Couldn't lock vertex buffer\n");
goto error;
}
hr = IDirect3DIndexBuffer9_Lock(index_buffer, 0, number_of_faces * sizeof(WORD) * 3,
(LPVOID *)&faces, D3DLOCK_DISCARD);
ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
if (hr != D3D_OK)
{
skip("Couldn't lock index buffer\n");
goto error;
}
face_idx1 = 0;
vtx_idx2 = 0;
face_idx2 = 0;
vtx_idx1 = 0;
for (i = 0; i < textlen; i++)
{
int nb_outline_vertices1, nb_outline_faces1;
int nb_outline_vertices2, nb_outline_faces2;
int first_vtx1, first_vtx2;
int first_face1, first_face2;
int j;
first_vtx1 = vtx_idx1;
first_vtx2 = vtx_idx2;
for (; vtx_idx1 < number_of_vertices; vtx_idx1++) {
if (vertices[vtx_idx1].normal.z != 0)
break;
}
for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++) {
if (mesh->vertices[vtx_idx2].normal.z != 0)
break;
}
nb_outline_vertices1 = vtx_idx1 - first_vtx1;
nb_outline_vertices2 = vtx_idx2 - first_vtx2;
ok(nb_outline_vertices1 == nb_outline_vertices2,
"Test %s, glyph %d, outline vertex count result %d, expected %d\n", name, i,
nb_outline_vertices1, nb_outline_vertices2);
for (j = 0; j < min(nb_outline_vertices1, nb_outline_vertices2); j++)
{
vtx_idx1 = first_vtx1 + j;
vtx_idx2 = first_vtx2 + j;
ok(compare_vec3(vertices[vtx_idx1].position, mesh->vertices[vtx_idx2].position),
"Test %s, glyph %d, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
vertices[vtx_idx1].position.x, vertices[vtx_idx1].position.y, vertices[vtx_idx1].position.z,
mesh->vertices[vtx_idx2].position.x, mesh->vertices[vtx_idx2].position.y, mesh->vertices[vtx_idx2].position.z);
ok(compare_vec3(vertices[vtx_idx1].normal, mesh->vertices[first_vtx2 + j].normal),
"Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
mesh->vertices[vtx_idx2].normal.x, mesh->vertices[vtx_idx2].normal.y, mesh->vertices[vtx_idx2].normal.z);
}
vtx_idx1 = first_vtx1 + nb_outline_vertices1;
vtx_idx2 = first_vtx2 + nb_outline_vertices2;
first_face1 = face_idx1;
first_face2 = face_idx2;
for (; face_idx1 < number_of_faces; face_idx1++)
{
if (faces[face_idx1][0] >= vtx_idx1 ||
faces[face_idx1][1] >= vtx_idx1 ||
faces[face_idx1][2] >= vtx_idx1)
break;
}
for (; face_idx2 < mesh->number_of_faces; face_idx2++)
{
if (mesh->faces[face_idx2][0] >= vtx_idx2 ||
mesh->faces[face_idx2][1] >= vtx_idx2 ||
mesh->faces[face_idx2][2] >= vtx_idx2)
break;
}
nb_outline_faces1 = face_idx1 - first_face1;
nb_outline_faces2 = face_idx2 - first_face2;
ok(nb_outline_faces1 == nb_outline_faces2,
"Test %s, glyph %d, outline face count result %d, expected %d\n", name, i,
nb_outline_faces1, nb_outline_faces2);
for (j = 0; j < min(nb_outline_faces1, nb_outline_faces2); j++)
{
face_idx1 = first_face1 + j;
face_idx2 = first_face2 + j;
ok(faces[face_idx1][0] - first_vtx1 == mesh->faces[face_idx2][0] - first_vtx2 &&
faces[face_idx1][1] - first_vtx1 == mesh->faces[face_idx2][1] - first_vtx2 &&
faces[face_idx1][2] - first_vtx1 == mesh->faces[face_idx2][2] - first_vtx2,
"Test %s, glyph %d, face %d, result (%d, %d, %d), expected (%d, %d, %d)\n", name, i, face_idx1,
faces[face_idx1][0], faces[face_idx1][1], faces[face_idx1][2],
mesh->faces[face_idx2][0] - first_vtx2 + first_vtx1,
mesh->faces[face_idx2][1] - first_vtx2 + first_vtx1,
mesh->faces[face_idx2][2] - first_vtx2 + first_vtx1);
}
face_idx1 = first_face1 + nb_outline_faces1;
face_idx2 = first_face2 + nb_outline_faces2;
/* skip to the outline for the next glyph */
for (; vtx_idx1 < number_of_vertices; vtx_idx1++) {
if (vertices[vtx_idx1].normal.z == 0)
break;
}
for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++) {
if (mesh->vertices[vtx_idx2].normal.z == 0)
break;
}
for (; face_idx1 < number_of_faces; face_idx1++)
{
if (faces[face_idx1][0] >= vtx_idx1 ||
faces[face_idx1][1] >= vtx_idx1 ||
faces[face_idx1][2] >= vtx_idx1)
break;
}
for (; face_idx2 < mesh->number_of_faces; face_idx2++)
{
if (mesh->faces[face_idx2][0] >= vtx_idx2 ||
mesh->faces[face_idx2][1] >= vtx_idx2 ||
mesh->faces[face_idx2][2] >= vtx_idx2) break;
}
}
error:
if (vertices) IDirect3DVertexBuffer9_Unlock(vertex_buffer);
if (faces) IDirect3DIndexBuffer9_Unlock(index_buffer);
if (index_buffer) IDirect3DIndexBuffer9_Release(index_buffer);
if (vertex_buffer) IDirect3DVertexBuffer9_Release(vertex_buffer);
}
static void test_createtext(IDirect3DDevice9 *device, HDC hdc, LPCSTR text, FLOAT deviation, FLOAT extrusion) static void test_createtext(IDirect3DDevice9 *device, HDC hdc, LPCSTR text, FLOAT deviation, FLOAT extrusion)
{ {
HRESULT hr; HRESULT hr;
ID3DXMesh *d3dxmesh; ID3DXMesh *d3dxmesh;
struct mesh mesh;
char name[256]; char name[256];
OUTLINETEXTMETRIC otm; OUTLINETEXTMETRIC otm;
GLYPHMETRICS gm; GLYPHMETRICS gm;
@ -2065,6 +2811,19 @@ static void test_createtext(IDirect3DDevice9 *device, HDC hdc, LPCSTR text, FLOA
compare_float(glyphmetrics_float[i].gmfCellIncY, gm.gmCellIncY / (float)otm.otmEMSquare); compare_float(glyphmetrics_float[i].gmfCellIncY, gm.gmCellIncY / (float)otm.otmEMSquare);
} }
ZeroMemory(&mesh, sizeof(mesh));
if (!compute_text_mesh(&mesh, hdc, text, deviation, extrusion, otm.otmEMSquare))
{
skip("Couldn't create mesh\n");
d3dxmesh->lpVtbl->Release(d3dxmesh);
return;
}
mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
compare_text_outline_mesh(name, d3dxmesh, &mesh, strlen(text));
free_mesh(&mesh);
d3dxmesh->lpVtbl->Release(d3dxmesh); d3dxmesh->lpVtbl->Release(d3dxmesh);
SelectObject(hdc, oldfont); SelectObject(hdc, oldfont);
} }