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;
dlsym(HMODULE Lib,const char * func)51 void * dlsym(HMODULE Lib, const char *func) {
52 void * funcp;
53 if((funcp = (void *) GetProcAddress(Lib, func)))
54 return funcp;
55 else
56 return (void *) wglGetProcAddress(func);
57 }
58
dlopen(const WCHAR * DLL,int unused)59 HMODULE dlopen(const WCHAR *DLL, int unused) {
60 return LoadLibrary(DLL);
61 }
62
dlclose(HMODULE Lib)63 void dlclose(HMODULE Lib) {
64 FreeLibrary(Lib);
65 }
66
67 #else
68 typedef void * DL_LIB_P;
69 typedef char DL_CHAR;
70 # ifdef _MACOSX
71 # define OPENGL_LIB "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib"
72 # define OPENGLU_LIB "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGLU.dylib"
73 # else
74 # define OPENGL_LIB "libGL.so.1"
75 # define OPENGLU_LIB "libGLU.so.1"
76 # endif
77 #endif
78 extern "C" {
DRIVER_INIT(EGL_DRIVER)79 DRIVER_INIT(EGL_DRIVER) {
80 return NULL;
81 }
82 }
83
egl_init_opengl(void * erlCallbacks)84 int egl_init_opengl(void *erlCallbacks)
85 {
86 #ifdef _WIN32
87 driver_init((TWinDynDriverCallbacks *) erlCallbacks);
88 #endif
89 if(egl_initiated == 0) {
90 if(load_gl_functions()) {
91 init_tess();
92 egl_initiated = 1;
93 }
94 }
95 return 1;
96 }
97
load_gl_functions()98 int load_gl_functions() {
99 DL_CHAR * DLName = (DL_CHAR *) OPENGL_LIB;
100 DL_LIB_P LIBhandle = dlopen(DLName, RTLD_LAZY);
101 //fprintf(stderr, "Loading GL: %s\r\n", (const char*)DLName);
102 void * func = NULL;
103 int i;
104
105 if(LIBhandle) {
106 for(i=0; gl_fns[i].name != NULL; i++) {
107 if((func = dlsym(LIBhandle, gl_fns[i].name))) {
108 * (void **) (gl_fns[i].func) = func;
109 // fprintf(stderr, "GL LOADED %s \r\n", gl_fns[i].name);
110 } else {
111 if(gl_fns[i].alt != NULL) {
112 if((func = dlsym(LIBhandle, gl_fns[i].alt))) {
113 * (void **) (gl_fns[i].func) = func;
114 // fprintf(stderr, "GL LOADED %s \r\n", gl_fns[i].alt);
115 } else {
116 * (void **) (gl_fns[i].func) = (void *) &gl_error;
117 // fprintf(stderr, "GL Skipped %s and %s \r\n", gl_fns[i].name, gl_fns[i].alt);
118 };
119 } else {
120 * (void **) (gl_fns[i].func) = (void *) &gl_error;
121 // fprintf(stderr, "GL Skipped %s \r\n", gl_fns[i].name);
122 }
123 }
124 }
125 // dlclose(LIBhandle);
126 // fprintf(stderr, "OPENGL library is loaded\r\n");
127 } else {
128 fprintf(stderr, "Could NOT load OpenGL library: %s\r\n", DLName);
129 };
130
131 DLName = (DL_CHAR *) OPENGLU_LIB;
132 LIBhandle = dlopen(DLName, RTLD_LAZY);
133 // fprintf(stderr, "Loading GLU: %s\r\n", (const char*)DLName);
134 func = NULL;
135
136 if(LIBhandle) {
137 for(i=0; glu_fns[i].name != NULL; i++) {
138 if((func = dlsym(LIBhandle, glu_fns[i].name))) {
139 * (void **) (glu_fns[i].func) = func;
140 } else {
141 if(glu_fns[i].alt != NULL) {
142 if((func = dlsym(LIBhandle, glu_fns[i].alt))) {
143 * (void **) (glu_fns[i].func) = func;
144 } else {
145 * (void **) (glu_fns[i].func) = (void *) &gl_error;
146 // fprintf(stderr, "GLU Skipped %s\r\n", glu_fns[i].alt);
147 };
148 } else {
149 * (void **) (glu_fns[i].func) = (void *) &gl_error;
150 // fprintf(stderr, "GLU Skipped %s\r\n", glu_fns[i].name);
151 }
152 }
153 }
154 // dlclose(LIBhandle);
155 // fprintf(stderr, "GLU library is loaded\r\n");
156 } else {
157 fprintf(stderr, "Could NOT load OpenGL GLU library: %s\r\n", DLName);
158 };
159
160 return 1;
161 }
162
gl_error()163 void gl_error() {
164 // fprintf(stderr, "OpenGL Extension not available \r\n");
165 throw "undef_extension";
166 }
167
168 /* *******************************************************************************
169 * GLU Tesselation special
170 * ******************************************************************************/
171
172 static GLUtesselator* tess;
173
174 typedef struct {
175 GLdouble * tess_coords;
176 int alloc_n;
177 int alloc_max;
178
179 int * tess_index_list;
180 int index_n;
181 int index_max;
182
183 int error;
184 } egl_tess_data;
185
186 #define NEED_MORE_ALLOC 1
187 #define NEED_MORE_INDEX 2
188
189 static egl_tess_data egl_tess;
190
191 void CALLBACK
egl_ogla_vertex(GLdouble * coords)192 egl_ogla_vertex(GLdouble* coords)
193 {
194 /* fprintf(stderr, "%d\r\n", (int) (coords - tess_coords) / 3); */
195 if(egl_tess.index_n < egl_tess.index_max) {
196 egl_tess.tess_index_list[egl_tess.index_n] = (int) (coords - egl_tess.tess_coords) / 3;
197 egl_tess.index_n++;
198 }
199 else
200 egl_tess.error = NEED_MORE_INDEX;
201 }
202
203 void CALLBACK
egl_ogla_combine(GLdouble coords[3],void * vertex_data[4],GLfloat w[4],void ** dataOut)204 egl_ogla_combine(GLdouble coords[3],
205 void* vertex_data[4],
206 GLfloat w[4],
207 void **dataOut)
208 {
209 GLdouble* vertex = &egl_tess.tess_coords[egl_tess.alloc_n];
210 if(egl_tess.alloc_n < egl_tess.alloc_max) {
211 egl_tess.alloc_n += 3;
212 vertex[0] = coords[0];
213 vertex[1] = coords[1];
214 vertex[2] = coords[2];
215 *dataOut = vertex;
216
217 #if 0
218 fprintf(stderr, "combine: ");
219 int i;
220 for (i = 0; i < 4; i++) {
221 if (w[i] > 0.0) {
222 fprintf(stderr, "%d(%g) ", (int) vertex_data[i], w[i]);
223 }
224 }
225 fprintf(stderr, "\r\n");
226 fprintf(stderr, "%g %g %g\r\n", vertex[0], vertex[1], vertex[2]);
227 #endif
228
229 } else {
230 egl_tess.error = NEED_MORE_ALLOC;
231 *dataOut = NULL;
232 }
233 }
234
235 void CALLBACK
egl_ogla_edge_flag(GLboolean flag)236 egl_ogla_edge_flag(GLboolean flag)
237 {
238 }
239
240 void CALLBACK
egl_ogla_error(GLenum errorCode)241 egl_ogla_error(GLenum errorCode)
242 {
243 // const GLubyte *err;
244 // err = gluErrorString(errorCode);
245 // fprintf(stderr, "Tesselation error: %d: %s\r\n", (int) errorCode, err);
246 }
247
init_tess()248 void init_tess()
249 {
250 tess = gluNewTess();
251
252 gluTessCallback(tess, GLU_TESS_VERTEX, (GLUfuncptr) egl_ogla_vertex);
253 gluTessCallback(tess, GLU_TESS_EDGE_FLAG, (GLUfuncptr) egl_ogla_edge_flag);
254 gluTessCallback(tess, GLU_TESS_COMBINE, (GLUfuncptr) egl_ogla_combine);
255 gluTessCallback(tess, GLU_TESS_ERROR, (GLUfuncptr) egl_ogla_error);
256
257 }
258
exit_tess()259 void exit_tess()
260 {
261 gluDeleteTess(tess);
262 }
263
erl_tess_impl(char * buff,ErlDrvPort port,ErlDrvTermData caller)264 int erl_tess_impl(char* buff, ErlDrvPort port, ErlDrvTermData caller)
265 {
266 ErlDrvBinary* bin;
267 int i;
268 int num_vertices;
269 GLdouble *n;
270 int AP;
271 int a_max = 2;
272 int i_max = 6;
273 num_vertices = * (int *) buff; buff += 8; /* Align */
274 n = (double *) buff; buff += 8*3;
275
276 egl_tess.alloc_max = a_max*num_vertices*3;
277 bin = driver_alloc_binary(egl_tess.alloc_max*sizeof(GLdouble));
278 egl_tess.error = 0;
279 egl_tess.tess_coords = (double *) bin->orig_bytes;
280 memcpy(egl_tess.tess_coords,buff,num_vertices*3*sizeof(GLdouble));
281 egl_tess.index_max = i_max*3*num_vertices;
282 egl_tess.tess_index_list = (int *) driver_alloc(sizeof(int) * egl_tess.index_max);
283
284 egl_tess.tess_coords = (double *) bin->orig_bytes;
285 egl_tess.index_n = 0;
286 egl_tess.alloc_n = num_vertices*3;
287
288 gluTessNormal(tess, n[0], n[1], n[2]);
289 gluTessBeginPolygon(tess, 0);
290 gluTessBeginContour(tess);
291 for (i = 0; i < num_vertices; i++) {
292 gluTessVertex(tess, egl_tess.tess_coords+3*i, egl_tess.tess_coords+3*i);
293 }
294 gluTessEndContour(tess);
295 gluTessEndPolygon(tess);
296
297 AP = 0; ErlDrvTermData *rt;
298 rt = (ErlDrvTermData *) driver_alloc(sizeof(ErlDrvTermData) * (13+egl_tess.index_n*2));
299 rt[AP++]=ERL_DRV_ATOM; rt[AP++]=driver_mk_atom((char *) "_egl_result_");
300
301 for(i=0; i < egl_tess.index_n; i++) {
302 rt[AP++] = ERL_DRV_INT; rt[AP++] = (int) egl_tess.tess_index_list[i];
303 };
304 rt[AP++] = ERL_DRV_NIL; rt[AP++] = ERL_DRV_LIST; rt[AP++] = egl_tess.index_n+1;
305
306 rt[AP++] = ERL_DRV_BINARY; rt[AP++] = (ErlDrvTermData) bin;
307 rt[AP++] = egl_tess.alloc_n*sizeof(GLdouble); rt[AP++] = 0;
308
309 rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2; // Return tuple {list, Bin}
310 rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2; // Result tuple
311
312 driver_send_term(port,caller,rt,AP);
313 /* fprintf(stderr, "List %d: %d %d %d \r\n", */
314 /* res, */
315 /* n_pos, */
316 /* (tess_alloc_vertex-new_vertices)*sizeof(GLdouble), */
317 /* num_vertices*6*sizeof(GLdouble)); */
318 driver_free_binary(bin);
319 driver_free(egl_tess.tess_index_list);
320 driver_free(rt);
321 return 0;
322 }
323