1    | /***************************************
2    |   $Header: /cvsroot/petscgraphics/render.c,v 1.5 2004/08/17 15:05:56 hazelsct Exp $
3    | 
4    |   This file contains the rendering code for Illuminator, which renders 2-D or
5    |   3-D data into an RGB(A) unsigned char array (using perspective in 3-D).
6    | ***************************************/
7    | 
8    | #include "illuminator.h"
9    | 
10   | 
11   | #undef __FUNCT__
12   | #define __FUNCT__ "pseudocolor"
13   | 
14   | /*++++++++++++++++++++++++++++++++++++++
15   |   This little function converts a scalar value into an rgb color from red to
16   |   blue.
17   | 
18   |   PetscScalar val Value to convert.
19   | 
20   |   PetscScalar* minmax Array with minimum and maximum values in which to scale
21   |   val.
22   | 
23   |   guchar *pixel Address in rgb buffer where this pixel should be painted.
24   |   ++++++++++++++++++++++++++++++++++++++*/
25   | 
26   | static inline void pseudocolor (PetscScalar val, PetscScalar* minmax,
27   | 				guchar *pixel)
28   | {
29   |   PetscScalar shade = (val - minmax[0]) / (minmax[1] - minmax[0]);
30   |   /* Old stuff *
31   |   if (shade < 0.2) {      /* red -> yellow *
32   |     *pixel++ = 255;
33   |     *pixel++ = 1275*shade;
34   |     *pixel++ = 0; }
35   |   else if (shade < 0.4) { /* yellow -> green *
36   |     *pixel++ = 510-1275*shade;
37   |     *pixel++ = 255;
38   |     *pixel++ = 0; }
39   |   else if (shade < 0.6) { /* green -> cyan *
40   |     *pixel++ = 0;
41   |     *pixel++ = 255;
42   |     *pixel++ = 1275*shade-510; }
43   |   else if (shade < 0.8) { /* cyan -> blue *
44   |     *pixel++ = 0;
45   |     *pixel++ = 1020-1275*shade;
46   |     *pixel++ = 255; }
47   |   else {                  /* blue -> magenta *
48   |     *pixel++ = 1275*shade-1020;
49   |     *pixel++ = 0;
50   |     *pixel++ = 255; }
51   |   /* New stuff */
52   |   if (shade < 0.25) {      /* red -> yellow */
53   |     *pixel++ = 255;
54   |     *pixel++ = 1020*shade;
55   |     *pixel++ = 0; }
56   |   else if (shade < 0.5) { /* yellow -> green */
57   |     *pixel++ = 510-1020*shade;
58   |     *pixel++ = 255;
59   |     *pixel++ = 0; }
60   |   else if (shade < 0.75) { /* green -> cyan */
61   |     *pixel++ = 0;
62   |     *pixel++ = 255;
63   |     *pixel++ = 1020*shade-510; }
64   |   else { /* cyan -> blue */
65   |     *pixel++ = 0;
66   |     *pixel++ = 1020-1020*shade;
67   |     *pixel++ = 255; }
68   | }
69   | 
70   | 
71   | #undef __FUNCT__
72   | #define __FUNCT__ "pseudohueintcolor"
73   | 
74   | /*++++++++++++++++++++++++++++++++++++++
75   |   This little function converts a vector into an rgb color with hue indicating
76   |   direction (green, yellow, red, blue at 0, 90, 180, 270 degrees) and intensity
77   |   indicating magnitude relative to reference magnitude in minmax[1].
78   | 
79   |   PetscScalar vx Vector's
80   |   +latex+$x$-component.
81   |   +html+ <i>x</i>-component.
82   | 
83   |   PetscScalar vy Vector's
84   |   +latex+$y$-component.
85   |   +html+ <i>y</i>-component.
86   | 
87   |   PetscScalar *minmax Array whose second entry has the reference magnitude.
88   | 
89   |   guchar *pixel Address in rgb buffer where this pixel should be painted.
90   |   ++++++++++++++++++++++++++++++++++++++*/
91   | 
92   | static inline void pseudohueintcolor
93   | (PetscScalar vx, PetscScalar vy, PetscScalar *minmax, guchar *pixel)
94   | {
95   |   PetscScalar mag=sqrt(vx*vx+vy*vy), theta=atan2(vy,vx), red, green, blue;
96   |   if (minmax[1] <= 0.)
97   |     {
98   |       *pixel = *(pixel+1) = *(pixel+2) = 0;
99   |       return;
100  |     }
101  |   mag = (mag > minmax[1]) ? 1.0 : mag/minmax[1];
102  | 
103  |   red = 2./M_PI * ((theta<-M_PI/2.) ? -M_PI/2.-theta :
104  | 		   ((theta<0.) ? 0. : ((theta<M_PI/2.) ? theta : M_PI/2.)));
105  |   green = 2./M_PI * ((theta<-M_PI/2.) ? 0. :
106  | 		     ((theta<0.) ? theta+M_PI/2. :
107  | 		      ((theta<M_PI/2.) ? M_PI/2. : M_PI-theta)));
108  |   blue = 2./M_PI * ((theta<-M_PI/2.) ? theta+M_PI :
109  | 		    ((theta<0.) ? -theta : 0.));
110  | 
111  |   *pixel++ = 255*mag*red;
112  |   *pixel++ = 255*mag*green;
113  |   *pixel++ = 255*mag*blue;
114  | }
115  | 
116  | #undef __FUNCT__
117  | #define __FUNCT__ "pseudoternarycolor"
118  | 
119  | /*++++++++++++++++++++++++++++++++++++++
120  |   This little function converts two ternary fractions into an rgb color, with
121  |   yellow, cyan and magenta indicating the corners.
122  | 
123  |   PetscScalar A First ternary fraction.
124  | 
125  |   PetscScalar B Second ternary fraction.
126  | 
127  |   PetscScalar *minmax Array first and second ternary fractions of each of the
128  |   three corner values for scaling.
129  | 
130  |   guchar *pixel  Address in rgb buffer where this pixel should be painted.
131  |   ++++++++++++++++++++++++++++++++++++++*/
132  | 
133  | static inline void pseudoternarycolor
134  | (PetscScalar A, PetscScalar B, PetscScalar *minmax, guchar *pixel)
135  | {
136  |   PetscScalar x1, x2, inverse_det;
137  | 
138  |   /* Transform A,B into x1,x2 based on corners */
139  |   inverse_det = 1./((minmax[2]-minmax[0])*(minmax[5]-minmax[1]) -
140  | 		    (minmax[4]-minmax[0])*(minmax[3]-minmax[1]));
141  |   x1 = ((A-minmax[0])*(minmax[5]-minmax[1]) -
142  | 	(B-minmax[1])*(minmax[4]-minmax[0])) * inverse_det;
143  |   x2 = ((B-minmax[1])*(minmax[2]-minmax[0]) -
144  | 	(A-minmax[0])*(minmax[3]-minmax[1])) * inverse_det;
145  | 
146  |   /* Now colorize */
147  |   *pixel++ = 255*(1.-x1);
148  |   *pixel++ = 255*(x1+x2);
149  |   *pixel++ = 255*(1.-x2);
150  | }
151  | 
152  | 
153  | #undef __FUNCT__
154  | #define __FUNCT__ "render_rgb_local_2d"
155  | 
156  | /*++++++++++++++++++++++++++++++++++++++
157  |   Render data from global_array into local part of an RGB buffer.  When running
158  |   in parallel, these local buffers should be collected and layered to produce
159  |   the full image.
160  | 
161  |   int render_rgb_local_2d Returns zero or an error code.
162  | 
163  |   guchar *rgb RGB buffer in which to render.
164  | 
165  |   int rwidth Total width of the RGB buffer.
166  | 
167  |   int rheight Total height of the RGB buffer.
168  | 
169  |   int bytes_per_pixel Number of bytes per pixel in this RGB buffer (typically 3
170  |   or 4).
171  | 
172  |   PetscScalar *global_array Local array of global vector data to render.
173  | 
174  |   int num_fields Number of field variables in the array.
175  | 
176  |   int display_field The (first) field we are rendering now.
177  | 
178  |   field_plot_type fieldtype The type of this field.
179  | 
180  |   PetscScalar *minmax Array of minimum and maximum values to pass to the
181  |   various pseudocolor functions; if NULL, call minmax_scale to determine those
182  |   values.
183  | 
184  |   int nx Width of the array.
185  | 
186  |   int ny Height of the array.
187  | 
188  |   int xs Starting
189  |   +latex+$x$-coordinate
190  |   +html+ <i>x</i>-coordinate
191  |   of the local part of the global vector.
192  | 
193  |   int ys Starting
194  |   +latex+$y$-coordinate
195  |   +html+ <i>y</i>-coordinate
196  |   of the local part of the global vector.
197  | 
198  |   int xm Width of the local part of the global vector.
199  | 
200  |   int ym Height of the local part of the global vector.
201  |   ++++++++++++++++++++++++++++++++++++++*/
202  | 
203  | int render_rgb_local_2d
204  | (guchar *rgb, int rwidth, int rheight, int bytes_per_pixel,
205  |  PetscScalar *global_array, int num_fields, int display_field,
206  |  field_plot_type fieldtype, PetscScalar *minmax, int nx,int ny, int xs,int ys,
207  |  int xm,int ym)
208  | {
209  |   int ix,iy, ierr;
210  |   PetscScalar local_minmax[6];
211  | 
212  |   /* Determine default min and max if none are provided */
213  |   if (minmax == NULL)
214  |     {
215  |       minmax = local_minmax;
216  |       ierr = minmax_scale (global_array, xm*ym, num_fields, display_field,
217  | 			   fieldtype, 2, minmax); CHKERRQ (ierr);
218  |     }
219  | 
220  |   /* Do the rendering (note switch in inner loop, gotta get rid of that) */
221  |   for (iy=rheight*ys/ny; iy<rheight*(ys+ym)/ny; iy++)
222  |     for (ix=rwidth*xs/nx; ix<rwidth*(xs+xm)/nx; ix++)
223  |       {
224  | 	int vecindex = (((rheight-iy-1)*ny/rheight)*nx +
225  | 			ix*nx/rwidth)*num_fields + display_field;
226  | 	guchar *pixel = rgb + bytes_per_pixel*(iy*rwidth + ix);
227  | 
228  | 	switch (fieldtype)
229  | 	  {
230  | 	  case FIELD_SCALAR:
231  | 	  case FIELD_SCALAR+1:
232  | 	    {
233  | 	      pseudocolor (global_array [vecindex], minmax, pixel);
234  | 	      break;
235  | 	    }
236  | 	  case FIELD_VECTOR:
237  | 	  case FIELD_VECTOR+1:
238  | 	    {
239  | 	      pseudohueintcolor
240  | 		(global_array [vecindex], global_array [vecindex+1], minmax,
241  | 		 pixel);
242  | 	      break;
243  | 	    }
244  | 	  case FIELD_TERNARY:
245  | 	    {
246  | 	      pseudoternarycolor
247  | 		(global_array [vecindex], global_array [vecindex+1], minmax,
248  | 		 pixel);
249  | 	      break;
250  | 	    }
251  | 	  default:
252  | 	    SETERRQ (PETSC_ERR_ARG_OUTOFRANGE, "Field type not yet supported");
253  | 	  }
254  |       }
255  |   return 0;
256  | }
257  | 
258  | 
259  | /*++++++++++++++++++++++++++++++++++++++
260  |   Render triangle data into an RGB buffer.  When called in parallel, the
261  |   resulting images should be layered to give the complete picture.  Zooming is
262  |   done by adjusting the ratio of the dir vector to the right vector.
263  | 
264  |   int render_rgb_local_3d Returns zero or an error code.
265  | 
266  |   guchar *rgb RGB buffer in which to render.
267  | 
268  |   int rwidth Total width of the RGB buffer.
269  | 
270  |   int rheight Total height of the RGB buffer.
271  | 
272  |   int bytes_per_pixel Number of bytes per pixel in this RGB buffer (typically 3
273  |   or 4).
274  | 
275  |   int num_triangles Number of triangles to render.
276  | 
277  |   PetscScalar *vertices Table of coordinates (x1,y1,z1, x2,y2,z2, x3,y3,z3) and
278  |   colors (RGBA 0-1) making thirteen values per triangle.
279  | 
280  |   PetscScalar *eye Point from where we're looking (x,y,z).
281  | 
282  |   PetscScalar *dir Direction we're looking (x,y,z).
283  | 
284  |   PetscScalar *right Rightward direction in physical space (x,y,z).
285  |   ++++++++++++++++++++++++++++++++++++++*/
286  | 
287  | int render_rgb_local_3d
288  | (guchar *rgb, int rwidth, int rheight, int bytes_per_pixel,
289  |  int num_triangles, PetscScalar *vertices,
290  |  PetscScalar *eye, PetscScalar *dir, PetscScalar *right)
291  | {
292  |   SETERRQ (PETSC_ERR_SUP, "3-D rendering is not yet ready");
293  | }