Tachyon (current)  Current Main Branch
imap.c
Go to the documentation of this file.
1 /*
2  * imap.c - This file contains code for doing image map type things.
3  *
4  * (C) Copyright 1994-2022 John E. Stone
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * $Id: imap.c,v 1.42 2022/03/25 06:13:10 johns Exp $
8  *
9  */
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <math.h>
15 
16 #define TACHYON_INTERNAL 1
17 #include "tachyon.h"
18 #include "imap.h"
19 #include "global.h" /* XXX this needs to go */
20 #include "util.h"
21 #include "parallel.h"
22 #include "imageio.h"
23 #include "ui.h"
24 
25 void ResetImages(void) {
26  int i;
28  for (i=0; i<MAXIMGS; i++) {
29  global_imagelist[i]=NULL;
30  }
31 }
32 
33 void FreeImages(void) {
34  int i;
35  for (i=0; i<global_numimages; i++) {
37  }
38  ResetImages();
39 }
40 
41 void LoadRawImage(rawimage * image) {
42  if (!image->loaded) {
43  readimage(image);
44  image->loaded=1;
45  }
46 }
47 
48 rawimage * AllocateImageRGB24(const char * filename, int xs, int ys, int zs, unsigned char * rgb) {
49  rawimage * newimage = NULL;
50  int i, len, intable;
51 
52  intable=0;
53  if (global_numimages!=0) {
54  for (i=0; i<global_numimages; i++) {
55  if (!strcmp(filename, global_imagelist[i]->name)) {
56  newimage=global_imagelist[i];
57  intable=1;
58  }
59  }
60  }
61 
62  if (!intable) {
63  newimage=malloc(sizeof(rawimage));
64  newimage->loaded=1;
65  newimage->xres=xs;
66  newimage->yres=ys;
67  newimage->zres=zs;
68  newimage->bpp=3;
69  newimage->data=rgb;
70  len=strlen(filename);
71  if (len > 80)
72  return NULL;
73  strcpy(newimage->name, filename);
74 
75  global_imagelist[global_numimages]=newimage; /* add new one to the table */
76  global_numimages++; /* increment the number of images */
77  }
78 
79  return newimage;
80 }
81 
82 rawimage * AllocateImageFile(const char * filename) {
83  rawimage * newimage = NULL;
84  int i, len, intable;
85 
86  intable=0;
87  if (global_numimages!=0) {
88  for (i=0; i<global_numimages; i++) {
89  if (!strcmp(filename, global_imagelist[i]->name)) {
90  newimage=global_imagelist[i];
91  intable=1;
92  }
93  }
94  }
95 
96  if (!intable) {
97  newimage=malloc(sizeof(rawimage));
98  newimage->loaded=0;
99  newimage->xres=0;
100  newimage->yres=0;
101  newimage->zres=0;
102  newimage->bpp=0;
103  newimage->data=NULL;
104  len=strlen(filename);
105  if (len > 80)
106  return NULL;
107  strcpy(newimage->name, filename);
108 
109  global_imagelist[global_numimages]=newimage; /* add new tex to table and */
110  global_numimages++; /* increment image count */
111  }
112 
113  return newimage;
114 }
115 
116 rawimage * NewImage(int x, int y, int z) {
117  rawimage * newimage = NULL;
118  newimage=malloc(sizeof(rawimage));
119  if (newimage == NULL)
120  return NULL;
121 
122  newimage->loaded=1;
123  newimage->xres=x;
124  newimage->yres=y;
125  newimage->zres=z;
126  newimage->bpp=0;
127  newimage->data=malloc(((long)x)*((long)y)*((long)z)*3L);
128  if (newimage->data == NULL) {
129  free(newimage);
130  return NULL;
131  }
132 
133  return newimage;
134 }
135 
136 void DeallocateImage(rawimage * image) {
137  image->loaded=0;
138  free(image->data);
139  image->data=NULL;
140  free(image);
141 }
142 
143 void FreeMIPMap(mipmap * mip) {
144  int i;
145 
146  /* don't free the original image here, FreeImages() will */
147  /* get it when all else is completed. */
148  for (i=1; i<mip->levels; i++) {
149  DeallocateImage(mip->images[i]);
150  }
151  free(mip->images);
152  free(mip);
153 }
154 
155 mipmap * LoadMIPMap(const char * filename, int maxlevels) {
156  rawimage * img;
157  mipmap * mip;
158 
159  img = AllocateImageFile(filename);
160  if (img == NULL)
161  return NULL;
162 
163  LoadRawImage(img);
164 
165  mip = CreateMIPMap(img, maxlevels);
166  if (mip == NULL) {
167  DeallocateImage(img);
168  free(mip);
169  return NULL;
170  }
171 
172  return mip;
173 }
174 
175 rawimage * DecimateImage(const rawimage * image) {
176  rawimage * newimage;
177  long x, y, addr, addr2;
178 
179  x = (long) image->xres >> 1;
180  if (x == 0)
181  x = 1;
182 
183  y = (long) image->yres >> 1;
184  if (y == 0)
185  y = 1;
186 
187  newimage = NewImage(x, y, 1);
188 
189  if (image->xres > 1 && image->yres > 1) {
190  for (y=0; y<newimage->yres; y++) {
191  for (x=0; x<newimage->xres; x++) {
192  addr = (newimage->xres*y + x)*3L;
193  addr2 = (image->xres*y + x)*3L*2L;
194  newimage->data[addr] = (int)
195  (image->data[addr2] +
196  image->data[addr2 + 3] +
197  image->data[addr2 + image->xres*3] +
198  image->data[addr2 + (image->xres + 1)*3]) >> 2;
199  addr++;
200  addr2++;
201  newimage->data[addr] = (int)
202  (image->data[addr2] +
203  image->data[addr2 + 3] +
204  image->data[addr2 + image->xres*3] +
205  image->data[addr2 + (image->xres + 1)*3]) >> 2;
206  addr++;
207  addr2++;
208  newimage->data[addr] = (int)
209  (image->data[addr2] +
210  image->data[addr2 + 3] +
211  image->data[addr2 + image->xres*3] +
212  image->data[addr2 + (image->xres + 1)*3]) >> 2;
213  }
214  }
215  } else if (image->xres == 1) {
216  for (y=0; y<newimage->yres; y++) {
217  addr = y*3L;
218  addr2 = y*3L*2L;
219  newimage->data[addr] = (int)
220  (image->data[addr2] +
221  image->data[addr2 + 3]) >> 1;
222  addr++;
223  addr2++;
224  newimage->data[addr] = (int)
225  (image->data[addr2] +
226  image->data[addr2 + 3]) >> 1;
227  addr++;
228  addr2++;
229  newimage->data[addr] = (int)
230  (image->data[addr2] +
231  image->data[addr2 + 3]) >> 1;
232  }
233  } else if (image->yres == 1) {
234  for (x=0; x<newimage->xres; x++) {
235  addr = x*3L;
236  addr2 = x*3L*2L;
237  newimage->data[addr] = (int)
238  (image->data[addr2] +
239  image->data[addr2 + 3]) >> 1;
240  addr++;
241  addr2++;
242  newimage->data[addr] = (int)
243  (image->data[addr2] +
244  image->data[addr2 + 3]) >> 1;
245  addr++;
246  addr2++;
247  newimage->data[addr] = (int)
248  (image->data[addr2] +
249  image->data[addr2 + 3]) >> 1;
250  }
251  }
252 
253  return newimage;
254 }
255 
256 mipmap * CreateMIPMap(rawimage * image, int maxlevels) {
257  mipmap * mip;
258  int xlevels, ylevels, zlevels, i;
259 
260  if (image == NULL)
261  return NULL;
262 
263  mip = (mipmap *) malloc(sizeof(mipmap));
264  if (mip == NULL)
265  return NULL;
266 
267  xlevels = 0;
268  i = abs(image->xres);
269  while (i) {
270  i >>= 1;
271  xlevels++;
272  }
273 
274  ylevels = 0;
275  i = abs(image->yres);
276  while (i) {
277  i >>= 1;
278  ylevels++;
279  }
280 
281  zlevels = 0;
282  i = abs(image->zres);
283  while (i) {
284  i >>= 1;
285  zlevels++;
286  }
287 
288  mip->levels = (xlevels > ylevels) ? xlevels : ylevels;
289  if (zlevels > mip->levels)
290  mip->levels=zlevels;
291 
292  /* XXX at present, the decimation routine will not */
293  /* handle volumetric images, so if we get one, we */
294  /* have to clamp the maximum MIP levels to 1 */
295  if (image->zres > 1) {
296  maxlevels = 1;
297  }
298 
299  if (maxlevels > 0) {
300  if (maxlevels < mip->levels)
301  mip->levels = maxlevels;
302  }
303 
304  if (rt_mynode() == 0) {
305  char msgtxt[1024];
306  sprintf(msgtxt, "Creating MIP Map: xlevels: %d ylevels: %d zlevels: %d levels: %d", xlevels, ylevels, zlevels, mip->levels);
307  rt_ui_message(MSG_0, msgtxt);
308  }
309 
310  mip->images = (rawimage **) malloc(mip->levels * sizeof(rawimage *));
311  if (mip->images == NULL) {
312  free(mip);
313  return NULL;
314  }
315 
316  for (i=0; i<mip->levels; i++) {
317  mip->images[i] = NULL;
318  }
319 
320  mip->images[0] = image;
321  for (i=1; i<mip->levels; i++) {
322  mip->images[i] = DecimateImage(mip->images[i - 1]);
323  }
324 
325  return mip;
326 }
327 
328 color MIPMap(const mipmap * mip, flt u, flt v, flt d) {
329  int mapindex;
330  flt mapflt;
331  color col, col1, col2;
332 
333  if ((u <= 1.0) && (u >= 0.0) && (v <= 1.0) && (v >= 0.0)) {
334  flt t;
335  t = (d > 1.0) ? 1.0 : d;
336  d = (t < 0.0) ? 0.0 : t;
337 
338  mapflt = d * (mip->levels - 0.9999); /* convert range to mapindex */
339  mapindex = (int) mapflt; /* truncate to nearest integer */
340  mapflt = mapflt - mapindex; /* fractional part of mip map level */
341 
342  /* interpolate between two nearest image maps */
343  if (mapindex < (mip->levels - 2)) {
344  col1 = ImageMap(mip->images[mapindex ], u, v);
345  col2 = ImageMap(mip->images[mapindex + 1], u, v);
346  col.r = col1.r + mapflt*(col2.r - col1.r);
347  col.g = col1.g + mapflt*(col2.g - col1.g);
348  col.b = col1.b + mapflt*(col2.b - col1.b);
349  }
350  else {
351  /* if mapindex is too high, use the highest, */
352  /* with no MIP-Map interpolation. */
353  col = ImageMap(mip->images[mip->levels - 1], u, v);
354  }
355  }
356  else {
357  col.r=0.0;
358  col.g=0.0;
359  col.b=0.0;
360  }
361 
362  return col;
363 }
364 
365 
366 color ImageMap(const rawimage * image, flt u, flt v) {
367  color col, colx, colx2;
368  flt x, y, px, py;
369  int ix, iy, nx, ny;
370  unsigned char * ptr;
371  const flt texel_inv = 1.0 / 255.0;
372 
373  /*
374  * Perform bilinear interpolation between 4 closest pixels.
375  */
376  nx = (image->xres > 1) ? 3 : 0;
377  x = (image->xres - 1.0) * u; /* floating point X location */
378  ix = (int) x; /* integer X location */
379  px = x - ix; /* fractional X location */
380 
381  ny = (image->yres > 1) ? image->xres * 3 : 0;
382  y = (image->yres - 1.0) * v; /* floating point Y location */
383  iy = (int) y; /* integer Y location */
384  py = y - iy; /* fractional Y location */
385 
386  /* pointer to the left lower pixel */
387  ptr = image->data + ((image->xres * iy) + ix) * 3;
388 
389  /* interpolate between left and right lower pixels */
390  colx.r = (flt) ((flt)ptr[0] + px*((flt)ptr[nx ] - (flt) ptr[0]));
391  colx.g = (flt) ((flt)ptr[1] + px*((flt)ptr[nx+1] - (flt) ptr[1]));
392  colx.b = (flt) ((flt)ptr[2] + px*((flt)ptr[nx+2] - (flt) ptr[2]));
393 
394  /* pointer to the left upper pixel */
395  ptr += ny;
396 
397  /* interpolate between left and right upper pixels */
398  colx2.r = ((flt)ptr[0] + px*((flt)ptr[nx ] - (flt)ptr[0]));
399  colx2.g = ((flt)ptr[1] + px*((flt)ptr[nx+1] - (flt)ptr[1]));
400  colx2.b = ((flt)ptr[2] + px*((flt)ptr[nx+2] - (flt)ptr[2]));
401 
402  /* interpolate between upper and lower interpolated pixels */
403  col.r = (colx.r + py*(colx2.r - colx.r)) * texel_inv;
404  col.g = (colx.g + py*(colx2.g - colx.g)) * texel_inv;
405  col.b = (colx.b + py*(colx2.b - colx.b)) * texel_inv;
406 
407  return col;
408 }
409 
410 
411 color VolImageMapNearest(const rawimage * img, flt u, flt v, flt w) {
412  color col;
413  flt x, y, z;
414  long ix, iy, iz;
415  long addr;
416 
417  x = (img->xres - 1.0) * u; /* floating point X location */
418  ix = (long) x;
419  y = (img->yres - 1.0) * v; /* floating point Y location */
420  iy = (long) y;
421  z = (img->zres - 1.0) * w; /* floating point Z location */
422  iz = (long) z;
423 
424  addr = ((iz * img->xres * img->yres) + (iy * img->xres) + ix) * 3;
425  col.r = img->data[addr ];
426  col.g = img->data[addr + 1];
427  col.b = img->data[addr + 2];
428 
429  return col;
430 }
431 
432 
433 color VolImageMapTrilinear(const rawimage * img, flt u, flt v, flt w) {
434  color col, colL, colU, colll, colul, colLL, colUL;
435  flt x, y, z, px, py, pz;
436  long ix, iy, iz, nx, ny, nz;
437  unsigned char *llptr, *ulptr, *LLptr, *ULptr;
438  long addr;
439  const flt texel_inv = 1.0 / 255.0;
440 
441  /*
442  * Perform trilinear interpolation between 8 closest pixels.
443  */
444  nx = (img->xres > 1) ? 3L : 0L;
445  x = (img->xres - 1.0) * u; /* floating point X location */
446  ix = (long) x; /* integer X location */
447  px = x - ix; /* fractional X location */
448 
449  ny = (img->yres > 1) ? (img->xres * 3L) : 0L;
450  y = (img->yres - 1.0) * v; /* floating point Y location */
451  iy = (long) y; /* integer Y location */
452  py = y - iy; /* fractional Y location */
453 
454  nz = (img->zres > 1) ? (img->xres * img->yres * 3L) : 0L;
455  z = (img->zres - 1.0) * w; /* floating point Z location */
456  iz = (long) z; /* integer Z location */
457  pz = z - iz; /* fractional Z location */
458 
459  addr = ((img->xres*img->yres * iz) + (img->xres * iy) + ix) * 3L;
460 
461  /* pointer to the lower left lower pixel (Y ) */
462  llptr = img->data + addr;
463 
464  /* pointer to the lower left upper pixel (Y+1) */
465  ulptr = llptr + ny;
466 
467  /* pointer to the upper left lower pixel (Z+1) (Y ) */
468  LLptr = llptr + nz;
469  /* pointer to the upper left upper pixel (Z+1) (Y+1) */
470  ULptr = LLptr + ny;
471 
472  /* interpolate between left and right lower pixels */
473  colll.r = (flt) ((flt)llptr[0] + px*((flt)llptr[nx ] - (flt) llptr[0]));
474  colll.g = (flt) ((flt)llptr[1] + px*((flt)llptr[nx+1] - (flt) llptr[1]));
475  colll.b = (flt) ((flt)llptr[2] + px*((flt)llptr[nx+2] - (flt) llptr[2]));
476 
477  /* interpolate between left and right upper pixels */
478  colul.r = ((flt)ulptr[0] + px*((flt)ulptr[nx ] - (flt)ulptr[0]));
479  colul.g = ((flt)ulptr[1] + px*((flt)ulptr[nx+1] - (flt)ulptr[1]));
480  colul.b = ((flt)ulptr[2] + px*((flt)ulptr[nx+2] - (flt)ulptr[2]));
481 
482  /* interpolate between left and right lower pixels */
483  colLL.r = (flt) ((flt)LLptr[0] + px*((flt)LLptr[nx ] - (flt) LLptr[0]));
484  colLL.g = (flt) ((flt)LLptr[1] + px*((flt)LLptr[nx+1] - (flt) LLptr[1]));
485  colLL.b = (flt) ((flt)LLptr[2] + px*((flt)LLptr[nx+2] - (flt) LLptr[2]));
486 
487  /* interpolate between left and right upper pixels */
488  colUL.r = ((flt)ULptr[0] + px*((flt)ULptr[nx ] - (flt)ULptr[0]));
489  colUL.g = ((flt)ULptr[1] + px*((flt)ULptr[nx+1] - (flt)ULptr[1]));
490  colUL.b = ((flt)ULptr[2] + px*((flt)ULptr[nx+2] - (flt)ULptr[2]));
491 
492  /* interpolate between upper and lower interpolated pixels */
493  colL.r = (colll.r + py*(colul.r - colll.r));
494  colL.g = (colll.g + py*(colul.g - colll.g));
495  colL.b = (colll.b + py*(colul.b - colll.b));
496 
497  /* interpolate between upper and lower interpolated pixels */
498  colU.r = (colLL.r + py*(colUL.r - colLL.r));
499  colU.g = (colLL.g + py*(colUL.g - colLL.g));
500  colU.b = (colLL.b + py*(colUL.b - colLL.b));
501 
502  /* interpolate between upper and lower interpolated pixels */
503  col.r = (colL.r + pz*(colU.r - colL.r)) * texel_inv;
504  col.g = (colL.g + pz*(colU.g - colL.g)) * texel_inv;
505  col.b = (colL.b + pz*(colU.b - colL.b)) * texel_inv;
506 
507  return col;
508 }
509 
510 
511 color VolMIPMap(const mipmap * mip, flt u, flt v, flt w, flt d) {
512  int mapindex;
513  flt mapflt;
514  color col, col1, col2;
515 
516  if ((u <= 1.0) && (u >= 0.0) &&
517  (v <= 1.0) && (v >= 0.0) &&
518  (w <= 1.0) && (w >= 0.0)) {
519  flt t;
520  t = (d > 1.0) ? 1.0 : d;
521  d = (t < 0.0) ? 0.0 : t;
522 
523  mapflt = d * (mip->levels - 0.9999); /* convert range to mapindex */
524  mapindex = (int) mapflt; /* truncate to nearest integer */
525  mapflt = mapflt - mapindex; /* fractional part of mip map level */
526 
527  /* interpolate between two nearest image maps */
528  if (mapindex < (mip->levels - 2)) {
529  col1 = VolImageMapTrilinear(mip->images[mapindex ], u, v, w);
530  col2 = VolImageMapTrilinear(mip->images[mapindex + 1], u, v, w);
531  col.r = col1.r + mapflt*(col2.r - col1.r);
532  col.g = col1.g + mapflt*(col2.g - col1.g);
533  col.b = col1.b + mapflt*(col2.b - col1.b);
534  } else {
535  /* if mapindex is too high, use the highest, */
536  /* with no MIP-Map interpolation. */
537  col = VolImageMapTrilinear(mip->images[mip->levels - 1], u, v, w);
538  }
539  } else {
540  col.r=0.0;
541  col.g=0.0;
542  col.b=0.0;
543  }
544 
545  return col;
546 }
547 
color VolMIPMap(const mipmap *mip, flt u, flt v, flt w, flt d)
Definition: imap.c:511
void FreeMIPMap(mipmap *mip)
Definition: imap.c:143
void FreeImages(void)
Definition: imap.c:33
color VolImageMapTrilinear(const rawimage *img, flt u, flt v, flt w)
Definition: imap.c:433
int readimage(rawimage *img)
Definition: imageio.c:56
rawimage * global_imagelist[MAXIMGS]
texture map cache
Definition: global.c:18
void rt_ui_message(int level, char *msg)
Definition: ui.c:31
color VolImageMapNearest(const rawimage *img, flt u, flt v, flt w)
Definition: imap.c:411
mipmap * LoadMIPMap(const char *filename, int maxlevels)
Definition: imap.c:155
rawimage * NewImage(int x, int y, int z)
Definition: imap.c:116
double flt
generic floating point number, using double
Definition: tachyon.h:47
int rt_mynode(void)
distributed memory parallel node rank
Definition: api.c:49
color MIPMap(const mipmap *mip, flt u, flt v, flt d)
Definition: imap.c:328
void ResetImages(void)
Definition: imap.c:25
rawimage * DecimateImage(const rawimage *image)
Definition: imap.c:175
Tachyon cross-platform timers, special math function wrappers, and RNGs.
mipmap * CreateMIPMap(rawimage *image, int maxlevels)
Definition: imap.c:256
void DeallocateImage(rawimage *image)
Definition: imap.c:136
int global_numimages
Definition: global.c:19
color ImageMap(const rawimage *image, flt u, flt v)
Definition: imap.c:366
#define MSG_0
Definition: ui.h:12
rawimage * AllocateImageFile(const char *filename)
Definition: imap.c:82
Tachyon public API function prototypes and declarations used to drive the ray tracing engine...
void LoadRawImage(rawimage *image)
Definition: imap.c:41
rawimage * AllocateImageRGB24(const char *filename, int xs, int ys, int zs, unsigned char *rgb)
Definition: imap.c:48