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" },
95 typedef void (*_GLUfuncptr
)(void);
97 static void (*p_gluBeginCurve
)( GLUnurbs
* nurb
);
98 static void (*p_gluBeginSurface
)( GLUnurbs
* nurb
);
99 static void (*p_gluBeginTrim
)( GLUnurbs
* nurb
);
100 static void (*p_gluDeleteNurbsRenderer
)( GLUnurbs
* nurb
);
101 static void (*p_gluEndCurve
)( GLUnurbs
* nurb
);
102 static void (*p_gluEndSurface
)( GLUnurbs
* nurb
);
103 static void (*p_gluEndTrim
)( GLUnurbs
* nurb
);
104 static void (*p_gluGetNurbsProperty
)( GLUnurbs
* nurb
, GLenum property
, GLfloat
* data
);
105 static void (*p_gluLoadSamplingMatrices
)( GLUnurbs
* nurb
, const GLfloat
*model
, const GLfloat
*perspective
, const GLint
*view
);
106 static GLUnurbs
* (*p_gluNewNurbsRenderer
)(void);
107 static void (*p_gluNurbsCallback
)( GLUnurbs
* nurb
, GLenum which
, _GLUfuncptr CallBackFunc
);
108 static void (*p_gluNurbsCurve
)( GLUnurbs
* nurb
, GLint knotCount
, GLfloat
*knots
, GLint stride
, GLfloat
*control
, GLint order
, GLenum type
);
109 static void (*p_gluNurbsProperty
)( GLUnurbs
* nurb
, GLenum property
, GLfloat value
);
110 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
);
111 static void (*p_gluPwlCurve
)( GLUnurbs
* nurb
, GLint count
, GLfloat
* data
, GLint stride
, GLenum type
);
113 static void *libglu_handle
;
114 static INIT_ONCE init_once
= INIT_ONCE_STATIC_INIT
;
116 static BOOL WINAPI
load_libglu( INIT_ONCE
*once
, void *param
, void **context
)
121 if ((libglu_handle
= wine_dlopen( SONAME_LIBGLU
, RTLD_NOW
, error
, sizeof(error
) )))
122 TRACE( "loaded %s\n", SONAME_LIBGLU
);
124 ERR( "Failed to load %s: %s\n", SONAME_LIBGLU
, error
);
126 ERR( "libGLU is needed but support was not included at build time\n" );
128 return libglu_handle
!= NULL
;
131 static void *load_glufunc( const char *name
)
135 if (!InitOnceExecuteOnce( &init_once
, load_libglu
, NULL
, NULL
)) return NULL
;
136 if (!(ret
= wine_dlsym( libglu_handle
, name
, NULL
, 0 ))) ERR( "Can't find %s\n", name
);
140 #define LOAD_FUNCPTR(f) (p_##f || (p_##f = load_glufunc( #f )))
143 /***********************************************************************
144 * gluErrorString (GLU32.@)
146 const GLubyte
* WINAPI
wine_gluErrorString( GLenum errCode
)
150 for (i
= 0; i
< ARRAY_SIZE(errors
); i
++)
151 if (errors
[i
].err
== errCode
) return (const GLubyte
*)errors
[i
].str
;
156 /***********************************************************************
157 * gluErrorUnicodeStringEXT (GLU32.@)
159 const WCHAR
* WINAPI
wine_gluErrorUnicodeStringEXT( GLenum errCode
)
161 static WCHAR errorsW
[ARRAY_SIZE(errors
)][64];
164 for (i
= 0; i
< ARRAY_SIZE(errors
); i
++)
166 if (errors
[i
].err
!= errCode
) continue;
167 if (!errorsW
[i
][0]) /* errors use only ASCII, do a simple mapping */
168 for (j
= 0; errors
[i
].str
[j
]; j
++) errorsW
[i
][j
] = (WCHAR
)errors
[i
].str
[j
];
174 /***********************************************************************
175 * gluNewNurbsRenderer (GLU32.@)
177 GLUnurbs
* WINAPI
wine_gluNewNurbsRenderer(void)
179 if (!LOAD_FUNCPTR( gluNewNurbsRenderer
)) return NULL
;
180 return p_gluNewNurbsRenderer();
183 /***********************************************************************
184 * gluDeleteNurbsRenderer (GLU32.@)
186 void WINAPI
wine_gluDeleteNurbsRenderer( GLUnurbs
*nobj
)
188 if (!LOAD_FUNCPTR( gluDeleteNurbsRenderer
)) return;
189 p_gluDeleteNurbsRenderer( nobj
);
192 /***********************************************************************
193 * gluLoadSamplingMatrices (GLU32.@)
195 void WINAPI
wine_gluLoadSamplingMatrices( GLUnurbs
*nobj
, const GLfloat modelMatrix
[16],
196 const GLfloat projMatrix
[16], const GLint viewport
[4] )
198 if (!LOAD_FUNCPTR( gluLoadSamplingMatrices
)) return;
199 p_gluLoadSamplingMatrices( nobj
, modelMatrix
, projMatrix
, viewport
);
202 /***********************************************************************
203 * gluNurbsProperty (GLU32.@)
205 void WINAPI
wine_gluNurbsProperty( GLUnurbs
*nobj
, GLenum property
, GLfloat value
)
207 if (!LOAD_FUNCPTR( gluNurbsProperty
)) return;
208 p_gluNurbsProperty( nobj
, property
, value
);
211 /***********************************************************************
212 * gluGetNurbsProperty (GLU32.@)
214 void WINAPI
wine_gluGetNurbsProperty( GLUnurbs
*nobj
, GLenum property
, GLfloat
*value
)
216 if (!LOAD_FUNCPTR( gluGetNurbsProperty
)) return;
217 p_gluGetNurbsProperty( nobj
, property
, value
);
220 /***********************************************************************
221 * gluBeginCurve (GLU32.@)
223 void WINAPI
wine_gluBeginCurve( GLUnurbs
*nobj
)
225 if (!LOAD_FUNCPTR( gluBeginCurve
)) return;
226 p_gluBeginCurve( nobj
);
229 /***********************************************************************
230 * gluEndCurve (GLU32.@)
232 void WINAPI
wine_gluEndCurve( GLUnurbs
*nobj
)
234 if (!LOAD_FUNCPTR( gluEndCurve
)) return;
235 p_gluEndCurve( nobj
);
238 /***********************************************************************
239 * gluNurbsCurve (GLU32.@)
241 void WINAPI
wine_gluNurbsCurve( GLUnurbs
*nobj
, GLint nknots
, GLfloat
*knot
,
242 GLint stride
, GLfloat
*ctlarray
, GLint order
, GLenum type
)
244 if (!LOAD_FUNCPTR( gluNurbsCurve
)) return;
245 p_gluNurbsCurve( nobj
, nknots
, knot
, stride
, ctlarray
, order
, type
);
248 /***********************************************************************
249 * gluBeginSurface (GLU32.@)
251 void WINAPI
wine_gluBeginSurface( GLUnurbs
*nobj
)
253 if (!LOAD_FUNCPTR( gluBeginSurface
)) return;
254 p_gluBeginSurface( nobj
);
257 /***********************************************************************
258 * gluEndSurface (GLU32.@)
260 void WINAPI
wine_gluEndSurface( GLUnurbs
*nobj
)
262 if (!LOAD_FUNCPTR( gluEndSurface
)) return;
263 p_gluEndSurface( nobj
);
266 /***********************************************************************
267 * gluNurbsSurface (GLU32.@)
269 void WINAPI
wine_gluNurbsSurface( GLUnurbs
*nobj
, GLint sknot_count
, float *sknot
, GLint tknot_count
,
270 GLfloat
*tknot
, GLint s_stride
, GLint t_stride
, GLfloat
*ctlarray
,
271 GLint sorder
, GLint torder
, GLenum type
)
273 if (!LOAD_FUNCPTR( gluNurbsSurface
)) return;
274 p_gluNurbsSurface( nobj
, sknot_count
, sknot
, tknot_count
, tknot
,
275 s_stride
, t_stride
, ctlarray
, sorder
, torder
, type
);
278 /***********************************************************************
279 * gluBeginTrim (GLU32.@)
281 void WINAPI
wine_gluBeginTrim( GLUnurbs
*nobj
)
283 if (!LOAD_FUNCPTR( gluBeginTrim
)) return;
284 p_gluBeginTrim( nobj
);
287 /***********************************************************************
288 * gluEndTrim (GLU32.@)
290 void WINAPI
wine_gluEndTrim( GLUnurbs
*nobj
)
292 if (!LOAD_FUNCPTR( gluEndTrim
)) return;
293 p_gluEndTrim( nobj
);
296 /***********************************************************************
297 * gluPwlCurve (GLU32.@)
299 void WINAPI
wine_gluPwlCurve( GLUnurbs
*nobj
, GLint count
, GLfloat
*array
, GLint stride
, GLenum type
)
301 if (!LOAD_FUNCPTR( gluPwlCurve
)) return;
302 p_gluPwlCurve( nobj
, count
, array
, stride
, type
);
305 /***********************************************************************
306 * gluNurbsCallback (GLU32.@)
308 void WINAPI
wine_gluNurbsCallback( GLUnurbs
*nobj
, GLenum which
, void (CALLBACK
*fn
)(void) )
310 if (!LOAD_FUNCPTR( gluNurbsCallback
)) return;
311 /* FIXME: callback calling convention */
312 p_gluNurbsCallback( nobj
, which
, (_GLUfuncptr
)fn
);
315 /***********************************************************************
316 * gluGetString (GLU32.@)
318 const GLubyte
* WINAPI
wine_gluGetString( GLenum name
)
322 case GLU_VERSION
: return (const GLubyte
*)"1.2.2.0 Microsoft Corporation"; /* sic */
323 case GLU_EXTENSIONS
: return (const GLubyte
*)"";
328 /***********************************************************************
329 * gluCheckExtension (GLU32.@)
331 GLboolean WINAPI
wine_gluCheckExtension( const GLubyte
*extName
, const GLubyte
*extString
)
333 const char *list
= (const char *)extString
;
334 const char *ext
= (const char *)extName
;
335 size_t len
= strlen( ext
);
339 while (*list
== ' ') list
++;
340 if (!strncmp( list
, ext
, len
) && (!list
[len
] || list
[len
] == ' ')) return GLU_TRUE
;
341 list
= strchr( list
, ' ' );