GRASS GIS 8 Programmer's Manual  8.4.0dev(2024)-b656141cbc
gs.c
Go to the documentation of this file.
1 /*!
2  \file lib/ogsf/gs.c
3 
4  \brief OGSF library - loading and manipulating surfaces (lower level
5  functions)
6 
7  GRASS OpenGL gsurf OGSF Library
8 
9  (C) 1999-2008 by the GRASS Development Team
10 
11  This program is free software under the
12  GNU General Public License (>=v2).
13  Read the file COPYING that comes with GRASS
14  for details.
15 
16  \author Bill Brown USACERL, GMSL/University of Illinois (January 1993)
17  \author Doxygenized by Martin Landa <landa.martin gmail.com> (May 2008)
18  */
19 
20 #include <stdlib.h>
21 #include <stdio.h>
22 
23 #include <grass/ogsf.h>
24 #include <grass/glocale.h>
25 
26 #include "gsget.h"
27 #include "rowcol.h"
28 
29 #define FIRST_SURF_ID 110658
30 
31 static geosurf *Surf_top;
32 static int Invertmask;
33 
34 /***********************************************************************/
35 void gs_err(const char *msg)
36 {
37  G_warning("%s", msg);
38 
39  return;
40 }
41 
42 /*!
43  \brief Initialize library
44 
45  Still need to take care of library initialization,
46  probably want to define a Surf_top of constant value (i.e., 0)
47  */
48 void gs_init(void)
49 {
50  Surf_top = NULL;
51 
52  return;
53 }
54 
55 /*!
56  \brief Get geosurf struct
57 
58  \param id surface id
59 
60  \return pointer to geosurf struct
61  \return NULL if not found
62  */
64 {
65  geosurf *gs;
66 
67  G_debug(5, "gs_get_surf():");
68 
69  for (gs = Surf_top; gs; gs = gs->next) {
70  if (gs->gsurf_id == id) {
71  G_debug(5, " id=%d", id);
72  return (gs);
73  }
74  }
75 
76  return (NULL);
77 }
78 
79 /*!
80  \brief Get previous geosurf struct
81 
82  \param id current surface id
83 
84  \return pointer to geosurf struct
85  \return NULL if not found
86  */
88 {
89  geosurf *ps;
90 
91  G_debug(5, "gs_get_prev_surface");
92 
93  for (ps = Surf_top; ps; ps = ps->next) {
94  if (ps->gsurf_id == id - 1) {
95  return (ps);
96  }
97  }
98 
99  return (NULL);
100 }
101 
102 /*!
103  \brief Get array of geosurf structs
104 
105  \param gsurfs pointer to array
106 
107  \return number of geosurfs
108  */
110 {
111  geosurf *gs;
112  int i;
113 
114  for (i = 0, gs = Surf_top; gs; gs = gs->next, i++) {
115  gsurfs[i] = gs;
116  }
117 
118  G_debug(5, "gs_num_surfaces(): num=%d", i);
119 
120  return (i);
121 }
122 
123 /*!
124  \brief Get number of surfaces
125 
126  \return number of surfaces
127  */
129 {
130  geosurf *gs;
131  int i;
132 
133  for (i = 0, gs = Surf_top; gs; gs = gs->next, i++)
134  ;
135 
136  G_debug(5, "gs_num_surfaces(): num=%d", i);
137 
138  return (i);
139 }
140 
141 /*!
142  \brief Check if attribute is set
143 
144  \param surf pointer to gsurf or NULL to look at all geosurfs
145  \param att attribute id
146 
147  \return 1 attribute is set up
148  \return 0 attribute is not set up
149  */
150 int gs_att_is_set(geosurf *surf, IFLAG att)
151 {
152  geosurf *gs;
153 
154  if (surf) {
155  return (NOTSET_ATT != surf->att[att].att_src);
156  }
157 
158  /* if surf == NULL, look at all surfs */
159  for (gs = Surf_top; gs; gs = gs->next) {
160  if (NOTSET_ATT != gs->att[att].att_src) {
161  return (1);
162  }
163  }
164 
165  return (0);
166 }
167 
168 /*!
169  \brief Get last allocated geosurf struct from list
170 
171  \return pointer to geosurf struct
172  */
174 {
175  geosurf *ls;
176 
177  if (!Surf_top) {
178  return (NULL);
179  }
180 
181  for (ls = Surf_top; ls->next; ls = ls->next)
182  ;
183 
184  G_debug(5, "gs_get_last_surface(): last surface id=%d", ls->gsurf_id);
185 
186  return (ls);
187 }
188 
189 /*!
190  \brief Allocate new geosurf struct
191 
192  \return pointer to geosurf struct
193  */
195 {
196  geosurf *ns, *ls;
197 
198  ns = (geosurf *)G_malloc(sizeof(geosurf)); /* G_fatal_error */
199  if (!ns) {
200  return (NULL);
201  }
202 
203  if ((ls = gs_get_last_surface())) {
204  ls->next = ns;
205  ns->gsurf_id = ls->gsurf_id + 1;
206  }
207  else {
208  Surf_top = ns;
209  ns->gsurf_id = FIRST_SURF_ID;
210  }
211 
212  ns->next = NULL;
213 
214  G_debug(5, "gs_get_new_surface(): id=%d", ns->gsurf_id);
215 
216  return (ns);
217 }
218 
219 /*!
220  \brief Initialize allocated geosurf struct
221 
222  \todo Now xmin & ox are the same, right? - get rid of ox, oy in geosurf
223  struct?
224 
225  \param gs pointer to geosurf struct
226  \param ox,oy x/y origin coordinates
227  \param rows number of rows
228  \param cols number of cols
229  \param xres,yres x/y resolution value
230 
231  \return -1 on error
232  \return 0 on success
233  */
234 int gs_init_surf(geosurf *gs, double ox, double oy, int rows, int cols,
235  double xres, double yres)
236 {
237  geosurf *ps;
238  int i;
239 
240  if (!gs) {
241  return (-1);
242  }
243 
244  G_debug(5, "gs_init_surf() id=%d", gs->gsurf_id);
245 
246  /* default attributes */
247  for (i = 0; i < MAX_ATTS; i++) {
248  gs->att[i].att_src = NOTSET_ATT;
249  gs->att[i].att_type = ATTY_INT;
250  gs->att[i].hdata = -1;
251  gs->att[i].user_func = NULL;
252  gs->att[i].constant = 0.;
253  gs->att[i].lookup = NULL;
254  gs->att[i].min_nz = gs->att[i].max_nz = gs->att[i].range_nz = 0;
255  gs->att[i].default_null = 0.;
256  }
257 
258  /* default values */
259  gs->ox = ox;
260  gs->oy = oy;
261  gs->rows = rows;
262  gs->cols = cols;
263  gs->xres = xres;
264  gs->yres = yres;
265  gs->x_mod = 2;
266  gs->y_mod = 2;
267  gs->x_modw = rows / 30;
268  gs->y_modw = rows / 30;
269  gs->xmin = ox;
270  gs->xmax = ox + (cols - 1) * xres;
271  gs->xrange = gs->xmax - gs->xmin;
272  gs->ymin = oy;
273  gs->ymax = oy + (rows - 1) * yres;
274  gs->yrange = gs->ymax - gs->ymin;
275  gs->zmin = gs->zmin_nz = gs->zminmasked = 0;
276  gs->zmax = gs->zmax_nz = 0;
277  gs->zrange = gs->zrange_nz = 0;
278  gs->wire_color = 0x00888888;
279  gs->x_trans = gs->y_trans = gs->z_trans = 0.0;
280  gs->nz_topo = gs->nz_color = 0;
281  gs->norm_needupdate = 1;
282  gs->mask_needupdate = 1;
283  gs->curmask = NULL;
284  gs->norms = NULL;
285 
286  gs->draw_mode = DM_GOURAUD;
287 
288  /* default z_exag value */
289  if (gs->gsurf_id == FIRST_SURF_ID) {
290  gs->z_exag = 1.0;
291  }
292  else {
294  gs->z_exag = ps->z_exag;
295  }
296 
297  return (0);
298 }
299 
300 /*!
301  \brief Init geosurf normbuff
302 
303  \param gs pointer to geosurf struct
304 
305  \return 0 on error
306  \return 1 on success
307  */
309 {
310  long size;
311 
312  if (!gs) {
313  return (0);
314  }
315 
316  if (gs->norms) {
317  G_free(gs->norms);
318  }
319 
320  size = gs->rows * gs->cols * sizeof(unsigned long);
321 
322  gs->norms = (unsigned long *)G_malloc(size); /* G_fatal_error */
323  if (!gs->norms) {
324  return (-1);
325  }
326 
327  gs->norm_needupdate = 1;
328 
329  return (1);
330 }
331 
332 /*!
333  \brief Debugging, print 'from/to' model coordinates to stderr
334 
335  \todo G_debug ?
336 
337  \param ft pointer to coordinates
338  */
339 void print_frto(float (*ft)[4])
340 {
341  fprintf(stderr, "FROM: %f, %f, %f\n", ft[FROM][X], ft[FROM][Y],
342  ft[FROM][Z]);
343  fprintf(stderr, "TO: %f, %f, %f\n", ft[TO][X], ft[TO][Y], ft[TO][Z]);
344 
345  return;
346 }
347 
348 /*!
349  \brief Debugging, print 'to' real coordinates to stderr
350 
351  \todo G_debug ?
352 
353  \param ft pointer to coordinates
354  */
355 void print_realto(float *rt)
356 {
357  fprintf(stderr, "REAL TO: %f, %f, %f\n", rt[X], rt[Y], rt[Z]);
358 
359  return;
360 }
361 
362 /*!
363  \brief Debugging, 256 integer values from buffer
364 
365  \todo G_debug ?
366 
367  \param ft pointer to buffer
368  */
369 void print_256lookup(int *buff)
370 {
371  int i;
372 
373  for (i = 0; i < 256; i++) {
374  if (!(i % 8)) {
375  fprintf(stderr, "\n");
376  }
377 
378  fprintf(stderr, "%x ", buff[i]);
379  }
380 
381  fprintf(stderr, "\n");
382 
383  return;
384 }
385 
386 /*!
387  \brief Debugging, print geosurf fields to stderr
388 
389  \todo G_debug ?
390 
391  \param s pointer to geosurf struct
392  */
394 {
395  fprintf(stderr, "ID: %d\n", s->gsurf_id);
396  fprintf(stderr, "rows: %d cols: %d\n", s->rows, s->cols);
397  fprintf(stderr, "draw_mode: %x\n", s->draw_mode);
398  fprintf(stderr, "wire_color: %lx\n", s->wire_color);
399  fprintf(stderr, "ox: %lf oy: %lf\n", s->ox, s->oy);
400  fprintf(stderr, "xres: %lf yres: %lf\n", s->xres, s->yres);
401  fprintf(stderr, "z_exag: %f \n", s->z_exag);
402  fprintf(stderr, "x_trans: %f y_trans: %f z_trans: %f\n", s->x_trans,
403  s->y_trans, s->z_trans);
404  fprintf(stderr, "xmin: %f ymin: %f zmin: %f\n", s->xmin, s->ymin, s->zmin);
405  fprintf(stderr, "xmax: %f ymax: %f zmax: %f\n", s->xmax, s->ymax, s->zmax);
406  fprintf(stderr, "x_mod: %d y_mod: %d x_modw: %d y_modw: %d\n", s->x_mod,
407  s->y_mod, s->x_modw, s->y_modw);
408 
409  return;
410 }
411 
412 /*!
413  \brief Debugging, print geoview fields to stderr
414 
415  \todo G_debug ?
416 
417  \param gv pointer to geoview struct
418  */
420 {
421  fprintf(stderr, "coord_sys: %d\n", gv->coord_sys);
422  fprintf(stderr, "view_proj: %d\n", gv->view_proj);
423  fprintf(stderr, "infocus: %d\n", gv->infocus);
424  print_frto(gv->from_to);
425  fprintf(stderr, "twist: %d fov: %d\n", gv->twist, gv->fov);
426  fprintf(stderr, "incl: %d look: %d\n", gv->incl, gv->look);
427  fprintf(stderr, "real_to: %f %f %f\n", gv->real_to[X], gv->real_to[Y],
428  gv->real_to[Z]);
429  fprintf(stderr, "vert_exag: %f scale: %f \n", gv->vert_exag, gv->scale);
430 
431  return;
432 }
433 
434 /*!
435  \brief Set default attribute values
436 
437  \param gs pointer to geosurf struct
438  \param defs array of default values (dim MAX_ATTRS)
439  \param null_defs array of null default values (dim MAX_ATTRS)
440  */
441 void gs_set_defaults(geosurf *gs, float *defs, float *null_defs)
442 {
443  int i;
444 
445  G_debug(5, "gs_set_defaults(): id=%d", gs->gsurf_id);
446 
447  for (i = 0; i < MAX_ATTS; i++) {
448  gs->att[i].constant = defs[i];
449  gs->att[i].default_null = null_defs[i];
450  gs->att[i].lookup = NULL;
451  gs->att[i].hdata = -1;
452  gs->att[i].att_src = NOTSET_ATT;
453  }
454 
455  return;
456 }
457 
458 /*!
459  \brief Remove geosurf struct from list
460 
461  \param id surface id
462  */
463 void gs_delete_surf(int id)
464 {
465  geosurf *fs;
466 
467  G_debug(5, "gs_delete_surf");
468 
469  fs = gs_get_surf(id);
470 
471  if (fs) {
472  gs_free_surf(fs);
473  }
474 
475  return;
476 }
477 
478 /*!
479  \brief Free geosurf struct
480 
481  \param fs pointer to geosurf struct
482 
483  \return 1 found
484  \return 0 not found
485  \return -1 on error
486  */
488 {
489  geosurf *gs;
490  int found = 0;
491 
492  G_debug(5, "gs_free_surf");
493 
494  if (Surf_top) {
495  if (fs == Surf_top) {
496  if (Surf_top->next) {
497  /* can't free top if last */
498  found = 1;
499  Surf_top = fs->next;
500  }
501  else {
503 
504  if (fs->curmask) {
505  G_free(fs->curmask);
506  }
507 
508  if (fs->norms) {
509  G_free(fs->norms);
510  }
511 
512  G_free(fs);
513  Surf_top = NULL;
514  }
515  }
516  else {
517  for (gs = Surf_top; gs && !found; gs = gs->next) {
518  if (gs->next) {
519  if (gs->next == fs) {
520  found = 1;
521  gs->next = fs->next;
522  }
523  }
524  }
525  }
526 
527  if (found) {
529 
530  if (fs->curmask) {
531  G_free(fs->curmask);
532  }
533 
534  if (fs->norms) {
535  G_free(fs->norms);
536  }
537 
538  G_free(fs);
539  fs = NULL;
540  }
541 
542  return (found);
543  }
544 
545  return (-1);
546 }
547 
548 /*!
549  \brief Free unshared buffers of geosurf struct
550 
551  <i>fs</i> has already been taken out of the list
552 
553  This function is fairly revealing about how shared datasets work
554 
555  \param fs pointer to geosurf struct
556  */
558 {
559  geosurf *gs;
560  int i, j, same;
561  int old_datah;
562 
563  G_debug(5, "gs_free_unshared_buffs");
564 
565  /* for each attribute
566  if !same, free buff
567  */
568  for (i = 0; i < MAX_ATTS; i++) {
569  same = 0;
570 
571  if (0 < (old_datah = fs->att[i].hdata)) {
572  /* for ea att of all other surfs */
573  for (gs = Surf_top; gs; gs = gs->next) {
574  for (j = 0; j < MAX_ATTS; j++) {
575  if ((old_datah == gs->att[j].hdata) && (fs != gs)) {
576  same = 1;
577  }
578  }
579  }
580 
581  if (!same) {
582  gsds_free_datah(old_datah);
583  }
584  }
585  }
586 
587  return;
588 }
589 
590 /*!
591  \brief Get number of reused values
592 
593  \param dh value
594 
595  \return number of reused values
596  */
598 {
599  geosurf *gs;
600  int ref, j;
601 
602  G_debug(5, "gs_num_datah_reused");
603 
604  /* for each attribute
605  if same, ++reference
606  */
607  /* for ea att of all surfs */
608  ref = 0;
609 
610  for (gs = Surf_top; gs; gs = gs->next) {
611  for (j = 0; j < MAX_ATTS; j++) {
612  if (dh == gs->att[j].hdata) {
613  ref++;
614  }
615  }
616  }
617 
618  return (ref);
619 }
620 
621 /*!
622  \brief Get attribute type
623 
624  \param gs pointer to geosurf struct
625  \param desc attribute id
626 
627  \return -1 on error
628  \return attribute type
629  */
630 int gs_get_att_type(geosurf *gs, int desc)
631 {
632  G_debug(5, "gs_get_att_type");
633 
634  if (!LEGAL_ATT(desc)) {
635  return (-1);
636  }
637 
638  if (gs) {
639  if (gs->att[desc].att_src != NOTSET_ATT) {
640  return (gs->att[desc].att_type);
641  }
642  }
643 
644  return (-1);
645 }
646 
647 /*!
648  \brief Get attribute source
649 
650  \param gs pointer to geosurf struct
651  \param desc attribute id (descriptor)
652 
653  \return -1 on error
654  \return attribute source id
655  */
656 int gs_get_att_src(geosurf *gs, int desc)
657 {
658  if (gs)
659  G_debug(5, "gs_get_att_src(): id=%d, desc=%d", gs->gsurf_id, desc);
660  if (!LEGAL_ATT(desc)) {
661  return (-1);
662  }
663 
664  if (gs) {
665  return (gs->att[desc].att_src);
666  }
667 
668  return (-1);
669 }
670 
671 /*!
672  \brief Get attribute data buffer
673 
674  \param gs pointer to geosurf struct
675  \param desc attribute id (descriptor)
676  \param to_write non-zero value for 'write'
677 
678  \return NULL on error
679  \return pointer to typbuff
680  */
681 typbuff *gs_get_att_typbuff(geosurf *gs, int desc, int to_write)
682 {
683  typbuff *tb;
684  geosurf *gsref;
685 
686  if (gs) {
687  G_debug(5, "gs_get_att_typbuff(): id=%d desc=%d to_write=%d",
688  gs->gsurf_id, desc, to_write);
689  if ((tb = gsds_get_typbuff(gs->att[desc].hdata, to_write))) {
690  tb->tfunc = NULL;
691 
692  if (desc == ATT_TOPO) {
693  gsref = gsdiff_get_SDref();
694 
695  if (gsref && gsref != gs) {
696  tb->tfunc = gsdiff_do_SD;
697  }
698  }
699 
700  return (tb);
701  }
702  }
703 
704  return (NULL);
705 }
706 
707 /*!
708  \brief Allocate attribute buffer
709 
710  \param gs pointer to geosurf struct
711  \param desc attribute id (descriptor)
712  \param type buffer type (based on raster map type)
713 
714  \return -1 on error
715  \return amount of allocated memory
716  */
717 size_t gs_malloc_att_buff(geosurf *gs, int desc, int type)
718 {
719  int hdata, dims[2], ndims;
720 
721  G_debug(5, "gs_malloc_att_buff");
722 
723  if (gs) {
724  if (0 < (hdata = gs->att[desc].hdata)) {
725  dims[0] = gs->rows;
726  dims[1] = gs->cols;
727  ndims = 2;
728  gs_set_att_type(gs, desc, type);
729 
730  return (gsds_alloc_typbuff(hdata, dims, ndims, type));
731  }
732  }
733 
734  return 0;
735 }
736 
737 /*!
738  \brief Allocate attribute lookup
739 
740  \param gs pointer to geosurf struct
741  \param desc attribute id
742 
743  \return -1 on error
744  \return pointer to typbuff (casted)
745  */
746 int gs_malloc_lookup(geosurf *gs, int desc)
747 {
748  int size;
749 
750  G_debug(5, "gs_malloc_lookup");
751 
752  if (gs) {
753  if (gs->att[desc].lookup) {
754  G_free(gs->att[desc].lookup);
755  gs->att[desc].lookup = NULL;
756  }
757 
758  switch (gs->att[desc].att_type) {
759  case (ATTY_SHORT):
760  size = 32768 * sizeof(int);
761 
762  /* positive integers only, because use as array index */
763  gs->att[desc].lookup = (int *)G_malloc(size); /* G_fatal_error */
764  if (!gs->att[desc].lookup) {
765  return (-1);
766  }
767 
768  break;
769  case (ATTY_CHAR):
770  size = 256 * sizeof(int);
771 
772  /* unsigned char */
773  gs->att[desc].lookup = (int *)G_malloc(size);
774  if (!gs->att[desc].lookup) {
775  return (-1);
776  }
777 
778  break;
779  default:
780  G_warning("bad type: gs_malloc_lookup");
781  return (-1);
782  }
783 
784  if (gs->att[desc].lookup) {
785  return (0);
786  }
787  }
788 
789  return (-1);
790 }
791 
792 /*!
793  \brief Set attribute type
794 
795  \param gs pointer to geosurf struct
796  \param desc attribute id
797  \param type attribute type
798 
799  \return -1 on error
800  \return 0 on success
801  */
802 int gs_set_att_type(geosurf *gs, int desc, int type)
803 {
804 
805  G_debug(5, "gs_set_att_type(): desc=%d, type=%d", desc, type);
806 
807  if (gs && LEGAL_TYPE(type)) {
808  gs->att[desc].att_type = type;
809 
810  return (0);
811  }
812 
813  return (-1);
814 }
815 
816 /*!
817  \brief Set attribute source
818 
819  \param gs pointer to geosurf struct
820  \param desc attribute id (descriptor)
821  \param src source id
822 
823  \return -1 on error
824  \return 0 on success
825  */
826 int gs_set_att_src(geosurf *gs, int desc, int src)
827 {
828  if (gs)
829  G_debug(5, "gs_set_att_src(): id=%d desc=%d src=%d", gs->gsurf_id, desc,
830  src);
831 
832  /* check if old source was MAP_ATT, free buff */
833  if (MAP_ATT == gs_get_att_src(gs, desc)) {
834  if (1 == gs_num_datah_reused(gs->att[desc].hdata)) {
835  /* only reference */
836  G_debug(5, "gs_set_att_src(): replacing existing map");
837  gsds_free_datah(gs->att[desc].hdata);
838  }
839 
840  if (ATT_TOPO == desc) {
841  if (gs->norms) {
842  G_free(gs->norms);
843  }
844 
845  gs->norms = NULL;
846  gs->norm_needupdate = 0;
847  }
848  }
849 
850  if (gs && LEGAL_SRC(src)) {
851  gs->att[desc].att_src = src;
852 
853  return (0);
854  }
855 
856  return (-1);
857 }
858 
859 /*!
860  \brief Set attribute constant value
861 
862  \todo set typbuf constant
863 
864  \param gs pointer to geosurf struct
865  \param desc attribute id
866  \param constant constant value
867 
868  \return 0 on success
869  \return -1 on error
870  */
871 int gs_set_att_const(geosurf *gs, int desc, float constant)
872 {
873 
874  if (gs) {
875  G_debug(5, "gs_set_att_const(): id=%d, desc=%d, const=%f", gs->gsurf_id,
876  desc, constant);
877  gs->att[desc].constant = constant;
878 
879  if (ATT_MASK == desc) {
880  gs->mask_needupdate = 1;
881  }
882  else {
883  gs_set_att_src(gs, desc, CONST_ATT);
884  }
885 
886  Gs_update_attrange(gs, desc);
887 
888  return (0);
889  }
890 
891  return (-1);
892 }
893 
894 /*!
895  \brief Set geosurf mask mode
896 
897  \param invert invert mask
898  */
899 void gs_set_maskmode(int invert)
900 {
901  Invertmask = invert;
902 
903  return;
904 }
905 
906 /*!
907  \brief Check if mask is defined
908 
909  \param gs pointer to geosurf struct
910 
911  \return 1 if defined
912  \return 0 not defined
913  */
915 {
916  return (gs->att[ATT_MASK].att_src != NOTSET_ATT);
917 }
918 
919 /*!
920  \brief
921 
922  Should only be called when setting up the current mask (gs_bm.c)
923 
924  \param tb pointer to typbuff
925  \param col number of cols
926  \param row number of rows
927  \param offset offset value
928 
929  \return 1
930  \return 0
931  */
932 int gs_masked(typbuff *tb, int col, int row, int offset)
933 {
934  int ret;
935 
936  ret = 1;
937 
938  if (tb->bm) {
939  ret = BM_get(tb->bm, col, row);
940  }
941  else if (tb->cb) {
942  ret = tb->cb[offset];
943  }
944  else if (tb->sb) {
945  ret = tb->sb[offset];
946  }
947  else if (tb->ib) {
948  ret = tb->ib[offset];
949  }
950  else if (tb->fb) {
951  ret = tb->fb[offset];
952  }
953 
954  return (Invertmask ? ret : !ret);
955 }
956 
957 /*!
958  \brief
959 
960  Call this one when you already know att_src is MAP_ATT
961 
962  \param cobuff
963  \param coloratt color attribute
964  \param offset offset value
965 
966  \return packed color for category at offset
967  */
968 int gs_mapcolor(typbuff *cobuff, gsurf_att *coloratt, int offset)
969 {
970  if (coloratt->lookup) {
971  /* for now, but may add larger color lookup capabilities later,
972  so would have to use GET_MAPATT */
973  return (coloratt->lookup[cobuff->cb[offset]]);
974  }
975 
976  return (cobuff->ib[offset]);
977 }
978 
979 /*
980  In the following functions, "extents" refers to translated extents for
981  a single surface, while "range" refers to accumulated extents of all
982  loaded surfaces
983  */
984 
985 /*!
986  \brief Get z-extent values
987 
988  \todo pass flag to use zminmasked instead of zmin
989 
990  \param gs pointer to geosurf struct
991  \param[out] min z-min value
992  \param[out] max z-max value
993  \param[out] mid z-middle value
994 
995  \return 1
996  */
997 int gs_get_zextents(geosurf *gs, float *min, float *max, float *mid)
998 {
999  *min = gs->zmin + gs->z_trans;
1000  *max = gs->zmax + gs->z_trans;
1001  *mid = (*max + *min) / 2.;
1002 
1003  return (1);
1004 }
1005 
1006 /*!
1007  \brief Get x-extent values
1008 
1009  \param gs pointer to geosurf struct
1010  \param[out] min x-min value
1011  \param[out] max x-max value
1012 
1013  \return 1
1014  */
1015 int gs_get_xextents(geosurf *gs, float *min, float *max)
1016 {
1017  *min = gs->xmin + gs->x_trans;
1018  *max = gs->xmax + gs->x_trans;
1019 
1020  return (1);
1021 }
1022 
1023 /*!
1024  \brief Get y-extent values
1025 
1026  \param gs pointer to geosurf struct
1027  \param[out] min y-min value
1028  \param[out] max y-max value
1029 
1030  \return 1
1031  */
1032 int gs_get_yextents(geosurf *gs, float *min, float *max)
1033 {
1034  *min = gs->ymin + gs->y_trans;
1035  *max = gs->ymax + gs->y_trans;
1036 
1037  return (1);
1038 }
1039 
1040 /*!
1041  \brief Get z-range
1042 
1043  \todo pass flag to use zminmasked instead of zmin
1044  could also have this return a weighted average for vertical "centroid"
1045 
1046  \param[out] min z-min value
1047  \param[out] max z-max value
1048 
1049  \return -1 on error (no surface)
1050  \return 1 on success
1051  */
1052 int gs_get_zrange0(float *min, float *max)
1053 {
1054  geosurf *gs;
1055 
1056  if (Surf_top) {
1057  *min = Surf_top->zmin;
1058  *max = Surf_top->zmax;
1059  }
1060  else {
1061  return (-1);
1062  }
1063 
1064  for (gs = Surf_top->next; gs; gs = gs->next) {
1065  if (gs->zmin < *min) {
1066  *min = gs->zmin;
1067  }
1068 
1069  if (gs->zmax > *max) {
1070  *max = gs->zmax;
1071  }
1072  }
1073 
1074  return (1);
1075 }
1076 
1077 /*!
1078  \brief Get z-range
1079 
1080  \param[out] min z-min value
1081  \param[out] max z-max value
1082 
1083  \return -1 on error (no surface)
1084  \return 1 on success
1085  */
1086 int gs_get_zrange(float *min, float *max)
1087 {
1088  geosurf *gs;
1089  float tmin, tmax, tmid;
1090 
1091  if (Surf_top) {
1092  gs_get_zextents(Surf_top, &tmin, &tmax, &tmid);
1093  *min = tmin;
1094  *max = tmax;
1095  }
1096  else {
1097  return (-1);
1098  }
1099 
1100  for (gs = Surf_top->next; gs; gs = gs->next) {
1101  gs_get_zextents(gs, &tmin, &tmax, &tmid);
1102 
1103  if (tmin < *min) {
1104  *min = tmin;
1105  }
1106 
1107  if (tmax > *max) {
1108  *max = tmax;
1109  }
1110  }
1111 
1112  return (1);
1113 }
1114 
1115 /*!
1116  \brief Get x-range
1117 
1118  \param[out] min x-min value
1119  \param[out] max x-max value
1120 
1121  \return -1 on error (no surface)
1122  \return 1 on success
1123  */
1124 int gs_get_xrange(float *min, float *max)
1125 {
1126  geosurf *gs;
1127  float tmin, tmax;
1128 
1129  if (Surf_top) {
1130  gs_get_xextents(Surf_top, &tmin, &tmax);
1131  *min = tmin;
1132  *max = tmax;
1133  }
1134  else {
1135  return (-1);
1136  }
1137 
1138  for (gs = Surf_top->next; gs; gs = gs->next) {
1139  gs_get_xextents(gs, &tmin, &tmax);
1140 
1141  if (tmin < *min) {
1142  *min = tmin;
1143  }
1144 
1145  if (tmax > *max) {
1146  *max = tmax;
1147  }
1148  }
1149 
1150  return (1);
1151 }
1152 
1153 /*!
1154  \brief Get y-range
1155 
1156  \param[out] min y-min value
1157  \param[out] max y-max value
1158 
1159  \return -1 on error (no surface)
1160  \return 1 on success
1161  */
1162 int gs_get_yrange(float *min, float *max)
1163 {
1164  geosurf *gs;
1165  float tmin, tmax;
1166 
1167  if (Surf_top) {
1168  gs_get_yextents(Surf_top, &tmin, &tmax);
1169  *min = tmin;
1170  *max = tmax;
1171  }
1172  else {
1173  return (-1);
1174  }
1175 
1176  for (gs = Surf_top->next; gs; gs = gs->next) {
1177  gs_get_yextents(gs, &tmin, &tmax);
1178 
1179  if (tmin < *min) {
1180  *min = tmin;
1181  }
1182 
1183  if (tmax > *max) {
1184  *max = tmax;
1185  }
1186  }
1187 
1188  return (1);
1189 }
1190 
1191 /*!
1192  \brief Get average z-max value
1193 
1194  Useful for setting position of cplane, lighting ball, etc.
1195 
1196  \param[out] azmax average z-max value
1197 
1198  \return -1 on error
1199  \return 1 on success
1200  */
1201 int gs_get_data_avg_zmax(float *azmax)
1202 {
1203  float zmax;
1204  int i;
1205  geosurf *gs;
1206 
1207  zmax = *azmax = 0.0;
1208 
1209  if (Surf_top) {
1210  for (i = 0, gs = Surf_top; gs; i++, gs = gs->next) {
1211  zmax += (gs->zmax + gs->z_trans);
1212  }
1213 
1214  *azmax = zmax / i;
1215 
1216  return (1);
1217  }
1218 
1219  return (-1);
1220 }
1221 
1222 /*!
1223  \brief Get data center point
1224 
1225  \param[out] center (array X,Y,Z)
1226 
1227  \return -1 on error
1228  \return 1 on success
1229  */
1230 int gs_get_datacenter(float *cen)
1231 {
1232  float zmin, zmax, ymin, ymax, xmin, xmax;
1233  geosurf *gs;
1234 
1235  if (Surf_top) {
1236  zmin = Surf_top->zmin;
1237  zmax = Surf_top->zmax;
1238  ymin = Surf_top->ymin;
1239  ymax = Surf_top->ymax;
1240  xmin = Surf_top->xmin;
1241  xmax = Surf_top->xmax;
1242 
1243  for (gs = Surf_top->next; gs; gs = gs->next) {
1244  if (gs->zmin < zmin) {
1245  zmin = gs->zmin;
1246  }
1247 
1248  if (gs->zmax > zmax) {
1249  zmax = gs->zmax;
1250  }
1251 
1252  if (gs->ymin < ymin) {
1253  ymin = gs->ymin;
1254  }
1255 
1256  if (gs->ymax > ymax) {
1257  ymax = gs->ymax;
1258  }
1259 
1260  if (gs->xmin < xmin) {
1261  xmin = gs->xmin;
1262  }
1263 
1264  if (gs->xmax > xmax) {
1265  xmax = gs->xmax;
1266  }
1267  }
1268 
1269  cen[X] = (xmin + xmax) / 2. - xmin;
1270  cen[Y] = (ymin + ymax) / 2. - ymin;
1271  cen[Z] = (zmin + zmax) / 2.;
1272 
1273  return (1);
1274  }
1275 
1276  cen[X] = cen[Y] = cen[Z] = 0.0;
1277 
1278  return (-1);
1279 }
1280 
1281 /*!
1282  \brief Set for geosurf need-to-update mark
1283 
1284  \return -1 no surface available
1285  \return 1 on success
1286  */
1288 {
1289  geosurf *gs;
1290 
1291  if (Surf_top) {
1292  Surf_top->norm_needupdate = 1;
1293  }
1294  else {
1295  return (-1);
1296  }
1297 
1298  for (gs = Surf_top->next; gs; gs = gs->next) {
1299  gs->norm_needupdate = 1;
1300  }
1301 
1302  return (1);
1303 }
1304 
1305 /*!
1306  \brief Check if point is masked
1307 
1308  \param gs pointer to geosurf struct
1309  \param pt point coordinates (X,Y,Z)
1310 
1311  \return 1 masked
1312  \return 0 not masked
1313  */
1314 int gs_point_is_masked(geosurf *gs, float *pt)
1315 {
1316  int vrow, vcol, drow, dcol;
1317  int retmask = 0, npts = 0;
1318  float p2[2];
1319 
1320  if (!gs->curmask) {
1321  return (0);
1322  }
1323 
1324  vrow = Y2VROW(gs, pt[Y]);
1325  vcol = X2VCOL(gs, pt[X]);
1326 
1327  /* check right & bottom edges */
1328  if (pt[X] == VCOL2X(gs, VCOLS(gs))) {
1329  /* right edge */
1330  vcol -= 1;
1331  }
1332 
1333  if (pt[Y] == VROW2Y(gs, VROWS(gs))) {
1334  /* bottom edge */
1335  vrow -= 1;
1336  }
1337 
1338  drow = VROW2DROW(gs, vrow);
1339  dcol = VCOL2DCOL(gs, vcol);
1340 
1341  if (BM_get(gs->curmask, dcol, drow)) {
1342  retmask |= MASK_TL;
1343  npts++;
1344  }
1345 
1346  dcol = VCOL2DCOL(gs, vcol + 1);
1347 
1348  if (BM_get(gs->curmask, dcol, drow)) {
1349  retmask |= MASK_TR;
1350  npts++;
1351  }
1352 
1353  drow = VROW2DROW(gs, vrow + 1);
1354 
1355  if (BM_get(gs->curmask, dcol, drow)) {
1356  retmask |= MASK_BR;
1357  npts++;
1358  }
1359 
1360  dcol = VCOL2DCOL(gs, vcol);
1361 
1362  if (BM_get(gs->curmask, dcol, drow)) {
1363  retmask |= MASK_BL;
1364  npts++;
1365  }
1366 
1367  if (npts != 1) {
1368  /* zero or masked */
1369  return (retmask | npts);
1370  }
1371 
1372  p2[X] = VCOL2X(gs, vcol);
1373  p2[Y] = VROW2Y(gs, vrow + 1);
1374 
1375  switch (retmask) {
1376  case MASK_TL:
1377  if ((pt[X] - p2[X]) / VXRES(gs) > (pt[Y] - p2[Y]) / VYRES(gs)) {
1378  /* lower triangle */
1379  return (0);
1380  }
1381 
1382  return (retmask | npts);
1383  case MASK_TR:
1384 
1385  return (retmask | npts);
1386  case MASK_BR:
1387  if ((pt[X] - p2[X]) / VXRES(gs) <= (pt[Y] - p2[Y]) / VYRES(gs)) {
1388  /* upper triangle */
1389  return (0);
1390  }
1391 
1392  return (retmask | npts);
1393  case MASK_BL:
1394 
1395  return (retmask | npts);
1396  }
1397 
1398  /* Assume that if we get here it is an error */
1399  return (0);
1400 }
1401 
1402 /*!
1403  \brief Calculate distance on surface
1404 
1405  \param gs pointer to geosurf struct
1406  \param p1 from point
1407  \param p2 to point
1408  \param[out] dist distance
1409  \param use_exag use exag for calculation
1410 
1411  \return 0 on error (points not in region)
1412  \return 1 on success
1413  */
1414 int gs_distance_onsurf(geosurf *gs, float *p1, float *p2, float *dist,
1415  int use_exag)
1416 {
1417  Point3 *tmp;
1418  int np, i;
1419  float exag, length;
1420 
1421  if (in_vregion(gs, p1) && in_vregion(gs, p2)) {
1422  if (NULL == (tmp = gsdrape_get_segments(gs, p1, p2, &np))) {
1423  return (0);
1424  }
1425 
1426  length = 0.;
1427 
1428  if (use_exag) {
1429  exag = GS_global_exag();
1430  tmp[0][Z] *= exag;
1431 
1432  for (i = 0; i < (np - 1); i++) {
1433  tmp[i + 1][Z] *= exag;
1434  length += GS_distance(tmp[i], tmp[i + 1]);
1435  }
1436  }
1437  else {
1438  for (i = 0; i < (np - 1); i++) {
1439  length += GS_distance(tmp[i], tmp[i + 1]);
1440  }
1441  }
1442 
1443  *dist = length;
1444 
1445  return (1);
1446  }
1447 
1448  return (0);
1449 }
#define NULL
Definition: ccmath.h:32
int BM_get(struct BM *, int, int)
Gets 'val' from the bitmap.
Definition: bitmap.c:217
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:150
void G_warning(const char *,...) __attribute__((format(printf
#define G_malloc(n)
Definition: defs/gis.h:94
int G_debug(int, const char *,...) __attribute__((format(printf
int gsds_free_datah(int)
Free allocated dataset.
Definition: gsds.c:329
typbuff * gsds_get_typbuff(int, IFLAG)
Get data buffer.
Definition: gsds.c:281
int Gs_update_attrange(geosurf *, int)
Update no_zero ranges for attribute (actually no_null now)
Definition: gs3.c:1078
size_t gsds_alloc_typbuff(int, int *, int, int)
Allocates correct buffer according to type, keeps track of total mem.
Definition: gsds.c:480
int in_vregion(geosurf *, float *)
ADD.
Definition: gsdrape.c:691
Point3 * gsdrape_get_segments(geosurf *, float *, float *, int *)
ADD.
Definition: gsdrape.c:349
geosurf * gsdiff_get_SDref(void)
ADD.
Definition: gsdiff.c:77
float gsdiff_do_SD(float, int)
ADD.
Definition: gsdiff.c:94
float GS_distance(float *, float *)
Calculate distance.
Definition: gs_util.c:141
float GS_global_exag(void)
Get global z-exag value.
Definition: gs2.c:1997
#define min(x, y)
Definition: draw2.c:29
#define max(x, y)
Definition: draw2.c:30
geosurf * gs_get_prev_surface(int id)
Get previous geosurf struct.
Definition: gs.c:87
geosurf * gs_get_new_surface(void)
Allocate new geosurf struct.
Definition: gs.c:194
int gs_get_xextents(geosurf *gs, float *min, float *max)
Get x-extent values.
Definition: gs.c:1015
int gs_masked(typbuff *tb, int col, int row, int offset)
Should only be called when setting up the current mask (gs_bm.c)
Definition: gs.c:932
void print_view_fields(geoview *gv)
Debugging, print geoview fields to stderr.
Definition: gs.c:419
int gs_get_datacenter(float *cen)
Get data center point.
Definition: gs.c:1230
int gs_get_zextents(geosurf *gs, float *min, float *max, float *mid)
Get z-extent values.
Definition: gs.c:997
int gs_get_zrange(float *min, float *max)
Get z-range.
Definition: gs.c:1086
size_t gs_malloc_att_buff(geosurf *gs, int desc, int type)
Allocate attribute buffer.
Definition: gs.c:717
int gs_set_att_src(geosurf *gs, int desc, int src)
Set attribute source.
Definition: gs.c:826
int gs_get_yextents(geosurf *gs, float *min, float *max)
Get y-extent values.
Definition: gs.c:1032
int gs_mapcolor(typbuff *cobuff, gsurf_att *coloratt, int offset)
Call this one when you already know att_src is MAP_ATT.
Definition: gs.c:968
void gs_free_unshared_buffs(geosurf *fs)
Free unshared buffers of geosurf struct.
Definition: gs.c:557
void gs_err(const char *msg)
Definition: gs.c:35
int gs_get_xrange(float *min, float *max)
Get x-range.
Definition: gs.c:1124
geosurf * gs_get_surf(int id)
Get geosurf struct.
Definition: gs.c:63
int gs_set_att_const(geosurf *gs, int desc, float constant)
Set attribute constant value.
Definition: gs.c:871
int gs_malloc_lookup(geosurf *gs, int desc)
Allocate attribute lookup.
Definition: gs.c:746
int gs_get_yrange(float *min, float *max)
Get y-range.
Definition: gs.c:1162
void gs_delete_surf(int id)
Remove geosurf struct from list.
Definition: gs.c:463
int gs_set_att_type(geosurf *gs, int desc, int type)
Set attribute type.
Definition: gs.c:802
void print_surf_fields(geosurf *s)
Debugging, print geosurf fields to stderr.
Definition: gs.c:393
int gs_getall_surfaces(geosurf **gsurfs)
Get array of geosurf structs.
Definition: gs.c:109
int gs_setall_norm_needupdate(void)
Set for geosurf need-to-update mark.
Definition: gs.c:1287
void print_256lookup(int *buff)
Debugging, 256 integer values from buffer.
Definition: gs.c:369
int gs_init_surf(geosurf *gs, double ox, double oy, int rows, int cols, double xres, double yres)
Initialize allocated geosurf struct.
Definition: gs.c:234
#define FIRST_SURF_ID
Definition: gs.c:29
void gs_init(void)
Initialize library.
Definition: gs.c:48
void gs_set_maskmode(int invert)
Set geosurf mask mode.
Definition: gs.c:899
int gs_free_surf(geosurf *fs)
Free geosurf struct.
Definition: gs.c:487
int gs_get_att_type(geosurf *gs, int desc)
Get attribute type.
Definition: gs.c:630
int gs_distance_onsurf(geosurf *gs, float *p1, float *p2, float *dist, int use_exag)
Calculate distance on surface.
Definition: gs.c:1414
int gs_num_surfaces(void)
Get number of surfaces.
Definition: gs.c:128
geosurf * gs_get_last_surface(void)
Get last allocated geosurf struct from list.
Definition: gs.c:173
int gs_init_normbuff(geosurf *gs)
Init geosurf normbuff.
Definition: gs.c:308
int gs_num_datah_reused(int dh)
Get number of reused values.
Definition: gs.c:597
typbuff * gs_get_att_typbuff(geosurf *gs, int desc, int to_write)
Get attribute data buffer.
Definition: gs.c:681
void print_frto(float(*ft)[4])
Debugging, print 'from/to' model coordinates to stderr.
Definition: gs.c:339
int gs_mask_defined(geosurf *gs)
Check if mask is defined.
Definition: gs.c:914
int gs_get_zrange0(float *min, float *max)
Get z-range.
Definition: gs.c:1052
int gs_point_is_masked(geosurf *gs, float *pt)
Check if point is masked.
Definition: gs.c:1314
int gs_get_data_avg_zmax(float *azmax)
Get average z-max value.
Definition: gs.c:1201
int gs_att_is_set(geosurf *surf, IFLAG att)
Check if attribute is set.
Definition: gs.c:150
int gs_get_att_src(geosurf *gs, int desc)
Get attribute source.
Definition: gs.c:656
void gs_set_defaults(geosurf *gs, float *defs, float *null_defs)
Set default attribute values.
Definition: gs.c:441
void print_realto(float *rt)
Debugging, print 'to' real coordinates to stderr.
Definition: gs.c:355
#define NOTSET_ATT
Definition: ogsf.h:84
#define ATT_MASK
Definition: ogsf.h:77
#define ATTY_SHORT
Definition: ogsf.h:170
#define X
Definition: ogsf.h:140
#define MAX_ATTS
Definition: ogsf.h:45
#define MASK_TR
Definition: ogsf.h:191
#define ATT_TOPO
Definition: ogsf.h:75
float Point3[3]
Definition: ogsf.h:205
#define Z
Definition: ogsf.h:142
#define MASK_BL
Definition: ogsf.h:193
#define IFLAG
Definition: ogsf.h:71
#define LEGAL_ATT(a)
Definition: ogsf.h:81
#define Y
Definition: ogsf.h:141
#define MAP_ATT
Definition: ogsf.h:85
#define MASK_BR
Definition: ogsf.h:192
#define MASK_TL
Definition: ogsf.h:190
#define ATTY_INT
Definition: ogsf.h:169
#define ATTY_CHAR
Definition: ogsf.h:171
#define LEGAL_SRC(s)
Definition: ogsf.h:88
#define DM_GOURAUD
Definition: ogsf.h:56
#define CONST_ATT
Definition: ogsf.h:86
#define LEGAL_TYPE(t)
Definition: ogsf.h:173
#define TO
Definition: ogsf.h:145
struct ps_state ps
#define VYRES(gs)
Definition: rowcol.h:10
#define Y2VROW(gs, py)
Definition: rowcol.h:27
#define VXRES(gs)
Definition: rowcol.h:9
#define VCOL2X(gs, vcol)
Definition: rowcol.h:40
#define VCOLS(gs)
Definition: rowcol.h:14
#define VROWS(gs)
Definition: rowcol.h:13
#define VROW2Y(gs, vrow)
Definition: rowcol.h:39
#define VROW2DROW(gs, vrow)
Definition: rowcol.h:31
#define X2VCOL(gs, px)
Definition: rowcol.h:28
#define VCOL2DCOL(gs, vcol)
Definition: rowcol.h:32
@ FROM
Definition: sqlp.tab.h:67
Definition: ogsf.h:256
float x_trans
Definition: ogsf.h:266
float ymax
Definition: ogsf.h:267
int nz_color
Definition: ogsf.h:271
int rows
Definition: ogsf.h:258
float ymin
Definition: ogsf.h:267
double yres
Definition: ogsf.h:264
float zrange_nz
Definition: ogsf.h:269
float yrange
Definition: ogsf.h:268
float xmax
Definition: ogsf.h:267
int cols
Definition: ogsf.h:258
double ox
Definition: ogsf.h:263
float xrange
Definition: ogsf.h:268
long wire_color
Definition: ogsf.h:262
gsurf_att att[MAX_ATTS]
Definition: ogsf.h:259
unsigned long * norms
Definition: ogsf.h:273
float xmin
Definition: ogsf.h:267
int gsurf_id
Definition: ogsf.h:257
int y_mod
Definition: ogsf.h:270
int x_modw
Definition: ogsf.h:270
float zmax_nz
Definition: ogsf.h:269
int y_modw
Definition: ogsf.h:270
double xres
Definition: ogsf.h:264
struct BM * curmask
Definition: ogsf.h:274
int x_mod
Definition: ogsf.h:270
struct g_surf * next
Definition: ogsf.h:275
int norm_needupdate
Definition: ogsf.h:272
double oy
Definition: ogsf.h:263
float z_exag
Definition: ogsf.h:265
float zmin_nz
Definition: ogsf.h:269
int mask_needupdate
Definition: ogsf.h:272
int nz_topo
Definition: ogsf.h:271
float z_trans
Definition: ogsf.h:266
float zmin
Definition: ogsf.h:267
float zrange
Definition: ogsf.h:268
IFLAG draw_mode
Definition: ogsf.h:260
float zminmasked
Definition: ogsf.h:267
float zmax
Definition: ogsf.h:267
float y_trans
Definition: ogsf.h:266
Definition: ogsf.h:467
float vert_exag
Definition: ogsf.h:474
int twist
Definition: ogsf.h:473
int incl
Definition: ogsf.h:473
int view_proj
Definition: ogsf.h:469
float real_to[4]
Definition: ogsf.h:474
float from_to[2][4]
Definition: ogsf.h:471
int fov
Definition: ogsf.h:473
int look
Definition: ogsf.h:473
float scale
Definition: ogsf.h:475
int coord_sys
Definition: ogsf.h:468
int infocus
Definition: ogsf.h:470
int hdata
Definition: ogsf.h:248
float range_nz
Definition: ogsf.h:252
IFLAG att_type
Definition: ogsf.h:247
float max_nz
Definition: ogsf.h:252
float constant
Definition: ogsf.h:250
IFLAG att_src
Definition: ogsf.h:246
int * lookup
Definition: ogsf.h:251
int(* user_func)(void)
Definition: ogsf.h:249
float default_null
Definition: ogsf.h:253
float min_nz
Definition: ogsf.h:252
Definition: ogsf.h:208
float * fb
Definition: ogsf.h:209
unsigned char * cb
Definition: ogsf.h:212
float(* tfunc)(float, int)
Definition: ogsf.h:215
short * sb
Definition: ogsf.h:211
int * ib
Definition: ogsf.h:210
struct BM * bm
Definition: ogsf.h:213