mirror of
https://github.com/reactos/reactos.git
synced 2025-04-21 12:40:33 +00:00
[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
This commit is contained in:
parent
b228abd258
commit
86ec9a3cc3
4 changed files with 605 additions and 47 deletions
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
564
reactos/dll/opengl/opengl32_new/wgl_font.c
Normal file
564
reactos/dll/opengl/opengl32_new/wgl_font.c
Normal file
|
@ -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 <math.h>
|
||||
#include <wine/debug.h>
|
||||
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; 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;
|
||||
if(format == WGL_FONT_POLYGONS)
|
||||
pgluTessVertex(tess, vertices, vertices);
|
||||
else
|
||||
funcs->Vertex3d(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);
|
||||
}
|
Loading…
Reference in a new issue