BRL-CAD
sh_grass.c
Go to the documentation of this file.
1 /* S H _ G R A S S . C
2  * BRL-CAD
3  *
4  * Copyright (c) 1998-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/sh_grass.c
21  *
22  * A procedural shader to produce grass
23  *
24  */
25 
26 #include "common.h"
27 
28 #include <stddef.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <math.h>
32 
33 #include "bu/parallel.h"
34 #include "vmath.h"
35 #include "plot3.h"
36 #include "raytrace.h"
37 #include "optical.h"
38 
39 
40 #define SHADE_CONT 0
41 #define SHADE_ABORT_GRASS 1 /* bit_flag */
42 #define SHADE_ABORT_STACK 2 /* bit_flag */
43 
44 
45 #define grass_MAGIC 0x1834 /* make this a unique number for each shader */
46 #define CK_grass_SP(_p) BU_CKMAG(_p, grass_MAGIC, "grass_specific")
47 
48 /* compute the Region coordinates of the origin of a cell */
49 #define CELL_POS(cell_pos, grass_sp, cell_num) { \
50  cell_pos[X] = cell_num[X] * grass_sp->cell[X]; \
51  cell_pos[Y] = cell_num[Y] * grass_sp->cell[Y]; \
52  }
53 
54 
55 #define BLADE_SEGS_MAX 4
56 
57 #define LEAF_MAGIC 1024
58 #define BLADE_MAGIC 1023
59 #define PLANT_MAGIC 1022
60 
61 struct leaf_segment {
62  uint32_t magic;
63  double len; /* length of blade segment */
64  vect_t blade; /* direction of blade growth */
65  vect_t N; /* surface normal of blade segment */
66 };
67 
68 
69 struct blade {
70  uint32_t magic;
71  double width;
72  double tot_len; /* total length of blade */
73  int segs; /* # of segments in blade */
74  struct leaf_segment leaf[BLADE_SEGS_MAX]; /* segments */
75  point_t pmin; /* blade bbox min */
76  point_t pmax; /* blade bbox max */
77 };
78 
79 
80 #define BLADE_MAX 6
81 #define BLADE_LAST (BLADE_MAX-1)
82 struct plant {
83  uint32_t magic;
84  point_t root; /* location of base of blade */
85  int blades; /* # of blades from same root */
86  struct blade b[BLADE_MAX]; /* blades */
87  point_t pmin; /* plant bbox min */
88  point_t pmax; /* plant bbox max */
89 };
90 
91 
92 #define GRASSRAY_MAGIC 2048
93 struct grass_ray {
94  uint32_t magic;
95  double occlusion;
96  struct xray r;
97  double d_max;
98  vect_t rev;
99  double diverge;
100  double radius;
101  struct bn_tol tol;
102  struct hit hit;
103  FILE *fd;
104  struct application *ap;
105 };
106 #define grass_ray_MAGIC 0x2461
107 #define CK_grass_r(_p) BU_CKMAG(_p, grass_ray_MAGIC, "grass_ray")
108 
109 /*
110  * the shader specific structure contains all variables which are unique
111  * to any particular use of the shader.
112  */
114  uint32_t magic; /* magic # for memory validity check, must come 1st */
115  int debug;
116  FILE *fd;
117  double cell[2]; /* size of a cell in Region coordinates */
118  double ppc; /* mean # plants_per_cell */
119  double ppcd; /* deviation of plants_per_cell */
120  double t; /* mean length of leaf segment */
121  double blade_width; /* max width of blade segment */
122  int nsegs; /* #segs per blade */
123  double seg_ratio;
124  double lacunarity; /* the usual noise parameters */
125  double h_val;
126  double octaves;
127  double size; /* size of noise coordinate space */
128  point_t vscale; /* size of noise coordinate space */
129  vect_t delta;
130  point_t brown;
131  struct plant proto;
132 
133  mat_t m_to_sh; /* model to shader space matrix */
134  mat_t sh_to_m; /* model to shader space matrix */
135 };
136 
137 
138 /* The default values for the variables in the shader specific structure */
139 static const struct grass_specific grass_defaults = {
140  grass_MAGIC,
141  0,
142  (FILE *)0,
143  {400.0, 400.0}, /* cell */
144  5.0, /* plants_per_cell */
145  3.0, /* deviation of plants_per_cell */
146  300.0, /* "t" mean length of leaf (mm)*/
147  3.0, /* max width (mm) of blade segment */
148  4, /* # segs per blade */
149  1.0, /* seg ratio */
150  2.1753974, /* lacunarity */
151  1.0, /* h_val */
152  4.0, /* octaves */
153  .31415926535, /* size */
154  VINITALL(1.0), /* vscale */
155  { 1001.6, 1020.5, 1300.4 }, /* delta into noise space */
156  {.7, .6, .3}, /* brown */
157  { /* struct plant proto */
158  0, /* magic */
159  VINIT_ZERO, /* root */
160  0, /* blades */
161  {{ /* struct blade */
162  0, /* magic */
163  0.0, /* width */
164  0.0, /* tot_len */
165  0, /* segs */
166  {{ /* struct leaf_segment */
167  0, /* magic */
168  0.0, /* len */
169  VINIT_ZERO, /* blade */
170  VINIT_ZERO /* N */
171  }},
172  VINIT_ZERO, /* pmin */
173  VINIT_ZERO /* pmax */
174  }},
175  VINIT_ZERO, /* pmin */
176  VINIT_ZERO /* pmax */
177  },
178  MAT_INIT_IDN, /* m_to_sh */
179  MAT_INIT_IDN /* sh_to_m */
180 };
181 
182 #define SHDR_NULL ((struct grass_specific *)0)
183 #define SHDR_O(m) bu_offsetof(struct grass_specific, m)
184 
185 /* description of how to parse/print the arguments to the shader
186  * There is at least one line here for each variable in the shader specific
187  * structure above
188  */
190  {"%g", 2, "cell", SHDR_O(cell), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
191  {"%g", 1, "ppc", SHDR_O(ppc), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
192  {"%g", 1, "ppcd", SHDR_O(ppcd), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
193  {"%g", 1, "t", SHDR_O(t), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
194  {"%g", 1, "width", SHDR_O(blade_width), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
195  {"%g", 1, "lacunarity", SHDR_O(lacunarity), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
196  {"%g", 1, "H", SHDR_O(h_val), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
197  {"%g", 1, "octaves", SHDR_O(octaves), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
198  {"%g", 1, "size", SHDR_O(size), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
199  {"%d", 1, "nsegs", SHDR_O(nsegs), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
200  {"%g", 1, "seg_ratio", SHDR_O(seg_ratio), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
201  {"", 0, (char *)0, 0, BU_STRUCTPARSE_FUNC_NULL, NULL, NULL }
202 };
204  {"%p", 1, "grass_print_tab", bu_byteoffset(grass_print_tab[0]), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
205  {"%g", 2, "c", SHDR_O(cell), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
206  {"%g", 1, "p", SHDR_O(ppc), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
207  {"%g", 1, "pd", SHDR_O(ppcd), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
208  {"%g", 1, "l", SHDR_O(lacunarity), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
209  {"%g", 1, "o", SHDR_O(octaves), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
210  {"%g", 1, "s", SHDR_O(size), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
211  {"%g", 1, "w", SHDR_O(blade_width), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
212  {"%d", 1, "n", SHDR_O(nsegs), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
213  {"%g", 1, "r", SHDR_O(seg_ratio), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
214  {"%d", 1, "d", SHDR_O(debug), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
215  {"", 0, (char *)0, 0, BU_STRUCTPARSE_FUNC_NULL, NULL, NULL }
216 };
217 
218 
219 HIDDEN int grass_setup(register struct region *rp, struct bu_vls *matparm, void **dpp, const struct mfuncs *mfp, struct rt_i *rtip);
220 HIDDEN int grass_render(struct application *ap, const struct partition *pp, struct shadework *swp, void *dp);
221 HIDDEN void grass_print(register struct region *rp, void *dp);
222 HIDDEN void grass_free(void *cp);
223 
224 /* The "mfuncs" structure defines the external interface to the shader.
225  * Note that more than one shader "name" can be associated with a given
226  * shader by defining more than one mfuncs struct in this array.
227  * See sh_phong.c for an example of building more than one shader "name"
228  * from a set of source functions. There you will find that "glass" "mirror"
229  * and "plastic" are all names for the same shader with different default
230  * values for the parameters.
231  */
232 struct mfuncs grass_mfuncs[] = {
233  {MF_MAGIC, "grass", 0, MFI_NORMAL|MFI_HIT|MFI_UV, MFF_PROC, grass_setup, grass_render, grass_print, grass_free },
234  {0, (char *)0, 0, 0, 0, 0, 0, 0, 0 }
235 };
236 
237 
238 /* fraction of total allowed returned */
239 static double
240 plants_this_cell(long int *cell, struct grass_specific *grass_sp)
241 /* integer cell number */
242 
243 {
244  point_t c;
245  double val;
246 
247  VSCALE(c, cell, grass_sp->size); /* int/float conv */
248  VADD2(c, c, grass_sp->delta);
249 
250  val = fabs(bn_noise_fbm(c, grass_sp->h_val, grass_sp->lacunarity,
251  grass_sp->octaves));
252 
253  CLAMP(val, 0.0, 1.0);
254 
255  return val;
256 }
257 
258 
259 static void
260 print_plant(char *str, const struct plant *plant)
261 {
262  int blade, seg;
263 
264  bu_log("%s: %d blades\n", str, plant->blades);
265  bu_log(" root: %g %g %g\n", V3ARGS(plant->root));
266 
267  for (blade=0; blade < plant->blades; blade++) {
268  bu_log(" blade %d segs:%d tot_len:%g\n", blade, plant->b[blade].segs, plant->b[blade].tot_len);
269  /* this printing is separated in two to avoid a nasty -O bug in gcc 2.95.2 */
270  bu_log(" min:%g %g %g", V3ARGS(plant->b[blade].pmin));
271  bu_log(" max:%g %g %g\n", V3ARGS(plant->b[blade].pmax));
272  for (seg=0; seg < plant->b[blade].segs; seg++) {
273  /* this printing is separated in two to avoid a nasty -O bug in gcc 2.95.2 */
274  bu_log(" leaf[%d](%g %g %g)", seg, V3ARGS(plant->b[blade].leaf[seg].blade));
275  bu_log(" %g\n", plant->b[blade].leaf[seg].len);
276  }
277  }
278 }
279 
280 
281 /*
282  * Rotate a blade about the Z axis, compute blade bounding box
283  *
284  */
285 static void
286 blade_rot(struct blade *o, struct blade *i, fastf_t *m, const fastf_t *root)
287 {
288  struct blade tmp;
289  int seg;
290  point_t pt;
291 
292  if (i == o) {
293  tmp = *i; /* struct copy */
294  i = &tmp;
295  }
296  VMOVE(pt, root);
297  VMOVE(o->pmin, root);
298  VMOVE(o->pmax, root);
299 
300  o->segs = i->segs;
301  o->tot_len = 0.0;
302  for (seg=0; seg < i->segs; seg++) {
303  o->leaf[seg].magic = i->leaf[seg].magic;
304  MAT4X3VEC(o->leaf[seg].blade, m, i->leaf[seg].blade);
305  MAT4X3VEC(o->leaf[seg].N, m, i->leaf[seg].N);
306  o->leaf[seg].len = i->leaf[seg].len;
307  o->tot_len += i->leaf[seg].len;
308 
309  VJOIN1(pt, pt, o->leaf[seg].len, o->leaf[seg].blade);
310  VMINMAX(o->pmin, o->pmax, pt);
311  }
312 }
313 static void
314 plant_rot(struct plant *pl, double a)
315 {
316  int blade;
317  mat_t m;
318 
319  bn_mat_zrot(m, sin(a), cos(a));
320 
321  for (blade=0; blade < pl->blades; blade++) {
322  blade_rot(&pl->b[blade], &pl->b[blade], m, pl->root);
323  }
324 }
325 
326 
327 /*
328  * decide how many blades to use, and how long the blades will be
329  *
330  */
331 static void
332 plant_scale(struct plant *pl, double w)
333 
334 /* 0..1, */
335 {
336  int blade, seg;
337  double d;
338 
339  if (rdebug&RDEBUG_SHADE)
340  bu_log("plant_scale(%g)\n", w);
341 
342  d = 1.0 - w;
343 
344  /* decide the number of blades */
345  if (d < .8) {
346  pl->blades -= d * pl->blades * .5;
347  CLAMP(pl->blades, 1, BLADE_LAST);
348  }
349 
350  for (blade=0; blade < pl->blades; blade++) {
351  pl->b[blade].tot_len = 0.0;
352  if (blade != BLADE_LAST)
353  pl->b[blade].width *= d;
354  else
355  d *= d;
356 
357  for (seg=0; seg < pl->b[blade].segs; seg++) {
358  pl->b[blade].leaf[seg].len *= d;
359 
360  pl->b[blade].tot_len += pl->b[blade].leaf[seg].len;
361  }
362  }
363 
364 }
365 
366 
367 /*
368  * Make a prototype blade we can copy for use later
369  * Doesn't set bounding box.
370  */
371 static void
372 make_proto(struct grass_specific *grass_sp)
373 {
374  static const point_t z_axis = { 0.0, 0.0, 1.0 };
375  vect_t left;
376  int blade, seg;
377  mat_t m, r;
378  double start_angle;
379  double seg_delta_angle;
380  double angle;
381  double val, tmp;
382  double seg_len;
383 
384  grass_sp->proto.magic = PLANT_MAGIC;
385  VSETALL(grass_sp->proto.root, 0.0);
386  VMOVE(grass_sp->proto.pmin, grass_sp->proto.root);
387  VMOVE(grass_sp->proto.pmax, grass_sp->proto.root);
388 
389  grass_sp->proto.blades = BLADE_MAX;
390 
391  /* First we make blade 0. This blade will be used as the prototype
392  * for all the other blades. Most significantly, the others are just
393  * a rotation/scale of this first one.
394  */
395  bn_mat_zrot(r, sin(DEG2RAD*137.0), cos(DEG2RAD*137.0));
396  MAT_COPY(m, r);
397 
398  seg_delta_angle = (87.0 / (double)BLADE_SEGS_MAX);
399 
400  for (blade=0; blade < BLADE_LAST; blade++) {
401  val = (double)blade / (double)(BLADE_LAST);
402 
403  grass_sp->proto.b[blade].magic = BLADE_MAGIC;
404  grass_sp->proto.b[blade].tot_len = 0.0;
405  grass_sp->proto.b[blade].width = grass_sp->blade_width;
406  grass_sp->proto.b[blade].segs = BLADE_SEGS_MAX; /* - (val*BLADE_SEGS_MAX*.25) */
407 
408  /* pick a start angle for the first segment */
409  start_angle = 55.0 + 30.0 * (1.0-val);
410  seg_len = grass_sp->t / grass_sp->proto.b[blade].segs;
411 
412  for (seg=0; seg < grass_sp->proto.b[blade].segs; seg++) {
413  grass_sp->proto.b[blade].leaf[seg].magic = LEAF_MAGIC;
414 
415  angle = start_angle - (double)seg * seg_delta_angle;
416  angle *= DEG2RAD;
417  VSET(grass_sp->proto.b[blade].leaf[seg].blade,
418  cos(angle), 0.0, sin(angle));
419 
420  /* pick a length for the blade */
421  tmp = (double)seg / (double)BLADE_SEGS_MAX;
422 
423  /* magic */
424  grass_sp->proto.b[blade].leaf[seg].len = seg_len * .25 + tmp * (seg_len*1.75);
425  grass_sp->proto.b[blade].tot_len += grass_sp->proto.b[blade].leaf[seg].len;
426 
427  VUNITIZE(grass_sp->proto.b[blade].leaf[seg].blade);
428  VCROSS(left, grass_sp->proto.b[blade].leaf[seg].blade, z_axis);
429  VUNITIZE(left);
430  VCROSS(grass_sp->proto.b[blade].leaf[seg].N,
431  left, grass_sp->proto.b[blade].leaf[seg].blade);
432  VUNITIZE(grass_sp->proto.b[blade].leaf[seg].N);
433  }
434  blade_rot(&grass_sp->proto.b[blade], &grass_sp->proto.b[blade], m, grass_sp->proto.root);
435  bn_mat_mul2(r, m);
436  }
437 
438 
439  /* The central stalk is a bit different. It's basically a straight tall
440  * shaft
441  */
442  blade = BLADE_LAST;
443  grass_sp->proto.b[blade].magic = BLADE_MAGIC;
444  grass_sp->proto.b[blade].tot_len = 0.0;
445  grass_sp->proto.b[blade].segs = BLADE_SEGS_MAX;
446  grass_sp->proto.b[blade].width = grass_sp->blade_width * 0.5;
447 
448 
449  seg_len = .75 * grass_sp->t / grass_sp->proto.b[blade].segs;
450  val = .9;
451  for (seg=0; seg < grass_sp->proto.b[blade].segs; seg++) {
452  tmp = (double)seg / (double)BLADE_SEGS_MAX;
453 
454  grass_sp->proto.b[blade].leaf[seg].magic = LEAF_MAGIC;
455 
456  VSET(grass_sp->proto.b[blade].leaf[seg].blade, 0.0, .1, val);
457  VUNITIZE(grass_sp->proto.b[blade].leaf[seg].blade);
458 
459 
460  grass_sp->proto.b[blade].leaf[seg].len = seg_len;
461 
462  grass_sp->proto.b[blade].tot_len += grass_sp->proto.b[blade].leaf[seg].len;
463 
464  VCROSS(left, grass_sp->proto.b[blade].leaf[seg].blade, z_axis);
465  VUNITIZE(left);
466  VCROSS(grass_sp->proto.b[blade].leaf[seg].N,
467  left, grass_sp->proto.b[blade].leaf[seg].blade);
468  VUNITIZE(grass_sp->proto.b[blade].leaf[seg].N);
469 
470  val -= tmp * .4;
471  }
472 
473  if (rdebug&RDEBUG_SHADE) {
474  print_plant("proto", &grass_sp->proto);
475  }
476 
477 
478 }
479 
480 
481 /*
482  * This routine is called (at prep time)
483  * once for each region which uses this shader.
484  * Any shader-specific initialization should be done here.
485  */
486 HIDDEN int
487 grass_setup(register struct region *rp, struct bu_vls *matparm, void **dpp, const struct mfuncs *UNUSED(mfp), struct rt_i *rtip)
488 
489 
490 /* pointer to reg_udata in *rp */
491 
492 /* New since 4.4 release */
493 {
494  register struct grass_specific *grass_sp;
495 
496  /* check the arguments */
497  RT_CHECK_RTI(rtip);
498  BU_CK_VLS(matparm);
499  RT_CK_REGION(rp);
500 
501 
502  if (rdebug&RDEBUG_SHADE)
503  bu_log("grass_setup(%s)\n", rp->reg_name);
504 
505  /* Get memory for the shader parameters and shader-specific data */
506  BU_GET(grass_sp, struct grass_specific);
507  *dpp = grass_sp;
508 
509  /* initialize the default values for the shader */
510  memcpy(grass_sp, &grass_defaults, sizeof(struct grass_specific));
511 
512  if (rp->reg_aircode == 0) {
513  bu_log("%s\n%s\n",
514  "*** WARNING: grass shader applied to non-air region!!! ***",
515  "Set air flag with 'edcodes' in mged");
516  bu_bomb("grass shader applied improperly");
517  }
518 
519  /* parse the user's arguments for this use of the shader. */
520  if (bu_struct_parse(matparm, grass_parse_tab, (char *)grass_sp, NULL) < 0)
521  return -1;
522 
523  /* The shader needs to operate in a coordinate system which stays
524  * fixed on the region when the region is moved (as in animation).
525  * We need to get a matrix to perform the appropriate transform(s).
526  */
527  db_region_mat(grass_sp->m_to_sh, rtip->rti_dbip, rp->reg_name, &rt_uniresource);
528 
529  bn_mat_inv(grass_sp->sh_to_m, grass_sp->m_to_sh);
530 
531  if (rdebug&RDEBUG_SHADE) {
532 
533  bu_struct_print(" Parameters:", grass_print_tab, (char *)grass_sp);
534  bn_mat_print("m_to_sh", grass_sp->m_to_sh);
535  bn_mat_print("sh_to_m", grass_sp->sh_to_m);
536  }
537 
538  if (grass_sp->proto.magic != PLANT_MAGIC) {
539  make_proto(grass_sp);
540  }
541 
542 
543  return 1;
544 }
545 
546 
547 HIDDEN void
548 grass_print(register struct region *rp, void *dp)
549 {
550  bu_struct_print(rp->reg_name, grass_print_tab, (char *)dp);
551 }
552 
553 
554 HIDDEN void
555 grass_free(void *cp)
556 {
557  BU_PUT(cp, struct grass_specific);
558 }
559 
560 
561 static void
562 plot_bush(struct plant *pl, struct grass_ray *r)
563 {
564  int blade, seg;
565  point_t pt;
566 
568  pl_color(r->fd, 150, 250, 150);
569 
570  for (blade=0; blade < pl->blades; blade++) {
571 
572  VMOVE(pt, pl->root);
573  pdv_3move(r->fd, pt);
574 
575  for (seg=0; seg < pl->b[blade].segs; seg++) {
576 
577  VJOIN1(pt, pt, pl->b[blade].leaf[seg].len,
578  pl->b[blade].leaf[seg].blade);
579 
580  pdv_3cont(r->fd, pt);
581  }
582  }
583 
584  /* plot bounding Box */
585  pl_color(r->fd, 100, 200, 100);
586  pdv_3move(r->fd, pl->pmin);
587  pd_3cont(r->fd, pl->pmin[X], pl->pmin[Y], pl->pmin[Z]);
588  pd_3cont(r->fd, pl->pmax[X], pl->pmin[Y], pl->pmin[Z]);
589  pd_3cont(r->fd, pl->pmax[X], pl->pmax[Y], pl->pmin[Z]);
590  pd_3cont(r->fd, pl->pmin[X], pl->pmax[Y], pl->pmin[Z]);
591  pd_3cont(r->fd, pl->pmin[X], pl->pmin[Y], pl->pmin[Z]);
592 
593  pd_3cont(r->fd, pl->pmin[X], pl->pmin[Y], pl->pmax[Z]);
594  pd_3cont(r->fd, pl->pmax[X], pl->pmin[Y], pl->pmax[Z]);
595  pd_3cont(r->fd, pl->pmax[X], pl->pmax[Y], pl->pmax[Z]);
596  pd_3cont(r->fd, pl->pmin[X], pl->pmax[Y], pl->pmax[Z]);
597  pd_3cont(r->fd, pl->pmin[X], pl->pmin[Y], pl->pmax[Z]);
598 
599  pl_color(r->fd, 255, 255, 255);
601 }
602 static void
603 make_bush(struct plant *pl, double seed, const fastf_t *cell_pos, const struct grass_specific *grass_sp, double w, struct grass_ray *r)
604 
605 /* derived from cell_num */
606 
607 
608 /* cell specific weight for count, height */
609 
610 {
611  point_t pt;
612  int blade, seg;
613  unsigned idx;
614 
615  if (rdebug&RDEBUG_SHADE)
616  bu_log("make_bush(%g, ... %g)\n", seed, w);
617 
618  CK_grass_SP(grass_sp);
619 
620  *pl = grass_sp->proto; /* struct copy */
621 
622  /* get coordinates for the plant root within the cell */
623  VMOVE(pl->root, cell_pos);
624  pl->root[Z] = 0.0;
625 
626  BN_RANDSEED(idx, seed);
627  pl->root[X] += BN_RANDOM(idx) * grass_sp->cell[X];
628 
629  pl->root[Y] += BN_RANDOM(idx) * grass_sp->cell[Y];
630 
631  /* set up for bounding box computation */
632  VADD2(pl->pmin, pl->pmin, pl->root);
633  VADD2(pl->pmax, pl->pmax, pl->root);
634 
635  VSCALE(pt, pl->root, grass_sp->size);
636 
637  plant_scale(pl, w); /* must come first */
638  plant_rot(pl, BN_RANDOM(idx) * M_2PI);/* computes bounding box */
639 
640  /* set bounding boxes */
641  for (blade=0; blade < pl->blades; blade++) {
642  VMOVE(pt, pl->root);
643  for (seg=0; seg < pl->b[blade].segs; seg++) {
644  VJOIN1(pt, pt, pl->b[blade].leaf[seg].len,
645  pl->b[blade].leaf[seg].blade);
646 
647  VMINMAX(pl->b[blade].pmin, pl->b[blade].pmax, pt);
648  }
649  VMINMAX(pl->pmin, pl->pmax, pl->b[blade].pmin);
650  VMINMAX(pl->pmin, pl->pmax, pl->b[blade].pmax);
651  }
652  if (rdebug&RDEBUG_SHADE && r->fd) plot_bush(pl, r);
653 }
654 
655 
656 /* Intersect ray with leaf segment. We already know we're within
657  * max width of the segment.
658  *
659  */
660 static void
661 hit_blade(const struct blade *UNUSED(bl), struct grass_ray *r, struct shadework *UNUSED(swp), const struct grass_specific *grass_sp, int UNUSED(seg), fastf_t *UNUSED(ldist), int UNUSED(blade_num), double UNUSED(fract))
662 
663 
664 /* defined in material.h */
665 
666 
667 {
668  CK_grass_SP(grass_sp);
669  BU_CKMAG(r, GRASSRAY_MAGIC, "grass_ray");
670 
671 
672  /* get the hit point/PCA */
673  if (rdebug&RDEBUG_SHADE)
674  bu_log("\t hit_blade()\n");
675 
676  r->occlusion = 1.0;
677  return;
678 }
679 
680 
681 /* intersect ray with leaves of single blade
682  *
683  */
684 static void
685 isect_blade(const struct blade *bl, const fastf_t *root, struct grass_ray *r, struct shadework *swp, const struct grass_specific *grass_sp, int blade_num)
686 
687 
688 /* defined in material.h */
689 
690 
691 {
692  fastf_t ldist[2];
693  point_t pt;
694  int cond;
695  int seg;
696  point_t PCA_ray;
697  double PCA_ray_radius;
698  point_t PCA_grass;
699  vect_t tmp;
700  double dist;
701  double accum_len;/* accumulated distance along blade from prev segs */
702  double fract; /* fraction of total blade length to PCA */
703  double blade_width;/* width of blade at PCA with ray */
704 
705 
706  CK_grass_SP(grass_sp);
707  BU_CKMAG(r, GRASSRAY_MAGIC, "grass_ray");
708 
709  if (rdebug&RDEBUG_SHADE)
710  bu_log("\t isect_blade()\n");
711 
712 
713  BU_CKMAG(bl, BLADE_MAGIC, "blade");
714 
715  VMOVE(pt, root);
716 
717  accum_len = 0.0;
718 
719  for (seg=0; seg < bl->segs; accum_len += bl->leaf[seg].len) {
720 
721  BU_CKMAG(&bl->leaf[seg].magic, LEAF_MAGIC, "leaf");
722 
723  cond = bn_dist_line3_line3(ldist, r->r.r_pt, r->r.r_dir,
724  pt, bl->leaf[seg].blade, &r->tol);
725 
726  if (rdebug&RDEBUG_SHADE) {
727  bu_log("\t ");
728  switch (cond) {
729  case -2: bu_log("lines parallel "); break;
730  case -1: bu_log("lines collinear "); break;
731  case 0: bu_log("lines intersect "); break;
732  case 1: bu_log("lines miss "); break;
733  }
734  bu_log("d1:%d d2:%g %g\n", cond, V2ARGS(ldist));
735  }
736  if (ldist[0] < 0.0 /* behind ray */ ||
737  ldist[0] >= r->d_max /* beyond out point */ ||
738  ldist[1] < 0.0 /* under ground */ ||
739  ldist[1] > bl->leaf[seg].len/* beyond end of seg */
740  ) goto iter;
741 
742  VJOIN1(PCA_ray, r->r.r_pt, ldist[0], r->r.r_dir);
743  PCA_ray_radius = r->radius + ldist[0] * r->diverge;
744 
745  VJOIN1(PCA_grass, pt, ldist[1], bl->leaf[seg].blade);
746  VSUB2(tmp, PCA_grass, PCA_ray);
747  dist = MAGNITUDE(tmp);
748 
749 
750  /* We want to narrow the blade of grass toward the tip.
751  * So we scale the width of the blade based upon the
752  * fraction of total blade length to PCA.
753  */
754  fract = (accum_len + ldist[1]) / bl->tot_len;
755  if (blade_num < BLADE_LAST) {
756  blade_width = bl->width * (1.0 - fract);
757  } else {
758  blade_width = .5 * bl->width * (1.0 - fract);
759  }
760 
761  if (dist < (PCA_ray_radius+blade_width)) {
762  if (rdebug&RDEBUG_SHADE)
763  bu_log("\thit grass: %g < (%g + %g)\n",
764  dist, PCA_ray_radius,
765  bl->width);
766 
767  hit_blade(bl, r, swp, grass_sp, seg, ldist,
768  blade_num, fract);
769 
770  if (r->occlusion >= 1.0) return;
771 
772  }
773  if (rdebug&RDEBUG_SHADE) bu_log("\t (missed aside)\n");
774 
775  iter:
776  /* compute origin of NEXT leaf segment */
777  VJOIN1(pt, pt, bl->leaf[seg].len, bl->leaf[seg].blade);
778  seg++;
779  }
780 }
781 
782 
783 static void
784 isect_plant(const struct plant *pl, struct grass_ray *r, struct shadework *swp, const struct grass_specific *grass_sp)
785 
786 
787 /* defined in material.h */
788 
789 {
790  int i;
791 
792  CK_grass_SP(grass_sp);
793  BU_CKMAG(r, GRASSRAY_MAGIC, "grass_ray");
794  BU_CKMAG(pl, PLANT_MAGIC, "plant");
795 
796  if (rdebug&RDEBUG_SHADE) {
797  bu_log("isect_plant()\n");
798  print_plant("plant", pl);
799  }
800 
801  r->r.r_min = r->r.r_max = 0.0;
802  if (! rt_in_rpp(&r->r, r->rev, pl->pmin, pl->pmax)) {
803  if (rdebug&RDEBUG_SHADE) {
804  point_t in_pt, out_pt;
805  bu_log("min:%g max:%g\n", r->r.r_min, r->r.r_max);
806 
807  bu_log("ray %g %g %g->%g %g %g misses:\n\trpp %g %g %g, %g %g %g\n",
808  V3ARGS(r->r.r_pt), V3ARGS(r->r.r_dir),
809  V3ARGS(pl->pmin), V3ARGS(pl->pmax));
810  VJOIN1(in_pt, r->r.r_pt, r->r.r_min, r->r.r_dir);
811  VPRINT("\tin_pt", in_pt);
812 
813  VJOIN1(out_pt, r->r.r_pt, r->r.r_max, r->r.r_dir);
814  VPRINT("\tout_pt", out_pt);
815  bu_log("MISSED BBox\n");
816  }
817  return;
818  } else {
819  if (rdebug&RDEBUG_SHADE) {
820  point_t in_pt, out_pt;
821  bu_log("min:%g max:%g\n", r->r.r_min, r->r.r_max);
822  bu_log("ray %g %g %g->%g %g %g hit:\n\trpp %g %g %g, %g %g %g\n",
823  V3ARGS(r->r.r_pt),
824  V3ARGS(r->r.r_dir),
825  V3ARGS(pl->pmin),
826  V3ARGS(pl->pmax));
827  VJOIN1(in_pt, r->r.r_pt, r->r.r_min, r->r.r_dir);
828  VPRINT("\tin_pt", in_pt);
829 
830  VJOIN1(out_pt, r->r.r_pt, r->r.r_max, r->r.r_dir);
831  VPRINT("\tout_pt", out_pt);
832  bu_log("HIT BBox\n");
833  }
834  }
835 
836  for (i=0; i < pl->blades; i++) {
837  isect_blade(&pl->b[i], pl->root, r, swp, grass_sp, i);
838  if (r->occlusion >= 1.0)
839  return;
840  }
841 }
842 
843 
844 static int
845 stat_cell(fastf_t *UNUSED(cell_pos), struct grass_ray *r, struct grass_specific *grass_sp, struct shadework *swp, double dist_to_cell, double radius)
846 /* origin of cell in region coordinates */
847 
848 
849 /* radius of ray */
850 {
851  point_t tmp;
852  vect_t color;
853  double h;
854 
855  double ratio = grass_sp->blade_width / radius;
856  /* the ray is *large* so just pick something appropriate */
857 
858  CK_grass_SP(grass_sp);
859  BU_CKMAG(r, GRASSRAY_MAGIC, "grass_ray");
860 
861  if (rdebug&RDEBUG_SHADE)
862  bu_log("statistical bailout\n");
863 
864  r->hit.hit_dist = dist_to_cell;
865  VJOIN1(r->hit.hit_point, r->r.r_pt, dist_to_cell, r->r.r_dir);
866 
867  /* compute color at this point */
868  h = r->hit.hit_point[Z] / 400.0;
869 
870  VSCALE(color, swp->sw_basecolor, 1.0 - h);
871  VJOIN1(color, color, h, grass_sp->brown);
872 
873  if (VEQUAL(swp->sw_color, swp->sw_basecolor)) {
874  VSCALE(swp->sw_color, color, ratio);
875  swp->sw_transmit -= ratio;
876  } else {
877  VJOIN1(swp->sw_color, swp->sw_color, ratio, grass_sp->brown);
878  swp->sw_transmit -= ratio;
879  }
880 
881  VADD2(tmp, r->hit.hit_point, grass_sp->delta);
882  bn_noise_vec(tmp, r->hit.hit_normal);
883  if (r->hit.hit_normal[Z] < 0.0) r->hit.hit_normal[Z] *= -1.0;
884 
885  VUNITIZE(r->hit.hit_normal);
886  if (VDOT(r->hit.hit_normal, r->r.r_dir) > 0.0) {
887  VREVERSE(r->hit.hit_normal, r->hit.hit_normal);
888  }
889 
890  if (swp->sw_transmit < .05)
891  return SHADE_ABORT_GRASS;
892  else
893  return SHADE_CONT;
894 }
895 
896 
897 static void
898 plot_cell(long int *cell, struct grass_ray *r, struct grass_specific *grass_sp)
899 /* cell number (such as 5, 3) */
900 
901 
902 {
903  point_t cell_pos;
904 
905  CK_grass_SP(grass_sp);
906 
907  CELL_POS(cell_pos, grass_sp, cell);
908  bu_log("plotting cell %ld, %ld (%g, %g) %g %g\n",
909  V2ARGS(cell), V2ARGS(cell_pos), V2ARGS(grass_sp->cell));
910 
912  pl_color(r->fd, 100, 100, 200);
913 
914  pd_3move(r->fd, cell_pos[X], cell_pos[Y], 0.0);
915  pd_3cont(r->fd, cell_pos[X]+grass_sp->cell[X], cell_pos[Y], 0.0);
916  pd_3cont(r->fd, cell_pos[X]+grass_sp->cell[X], cell_pos[Y]+grass_sp->cell[Y], 0.0);
917  pd_3cont(r->fd, cell_pos[X], cell_pos[Y]+grass_sp->cell[Y], 0.0);
918  pd_3cont(r->fd, cell_pos[X], cell_pos[Y], 0.0);
919  pl_color(r->fd, 255, 255, 255);
921 
922 }
923 
924 
925 /*
926  * Intersects a region-space ray with a grid cell of grass.
927  *
928  */
929 static void
930 isect_cell(long int *cell, struct grass_ray *r, struct shadework *swp, double out_dist, struct grass_specific *grass_sp, double curr_dist)
931 /* cell number (such as 5, 3) */
932 
933 
934 {
935  point_t c = {0.0, 0.0, 0.0}; /* float version of cell # */
936  point_t cell_pos = {0.0, 0.0, 0.0}; /* origin of cell in region coordinates */
937  double val;
938  vect_t v;
939  int p; /* current plant number (loop variable) */
940  int ppc; /* # plants in this cell */
941  struct plant pl;
942  double dist_to_cell;
943 
944  CK_grass_SP(grass_sp);
945 
946  if (rdebug&RDEBUG_SHADE) {
947  static int plot_num = 0;
948  char buf[32];
949  point_t cell_in_pt;
950  point_t cell_out_pt; /* not really */
951 
952  bu_log("isect_cell(%ld, %ld)\n", V2ARGS(cell));
953 
954 
956  sprintf(buf, "g_ray%d, %d_%d_cell%ld, %ld_.plot3",
957  r->ap->a_x, r->ap->a_y, plot_num++, cell[0], cell[1]);
958  r->fd = fopen(buf, "wb");
959  if (r->fd) {
960  if (swp->sw_xmitonly)
961  pl_color(r->fd, 255, 255, 55);
962  else
963  pl_color(r->fd, 255, 55, 55);
964 
965  VJOIN1(cell_in_pt, r->r.r_pt, curr_dist, r->r.r_dir);
966  VJOIN1(cell_out_pt, r->r.r_pt, out_dist, r->r.r_dir);
967 
968  pdv_3move(r->fd, cell_in_pt);
969  pdv_3cont(r->fd, cell_out_pt);
970  pl_color(r->fd, 255, 255, 255);
971  }
972 
974  if (r->fd) plot_cell(cell, r, grass_sp);
975  }
976 
977 
978  /* get coords of cell */
979  CELL_POS(cell_pos, grass_sp, cell);
980 
981  VSUB2(v, cell_pos, r->r.r_pt);
982  dist_to_cell = MAGNITUDE(v);
983 
984 
985  /* radius of ray at cell origin */
986  val = r->radius + r->diverge * dist_to_cell;
987 
988  if (rdebug&RDEBUG_SHADE)
989  bu_log("\t ray radius @cell %g = %g, %g, %g (%g)\n\t cell:%g, %g\n",
990  val, r->radius, r->diverge, dist_to_cell, val*32.0,
991  V2ARGS(grass_sp->cell));
992 
993  if (val > grass_sp->blade_width * 3) {
994  stat_cell(cell_pos, r, grass_sp, swp, dist_to_cell, val);
995  return;
996  }
997 
998  /* Figure out how many plants are in this cell */
999 
1000  val = plants_this_cell(cell, grass_sp);
1001 
1002  ppc = grass_sp->ppc + grass_sp->ppcd * val;
1003 
1004  if (rdebug&RDEBUG_SHADE) {
1005  bu_log("cell pos(%g, %g .. %g, %g)\n", V2ARGS(cell_pos),
1006  cell_pos[X]+grass_sp->cell[X],
1007  cell_pos[Y]+grass_sp->cell[Y]);
1008 
1009  bu_log("%d plants ppc:%g v:%g\n", ppc, grass_sp->ppcd, val);
1010  }
1011 
1012  /* Get origin of cell in noise space (without delta)
1013  * to use for computing seed needed by make_bush
1014  */
1015  VSCALE(c, cell, grass_sp->size);
1016 
1017 
1018  /* intersect the ray with each plant */
1019  for (p=0; p < ppc; p++) {
1020 
1021  CK_grass_SP(grass_sp);
1022  BU_CKMAG(r, GRASSRAY_MAGIC, "grass_ray");
1023 
1024  make_bush(&pl, c[X]+c[Y], cell_pos, grass_sp, val, r);
1025 
1026  CK_grass_SP(grass_sp);
1027  BU_CKMAG(r, GRASSRAY_MAGIC, "grass_ray");
1028  BU_CKMAG(&pl, PLANT_MAGIC, "plant");
1029 
1030  isect_plant(&pl, r, swp, grass_sp);
1031  if (r->occlusion >= 1.0) return;
1032 
1033  VSCALE(c, c, grass_sp->lacunarity);
1034  }
1035 }
1036 
1037 
1038 /* Process a grid cell and any unprocessed adjoining neighbors.
1039  *
1040  * The flags argument indicates which cells (relative to the central
1041  * one) need to be processed. The bit values for the relative
1042  * positions are:
1043  *
1044  * pos bit pos bit pos bit
1045  *------------------------------------
1046  * -1, 1 0100 0, 1 0200 1, 1 0400
1047  * -1, 0 0010 0, 0 0020 1, 0 0040
1048  * -1, -1 0001 0, -1 0002 1, -1 0004
1049  *
1050  *
1051  * A set flag indicates that the cell has NOT been processed
1052  *
1053  * Return:
1054  * 0 continue grid marching
1055  * !0 abort grid marching
1056  */
1057 static void
1058 do_cells(long int *cell_num, struct grass_ray *r, short int flags, struct shadework *swp, double out_dist, struct grass_specific *grass_sp, double curr_dist)
1059 
1060 
1061 /* which adj cells need processing */
1062 
1063 /* defined in material.h */
1064 
1065 
1066 {
1067  int x, y;
1068  long cell[3] = {0, 0, 0};
1069 
1070 #define FLAG(x, y) ((1 << ((y+1)*3)) << (x+1))
1071 #define ISDONE(x, y, flags) (! (FLAG(x, y) & flags))
1072 
1073  CK_grass_SP(grass_sp);
1074  BU_CKMAG(r, GRASSRAY_MAGIC, "grass_ray");
1075 
1076  if (rdebug&RDEBUG_SHADE)
1077  bu_log("do_cells(%ld, %ld)\n", V2ARGS(cell_num));
1078 
1079  for (y=-1; y < 2; y++) {
1080  for (x=-1; x < 2; x++) {
1081 
1082  if (ISDONE(x, y, flags)) continue;
1083 
1084  cell[X] = cell_num[X] + x;
1085  cell[Y] = cell_num[Y] + y;
1086 
1087  if (rdebug&RDEBUG_SHADE)
1088  bu_log("checking relative cell %2d, %2d at(%ld, %ld)\n",
1089  x, y, V2ARGS(cell));
1090 
1091  isect_cell(cell, r, swp, out_dist, grass_sp, curr_dist);
1092  if (r->occlusion >= 1.0) return;
1093  }
1094  }
1095 }
1096 
1097 
1098 /*
1099  * This is called (from viewshade() in shade.c) once for each hit point
1100  * to be shaded. The purpose here is to fill in values in the shadework
1101  * structure.
1102  */
1103 int
1104 grass_render(struct application *ap, const struct partition *pp, struct shadework *swp, void *dp)
1105 
1106 
1107 /* defined in material.h */
1108 /* ptr to the shader-specific struct */
1109 {
1110  register struct grass_specific *grass_sp =
1111  (struct grass_specific *)dp;
1112  struct grass_ray gr;
1113  vect_t v;
1114  vect_t in_rad, out_rad;
1115  point_t in_pt, out_pt, curr_pt;
1116  double curr_dist, out_dist;
1117  double radius;
1118  short flags;
1119  double t[2], tD[2];
1120  int n;
1121  double t_orig[2];
1122  long tD_iter[2];
1123  long cell_num[3]; /* cell number */
1124  point_t out_pt_m;
1125 
1126 
1127  /* check the validity of the arguments we got */
1128  RT_AP_CHECK(ap);
1129  RT_CHECK_PT(pp);
1130  CK_grass_SP(grass_sp);
1131 
1132  if (rdebug&RDEBUG_SHADE)
1133  bu_struct_print("grass_render Parameters:", grass_print_tab, (char *)grass_sp);
1134 
1135  swp->sw_transmit = 1.0;
1136 
1137  /* XXX now how would you transform the tolerance structure
1138  * to the local coordinate space ?
1139  */
1140  gr.magic = GRASSRAY_MAGIC;
1141  gr.occlusion = 0.0;
1142  gr.tol = ap->a_rt_i->rti_tol;
1143  gr.ap = ap;
1144  gr.fd = NULL;
1145 
1146  /* Convert everything over to Region space.
1147  * First the ray and its radius then
1148  * the in/out points
1149  */
1150  MAT4X3PNT(gr.r.r_pt, grass_sp->m_to_sh, ap->a_ray.r_pt);
1151  MAT4X3VEC(gr.r.r_dir, grass_sp->m_to_sh, ap->a_ray.r_dir);
1152  VUNITIZE(gr.r.r_dir);
1153  VINVDIR(gr.rev, gr.r.r_dir);
1154 
1155  /* In Hit point */
1156  MAT4X3PNT(in_pt, grass_sp->m_to_sh, swp->sw_hit.hit_point);
1157 
1158  /* The only thing we can really do to get the size of the
1159  * ray footprint at the In Hit point is get 3 (possibly different)
1160  * radii in the Region coordinate system. We construct a unit vector
1161  * in model space with equal X, Y, Z and transform it to region space.
1162  */
1163  radius = ap->a_rbeam + swp->sw_hit.hit_dist * ap->a_diverge;
1164  VSETALL(v, radius);
1165  VUNITIZE(v);
1166  MAT4X3VEC(in_rad, grass_sp->m_to_sh, v);
1167 
1168  gr.radius = ap->a_rbeam; /* XXX Bogus if Region != Model space */
1169  gr.diverge = ap->a_diverge;/* XXX Bogus if Region != Model space */
1170 
1171  /* Out point */
1172  VJOIN1(out_pt_m, ap->a_ray.r_pt, pp->pt_outhit->hit_dist,
1173  ap->a_ray.r_dir);
1174  MAT4X3VEC(out_pt, grass_sp->m_to_sh, out_pt_m);
1175  radius = ap->a_rbeam + pp->pt_outhit->hit_dist * ap->a_diverge;
1176  VSETALL(v, radius);
1177  MAT4X3VEC(out_rad, grass_sp->m_to_sh, v);
1178 
1179 
1180  /* set up a DDA grid to march through. */
1181  VSUB2(v, in_pt, gr.r.r_pt);
1182  curr_dist = MAGNITUDE(v);
1183 
1184  /* We set up a hit on the out point so that when we get a hit on
1185  * a grass blade in a cell we can tell if it's closer than the
1186  * previous hits. This way we end up using the closest hit for
1187  * the final result.
1188  */
1189  VSUB2(v, out_pt, gr.r.r_pt);
1190  gr.d_max = gr.hit.hit_dist = out_dist = MAGNITUDE(v);
1191  VMOVE(gr.hit.hit_point, out_pt);
1192  MAT4X3VEC(gr.hit.hit_normal, grass_sp->m_to_sh, swp->sw_hit.hit_normal);
1193 
1194  if (rdebug&RDEBUG_SHADE) {
1195  bu_log("Pt: (%g %g %g)\nRPt:(%g %g %g)\n",
1196  V3ARGS(ap->a_ray.r_pt),
1197  V3ARGS(gr.r.r_pt));
1198  bu_log("Dir: (%g %g %g)\nRDir:(%g %g %g)\n", V3ARGS(ap->a_ray.r_dir),
1199  V3ARGS(gr.r.r_dir));
1200  bu_log("rev: (%g %g %g)\n", V3ARGS(gr.rev));
1201 
1202  bu_log("Hit Pt:(%g %g %g) d:%g r: %g\nRegHPt:(%g %g %g) d:%g Rr:(%g %g %g)\n",
1203  V3ARGS(swp->sw_hit.hit_point), swp->sw_hit.hit_dist,
1204  ap->a_rbeam + swp->sw_hit.hit_dist * ap->a_diverge,
1205  V3ARGS(in_pt), curr_dist, V3ARGS(in_rad));
1206 
1207  VJOIN1(v, ap->a_ray.r_pt, pp->pt_outhit->hit_dist, ap->a_ray.r_dir);
1208  bu_log("Out Pt:(%g %g %g) d:%g r: %g\nRegOPt:(%g %g %g) d:%g ROr:(%g %g %g)\n",
1209  V3ARGS(v), pp->pt_outhit->hit_dist, radius,
1210  V3ARGS(out_pt), out_dist, V3ARGS(out_rad));
1211  }
1212 
1213 
1214  /* tD[X] is the distance along the ray we have to travel
1215  * to traverse a cell (travel a unit distance) along the
1216  * X axis of the grid.
1217  *
1218  * t[X] is the distance along the ray to the first cell boundary
1219  * beyond the hit point in the X direction.
1220  *
1221  * t_orig[X] is the same as t[X] but won't get changed as we
1222  * march across the grid. At each X grid line crossing, we recompute
1223  * a new t[X] from t_orig[X], tD[X], tD_iter[X]. The tD_iter[X] is
1224  * the number of times we've made a full step in the X direction.
1225  */
1226  for (n=X; n < Z; n++) {
1227  char *s;
1228  if (n == X) s="X";
1229  else s="Y";
1230 
1231  /* compute distance from cell origin to in_pt */
1232  t[n] = in_pt[n] -
1233  floor(in_pt[n]/grass_sp->cell[n]) *
1234  grass_sp->cell[n];
1235  if (rdebug&RDEBUG_SHADE)
1236  bu_log("t[%s]:%g = in_pt[%s]:%g - floor():%g * cell[%s]%g\n",
1237  s, t[n], s, in_pt[n],
1238  floor(in_pt[n]/grass_sp->cell[n]),
1239  s, grass_sp->cell[n]);
1240 
1241  if (gr.r.r_dir[n] < -SMALL_FASTF) {
1242  tD[n] = -grass_sp->cell[n] / gr.r.r_dir[n];
1243  t[n] = t[n] / -gr.r.r_dir[n];
1244  t[n] += curr_dist;
1245  } else if (gr.r.r_dir[n] > SMALL_FASTF) {
1246  tD[n] = grass_sp->cell[n] / gr.r.r_dir[n];
1247  t[n] = grass_sp->cell[n] - t[n];
1248  t[n] = t[n] / gr.r.r_dir[n];
1249  t[n] += curr_dist;
1250  } else {
1251  tD[n] = t[n] = MAX_FASTF;
1252  }
1253  if (t[n] > out_dist) t[n] = out_dist;
1254  t_orig[n] = t[n];
1255  tD_iter[n] = 0;
1256  }
1257 
1258 
1259  if (rdebug&RDEBUG_SHADE) {
1260  bu_log("t[X]:%g tD[X]:%g\n", t[X], tD[X]);
1261  bu_log("t[Y]:%g tD[Y]:%g\n\n", t[Y], tD[Y]);
1262  }
1263 
1264  /* The flags argument indicates which cells (relative to the central
1265  * one) have already been processed. The bit values for the relative
1266  * positions are:
1267  *
1268  * pos bit pos bit pos bit
1269  *------------------------------------
1270  * -1, 1 0100 0, 1 0200 1, 1 0400
1271  * -1, 0 0010 0, 0 0020 1, 0 0040
1272  * -1, -1 0001 0, -1 0002 1, -1 0004
1273  *
1274  * A set bit indicates that the cell has NOT been processed.
1275  */
1276  flags = 0777; /* no adjacent cells processed */
1277  VMOVE(curr_pt, in_pt);
1278  cell_num[X] = (long)(in_pt[X] / grass_sp->cell[X]);
1279  cell_num[Y] = (long)(in_pt[Y] / grass_sp->cell[Y]);
1280  cell_num[Z] = 0.0;
1281 
1282  /* Time to go marching across the grid */
1283  while (curr_dist < out_dist) {
1284 
1285 
1286  if (rdebug&RDEBUG_SHADE) {
1287  point_t cell_pos; /* cell origin position */
1288 
1289  if (rdebug&RDEBUG_SHADE) {
1290  bu_log("dist:%g (%g %g %g)\n", curr_dist,
1291  V3ARGS(curr_pt));
1292  bu_log("cell num: %ld %ld\n", V2ARGS(cell_num));
1293  }
1294  CELL_POS(cell_pos, grass_sp, cell_num);
1295 
1296  if (rdebug&RDEBUG_SHADE)
1297  bu_log("cell pos: %g %g\n", V2ARGS(cell_pos));
1298  }
1299 
1300 
1301  do_cells(cell_num, &gr, flags, swp, out_dist, grass_sp, curr_dist);
1302  if (gr.occlusion >= 1.0)
1303  goto done;
1304 
1305  if (t[X] < t[Y]) {
1306  if (rdebug&RDEBUG_SHADE)
1307  bu_log("stepping X %le\n", t[X]);
1308  if (gr.r.r_dir[X] < 0.0) {
1309  flags = 0111;
1310  cell_num[X]--;
1311  } else {
1312  flags = 0444;
1313  cell_num[X]++;
1314  }
1315  n = X;
1316  } else {
1317  if (rdebug&RDEBUG_SHADE)
1318  bu_log("stepping Y %le\n", t[Y]);
1319  if (gr.r.r_dir[Y] < 0.0) {
1320  flags = 0007;
1321  cell_num[Y]--;
1322  } else {
1323  flags = 0700;
1324  cell_num[Y]++;
1325  }
1326  n = Y;
1327  }
1328  curr_dist = t[n];
1329  t[n] = t_orig[n] + tD[n] * ++tD_iter[n];
1330 
1331  if (t[n] > out_dist) t[n] = out_dist;
1332 
1333  VJOIN1(curr_pt, gr.r.r_pt, curr_dist, gr.r.r_dir);
1334  curr_pt[n] = ((long) ((curr_pt[n] / grass_sp->cell[n]) + .1))
1335  * grass_sp->cell[n];
1336  }
1337 
1338 
1339  if (rdebug&RDEBUG_SHADE)
1340  bu_log("Missed grass blades\n");
1341 
1342  /* Missed everything */
1343 
1344 
1345  if (grass_sp->debug && !swp->sw_xmitonly) {
1346  /* show the cell positions on the ground */
1347  double bc;
1348 
1349  bc = plants_this_cell(cell_num, grass_sp);
1350  CLAMP(bc, 0.0, 1.0);
1351  bc = .25 * bc + .7;
1352 
1353  if ((cell_num[X] + cell_num[Y]) & 1) {
1354  VSET(swp->sw_basecolor, bc, bc*.7, bc*.7);
1355  } else {
1356  VSET(swp->sw_basecolor, bc*.7, bc*.7, bc);
1357  }
1358  } else {
1359  /* setting basecolor to 1.0 prevents 'filterglass' effect */
1360  VSETALL(swp->sw_basecolor, 1.0);
1361  }
1362 
1363 
1364  (void)rr_render(ap, pp, swp);
1365 
1366 done:
1367  if (rdebug&RDEBUG_SHADE) {
1369  if (gr.fd) {
1370  fflush(gr.fd);
1371  fclose(gr.fd);
1372  }
1374  }
1375 
1376  return 1;
1377 }
1378 
1379 
1380 /*
1381  * Local Variables:
1382  * mode: C
1383  * tab-width: 8
1384  * indent-tabs-mode: t
1385  * c-file-style: "stroustrup"
1386  * End:
1387  * ex: shiftwidth=4 tabstop=8
1388  */
Definition: db_flip.c:35
struct xray a_ray
Actual ray to be shot.
Definition: raytrace.h:1583
uint32_t magic
Definition: sh_grass.c:70
#define SHADE_ABORT_GRASS
Definition: sh_grass.c:41
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
struct hit * pt_outhit
OUT hit ptr.
Definition: raytrace.h:579
#define bu_byteoffset(_i)
Definition: parse.h:81
double size
Definition: sh_grass.c:127
struct bu_structparse grass_parse_tab[]
Definition: sh_grass.c:203
#define BU_CKMAG(_ptr, _magic, _str)
Definition: magic.h:233
#define MF_MAGIC
Definition: magic.h:205
struct plant proto
Definition: sh_grass.c:131
void pdv_3move(register FILE *plotfp, const fastf_t *pt)
Definition: plot3.c:618
double seg_ratio
Definition: sh_grass.c:123
if lu s
Definition: nmg_mod.c:3860
double ppcd
Definition: sh_grass.c:119
struct application * ap
Definition: sh_grass.c:104
int segs
Definition: sh_grass.c:73
#define VSET(a, b, c, d)
Definition: color.c:53
#define VSETALL(a, s)
Definition: color.c:54
Definition: raytrace.h:215
void bu_semaphore_acquire(unsigned int i)
Definition: semaphore.c:180
HIDDEN int grass_render(struct application *ap, const struct partition *pp, struct shadework *swp, void *dp)
Definition: sh_grass.c:1104
Definition: raytrace.h:368
#define grass_MAGIC
Definition: sh_grass.c:45
point_t vscale
Definition: sh_grass.c:128
Definition: raytrace.h:248
#define SMALL_FASTF
Definition: defines.h:342
uint32_t magic
Definition: sh_grass.c:94
Header file for the BRL-CAD common definitions.
#define SHADE_CONT
Definition: sh_grass.c:40
double diverge
Definition: sh_grass.c:99
const char * reg_name
Identifying string.
Definition: raytrace.h:539
struct blade b[BLADE_MAX]
Definition: sh_grass.c:86
mat_t sh_to_m
Definition: sh_grass.c:134
int rt_in_rpp(struct xray *rp, const fastf_t *invdir, const fastf_t *min, const fastf_t *max)
#define CK_grass_SP(_p)
Definition: sh_grass.c:46
#define MAX_FASTF
Definition: defines.h:340
#define RT_CK_REGION(_p)
Definition: raytrace.h:559
point_t pmin
Definition: sh_grass.c:75
#define HIDDEN
Definition: common.h:86
void pd_3move(register FILE *plotfp, double x, double y, double z)
Definition: plot3.c:624
FILE * fd
Definition: sh_grass.c:103
void bu_struct_print(const char *title, const struct bu_structparse *parsetab, const char *base)
Definition: parse.c:1221
Definition: sh_grass.c:82
struct hit hit
Definition: sh_grass.c:102
void bn_mat_mul2(const mat_t i, mat_t o)
if(share_geom)
Definition: nmg_mod.c:3829
#define RT_AP_CHECK(_ap)
Definition: raytrace.h:1685
double radius
Definition: sh_grass.c:100
#define BLADE_MAGIC
Definition: sh_grass.c:58
Definition: color.c:49
double cell[2]
Definition: sh_grass.c:117
struct rt_i * a_rt_i
this librt instance
Definition: raytrace.h:1588
#define BU_CK_VLS(_vp)
Definition: vls.h:69
struct resource rt_uniresource
default. Defined in librt/globals.c
Definition: globals.c:41
vect_t N
Definition: sh_grass.c:65
uint32_t magic
Definition: sh_grass.c:62
double octaves
Definition: sh_grass.c:126
void bn_mat_print(const char *title, const mat_t m)
Definition: mat.c:81
point_t pmin
Definition: sh_grass.c:87
void pd_3cont(register FILE *plotfp, double x, double y, double z)
Definition: plot3.c:636
#define RT_CHECK_RTI(_p)
Definition: raytrace.h:1832
struct leaf_segment leaf[BLADE_SEGS_MAX]
Definition: sh_grass.c:74
fastf_t a_diverge
slope of beam divergence/mm
Definition: raytrace.h:1600
void bn_mat_inv(mat_t output, const mat_t input)
#define V3ARGS(a)
Definition: color.c:56
int a_x
Screen X of ray, if applicable.
Definition: raytrace.h:1596
struct bn_tol tol
Definition: sh_grass.c:101
#define BU_GET(_ptr, _type)
Definition: malloc.h:201
point_t hit_point
DEPRECATED: Intersection point, use VJOIN1 hit_dist.
Definition: raytrace.h:251
point_t root
Definition: sh_grass.c:84
#define CELL_POS(cell_pos, grass_sp, cell_num)
Definition: sh_grass.c:49
#define PLANT_MAGIC
Definition: sh_grass.c:59
HIDDEN void grass_print(register struct region *rp, void *dp)
Definition: sh_grass.c:548
#define BN_RANDSEED(_i, _seed)
Definition: rand.h:60
struct mfuncs grass_mfuncs[]
Definition: sh_grass.c:232
double width
Definition: sh_grass.c:71
fastf_t r_max
exit dist from bounding sphere
Definition: raytrace.h:221
#define GRASSRAY_MAGIC
Definition: sh_grass.c:92
double d_max
Definition: sh_grass.c:97
void pdv_3cont(register FILE *plotfp, const fastf_t *pt)
Definition: plot3.c:630
double tot_len
Definition: sh_grass.c:72
#define UNUSED(parameter)
Definition: common.h:239
#define BU_PUT(_ptr, _type)
Definition: malloc.h:215
Support for uniform tolerances.
Definition: tol.h:71
HIDDEN int grass_setup(register struct region *rp, struct bu_vls *matparm, void **dpp, const struct mfuncs *mfp, struct rt_i *rtip)
Definition: sh_grass.c:487
#define BU_STRUCTPARSE_FUNC_NULL
Definition: parse.h:153
void bu_semaphore_release(unsigned int i)
Definition: semaphore.c:218
void pl_color(register FILE *plotfp, int r, int g, int b)
Definition: plot3.c:325
vect_t r_dir
Direction of ray (UNIT Length)
Definition: raytrace.h:219
#define BLADE_LAST
Definition: sh_grass.c:81
struct bn_tol rti_tol
Math tolerances for this model.
Definition: raytrace.h:1765
int bn_dist_line3_line3(fastf_t dist[2], const point_t p1, const point_t p2, const vect_t d1, const vect_t d2, const struct bn_tol *tol)
struct xray r
Definition: sh_grass.c:96
mat_t m_to_sh
Definition: sh_grass.c:133
int db_region_mat(mat_t m, struct db_i *dbip, const char *name, struct resource *resp)
Definition: db_tree.c:2269
fastf_t r_min
entry dist to bounding sphere
Definition: raytrace.h:220
double ppc
Definition: sh_grass.c:118
point_t r_pt
Point at which ray starts.
Definition: raytrace.h:218
int reg_aircode
Region ID AIR code.
Definition: raytrace.h:543
#define BLADE_SEGS_MAX
Definition: sh_grass.c:55
#define RDEBUG_SHADE
Definition: optical.h:130
#define BU_SEM_SYSCALL
Definition: parallel.h:178
struct db_i * rti_dbip
prt to Database instance struct
Definition: raytrace.h:1774
struct bu_structparse grass_print_tab[]
Definition: sh_grass.c:189
int bu_struct_parse(const struct bu_vls *in_vls, const struct bu_structparse *desc, const char *base, void *data)
Definition: parse.c:878
int a_y
Screen Y of ray, if applicable.
Definition: raytrace.h:1597
#define BN_RANDOM(_i)
Definition: rand.h:73
#define SHDR_O(m)
Definition: sh_grass.c:183
int blades
Definition: sh_grass.c:85
double lacunarity
Definition: sh_grass.c:124
point_t brown
Definition: sh_grass.c:130
point_t pmax
Definition: sh_grass.c:88
Definition: color.c:51
double bn_noise_fbm(point_t point, double h_val, double lacunarity, double octaves)
Procedural fBm evaluated at "point"; returns value stored in "value".
point_t pmax
Definition: sh_grass.c:76
HIDDEN void grass_free(void *cp)
Definition: sh_grass.c:555
vect_t hit_normal
DEPRECATED: Surface Normal at hit_point, use RT_HIT_NORMAL.
Definition: raytrace.h:252
fastf_t a_rbeam
initial beam radius (mm)
Definition: raytrace.h:1599
int rr_render(struct application *app, const struct partition *pp, struct shadework *swp)
double blade_width
Definition: sh_grass.c:121
double len
Definition: sh_grass.c:63
#define LEAF_MAGIC
Definition: sh_grass.c:57
vect_t blade
Definition: sh_grass.c:64
vect_t delta
Definition: sh_grass.c:129
double h_val
Definition: sh_grass.c:125
vect_t rev
Definition: sh_grass.c:98
#define RT_CHECK_PT(_p)
compat
Definition: raytrace.h:588
Definition: sh_grass.c:69
fastf_t hit_dist
dist from r_pt to hit_point
Definition: raytrace.h:250
#define BLADE_MAX
Definition: sh_grass.c:80
void bn_noise_vec(point_t point, point_t result)
Definition: vls.h:56
void bu_bomb(const char *str) _BU_ATTR_NORETURN
Definition: bomb.c:91
double fastf_t
Definition: defines.h:300
double occlusion
Definition: sh_grass.c:95
#define VPRINT(a, b)
Definition: raytrace.h:1881
Header file for the BRL-CAD Optical Library, LIBOPTICAL.
void bn_mat_zrot(mat_t m, double sinz, double cosz)
uint32_t magic
Definition: sh_grass.c:83
int rdebug
Definition: init.c:39
#define ISDONE(x, y, flags)
Definition: color.c:50
uint32_t magic
Definition: sh_grass.c:114