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