BRL-CAD
material.c
Go to the documentation of this file.
1 /* M A T E R I A L . C
2  * BRL-CAD
3  *
4  * Copyright (c) 1985-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 /** @file liboptical/material.c
21  *
22  * Routines to coordinate the implementation of material properties
23  *
24  */
25 
26 #include "common.h"
27 
28 #include <ctype.h>
29 #include <math.h>
30 #include <string.h>
31 
32 #ifdef HAVE_DIRECT_H
33 # include <direct.h>
34 #endif
35 
36 #ifdef HAVE_SYS_PARAM_H
37 # include <sys/param.h>
38 #endif
39 
40 #include "bio.h"
41 #include "vmath.h"
42 #include "raytrace.h"
43 #include "optical.h"
44 
45 
46 static const char *mdefault = "default"; /* Name of default material */
47 
48 
49 /**
50  * Routine to add an array of mfuncs structures to the linked list of
51  * material (shader) routines.
52  */
53 void
54 mlib_add_shader(struct mfuncs **headp, struct mfuncs *mfp1)
55 {
56  register struct mfuncs *mfp;
57 
58  RT_CK_MF(mfp1);
59  for (mfp = mfp1; mfp && mfp->mf_name != (char *)0; mfp++) {
60  RT_CK_MF(mfp);
61  mfp->mf_forw = *headp;
62  *headp = mfp;
63  }
64 }
65 
66 
67 /**
68  * Try to load a DSO from the specified path. If we succeed in
69  * opening the DSO, then retrieve the symbol "shader_mfuncs" and look
70  * up the shader named "material" in the table.
71  */
72 static struct mfuncs *
73 try_load(const char *path, const char *material, const char *shader_name)
74 {
75  void *handle;
76  struct mfuncs *shader_mfuncs;
77  struct mfuncs *mfp;
78  const char *dl_error_str;
79  char sym[MAXPATHLEN];
80 
81  if (! (handle = bu_dlopen(path, BU_RTLD_NOW))) {
83  bu_log("bu_dlopen failed on \"%s\"\n", path);
84  return (struct mfuncs *)NULL;
85  } else if (R_DEBUG&RDEBUG_MATERIAL) {
86  bu_log("%s open... ", path);
87  }
88 
89  /* Find the {shader}_mfuncs symbol in the library */
90  snprintf(sym, MAXPATHLEN, "%s_mfuncs", shader_name);
91  shader_mfuncs = (struct mfuncs *)bu_dlsym((struct mfuncs *)handle, sym);
92 
93  dl_error_str=bu_dlerror();
94  if (dl_error_str == (char *)NULL) {
95 
96  /* We didn't find a {shader}_mfuncs symbol, so try the generic
97  * "shader_mfuncs" symbol.
98  */
99  shader_mfuncs = (struct mfuncs *)bu_dlsym((struct mfuncs *)handle, "shader_mfuncs");
100  if ((dl_error_str=bu_dlerror()) != (char *)NULL) {
101  /* didn't find anything appropriate, give up */
102  if (R_DEBUG&RDEBUG_MATERIAL) bu_log("%s has no %s table, %s\n", material, sym, dl_error_str);
103  bu_dlclose(handle);
104  return (struct mfuncs *)NULL;
105  }
106  }
107 
108  if (R_DEBUG&RDEBUG_MATERIAL)
109  bu_log("%s_mfuncs table found\n", shader_name);
110 
111  /* make sure the shader we were looking for is in the mfuncs table */
112  for (mfp = shader_mfuncs; mfp && mfp->mf_name != (char *)NULL; mfp++) {
113  RT_CK_MF(mfp);
114 
115  if (BU_STR_EQUAL(mfp->mf_name, shader_name)) {
116  bu_dlclose(handle);
117  return shader_mfuncs; /* found it! */
118  }
119  }
120 
121  if (R_DEBUG&RDEBUG_MATERIAL) bu_log("shader '%s' not found in library\n", shader_name);
122 
123  /* found the library, but not the shader */
124  bu_dlclose(handle);
125  return (struct mfuncs *)NULL;
126 }
127 
128 
129 struct mfuncs *
130 load_dynamic_shader(const char *material)
131 {
132  struct mfuncs *shader_mfuncs = (struct mfuncs *)NULL;
133  char libname[MAXPATHLEN];
134  char libpath[MAXPATHLEN];
135  char *cwd = (char *)NULL;
136  int old_rdebug = R_DEBUG;
137  char sh_name[128]; /* XXX constants are bogus */
138 
139  if (strlen(material) < sizeof(sh_name)) {
140  bu_strlcpy(sh_name, material, sizeof(sh_name));
141  } else {
142  bu_log("shader name too long \"%s\" %zu > %lu\n",
143  material, strlen(material), sizeof(sh_name));
144  return (struct mfuncs *)NULL;
145  }
146 
147  if (R_DEBUG&RDEBUG_MATERIAL)
148  bu_log("load_dynamic_shader(\"%s\")\n", sh_name);
149 
150  cwd = getcwd((char *)NULL, (size_t)MAXPATHLEN);
151 
152  if (cwd) {
153  /* Look in the current working directory for {sh_name}.so */
154  snprintf(libname, sizeof(libname), "%s/%s.so", cwd, sh_name);
155  if ((shader_mfuncs = try_load(libname, material, sh_name)))
156  goto done;
157 
158 
159  /* Look in the current working directory for shaders.so */
160  snprintf(libname, sizeof(libname), "%s/shaders.so", cwd);
161  if ((shader_mfuncs = try_load(libname, material, sh_name)))
162  goto done;
163 
164  } else {
165  bu_log("Cannot get current working directory\n\tSkipping local shader load\n");
166  }
167 
168  /* Look in the location indicated by $LD_LIBRARY_PATH for
169  * lib{sh_name}.so
170  */
171  snprintf(libname, sizeof(libname), "lib%s.so", sh_name);
172  if ((shader_mfuncs = try_load(libname, material, sh_name)))
173  goto done;
174 
175  /* Look in BRL-CAD install dir under lib dir for lib{sh_name}.so */
176  snprintf(libpath, sizeof(libpath), "/lib/lib%s.so", sh_name);
177  bu_strlcpy(libname, bu_brlcad_root(libpath, 1), sizeof(libname));
178  if ((shader_mfuncs = try_load(libname, material, sh_name)))
179  goto done;
180 
181 done:
182  /* clean up memory allocated */
183  if (cwd) free(cwd);
184 
185  /* print appropriate log messages */
186  if (shader_mfuncs)
187  bu_log("loaded from %s\n", libname);
188  else
189  bu_log("WARNING: shader [%s] not found\n", sh_name);
190 
191  rdebug = old_rdebug;
192 
193  return shader_mfuncs;
194 }
195 
196 
197 /**
198  * Returns -
199  * -1 failed
200  * 0 indicates that this region should be dropped
201  * 1 success
202  */
203 int
204 mlib_setup(struct mfuncs **headp,
205  register struct region *rp,
206  struct rt_i *rtip)
207 {
208  struct mfuncs *mfp_new = NULL;
209 
210  const struct mfuncs *mfp;
211  int ret = -1;
212  struct bu_vls params = BU_VLS_INIT_ZERO;
213  struct bu_vls name = BU_VLS_INIT_ZERO;
214  const char *material;
215  size_t mlen;
216 
217  RT_CK_REGION(rp);
218  RT_CK_RTI(rtip);
219 
220  if (rp->reg_mfuncs != (char *)0) {
221  bu_log("mlib_setup: region %s already setup\n", rp->reg_name);
222  return -1;
223  }
224 
225  material = rp->reg_mater.ma_shader;
226  if (material == NULL || material[0] == '\0') {
227  material = mdefault;
228  mlen = strlen(mdefault);
229  } else {
230  const char *endp;
231  endp = strchr(material, ' ');
232  if (endp) {
233  mlen = endp - material;
234  bu_vls_strcpy(&params, rp->reg_mater.ma_shader+mlen+1);
235  } else {
236  mlen = strlen(material);
237  }
238  }
239  bu_vls_strncpy(&name, material, mlen);
240 
241 retry:
242  for (mfp = *headp; mfp && mfp->mf_name != NULL; mfp = mfp->mf_forw) {
243  if (material[0] != mfp->mf_name[0] || !BU_STR_EQUAL(bu_vls_addr(&name), mfp->mf_name))
244  continue;
245  goto found;
246  }
247 
248  /* If we get here, then the shader wasn't found in the list of
249  * compiled-in (or previously loaded) shaders. See if we can
250  * dynamically load it.
251  */
252 
253  bu_log("Shader (name: \"%s\" parameters: \"%s\")... ", bu_vls_addr(&name), bu_vls_addr(&params));
254 
255  mfp_new = load_dynamic_shader(bu_vls_addr(&name));
256  if (mfp_new) {
257  mlib_add_shader(headp, mfp_new);
258  bu_log("Found a dynamic load shader, retrying\n");
259  goto retry;
260  }
261 
262 
263  /* If we get here, then the shader was not found at all (either in
264  * the compiled-in or dynamically loaded shader sets). We set the
265  * shader name to "default" (which should match an entry in the
266  * table) and search again.
267  */
268 
269  bu_log("WARNING Unknown shader settings on %s\nDefault (plastic) material used instead of '%s'.\n\n",
270  rp->reg_name, bu_vls_addr(&name));
271 
272  if (material != mdefault) {
273  material = mdefault;
274  mlen = strlen(mdefault);
275  bu_vls_trunc(&params, 0);
276  bu_vls_strcpy(&name, mdefault);
277  goto retry;
278  }
279  bu_vls_free(&params);
280  bu_vls_free(&name);
281  return -1;
282 found:
283  rp->reg_mfuncs = (char *)mfp;
284  rp->reg_udata = (char *)0;
285 
286  if (R_DEBUG&RDEBUG_MATERIAL)
287  bu_log("mlib_setup(%s) shader=%s\n", rp->reg_name, mfp->mf_name);
288 
289  if (mfp && mfp->mf_setup)
290  ret = mfp->mf_setup(rp, &params, &rp->reg_udata, mfp, rtip);
291  if (ret < 0) {
292  bu_log("ERROR mlib_setup(%s) failed. material='%s', parameters='%s'.\n",
293  rp->reg_name, bu_vls_addr(&name), bu_vls_addr(&params));
294  if (material != mdefault) {
295  /* If not default material, change to default & retry */
296  bu_log("\tChanging %s material to default and retrying.\n", rp->reg_name);
297  material = mdefault;
298  bu_vls_trunc(&params, 0);
299  bu_vls_strcpy(&name, mdefault);
300  goto retry;
301  }
302  /* What to do if default setup fails? */
303  bu_log("mlib_setup(%s) error recovery failed.\n", rp->reg_name);
304  }
305  bu_vls_free(&params);
306  bu_vls_free(&name);
307  return ret; /* Good or bad, as mf_setup says */
308 }
309 
310 
311 /**
312  * Routine to free material-property specific data
313  */
314 void
315 mlib_free(register struct region *rp)
316 {
317  register const struct mfuncs *mfp = (struct mfuncs *)rp->reg_mfuncs;
318 
319  if (mfp == MF_NULL) {
320  bu_log("mlib_free(%s): reg_mfuncs NULL\n", rp->reg_name);
321  return;
322  }
323  if (mfp->mf_magic != MF_MAGIC) {
324  bu_log("mlib_free(%s): reg_mfuncs bad magic, %x != %x\n",
325  rp->reg_name,
326  mfp->mf_magic, MF_MAGIC);
327  return;
328  }
329 
330  if (mfp->mf_free)
331  mfp->mf_free(rp->reg_udata);
332  rp->reg_mfuncs = (char *)0;
333  rp->reg_udata = (char *)0;
334 }
335 
336 
337 /*
338  * Local Variables:
339  * mode: C
340  * tab-width: 8
341  * indent-tabs-mode: t
342  * c-file-style: "stroustrup"
343  * End:
344  * ex: shiftwidth=4 tabstop=8
345  */
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
#define MF_MAGIC
Definition: magic.h:205
#define RT_CK_RTI(_p)
Definition: raytrace.h:1833
#define R_DEBUG
Definition: optical.h:115
void bu_vls_trunc(struct bu_vls *vp, int len)
Definition: vls.c:198
void bu_vls_strncpy(struct bu_vls *vp, const char *s, size_t n)
Definition: vls.c:339
Header file for the BRL-CAD common definitions.
const char * reg_name
Identifying string.
Definition: raytrace.h:539
#define RT_CK_REGION(_p)
Definition: raytrace.h:559
struct mfuncs * load_dynamic_shader(const char *material)
Definition: material.c:130
if(share_geom)
Definition: nmg_mod.c:3829
char * strchr(const char *sp, int c)
void bu_vls_free(struct bu_vls *vp)
Definition: vls.c:248
const char * bu_dlerror(void)
Definition: dlfcn.c:76
#define bu_strlcpy(dst, src, size)
Definition: str.h:60
char * ma_shader
shader name & parms
Definition: raytrace.h:527
char * bu_vls_addr(const struct bu_vls *vp)
Definition: vls.c:111
void * bu_dlsym(void *path, const char *symbol)
Definition: dlfcn.c:50
struct mater_info reg_mater
Real material information.
Definition: raytrace.h:546
#define RDEBUG_MATERIAL
Definition: optical.h:127
int bu_dlclose(void *handle)
Definition: dlfcn.c:63
int mlib_setup(struct mfuncs **headp, register struct region *rp, struct rt_i *rtip)
Definition: material.c:204
void mlib_add_shader(struct mfuncs **headp, struct mfuncs *mfp1)
Definition: material.c:54
void * bu_dlopen(const char *path, int mode)
Definition: dlfcn.c:37
void bu_vls_strcpy(struct bu_vls *vp, const char *s)
Definition: vls.c:310
void * reg_udata
User appl. data for material.
Definition: raytrace.h:548
#define BU_VLS_INIT_ZERO
Definition: vls.h:84
const char * bu_brlcad_root(const char *rhs, int fail_quietly)
Definition: brlcad_path.c:292
#define BU_RTLD_NOW
Definition: file.h:550
Definition: vls.h:56
Header file for the BRL-CAD Optical Library, LIBOPTICAL.
void * reg_mfuncs
User appl. funcs for material.
Definition: raytrace.h:547
int rdebug
Definition: init.c:39
void mlib_free(register struct region *rp)
Definition: material.c:315
#define BU_STR_EQUAL(s1, s2)
Definition: str.h:126
#define MAXPATHLEN
Definition: defines.h:113