Tachyon (current)  Current Main Branch
texture.c
Go to the documentation of this file.
1 /*
2  * texture.c - This file contains functions for implementing textures.
3  *
4  * (C) Copyright 1994-2022 John E. Stone
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * $Id: texture.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 "macros.h"
19 #include "texture.h"
20 #include "coordsys.h"
21 #include "imap.h"
22 #include "vector.h"
23 #include "box.h"
24 #include "util.h"
25 
26 static texture_methods normal_methods = {
27  free
28 };
29 
30 static texture_methods standard_methods = {
32 };
33 
34 static texture_methods vcstri_methods = {
35  free
36 };
37 
38 texture * new_texture(void) {
39  texture * tex;
40  tex = (texture *) malloc(sizeof(texture));
41  tex->methods = &normal_methods;
42  return tex;
43 }
44 
45 texture * new_standard_texture(void) {
46  standard_texture * tex;
47  tex = (standard_texture *) malloc(sizeof(standard_texture));
48  tex->methods = &standard_methods;
49  return (texture *) tex;
50 }
51 
52 texture * new_vcstri_texture(void) {
53  vcstri_texture * tex;
54  tex = (vcstri_texture *) malloc(sizeof(vcstri_texture));
55  tex->methods = &vcstri_methods;
56  return (texture *) tex;
57 }
58 
59 void free_standard_texture(void * voidtex) {
60  standard_texture * tex = (standard_texture *) voidtex;
61  if (tex->img != NULL) {
62  if ((tex->texfunc == (color (*)(const void *, const void *, void *)) image_plane_texture) ||
63  (tex->texfunc == (color (*)(const void *, const void *, void *)) image_cyl_texture) ||
64  (tex->texfunc == (color (*)(const void *, const void *, void *)) image_sphere_texture) ||
65  (tex->texfunc == (color (*)(const void *, const void *, void *)) image_volume_texture)) {
66  FreeMIPMap(tex->img);
67  tex->img = NULL;
68  } else {
69 printf("XXX Doh, unrecognized image map type!\n");
70  }
71  }
72  free(tex);
73 }
74 
75 
76 /* standard solid background texture */
77 color solid_background_texture(ray *ry) {
78  return ry->scene->bgtex.bg_color;
79 }
80 
81 
82 /* sky sphere background texture, linear mapping */
84  color col;
85  flt tmp;
86  flt IdotG = VDot(&ry->d, &ry->scene->bgtex.bg_grad_updir);
87  flt val = (IdotG - ry->scene->bgtex.bg_grad_botval) *
88  ry->scene->bgtex.bg_grad_invrange;
89 
90  /*
91  * Compute and add random noise to the background gradient to
92  * avoid banding artifacts, particularly in compressed video.
93  * Noise RNG depends only on pixel index, with no sample/subframe
94  * contribution, so that dither pattern won't average out.
95  */
96  unsigned int randval = tea4(ry->idx, ry->idx);
97  flt u = rt_rand(&randval) * RT_RAND_MAX_INV;
98  flt noise = ry->scene->bgtex.bg_grad_noisemag * (u - 0.5);
99  val += noise;
100 
101  tmp = (val > 1.0) ? 1.0 : val;
102  val = (tmp < 0.0) ? 0.0 : tmp;
103 
104  col.r = ry->scene->bgtex.bg_grad_top.r * val +
105  ry->scene->bgtex.bg_grad_bot.r * (1.0 - val);
106  col.g = ry->scene->bgtex.bg_grad_top.g * val +
107  ry->scene->bgtex.bg_grad_bot.g * (1.0 - val);
108  col.b = ry->scene->bgtex.bg_grad_top.b * val +
109  ry->scene->bgtex.bg_grad_bot.b * (1.0 - val);
110 
111  return col;
112 }
113 
114 
115 /* sky orthographic plane background texture, linear mapping */
117  color col;
118  flt tmp;
119  flt IdotG = VDot(&ry->o, &ry->scene->bgtex.bg_grad_updir);
120  flt val = (IdotG - ry->scene->bgtex.bg_grad_botval) *
121  ry->scene->bgtex.bg_grad_invrange;
122 
123  /*
124  * Compute and add random noise to the background gradient to
125  * avoid banding artifacts, particularly in compressed video.
126  * Noise RNG depends only on pixel index, with no sample/subframe
127  * contribution, so that dither pattern won't average out.
128  */
129  unsigned int randval = tea4(ry->idx, ry->idx);
130  flt u = rt_rand(&randval) * RT_RAND_MAX_INV;
131  flt noise = ry->scene->bgtex.bg_grad_noisemag * (u - 0.5);
132  val += noise;
133 
134  tmp = (val > 1.0) ? 1.0 : val;
135  val = (tmp < 0.0) ? 0.0 : tmp;
136 
137  col.r = ry->scene->bgtex.bg_grad_top.r * val +
138  ry->scene->bgtex.bg_grad_bot.r * (1.0 - val);
139  col.g = ry->scene->bgtex.bg_grad_top.g * val +
140  ry->scene->bgtex.bg_grad_bot.g * (1.0 - val);
141  col.b = ry->scene->bgtex.bg_grad_top.b * val +
142  ry->scene->bgtex.bg_grad_bot.b * (1.0 - val);
143 
144  return col;
145 }
146 
147 
148 /* plain vanilla texture solely based on object color */
149 color constant_texture(const vector * hit, const texture * tx, const ray * ry) {
150  standard_texture * tex = (standard_texture *) tx;
151  return tex->col;
152 }
153 
154 /* cylindrical image map */
155 color image_cyl_texture(const vector * hit, const texture * tx, const ray * ry) {
156  vector rh;
157  flt u, v, miprad, maxscale, cyrad;
158  standard_texture * tex = (standard_texture *) tx;
159 
160  rh.x=hit->x - tex->ctr.x;
161  rh.z=hit->y - tex->ctr.y;
162  rh.y=hit->z - tex->ctr.z;
163 
164  xyztocyl(rh, 1.0, &u, &v);
165 
166  u = u * tex->scale.x;
167  u = u + tex->rot.x;
168  u = u - ((int) u);
169  if (u < 0.0) u+=1.0;
170 
171  v = v * tex->scale.y;
172  v = v + tex->rot.y;
173  v = v - ((int) v);
174  if (v < 0.0) v+=1.0;
175 
176  cyrad = EPSILON + 8.0 * SQRT(rh.x*rh.x + rh.y*rh.y + rh.z*rh.z);
177 
178  maxscale = (FABS(tex->scale.x) > FABS(tex->scale.y)) ?
179  tex->scale.x : tex->scale.y;
180 
181  miprad = (0.05 * ry->opticdist * FABS(maxscale)) / cyrad;
182 
183  return MIPMap(tex->img, u, v, miprad);
184 }
185 
186 /* spherical image map */
187 color image_sphere_texture(const vector * hit, const texture * tx, const ray * ry) {
188  vector rh;
189  flt u, v, miprad, maxscale, sprad;
190  standard_texture * tex = (standard_texture *) tx;
191 
192  rh.x=hit->x - tex->ctr.x;
193  rh.y=hit->y - tex->ctr.y;
194  rh.z=hit->z - tex->ctr.z;
195 
196  xyztospr(rh, &u, &v);
197 
198  u = u * tex->scale.x;
199  u = u + tex->rot.x;
200  u = u - ((int) u);
201  if (u < 0.0) u+=1.0;
202 
203  v = v * tex->scale.y;
204  v = v + tex->rot.y;
205  v = v - ((int) v);
206  if (v < 0.0) v+=1.0;
207 
208  sprad = EPSILON + 8.0 * SQRT(rh.x*rh.x + rh.y*rh.y + rh.z*rh.z);
209 
210  maxscale = (FABS(tex->scale.x) > FABS(tex->scale.y)) ?
211  tex->scale.x : tex->scale.y;
212 
213  miprad = (0.05 * ry->opticdist * FABS(maxscale)) / sprad;
214 
215  return MIPMap(tex->img, u, v, miprad);
216 }
217 
218 /* planar image map */
219 color image_plane_texture(const vector * hit, const texture * tx, const ray * ry) {
220  vector pnt;
221  flt u, v, miprad, maxscale;
222  standard_texture * tex = (standard_texture *) tx;
223 
224  pnt.x=hit->x - tex->ctr.x;
225  pnt.y=hit->y - tex->ctr.y;
226  pnt.z=hit->z - tex->ctr.z;
227 
228  VDOT(u, tex->uaxs, pnt);
229  VDOT(v, tex->vaxs, pnt);
230 
231  u = u * tex->scale.x;
232  u = u + tex->rot.x;
233  u = u - ((int) u);
234  if (u < 0.0) u += 1.0;
235 
236  v = v * tex->scale.y;
237  v = v + tex->rot.y;
238  v = v - ((int) v);
239  if (v < 0.0) v += 1.0;
240 
241 
242  maxscale = (FABS(tex->scale.x) > FABS(tex->scale.y)) ?
243  tex->scale.x : tex->scale.y;
244 
245  miprad = 0.05 * ry->opticdist * FABS(maxscale);
246 
247  return MIPMap(tex->img, u, v, miprad);
248 }
249 
250 
251 /* volumetric texture map (applied to surface geometry etc) */
252 color image_volume_texture(const vector * hit, const texture * tx, const ray * ry) {
253  vector pnt;
254  flt u, v, w, miprad, maxscale;
255  standard_texture * tex = (standard_texture *) tx;
256 
257  pnt.x=hit->x - tex->ctr.x;
258  pnt.y=hit->y - tex->ctr.y;
259  pnt.z=hit->z - tex->ctr.z;
260 
261  VDOT(u, tex->uaxs, pnt);
262  VDOT(v, tex->vaxs, pnt);
263  VDOT(w, tex->waxs, pnt);
264 
265  u = u * tex->scale.x;
266  u = u + tex->rot.x;
267  u = u - ((int) u);
268  if (u < 0.0) u += 1.0;
269 
270  v = v * tex->scale.y;
271  v = v + tex->rot.y;
272  v = v - ((int) v);
273  if (v < 0.0) v += 1.0;
274 
275  w = w * tex->scale.z;
276  w = w + tex->rot.z;
277  w = w - ((int) w);
278  if (w < 0.0) w += 1.0;
279 
280  maxscale = (FABS(tex->scale.x) > FABS(tex->scale.y)) ?
281  tex->scale.x : tex->scale.y;
282  if (FABS(tex->scale.z) > FABS(maxscale))
283  maxscale = tex->scale.z;
284 
285  miprad = 0.05 * ry->opticdist * FABS(maxscale);
286 
287  return VolMIPMap(tex->img, u, v, w, miprad);
288 }
289 
290 
291 color grit_texture(const vector * hit, const texture * tx, const ray * ry) {
292  int rnum;
293  flt fnum;
294  color col;
295  standard_texture * tex = (standard_texture *) tx;
296 
297  rnum=rand() % 4096;
298  fnum=(rnum / 4096.0 * 0.2) + 0.8;
299 
300  col.r=tex->col.r * fnum;
301  col.g=tex->col.g * fnum;
302  col.b=tex->col.b * fnum;
303 
304  return col;
305 }
306 
307 color checker_texture(const vector * hit, const texture * tx, const ray * ry) {
308  long x,y,z;
309  flt xh,yh,zh;
310  color col;
311  standard_texture * tex = (standard_texture *) tx;
312 
313  xh=hit->x - tex->ctr.x;
314  x=(long) ((FABS(xh) * 3) + 0.5);
315  x=x % 2;
316  yh=hit->y - tex->ctr.y;
317  y=(long) ((FABS(yh) * 3) + 0.5);
318  y=y % 2;
319  zh=hit->z - tex->ctr.z;
320  z=(long) ((FABS(zh) * 3) + 0.5);
321  z=z % 2;
322 
323  if (((x + y + z) % 2)==1) {
324  col.r=1.0;
325  col.g=0.2;
326  col.b=0.0;
327  }
328  else {
329  col.r=0.0;
330  col.g=0.2;
331  col.b=1.0;
332  }
333 
334  return col;
335 }
336 
337 color cyl_checker_texture(const vector * hit, const texture * tx, const ray * ry) {
338  long x,y;
339  vector rh;
340  flt u,v;
341  color col;
342  standard_texture * tex = (standard_texture *) tx;
343 
344  rh.x=hit->x - tex->ctr.x;
345  rh.y=hit->y - tex->ctr.y;
346  rh.z=hit->z - tex->ctr.z;
347 
348  xyztocyl(rh, 1.0, &u, &v);
349 
350  x=(long) (FABS(u) * 18.0);
351  x=x % 2;
352  y=(long) (FABS(v) * 10.0);
353  y=y % 2;
354 
355  if (((x + y) % 2)==1) {
356  col.r=1.0;
357  col.g=0.2;
358  col.b=0.0;
359  }
360  else {
361  col.r=0.0;
362  col.g=0.2;
363  col.b=1.0;
364  }
365 
366  return col;
367 }
368 
369 
370 color wood_texture(const vector * hit, const texture * tx, const ray * ry) {
371  flt radius, angle;
372  int grain;
373  color col;
374  flt x,y,z;
375  standard_texture * tex = (standard_texture *) tx;
376 
377  x=(hit->x - tex->ctr.x) / tex->scale.x;
378  y=(hit->y - tex->ctr.y) / tex->scale.y;
379  z=(hit->z - tex->ctr.z) / tex->scale.z;
380 
381  radius=sqrt(x*x + z*z);
382  if (z == 0.0)
383  angle=3.1415926/2.0;
384  else
385  angle=atan(x / z);
386 
387  radius=radius + 3.0 * SIN(20 * angle + y / 150.0);
388  grain=((int) (radius + 0.5)) % 60;
389  if (grain < 40) {
390  col.r=0.8;
391  col.g=1.0;
392  col.b=0.2;
393  }
394  else {
395  col.r=0.0;
396  col.g=0.0;
397  col.b=0.0;
398  }
399 
400  return col;
401 }
402 
403 
404 
405 #define NMAX 28
406 short int NoiseMatrix[NMAX][NMAX][NMAX];
407 
408 void InitNoise(void) {
409  byte x,y,z,i,j,k;
410  unsigned int rndval = 1234567; /* pathetic random number seed */
411 
412  for (x=0; x<NMAX; x++) {
413  for (y=0; y<NMAX; y++) {
414  for (z=0; z<NMAX; z++) {
415  NoiseMatrix[x][y][z]=(short int) ((rt_rand(&rndval) * RT_RAND_MAX_INV) * 12000.0);
416 
417  if (x==NMAX-1) i=0;
418  else i=x;
419 
420  if (y==NMAX-1) j=0;
421  else j=y;
422 
423  if (z==NMAX-1) k=0;
424  else k=z;
425 
426  NoiseMatrix[x][y][z]=NoiseMatrix[i][j][k];
427  }
428  }
429  }
430 }
431 
432 int Noise(flt x, flt y, flt z) {
433  byte ix, iy, iz;
434  flt ox, oy, oz;
435  int p000, p001, p010, p011;
436  int p100, p101, p110, p111;
437  int p00, p01, p10, p11;
438  int p0, p1;
439  int d00, d01, d10, d11;
440  int d0, d1, d;
441 
442  x=FABS(x);
443  y=FABS(y);
444  z=FABS(z);
445 
446  ix=((int) x) % NMAX;
447  iy=((int) y) % NMAX;
448  iz=((int) z) % NMAX;
449 
450  ox=(x - ((int) x));
451  oy=(y - ((int) y));
452  oz=(z - ((int) z));
453 
454  p000=NoiseMatrix[ix][iy][iz];
455  p001=NoiseMatrix[ix][iy][iz+1];
456  p010=NoiseMatrix[ix][iy+1][iz];
457  p011=NoiseMatrix[ix][iy+1][iz+1];
458  p100=NoiseMatrix[ix+1][iy][iz];
459  p101=NoiseMatrix[ix+1][iy][iz+1];
460  p110=NoiseMatrix[ix+1][iy+1][iz];
461  p111=NoiseMatrix[ix+1][iy+1][iz+1];
462 
463  d00=p100-p000;
464  d01=p101-p001;
465  d10=p110-p010;
466  d11=p111-p011;
467 
468  p00=(int) ((int) d00*ox) + p000;
469  p01=(int) ((int) d01*ox) + p001;
470  p10=(int) ((int) d10*ox) + p010;
471  p11=(int) ((int) d11*ox) + p011;
472  d0=p10-p00;
473  d1=p11-p01;
474  p0=(int) ((int) d0*oy) + p00;
475  p1=(int) ((int) d1*oy) + p01;
476  d=p1-p0;
477 
478  return (int) ((int) d*oz) + p0;
479 }
480 
481 color marble_texture(const vector * hit, const texture * tx, const ray * ry) {
482  flt i,d,t;
483  flt x,y,z;
484  color col;
485 /*
486  standard_texture * tex = (standard_texture *) tx;
487 */
488 
489  x=hit->x;
490  y=hit->y;
491  z=hit->z;
492 
493  x=x * 1.0;
494 
495  d=x + 0.0006 * Noise(x, (y * 1.0), (z * 1.0));
496  d=d*(((int) d) % 25);
497  i=0.0 + 0.10 * FABS(d - 10.0f - 20.0f * ((int) d * 0.05f));
498 
499  t = (i > 1.0) ? 1.0 : i;
500  i = (t < 0.0) ? 0.0 : t;
501 
502 /*
503  col.r=i * tex->col.r;
504  col.g=i * tex->col.g;
505  col.b=i * tex->col.b;
506 */
507 
508  col.r = (1.0 + SIN(i * 6.28)) / 2.0;
509  col.g = (1.0 + SIN(i * 16.28)) / 2.0;
510  col.b = (1.0 + COS(i * 30.28)) / 2.0;
511 
512  return col;
513 }
514 
515 
516 color gnoise_texture(const vector * hit, const texture * tx, const ray * ry) {
517  color col;
518  flt f, t;
519  standard_texture * tex = (standard_texture *) tx;
520 
521  f=Noise((hit->x - tex->ctr.x),
522  (hit->y - tex->ctr.y),
523  (hit->z - tex->ctr.z));
524 
525  t = (f > 1.0) ? 1.0 : f;
526  f = (t < 0.01) ? 0.01 : t;
527 
528  col.r=tex->col.r * f;
529  col.g=tex->col.g * f;
530  col.b=tex->col.b * f;
531 
532  return col;
533 }
534 
535 void InitTextures(void) {
536  InitNoise();
537  ResetImages();
538 }
539 
540 void FreeTextures(void) {
541  FreeImages();
542 }
543 
void free_standard_texture(void *voidtex)
Definition: texture.c:59
color VolMIPMap(const mipmap *mip, flt u, flt v, flt w, flt d)
Definition: imap.c:511
color sky_plane_background_texture(ray *ry)
Definition: texture.c:116
unsigned int rt_rand(unsigned int *idum)
Definition: util.c:324
void InitTextures(void)
Definition: texture.c:535
void FreeMIPMap(mipmap *mip)
Definition: imap.c:143
color solid_background_texture(ray *ry)
Definition: texture.c:77
#define RT_RAND_MAX_INV
Definition: util.h:72
texture * new_standard_texture(void)
Definition: texture.c:45
void InitNoise(void)
Definition: texture.c:408
void FreeImages(void)
Definition: imap.c:33
color sky_sphere_background_texture(ray *ry)
Definition: texture.c:83
color marble_texture(const vector *hit, const texture *tx, const ray *ry)
Definition: texture.c:481
color gnoise_texture(const vector *hit, const texture *tx, const ray *ry)
Definition: texture.c:516
static texture_methods standard_methods
Definition: texture.c:30
color image_volume_texture(const vector *hit, const texture *tx, const ray *ry)
Definition: texture.c:252
color grit_texture(const vector *hit, const texture *tx, const ray *ry)
Definition: texture.c:291
flt VDot(apivector *a, apivector *b)
color cyl_checker_texture(const vector *hit, const texture *tx, const ray *ry)
Definition: texture.c:337
texture * new_vcstri_texture(void)
Definition: texture.c:52
double flt
generic floating point number, using double
Definition: tachyon.h:47
#define SIN(x)
Definition: util.h:30
static texture_methods normal_methods
Definition: texture.c:26
#define VDOT(return, a, b)
Definition: macros.h:15
void FreeTextures(void)
Definition: texture.c:540
#define COS(x)
Definition: util.h:26
color MIPMap(const mipmap *mip, flt u, flt v, flt d)
Definition: imap.c:328
color image_sphere_texture(const vector *hit, const texture *tx, const ray *ry)
Definition: texture.c:187
color wood_texture(const vector *hit, const texture *tx, const ray *ry)
Definition: texture.c:370
void ResetImages(void)
Definition: imap.c:25
Tachyon cross-platform timers, special math function wrappers, and RNGs.
#define NMAX
Definition: texture.c:405
int Noise(flt x, flt y, flt z)
Definition: texture.c:432
color image_plane_texture(const vector *hit, const texture *tx, const ray *ry)
Definition: texture.c:219
short int NoiseMatrix[NMAX][NMAX][NMAX]
Definition: texture.c:406
#define SQRT(x)
Definition: util.h:31
static texture_methods vcstri_methods
Definition: texture.c:34
color checker_texture(const vector *hit, const texture *tx, const ray *ry)
Definition: texture.c:307
unsigned int tea4(unsigned int v0, unsigned int v1)
Definition: util.c:626
texture * new_texture(void)
Definition: texture.c:38
Tachyon public API function prototypes and declarations used to drive the ray tracing engine...
void xyztocyl(vector pnt, flt height, flt *u, flt *v)
Definition: coordsys.c:30
color image_cyl_texture(const vector *hit, const texture *tx, const ray *ry)
Definition: texture.c:155
#define FABS(x)
Definition: util.h:28
void xyztospr(vector pnt, flt *u, flt *v)
Definition: coordsys.c:42
color constant_texture(const vector *hit, const texture *tx, const ray *ry)
Definition: texture.c:149