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 | }