1 /*
2 * %CopyrightBegin%
3 *
4 * Copyright Ericsson AB 2011-2016. All Rights Reserved.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * %CopyrightEnd%
19 */
20
21 #include <stdio.h>
22 #include <string.h>
23
24 #ifdef _WIN32
25 #include <windows.h>
26 #endif
27
28 #include "egl_impl.h"
29
30 #define WX_DEF_EXTS
31 #include "gen/gl_fdefs.h"
32 #include "gen/gl_finit.h"
33 #include "gen/glu_finit.h"
34
35 void init_tess();
36 void exit_tess();
37 int load_gl_functions();
38
39 /* ****************************************************************************
40 * OPENGL INITIALIZATION
41 *****************************************************************************/
42
43 int egl_initiated = 0;
44
45 #ifdef _WIN32
46 #define RTLD_LAZY 0
47 #define OPENGL_LIB L"opengl32.dll"
48 #define OPENGLU_LIB L"glu32.dll"
49 typedef HMODULE DL_LIB_P;
50 typedef WCHAR DL_CHAR;
51 #define DL_STR_FMT "%S"
dlsym(HMODULE Lib,const char * func)52 void * dlsym(HMODULE Lib, const char *func) {
53 void * funcp;
54 if((funcp = (void *) GetProcAddress(Lib, func)))
55 return funcp;
56 else
57 return (void *) wglGetProcAddress(func);
58 }
59
dlopen(const WCHAR * DLL,int unused)60 HMODULE dlopen(const WCHAR *DLL, int unused) {
61 return LoadLibrary(DLL);
62 }
63
dlclose(HMODULE Lib)64 void dlclose(HMODULE Lib) {
65 FreeLibrary(Lib);
66 }
67
68 #else
69 typedef void * DL_LIB_P;
70 typedef char DL_CHAR;
71 # define DL_STR_FMT "%s"
72 # ifdef _MACOSX
73 # define OPENGL_LIB "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib"
74 # define OPENGLU_LIB "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGLU.dylib"
75 # else
76 # define OPENGL_LIB "libGL.so.1"
77 # define OPENGLU_LIB "libGLU.so.1"
78 # endif
79 #endif
80 extern "C" {
DRIVER_INIT(EGL_DRIVER)81 DRIVER_INIT(EGL_DRIVER) {
82 return NULL;
83 }
84 }
85
egl_init_opengl(void * erlCallbacks)86 int egl_init_opengl(void *erlCallbacks)
87 {
88 #ifdef _WIN32
89 driver_init((TWinDynDriverCallbacks *) erlCallbacks);
90 #endif
91 if(egl_initiated == 0) {
92 if(load_gl_functions()) {
93 init_tess();
94 egl_initiated = 1;
95 }
96 }
97 return 1;
98 }
99
load_gl_functions()100 int load_gl_functions() {
101 DL_CHAR * DLName = (DL_CHAR *) OPENGL_LIB;
102 DL_LIB_P LIBhandle = dlopen(DLName, RTLD_LAZY);
103 //fprintf(stderr, "Loading GL: %s\r\n", (const char*)DLName);
104 void * func = NULL;
105 int i;
106
107 if(LIBhandle) {
108 for(i=0; gl_fns[i].name != NULL; i++) {
109 if((func = dlsym(LIBhandle, gl_fns[i].name))) {
110 * (void **) (gl_fns[i].func) = func;
111 // fprintf(stderr, "GL LOADED %s \r\n", gl_fns[i].name);
112 } else {
113 if(gl_fns[i].alt != NULL) {
114 if((func = dlsym(LIBhandle, gl_fns[i].alt))) {
115 * (void **) (gl_fns[i].func) = func;
116 // fprintf(stderr, "GL LOADED %s \r\n", gl_fns[i].alt);
117 } else {
118 * (void **) (gl_fns[i].func) = (void *) &gl_error;
119 // fprintf(stderr, "GL Skipped %s and %s \r\n", gl_fns[i].name, gl_fns[i].alt);
120 };
121 } else {
122 * (void **) (gl_fns[i].func) = (void *) &gl_error;
123 // fprintf(stderr, "GL Skipped %s \r\n", gl_fns[i].name);
124 }
125 }
126 }
127 // dlclose(LIBhandle);
128 // fprintf(stderr, "OPENGL library is loaded\r\n");
129 } else {
130 fprintf(stderr, "Could NOT load OpenGL library: " DL_STR_FMT "\r\n", DLName);
131 };
132
133 DLName = (DL_CHAR *) OPENGLU_LIB;
134 LIBhandle = dlopen(DLName, RTLD_LAZY);
135 // fprintf(stderr, "Loading GLU: %s\r\n", (const char*)DLName);
136 func = NULL;
137
138 if(LIBhandle) {
139 for(i=0; glu_fns[i].name != NULL; i++) {
140 if((func = dlsym(LIBhandle, glu_fns[i].name))) {
141 * (void **) (glu_fns[i].func) = func;
142 } else {
143 if(glu_fns[i].alt != NULL) {
144 if((func = dlsym(LIBhandle, glu_fns[i].alt))) {
145 * (void **) (glu_fns[i].func) = func;
146 } else {
147 * (void **) (glu_fns[i].func) = (void *) &gl_error;
148 // fprintf(stderr, "GLU Skipped %s\r\n", glu_fns[i].alt);
149 };
150 } else {
151 * (void **) (glu_fns[i].func) = (void *) &gl_error;
152 // fprintf(stderr, "GLU Skipped %s\r\n", glu_fns[i].name);
153 }
154 }
155 }
156 // dlclose(LIBhandle);
157 // fprintf(stderr, "GLU library is loaded\r\n");
158 } else {
159 fprintf(stderr, "Could NOT load OpenGL GLU library: " DL_STR_FMT "\r\n", DLName);
160 };
161
162 return 1;
163 }
164
gl_error()165 void gl_error() {
166 // fprintf(stderr, "OpenGL Extension not available \r\n");
167 throw "undef_extension";
168 }
169
170 /* *******************************************************************************
171 * GLU Tesselation special
172 * ******************************************************************************/
173
174 static GLUtesselator* tess;
175
176 typedef struct {
177 GLdouble * tess_coords;
178 int alloc_n;
179 int alloc_max;
180
181 int * tess_index_list;
182 int index_n;
183 int index_max;
184
185 int error;
186 } egl_tess_data;
187
188 #define NEED_MORE_ALLOC 1
189 #define NEED_MORE_INDEX 2
190
191 static egl_tess_data egl_tess;
192
193 void CALLBACK
egl_ogla_vertex(GLdouble * coords)194 egl_ogla_vertex(GLdouble* coords)
195 {
196 /* fprintf(stderr, "%d\r\n", (int) (coords - tess_coords) / 3); */
197 if(egl_tess.index_n < egl_tess.index_max) {
198 egl_tess.tess_index_list[egl_tess.index_n] = (int) (coords - egl_tess.tess_coords) / 3;
199 egl_tess.index_n++;
200 }
201 else
202 egl_tess.error = NEED_MORE_INDEX;
203 }
204
205 void CALLBACK
egl_ogla_combine(GLdouble coords[3],void * vertex_data[4],GLfloat w[4],void ** dataOut)206 egl_ogla_combine(GLdouble coords[3],
207 void* vertex_data[4],
208 GLfloat w[4],
209 void **dataOut)
210 {
211 GLdouble* vertex = &egl_tess.tess_coords[egl_tess.alloc_n];
212 if(egl_tess.alloc_n < egl_tess.alloc_max) {
213 egl_tess.alloc_n += 3;
214 vertex[0] = coords[0];
215 vertex[1] = coords[1];
216 vertex[2] = coords[2];
217 *dataOut = vertex;
218
219 #if 0
220 fprintf(stderr, "combine: ");
221 int i;
222 for (i = 0; i < 4; i++) {
223 if (w[i] > 0.0) {
224 fprintf(stderr, "%d(%g) ", (int) vertex_data[i], w[i]);
225 }
226 }
227 fprintf(stderr, "\r\n");
228 fprintf(stderr, "%g %g %g\r\n", vertex[0], vertex[1], vertex[2]);
229 #endif
230
231 } else {
232 egl_tess.error = NEED_MORE_ALLOC;
233 *dataOut = NULL;
234 }
235 }
236
237 void CALLBACK
egl_ogla_edge_flag(GLboolean flag)238 egl_ogla_edge_flag(GLboolean flag)
239 {
240 }
241
242 void CALLBACK
egl_ogla_error(GLenum errorCode)243 egl_ogla_error(GLenum errorCode)
244 {
245 // const GLubyte *err;
246 // err = gluErrorString(errorCode);
247 // fprintf(stderr, "Tesselation error: %d: %s\r\n", (int) errorCode, err);
248 }
249
init_tess()250 void init_tess()
251 {
252 tess = gluNewTess();
253
254 gluTessCallback(tess, GLU_TESS_VERTEX, (GLUfuncptr) egl_ogla_vertex);
255 gluTessCallback(tess, GLU_TESS_EDGE_FLAG, (GLUfuncptr) egl_ogla_edge_flag);
256 gluTessCallback(tess, GLU_TESS_COMBINE, (GLUfuncptr) egl_ogla_combine);
257 gluTessCallback(tess, GLU_TESS_ERROR, (GLUfuncptr) egl_ogla_error);
258
259 }
260
exit_tess()261 void exit_tess()
262 {
263 gluDeleteTess(tess);
264 }
265
erl_tess_impl(char * buff,ErlDrvPort port,ErlDrvTermData caller)266 int erl_tess_impl(char* buff, ErlDrvPort port, ErlDrvTermData caller)
267 {
268 ErlDrvBinary* bin;
269 int i;
270 int num_vertices;
271 GLdouble *n;
272 int AP;
273 int a_max = 2;
274 int i_max = 6;
275 num_vertices = * (int *) buff; buff += 8; /* Align */
276 n = (double *) buff; buff += 8*3;
277
278 egl_tess.alloc_max = a_max*num_vertices*3;
279 bin = driver_alloc_binary(egl_tess.alloc_max*sizeof(GLdouble));
280 egl_tess.error = 0;
281 egl_tess.tess_coords = (double *) bin->orig_bytes;
282 memcpy(egl_tess.tess_coords,buff,num_vertices*3*sizeof(GLdouble));
283 egl_tess.index_max = i_max*3*num_vertices;
284 egl_tess.tess_index_list = (int *) driver_alloc(sizeof(int) * egl_tess.index_max);
285
286 egl_tess.tess_coords = (double *) bin->orig_bytes;
287 egl_tess.index_n = 0;
288 egl_tess.alloc_n = num_vertices*3;
289
290 gluTessNormal(tess, n[0], n[1], n[2]);
291 gluTessBeginPolygon(tess, 0);
292 gluTessBeginContour(tess);
293 for (i = 0; i < num_vertices; i++) {
294 gluTessVertex(tess, egl_tess.tess_coords+3*i, egl_tess.tess_coords+3*i);
295 }
296 gluTessEndContour(tess);
297 gluTessEndPolygon(tess);
298
299 AP = 0; ErlDrvTermData *rt;
300 rt = (ErlDrvTermData *) driver_alloc(sizeof(ErlDrvTermData) * (13+egl_tess.index_n*2));
301 rt[AP++]=ERL_DRV_ATOM; rt[AP++]=driver_mk_atom((char *) "_egl_result_");
302
303 for(i=0; i < egl_tess.index_n; i++) {
304 rt[AP++] = ERL_DRV_INT; rt[AP++] = (int) egl_tess.tess_index_list[i];
305 };
306 rt[AP++] = ERL_DRV_NIL; rt[AP++] = ERL_DRV_LIST; rt[AP++] = egl_tess.index_n+1;
307
308 rt[AP++] = ERL_DRV_BINARY; rt[AP++] = (ErlDrvTermData) bin;
309 rt[AP++] = egl_tess.alloc_n*sizeof(GLdouble); rt[AP++] = 0;
310
311 rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2; // Return tuple {list, Bin}
312 rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2; // Result tuple
313
314 driver_send_term(port,caller,rt,AP);
315 /* fprintf(stderr, "List %d: %d %d %d \r\n", */
316 /* res, */
317 /* n_pos, */
318 /* (tess_alloc_vertex-new_vertices)*sizeof(GLdouble), */
319 /* num_vertices*6*sizeof(GLdouble)); */
320 driver_free_binary(bin);
321 driver_free(egl_tess.tess_index_list);
322 driver_free(rt);
323 return 0;
324 }
325