2 * Copyright 2001 Marcus Meissner
3 * Copyright 2017 Alexandre Julliard
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "wine/port.h"
30 #include "wine/library.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(glu
);
35 static const struct { GLuint err
; const char *str
; } errors
[] =
37 { GL_NO_ERROR
, "no error" },
38 { GL_INVALID_ENUM
, "invalid enumerant" },
39 { GL_INVALID_VALUE
, "invalid value" },
40 { GL_INVALID_OPERATION
, "invalid operation" },
41 { GL_STACK_OVERFLOW
, "stack overflow" },
42 { GL_STACK_UNDERFLOW
, "stack underflow" },
43 { GL_OUT_OF_MEMORY
, "out of memory" },
44 { GL_TABLE_TOO_LARGE
, "table too large" },
45 { GL_INVALID_FRAMEBUFFER_OPERATION_EXT
, "invalid framebuffer operation" },
46 { GLU_INVALID_ENUM
, "invalid enumerant" },
47 { GLU_INVALID_VALUE
, "invalid value" },
48 { GLU_OUT_OF_MEMORY
, "out of memory" },
49 { GLU_INCOMPATIBLE_GL_VERSION
, "incompatible gl version" },
50 { GLU_TESS_ERROR1
, "gluTessBeginPolygon() must precede a gluTessEndPolygon()" },
51 { GLU_TESS_ERROR2
, "gluTessBeginContour() must precede a gluTessEndContour()" },
52 { GLU_TESS_ERROR3
, "gluTessEndPolygon() must follow a gluTessBeginPolygon()" },
53 { GLU_TESS_ERROR4
, "gluTessEndContour() must follow a gluTessBeginContour()" },
54 { GLU_TESS_ERROR5
, "a coordinate is too large" },
55 { GLU_TESS_ERROR6
, "need combine callback" },
56 { GLU_NURBS_ERROR1
, "spline order un-supported" },
57 { GLU_NURBS_ERROR2
, "too few knots" },
58 { GLU_NURBS_ERROR3
, "valid knot range is empty" },
59 { GLU_NURBS_ERROR4
, "decreasing knot sequence knot" },
60 { GLU_NURBS_ERROR5
, "knot multiplicity greater than order of spline" },
61 { GLU_NURBS_ERROR6
, "gluEndCurve() must follow gluBeginCurve()" },
62 { GLU_NURBS_ERROR7
, "gluBeginCurve() must precede gluEndCurve()" },
63 { GLU_NURBS_ERROR8
, "missing or extra geometric data" },
64 { GLU_NURBS_ERROR9
, "can't draw piecewise linear trimming curves" },
65 { GLU_NURBS_ERROR10
, "missing or extra domain data" },
66 { GLU_NURBS_ERROR11
, "missing or extra domain data" },
67 { GLU_NURBS_ERROR12
, "gluEndTrim() must precede gluEndSurface()" },
68 { GLU_NURBS_ERROR13
, "gluBeginSurface() must precede gluEndSurface()" },
69 { GLU_NURBS_ERROR14
, "curve of improper type passed as trim curve" },
70 { GLU_NURBS_ERROR15
, "gluBeginSurface() must precede gluBeginTrim()" },
71 { GLU_NURBS_ERROR16
, "gluEndTrim() must follow gluBeginTrim()" },
72 { GLU_NURBS_ERROR17
, "gluBeginTrim() must precede gluEndTrim()" },
73 { GLU_NURBS_ERROR18
, "invalid or missing trim curve" },
74 { GLU_NURBS_ERROR19
, "gluBeginTrim() must precede gluPwlCurve()" },
75 { GLU_NURBS_ERROR20
, "piecewise linear trimming curve referenced twice" },
76 { GLU_NURBS_ERROR21
, "piecewise linear trimming curve and nurbs curve mixed" },
77 { GLU_NURBS_ERROR22
, "improper usage of trim data type" },
78 { GLU_NURBS_ERROR23
, "nurbs curve referenced twice" },
79 { GLU_NURBS_ERROR24
, "nurbs curve and piecewise linear trimming curve mixed" },
80 { GLU_NURBS_ERROR25
, "nurbs surface referenced twice" },
81 { GLU_NURBS_ERROR26
, "invalid property" },
82 { GLU_NURBS_ERROR27
, "gluEndSurface() must follow gluBeginSurface()" },
83 { GLU_NURBS_ERROR28
, "intersecting or misoriented trim curves" },
84 { GLU_NURBS_ERROR29
, "intersecting trim curves" },
85 { GLU_NURBS_ERROR30
, "UNUSED" },
86 { GLU_NURBS_ERROR31
, "unconnected trim curves" },
87 { GLU_NURBS_ERROR32
, "unknown knot error" },
88 { GLU_NURBS_ERROR33
, "negative vertex count encountered" },
89 { GLU_NURBS_ERROR34
, "negative byte-stride encountered" },
90 { GLU_NURBS_ERROR35
, "unknown type descriptor" },
91 { GLU_NURBS_ERROR36
, "null control point reference" },
92 { GLU_NURBS_ERROR37
, "duplicate point on piecewise linear trimming curve" },
94 #define NB_ERRORS (sizeof(errors) / sizeof(errors[0]))
96 typedef void (*_GLUfuncptr
)(void);
98 static void (*p_gluBeginCurve
)( GLUnurbs
* nurb
);
99 static void (*p_gluBeginSurface
)( GLUnurbs
* nurb
);
100 static void (*p_gluBeginTrim
)( GLUnurbs
* nurb
);
101 static void (*p_gluDeleteNurbsRenderer
)( GLUnurbs
* nurb
);
102 static void (*p_gluEndCurve
)( GLUnurbs
* nurb
);
103 static void (*p_gluEndSurface
)( GLUnurbs
* nurb
);
104 static void (*p_gluEndTrim
)( GLUnurbs
* nurb
);
105 static void (*p_gluGetNurbsProperty
)( GLUnurbs
* nurb
, GLenum property
, GLfloat
* data
);
106 static void (*p_gluLoadSamplingMatrices
)( GLUnurbs
* nurb
, const GLfloat
*model
, const GLfloat
*perspective
, const GLint
*view
);
107 static GLUnurbs
* (*p_gluNewNurbsRenderer
)(void);
108 static void (*p_gluNurbsCallback
)( GLUnurbs
* nurb
, GLenum which
, _GLUfuncptr CallBackFunc
);
109 static void (*p_gluNurbsCurve
)( GLUnurbs
* nurb
, GLint knotCount
, GLfloat
*knots
, GLint stride
, GLfloat
*control
, GLint order
, GLenum type
);
110 static void (*p_gluNurbsProperty
)( GLUnurbs
* nurb
, GLenum property
, GLfloat value
);
111 static void (*p_gluNurbsSurface
)( GLUnurbs
* nurb
, GLint sKnotCount
, GLfloat
* sKnots
, GLint tKnotCount
, GLfloat
* tKnots
, GLint sStride
, GLint tStride
, GLfloat
* control
, GLint sOrder
, GLint tOrder
, GLenum type
);
112 static void (*p_gluPwlCurve
)( GLUnurbs
* nurb
, GLint count
, GLfloat
* data
, GLint stride
, GLenum type
);
114 static void *libglu_handle
;
115 static INIT_ONCE init_once
= INIT_ONCE_STATIC_INIT
;
117 static BOOL WINAPI
load_libglu( INIT_ONCE
*once
, void *param
, void **context
)
122 if ((libglu_handle
= wine_dlopen( SONAME_LIBGLU
, RTLD_NOW
, error
, sizeof(error
) )))
123 TRACE( "loaded %s\n", SONAME_LIBGLU
);
125 ERR( "Failed to load %s: %s\n", SONAME_LIBGLU
, error
);
127 ERR( "libGLU is needed but support was not included at build time\n" );
129 return libglu_handle
!= NULL
;
132 static void *load_glufunc( const char *name
)
136 if (!InitOnceExecuteOnce( &init_once
, load_libglu
, NULL
, NULL
)) return NULL
;
137 if (!(ret
= wine_dlsym( libglu_handle
, name
, NULL
, 0 ))) ERR( "Can't find %s\n", name
);
141 #define LOAD_FUNCPTR(f) (p_##f || (p_##f = load_glufunc( #f )))
144 /***********************************************************************
145 * gluErrorString (GLU32.@)
147 const GLubyte
* WINAPI
wine_gluErrorString( GLenum errCode
)
151 for (i
= 0; i
< NB_ERRORS
; i
++)
152 if (errors
[i
].err
== errCode
) return (const GLubyte
*)errors
[i
].str
;
157 /***********************************************************************
158 * gluErrorUnicodeStringEXT (GLU32.@)
160 const WCHAR
* WINAPI
wine_gluErrorUnicodeStringEXT( GLenum errCode
)
162 static WCHAR errorsW
[NB_ERRORS
][64];
165 for (i
= 0; i
< NB_ERRORS
; i
++)
167 if (errors
[i
].err
!= errCode
) continue;
168 if (!errorsW
[i
][0]) /* errors use only ASCII, do a simple mapping */
169 for (j
= 0; errors
[i
].str
[j
]; j
++) errorsW
[i
][j
] = (WCHAR
)errors
[i
].str
[j
];
175 /***********************************************************************
176 * gluNewNurbsRenderer (GLU32.@)
178 GLUnurbs
* WINAPI
wine_gluNewNurbsRenderer(void)
180 if (!LOAD_FUNCPTR( gluNewNurbsRenderer
)) return NULL
;
181 return p_gluNewNurbsRenderer();
184 /***********************************************************************
185 * gluDeleteNurbsRenderer (GLU32.@)
187 void WINAPI
wine_gluDeleteNurbsRenderer( GLUnurbs
*nobj
)
189 if (!LOAD_FUNCPTR( gluDeleteNurbsRenderer
)) return;
190 p_gluDeleteNurbsRenderer( nobj
);
193 /***********************************************************************
194 * gluLoadSamplingMatrices (GLU32.@)
196 void WINAPI
wine_gluLoadSamplingMatrices( GLUnurbs
*nobj
, const GLfloat modelMatrix
[16],
197 const GLfloat projMatrix
[16], const GLint viewport
[4] )
199 if (!LOAD_FUNCPTR( gluLoadSamplingMatrices
)) return;
200 p_gluLoadSamplingMatrices( nobj
, modelMatrix
, projMatrix
, viewport
);
203 /***********************************************************************
204 * gluNurbsProperty (GLU32.@)
206 void WINAPI
wine_gluNurbsProperty( GLUnurbs
*nobj
, GLenum property
, GLfloat value
)
208 if (!LOAD_FUNCPTR( gluNurbsProperty
)) return;
209 p_gluNurbsProperty( nobj
, property
, value
);
212 /***********************************************************************
213 * gluGetNurbsProperty (GLU32.@)
215 void WINAPI
wine_gluGetNurbsProperty( GLUnurbs
*nobj
, GLenum property
, GLfloat
*value
)
217 if (!LOAD_FUNCPTR( gluGetNurbsProperty
)) return;
218 p_gluGetNurbsProperty( nobj
, property
, value
);
221 /***********************************************************************
222 * gluBeginCurve (GLU32.@)
224 void WINAPI
wine_gluBeginCurve( GLUnurbs
*nobj
)
226 if (!LOAD_FUNCPTR( gluBeginCurve
)) return;
227 p_gluBeginCurve( nobj
);
230 /***********************************************************************
231 * gluEndCurve (GLU32.@)
233 void WINAPI
wine_gluEndCurve( GLUnurbs
*nobj
)
235 if (!LOAD_FUNCPTR( gluEndCurve
)) return;
236 p_gluEndCurve( nobj
);
239 /***********************************************************************
240 * gluNurbsCurve (GLU32.@)
242 void WINAPI
wine_gluNurbsCurve( GLUnurbs
*nobj
, GLint nknots
, GLfloat
*knot
,
243 GLint stride
, GLfloat
*ctlarray
, GLint order
, GLenum type
)
245 if (!LOAD_FUNCPTR( gluNurbsCurve
)) return;
246 p_gluNurbsCurve( nobj
, nknots
, knot
, stride
, ctlarray
, order
, type
);
249 /***********************************************************************
250 * gluBeginSurface (GLU32.@)
252 void WINAPI
wine_gluBeginSurface( GLUnurbs
*nobj
)
254 if (!LOAD_FUNCPTR( gluBeginSurface
)) return;
255 p_gluBeginSurface( nobj
);
258 /***********************************************************************
259 * gluEndSurface (GLU32.@)
261 void WINAPI
wine_gluEndSurface( GLUnurbs
*nobj
)
263 if (!LOAD_FUNCPTR( gluEndSurface
)) return;
264 p_gluEndSurface( nobj
);
267 /***********************************************************************
268 * gluNurbsSurface (GLU32.@)
270 void WINAPI
wine_gluNurbsSurface( GLUnurbs
*nobj
, GLint sknot_count
, float *sknot
, GLint tknot_count
,
271 GLfloat
*tknot
, GLint s_stride
, GLint t_stride
, GLfloat
*ctlarray
,
272 GLint sorder
, GLint torder
, GLenum type
)
274 if (!LOAD_FUNCPTR( gluNurbsSurface
)) return;
275 p_gluNurbsSurface( nobj
, sknot_count
, sknot
, tknot_count
, tknot
,
276 s_stride
, t_stride
, ctlarray
, sorder
, torder
, type
);
279 /***********************************************************************
280 * gluBeginTrim (GLU32.@)
282 void WINAPI
wine_gluBeginTrim( GLUnurbs
*nobj
)
284 if (!LOAD_FUNCPTR( gluBeginTrim
)) return;
285 p_gluBeginTrim( nobj
);
288 /***********************************************************************
289 * gluEndTrim (GLU32.@)
291 void WINAPI
wine_gluEndTrim( GLUnurbs
*nobj
)
293 if (!LOAD_FUNCPTR( gluEndTrim
)) return;
294 p_gluEndTrim( nobj
);
297 /***********************************************************************
298 * gluPwlCurve (GLU32.@)
300 void WINAPI
wine_gluPwlCurve( GLUnurbs
*nobj
, GLint count
, GLfloat
*array
, GLint stride
, GLenum type
)
302 if (!LOAD_FUNCPTR( gluPwlCurve
)) return;
303 p_gluPwlCurve( nobj
, count
, array
, stride
, type
);
306 /***********************************************************************
307 * gluNurbsCallback (GLU32.@)
309 void WINAPI
wine_gluNurbsCallback( GLUnurbs
*nobj
, GLenum which
, void (CALLBACK
*fn
)(void) )
311 if (!LOAD_FUNCPTR( gluNurbsCallback
)) return;
312 /* FIXME: callback calling convention */
313 p_gluNurbsCallback( nobj
, which
, (_GLUfuncptr
)fn
);
316 /***********************************************************************
317 * gluGetString (GLU32.@)
319 const GLubyte
* WINAPI
wine_gluGetString( GLenum name
)
323 case GLU_VERSION
: return (const GLubyte
*)"1.2.2.0 Microsoft Corporation"; /* sic */
324 case GLU_EXTENSIONS
: return (const GLubyte
*)"";
329 /***********************************************************************
330 * gluCheckExtension (GLU32.@)
332 GLboolean WINAPI
wine_gluCheckExtension( const GLubyte
*extName
, const GLubyte
*extString
)
334 const char *list
= (const char *)extString
;
335 const char *ext
= (const char *)extName
;
336 size_t len
= strlen( ext
);
340 while (*list
== ' ') list
++;
341 if (!strncmp( list
, ext
, len
) && (!list
[len
] || list
[len
] == ' ')) return GLU_TRUE
;
342 list
= strchr( list
, ' ' );