From 86ec9a3cc3f0051932eed44fe7415eb70e40dffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Gardou?= Date: Tue, 17 Sep 2013 19:08:09 +0000 Subject: [PATCH] [OPENGL32_NEW] - forward glFlush to glFinish for single buffered formats - import wglUseFontBitmaps and wglUseFontOutlines from wine 1.7.2 - Remove a useless call to OSMesaMakeContextCurrent - Add a few debug prints svn path=/trunk/; revision=60181 --- .../dll/opengl/opengl32_new/CMakeLists.txt | 1 + reactos/dll/opengl/opengl32_new/swimpl.c | 18 +- reactos/dll/opengl/opengl32_new/wgl.c | 69 +-- reactos/dll/opengl/opengl32_new/wgl_font.c | 564 ++++++++++++++++++ 4 files changed, 605 insertions(+), 47 deletions(-) create mode 100644 reactos/dll/opengl/opengl32_new/wgl_font.c diff --git a/reactos/dll/opengl/opengl32_new/CMakeLists.txt b/reactos/dll/opengl/opengl32_new/CMakeLists.txt index 740c0f51bfb..23dd207d0a0 100644 --- a/reactos/dll/opengl/opengl32_new/CMakeLists.txt +++ b/reactos/dll/opengl/opengl32_new/CMakeLists.txt @@ -19,6 +19,7 @@ list(APPEND SOURCE icdload.c swimpl.c wgl.c + wgl_font.c ${CMAKE_CURRENT_BINARY_DIR}/opengl32_stubs.c ${CMAKE_CURRENT_BINARY_DIR}/opengl32.def ) diff --git a/reactos/dll/opengl/opengl32_new/swimpl.c b/reactos/dll/opengl/opengl32_new/swimpl.c index 930ac9bed0f..0b3849b6bd7 100644 --- a/reactos/dll/opengl/opengl32_new/swimpl.c +++ b/reactos/dll/opengl/opengl32_new/swimpl.c @@ -280,9 +280,13 @@ BOOL sw_SetPixelFormat(struct wgl_dc_data* dc_data, INT format) /* For completeness */ sw_table_db.cEntries = sw_table_sb.cEntries = OPENGL_VERSION_110_ENTRIES; - /* We are not really single buffered, but this trick fits the bill */ + /* We are not really single buffered. */ pFinish = sw_table_sb.glDispatchTable.Finish; sw_table_sb.glDispatchTable.Finish = sw_sb_Finish; + /* OpenGL spec: flush == all pending commands are sent to the server, + * and the client will receive the data in finished time. + * We will call this finish in our case */ + sw_table_sb.glDispatchTable.Flush = sw_sb_Finish; osmesa_loaded: /* Now allocate our structure */ @@ -393,11 +397,10 @@ sw_call_window_proc( /* Do not reallocate for minimized windows */ if(width <= 0 || height <= 0) goto end; - /* Temporarily disable osmesa */ - pOSMesaMakeCurrent(NULL, NULL, GL_UNSIGNED_BYTE, 0, 0); /* Resize the buffer accordingly */ widthBytes = WIDTH_BYTES_ALIGN32(width, pixel_formats[fb->format_index].color_bits); fb->bits = HeapReAlloc(GetProcessHeap(), 0, fb->bits, widthBytes * height); + TRACE("New res: %lux%lu.\n", width, height); /* Update this */ fb->bmi.bmiHeader.biWidth = width; fb->bmi.bmiHeader.biHeight = height; @@ -474,6 +477,8 @@ const GLCLTPROCTABLE* sw_SetContext(struct wgl_dc_data* dc_data, DHGLRC dhglrc) if(!width) width = 1; if(!height) height = 1; + TRACE("Res: %lux%lu.\n", width, height); + if(bits) { if(fb->flags & SW_FB_FREE_BITS) @@ -513,8 +518,10 @@ const GLCLTPROCTABLE* sw_SetContext(struct wgl_dc_data* dc_data, DHGLRC dhglrc) ERR("OSMesaMakeCurrent failed!\n"); /* Damn! Free everything */ if(fb->flags & SW_FB_FREE_BITS) + { HeapFree(GetProcessHeap(), 0, fb->bits); - fb->flags &= ~SW_FB_FREE_BITS; + fb->flags ^= ~SW_FB_FREE_BITS; + } fb->bits = NULL; /* Unhook */ @@ -562,6 +569,9 @@ BOOL sw_SwapBuffers(HDC hdc, struct wgl_dc_data* dc_data) if(!(fb->bits)) return TRUE; + /* Finish before swapping */ + pFinish(); + return (SetDIBitsToDevice(hdc, 0, 0, diff --git a/reactos/dll/opengl/opengl32_new/wgl.c b/reactos/dll/opengl/opengl32_new/wgl.c index 1f0dca6c8db..93120c2eeca 100644 --- a/reactos/dll/opengl/opengl32_new/wgl.c +++ b/reactos/dll/opengl/opengl32_new/wgl.c @@ -348,27 +348,37 @@ HGLRC WINAPI wglCreateContext(HDC hdc) struct wgl_context* context; DHGLRC dhglrc; + TRACE("Creating context for %p, format %i\n", hdc); + if(!dc_data) { + WARN("Not a DC handle!\n"); SetLastError(ERROR_INVALID_HANDLE); return NULL; } if(!dc_data->pixelformat) { - release_dc_data(dc_data); + WARN("Pixel format not set!\n"); SetLastError(ERROR_INVALID_PIXEL_FORMAT); return NULL; } if(!dc_data->icd_data) + { + TRACE("Calling SW implementation.\n"); dhglrc = sw_CreateContext(dc_data); + TRACE("done\n"); + } else + { + TRACE("Calling ICD.\n"); dhglrc = dc_data->icd_data->DrvCreateContext(hdc); + } if(!dhglrc) { - release_dc_data(dc_data); + WARN("Failed!\n"); SetLastError(ERROR_INVALID_PIXEL_FORMAT); return NULL; } @@ -376,11 +386,11 @@ HGLRC WINAPI wglCreateContext(HDC hdc) context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context)); if(!context) { + WARN("Failed to allocate a context!\n"); if(!dc_data->icd_data) sw_DeleteContext(dhglrc); else dc_data->icd_data->DrvDeleteContext(dhglrc); - release_dc_data(dc_data); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; } @@ -391,8 +401,7 @@ HGLRC WINAPI wglCreateContext(HDC hdc) context->thread_id = 0; context->magic = 'GLRC'; - - release_dc_data(dc_data); + TRACE("Success!\n"); return (HGLRC)context; } @@ -768,46 +777,56 @@ BOOL WINAPI wglSetPixelFormat(HDC hdc, INT format, const PIXELFORMATDESCRIPTOR * INT sw_format; BOOL ret; + TRACE("HDC %p, format %i.\n", hdc, format); + if(!dc_data) { + WARN("Not a valid DC!.\n"); SetLastError(ERROR_INVALID_HANDLE); return FALSE; } if(!format) { + WARN("format == 0!\n"); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if(dc_data->pixelformat) { + TRACE("DC format already set, %i.\n", dc_data->pixelformat); return (format == dc_data->pixelformat); } if(format <= dc_data->nb_icd_formats) { + TRACE("Calling ICD.\n"); ret = dc_data->icd_data->DrvSetPixelFormat(hdc, format); if(ret) { + TRACE("Success!\n"); dc_data->pixelformat = format; - return TRUE; } + return ret; } sw_format = format - dc_data->nb_icd_formats; if(sw_format <= dc_data->nb_sw_formats) { + TRACE("Calling SW implementation.\n"); ret = sw_SetPixelFormat(dc_data, sw_format); if(ret) { + TRACE("Success!\n"); /* This is now officially a software-only HDC */ dc_data->icd_data = NULL; dc_data->pixelformat = format; - return TRUE; } + return ret; } + TRACE("Invalid pixel format!\n"); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } @@ -868,39 +887,3 @@ DWORD WINAPI wglSwapMultipleBuffers(UINT count, CONST WGLSWAP * toSwap) { return 0; } - -BOOL WINAPI wglUseFontBitmapsA(HDC hdc, DWORD first, DWORD count, DWORD listBase) -{ - FIXME("stub.\n"); - return FALSE; -} - -BOOL WINAPI wglUseFontBitmapsW(HDC hdc, DWORD first, DWORD count, DWORD listBase) -{ - FIXME("stub.\n"); - return FALSE; -} - -BOOL WINAPI wglUseFontOutlinesA(HDC hdc, - DWORD first, - DWORD count, - DWORD listBase, - FLOAT deviation, - FLOAT extrusion, - int format, - LPGLYPHMETRICSFLOAT lpgmf) -{ - return FALSE; -} - -BOOL WINAPI wglUseFontOutlinesW(HDC hdc, - DWORD first, - DWORD count, - DWORD listBase, - FLOAT deviation, - FLOAT extrusion, - int format, - LPGLYPHMETRICSFLOAT lpgmf) -{ - return FALSE; -} diff --git a/reactos/dll/opengl/opengl32_new/wgl_font.c b/reactos/dll/opengl/opengl32_new/wgl_font.c new file mode 100644 index 00000000000..c4c2ca6f73f --- /dev/null +++ b/reactos/dll/opengl/opengl32_new/wgl_font.c @@ -0,0 +1,564 @@ +/* Window-specific OpenGL functions implementation. + * + * Copyright (c) 1999 Lionel Ulmer + * Copyright (c) 2005 Raphael Junqueira + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "opengl32.h" + +#include +#include +WINE_DEFAULT_DEBUG_CHANNEL(wgl); + +/*********************************************************************** + * wglUseFontBitmaps_common + */ +static BOOL wglUseFontBitmaps_common( HDC hdc, DWORD first, DWORD count, DWORD listBase, BOOL unicode ) +{ + const GLDISPATCHTABLE * funcs = IntGetCurrentDispatchTable(); + GLYPHMETRICS gm; + unsigned int glyph, size = 0; + void *bitmap = NULL, *gl_bitmap = NULL; + int org_alignment; + BOOL ret = TRUE; + + funcs->GetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment); + funcs->PixelStorei(GL_UNPACK_ALIGNMENT, 4); + + for (glyph = first; glyph < first + count; glyph++) { + static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} }; + unsigned int needed_size, height, width, width_int; + + if (unicode) + needed_size = GetGlyphOutlineW(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, &identity); + else + needed_size = GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, &identity); + + TRACE("Glyph: %3d / List: %d size %d\n", glyph, listBase, needed_size); + if (needed_size == GDI_ERROR) { + ret = FALSE; + break; + } + + if (needed_size > size) { + size = needed_size; + HeapFree(GetProcessHeap(), 0, bitmap); + HeapFree(GetProcessHeap(), 0, gl_bitmap); + bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); + gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); + } + if (unicode) + ret = (GetGlyphOutlineW(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, &identity) != GDI_ERROR); + else + ret = (GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, &identity) != GDI_ERROR); + if (!ret) break; + + if (TRACE_ON(wgl)) { + unsigned int bitmask; + unsigned char *bitmap_ = bitmap; + + TRACE(" - bbox: %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY); + TRACE(" - origin: (%d, %d)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y); + TRACE(" - increment: %d - %d\n", gm.gmCellIncX, gm.gmCellIncY); + if (needed_size != 0) { + TRACE(" - bitmap:\n"); + for (height = 0; height < gm.gmBlackBoxY; height++) { + TRACE(" "); + for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) { + if (bitmask == 0) { + bitmap_ += 1; + bitmask = 0x80; + } + if (*bitmap_ & bitmask) + TRACE("*"); + else + TRACE(" "); + } + bitmap_ += (4 - ((UINT_PTR)bitmap_ & 0x03)); + TRACE("\n"); + } + } + } + + /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the + * glyph for it to be drawn properly. + */ + if (needed_size != 0) { + width_int = (gm.gmBlackBoxX + 31) / 32; + for (height = 0; height < gm.gmBlackBoxY; height++) { + for (width = 0; width < width_int; width++) { + ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] = + ((int *) bitmap)[height * width_int + width]; + } + } + } + + funcs->NewList(listBase++, GL_COMPILE); + if (needed_size != 0) { + funcs->Bitmap(gm.gmBlackBoxX, gm.gmBlackBoxY, + 0 - gm.gmptGlyphOrigin.x, (int) gm.gmBlackBoxY - gm.gmptGlyphOrigin.y, + gm.gmCellIncX, gm.gmCellIncY, + gl_bitmap); + } else { + /* This is the case of 'empty' glyphs like the space character */ + funcs->Bitmap(0, 0, 0, 0, gm.gmCellIncX, gm.gmCellIncY, NULL); + } + funcs->EndList(); + } + + funcs->PixelStorei(GL_UNPACK_ALIGNMENT, org_alignment); + HeapFree(GetProcessHeap(), 0, bitmap); + HeapFree(GetProcessHeap(), 0, gl_bitmap); + return ret; +} + +/*********************************************************************** + * wglUseFontBitmapsA (OPENGL32.@) + */ +BOOL WINAPI wglUseFontBitmapsA(HDC hdc, DWORD first, DWORD count, DWORD listBase) +{ + return wglUseFontBitmaps_common( hdc, first, count, listBase, FALSE ); +} + +/*********************************************************************** + * wglUseFontBitmapsW (OPENGL32.@) + */ +BOOL WINAPI wglUseFontBitmapsW(HDC hdc, DWORD first, DWORD count, DWORD listBase) +{ + return wglUseFontBitmaps_common( hdc, first, count, listBase, TRUE ); +} + +/* FIXME: should probably have a glu.h header */ + +typedef struct GLUtesselator GLUtesselator; +typedef void (WINAPI *_GLUfuncptr)(void); + +#define GLU_TESS_BEGIN 100100 +#define GLU_TESS_VERTEX 100101 +#define GLU_TESS_END 100102 + +static GLUtesselator * (WINAPI *pgluNewTess)(void); +static void (WINAPI *pgluDeleteTess)(GLUtesselator *tess); +static void (WINAPI *pgluTessNormal)(GLUtesselator *tess, GLdouble x, GLdouble y, GLdouble z); +static void (WINAPI *pgluTessBeginPolygon)(GLUtesselator *tess, void *polygon_data); +static void (WINAPI *pgluTessEndPolygon)(GLUtesselator *tess); +static void (WINAPI *pgluTessCallback)(GLUtesselator *tess, GLenum which, _GLUfuncptr fn); +static void (WINAPI *pgluTessBeginContour)(GLUtesselator *tess); +static void (WINAPI *pgluTessEndContour)(GLUtesselator *tess); +static void (WINAPI *pgluTessVertex)(GLUtesselator *tess, GLdouble *location, GLvoid* data); + +static HMODULE load_libglu(void) +{ + static const WCHAR glu32W[] = {'g','l','u','3','2','.','d','l','l',0}; + static int already_loaded; + static HMODULE module; + + if (already_loaded) return module; + already_loaded = 1; + + TRACE("Trying to load GLU library\n"); + module = LoadLibraryW( glu32W ); + if (!module) + { + WARN("Failed to load glu32\n"); + return NULL; + } +#define LOAD_FUNCPTR(f) p##f = (void *)GetProcAddress( module, #f ) + LOAD_FUNCPTR(gluNewTess); + LOAD_FUNCPTR(gluDeleteTess); + LOAD_FUNCPTR(gluTessBeginContour); + LOAD_FUNCPTR(gluTessNormal); + LOAD_FUNCPTR(gluTessBeginPolygon); + LOAD_FUNCPTR(gluTessCallback); + LOAD_FUNCPTR(gluTessEndContour); + LOAD_FUNCPTR(gluTessEndPolygon); + LOAD_FUNCPTR(gluTessVertex); +#undef LOAD_FUNCPTR + return module; +} + +static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3]) +{ + vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size; + vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size; + vertex[2] = 0.0; +} + +static void WINAPI tess_callback_vertex(GLvoid *vertex) +{ + const GLDISPATCHTABLE * funcs = IntGetCurrentDispatchTable(); + GLdouble *dbl = vertex; + TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]); + funcs->Vertex3dv(vertex); +} + +static void WINAPI tess_callback_begin(GLenum which) +{ + const GLDISPATCHTABLE * funcs = IntGetCurrentDispatchTable(); + TRACE("%d\n", which); + funcs->Begin(which); +} + +static void WINAPI tess_callback_end(void) +{ + const GLDISPATCHTABLE * funcs = IntGetCurrentDispatchTable(); + TRACE("\n"); + funcs->End(); +} + +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 + */ +static BOOL wglUseFontOutlines_common(HDC hdc, + DWORD first, + DWORD count, + DWORD listBase, + FLOAT deviation, + FLOAT extrusion, + int format, + LPGLYPHMETRICSFLOAT lpgmf, + BOOL unicode) +{ + const GLDISPATCHTABLE * funcs = IntGetCurrentDispatchTable(); + UINT glyph; + const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}}; + GLUtesselator *tess = NULL; + LOGFONTW lf; + HFONT old_font, unscaled_font; + UINT em_size = 1024; + RECT rc; + + TRACE("(%p, %d, %d, %d, %f, %f, %d, %p, %s)\n", hdc, first, count, + listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A"); + + if(deviation <= 0.0) + deviation = 1.0/em_size; + + if(format == WGL_FONT_POLYGONS) + { + if (!load_libglu()) + { + ERR("glu32 is required for this function but isn't available\n"); + return FALSE; + } + + tess = pgluNewTess(); + if(!tess) return FALSE; + pgluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex); + pgluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin); + pgluTessCallback(tess, GLU_TESS_END, tess_callback_end); + } + + GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf); + rc.left = rc.right = rc.bottom = 0; + rc.top = em_size; + DPtoLP(hdc, (POINT*)&rc, 2); + lf.lfHeight = -abs(rc.top - rc.bottom); + lf.lfOrientation = lf.lfEscapement = 0; + unscaled_font = CreateFontIndirectW(&lf); + old_font = SelectObject(hdc, unscaled_font); + + for (glyph = first; glyph < first + count; glyph++) + { + DWORD needed; + GLYPHMETRICS gm; + BYTE *buf; + TTPOLYGONHEADER *pph; + TTPOLYCURVE *ppc; + GLdouble *vertices = NULL; + int vertex_total = -1; + + if(unicode) + needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity); + else + needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity); + + if(needed == GDI_ERROR) + goto error; + + buf = HeapAlloc(GetProcessHeap(), 0, needed); + + if(unicode) + GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity); + else + GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity); + + TRACE("glyph %d\n", glyph); + + if(lpgmf) + { + lpgmf->gmfBlackBoxX = (float)gm.gmBlackBoxX / em_size; + lpgmf->gmfBlackBoxY = (float)gm.gmBlackBoxY / em_size; + lpgmf->gmfptGlyphOrigin.x = (float)gm.gmptGlyphOrigin.x / em_size; + lpgmf->gmfptGlyphOrigin.y = (float)gm.gmptGlyphOrigin.y / em_size; + lpgmf->gmfCellIncX = (float)gm.gmCellIncX / em_size; + lpgmf->gmfCellIncY = (float)gm.gmCellIncY / em_size; + + TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY, + lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY); + lpgmf++; + } + + funcs->NewList(listBase++, GL_COMPILE); + funcs->FrontFace(GL_CCW); + if(format == WGL_FONT_POLYGONS) + { + funcs->Normal3d(0.0, 0.0, 1.0); + pgluTessNormal(tess, 0, 0, 1); + pgluTessBeginPolygon(tess, NULL); + } + + while(!vertices) + { + if(vertex_total != -1) + vertices = HeapAlloc(GetProcessHeap(), 0, vertex_total * 3 * sizeof(GLdouble)); + vertex_total = 0; + + pph = (TTPOLYGONHEADER*)buf; + while((BYTE*)pph < buf + needed) + { + GLdouble previous[3]; + fixed_to_double(pph->pfxStart, em_size, previous); + + if(vertices) + TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value); + + if(format == WGL_FONT_POLYGONS) + pgluTessBeginContour(tess); + else + funcs->Begin(GL_LINE_LOOP); + + if(vertices) + { + fixed_to_double(pph->pfxStart, em_size, vertices); + if(format == WGL_FONT_POLYGONS) + pgluTessVertex(tess, vertices, vertices); + else + funcs->Vertex3d(vertices[0], vertices[1], vertices[2]); + vertices += 3; + } + vertex_total++; + + ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph)); + 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); + if(format == WGL_FONT_POLYGONS) + pgluTessVertex(tess, vertices, vertices); + else + funcs->Vertex3d(vertices[0], vertices[1], vertices[2]); + 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; jVertex3d(vertices[0], vertices[1], vertices[2]); + 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); + if(format == WGL_FONT_POLYGONS) + pgluTessEndContour(tess); + else + funcs->End(); + goto error_in_list; + } + + ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) + + (ppc->cpfx - 1) * sizeof(POINTFX)); + } + if(format == WGL_FONT_POLYGONS) + pgluTessEndContour(tess); + else + funcs->End(); + pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb); + } + } + +error_in_list: + if(format == WGL_FONT_POLYGONS) + pgluTessEndPolygon(tess); + funcs->Translated((GLdouble)gm.gmCellIncX / em_size, (GLdouble)gm.gmCellIncY / em_size, 0.0); + funcs->EndList(); + HeapFree(GetProcessHeap(), 0, buf); + HeapFree(GetProcessHeap(), 0, vertices); + } + + error: + DeleteObject(SelectObject(hdc, old_font)); + if(format == WGL_FONT_POLYGONS) + pgluDeleteTess(tess); + return TRUE; + +} + +/*********************************************************************** + * wglUseFontOutlinesA (OPENGL32.@) + */ +BOOL WINAPI wglUseFontOutlinesA(HDC hdc, + DWORD first, + DWORD count, + DWORD listBase, + FLOAT deviation, + FLOAT extrusion, + int format, + LPGLYPHMETRICSFLOAT lpgmf) +{ + return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE); +} + +/*********************************************************************** + * wglUseFontOutlinesW (OPENGL32.@) + */ +BOOL WINAPI wglUseFontOutlinesW(HDC hdc, + DWORD first, + DWORD count, + DWORD listBase, + FLOAT deviation, + FLOAT extrusion, + int format, + LPGLYPHMETRICSFLOAT lpgmf) +{ + return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE); +} \ No newline at end of file