1 /****************************************************************************
2 * normal.cpp
3 *
4 * This module implements solid texturing functions that perturb the surface
5 * normal to create a bumpy effect.
6 *
7 * from Persistence of Vision(tm) Ray Tracer version 3.6.
8 * Copyright 1991-2003 Persistence of Vision Team
9 * Copyright 2003-2004 Persistence of Vision Raytracer Pty. Ltd.
10 *---------------------------------------------------------------------------
11 * NOTICE: This source code file is provided so that users may experiment
12 * with enhancements to POV-Ray and to port the software to platforms other
13 * than those supported by the POV-Ray developers. There are strict rules
14 * regarding how you are permitted to use this file. These rules are contained
15 * in the distribution and derivative versions licenses which should have been
16 * provided with this file.
17 *
18 * These licences may be found online, linked from the end-user license
19 * agreement that is located at http://www.povray.org/povlegal.html
20 *---------------------------------------------------------------------------
21 * This program is based on the popular DKB raytracer version 2.12.
22 * DKBTrace was originally written by David K. Buck.
23 * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
24 *---------------------------------------------------------------------------
25 *
26 *===========================================================================
27 * This file is part of MegaPOV, a modified and unofficial version of POV-Ray
28 * For more information on MegaPOV visit our website:
29 * http://megapov.inetart.net/
30 *===========================================================================
31 *
32 * $RCSfile: normal.cpp,v $
33 * $Revision: 1.15 $
34 * $Author: chris $
35 *
36 *****************************************************************************/
37
38 /*
39 * Some texture ideas garnered from SIGGRAPH '85 Volume 19 Number 3,
40 * "An Image Synthesizer" By Ken Perlin.
41 *
42 * Further Ideas Garnered from "The RenderMan Companion" (Addison Wesley)
43 */
44
45 #include "frame.h"
46 #include "vector.h"
47 #include "texture.h"
48 #include "image.h"
49 #include "matrices.h"
50 #include "normal.h"
51 #include "objects.h"
52 #include "povray.h"
53 #include "txttest.h"
54 #include "pattern.h"
55 #include "pigment.h"
56
57 BEGIN_POV_NAMESPACE
58
59 /*****************************************************************************
60 * Local preprocessor defines
61 ******************************************************************************/
62
63
64
65 /*****************************************************************************
66 * Local typedefs
67 ******************************************************************************/
68
69
70
71 /*****************************************************************************
72 * Local constants
73 ******************************************************************************/
74
75 static const
76 VECTOR Pyramid_Vect [4]= {{ 0.942809041,-0.333333333, 0.0},
77 {-0.471404521,-0.333333333, 0.816496581},
78 {-0.471404521,-0.333333333,-0.816496581},
79 { 0.0 , 1.0 , 0.0}};
80
81
82 /*****************************************************************************
83 * Static functions
84 ******************************************************************************/
85
86 static void ripples (VECTOR EPoint, TNORMAL *Tnormal, VECTOR Vector);
87 static void waves (VECTOR EPoint, TNORMAL *Tnormal, VECTOR Vector);
88 static void bumps (VECTOR EPoint, TNORMAL *Tnormal, VECTOR normal);
89 static void dents (VECTOR EPoint, TNORMAL *Tnormal, VECTOR normal);
90 static void wrinkles (VECTOR EPoint, TNORMAL *Tnormal, VECTOR normal);
91 static void quilted (VECTOR EPoint, TNORMAL *Tnormal, VECTOR normal);
92 static DBL Hermite_Cubic (DBL T1,UV_VECT UV1,UV_VECT UV2);
93 static DBL Do_Slope_Map (DBL value, BLEND_MAP *Blend_Map);
94 static void Do_Average_Normals (VECTOR EPoint, TNORMAL *Tnormal, VECTOR normal, INTERSECTION *Inter);
95 static void facets (VECTOR EPoint, TNORMAL *Tnormal, VECTOR normal);
96
97
98 /*****************************************************************************
99 *
100 * FUNCTION
101 *
102 * ripples
103 *
104 * INPUT
105 *
106 * OUTPUT
107 *
108 * RETURNS
109 *
110 * AUTHOR
111 *
112 * POV-Ray Team
113 *
114 * DESCRIPTION
115 *
116 * CHANGES
117 *
118 ******************************************************************************/
119
ripples(VECTOR EPoint,TNORMAL * Tnormal,VECTOR normal)120 static void ripples (VECTOR EPoint, TNORMAL *Tnormal, VECTOR normal)
121 {
122 register unsigned int i;
123 register DBL length, scalar, index;
124 VECTOR point;
125
126 for (i = 0 ; i < Number_Of_Waves ; i++)
127 {
128 VSub (point, EPoint, Wave_Sources[i]);
129 VLength (length, point);
130
131 if (length == 0.0)
132 length = 1.0;
133
134 index = length * Tnormal->Frequency + Tnormal->Phase;
135
136 scalar = cycloidal(index) * Tnormal ->Amount;
137
138 VAddScaledEq(normal, scalar / (length * (DBL)Number_Of_Waves), point);
139 }
140 }
141
142
143
144 /*****************************************************************************
145 *
146 * FUNCTION
147 *
148 * waves
149 *
150 * INPUT
151 *
152 * OUTPUT
153 *
154 * RETURNS
155 *
156 * AUTHOR
157 *
158 * POV-Ray Team
159 *
160 * DESCRIPTION
161 *
162 * CHANGES
163 *
164 ******************************************************************************/
165
waves(VECTOR EPoint,TNORMAL * Tnormal,VECTOR normal)166 static void waves (VECTOR EPoint, TNORMAL *Tnormal, VECTOR normal)
167 {
168 register unsigned int i;
169 register DBL length, scalar, index, sinValue ;
170 VECTOR point;
171
172 for (i = 0 ; i < Number_Of_Waves ; i++)
173 {
174 VSub (point, EPoint, Wave_Sources[i]);
175
176 VLength (length, point);
177
178 if (length == 0.0)
179 {
180 length = 1.0;
181 }
182
183 index = length * Tnormal->Frequency * frequency[i] + Tnormal->Phase;
184
185 sinValue = cycloidal(index);
186
187 scalar = sinValue * Tnormal->Amount / frequency[i];
188
189 VAddScaledEq(normal, scalar / (length * (DBL)Number_Of_Waves), point);
190 }
191 }
192
193
194
195 /*****************************************************************************
196 *
197 * FUNCTION
198 *
199 * bumps
200 *
201 * INPUT
202 *
203 * OUTPUT
204 *
205 * RETURNS
206 *
207 * AUTHOR
208 *
209 * POV-Ray Team
210 *
211 * DESCRIPTION
212 *
213 * CHANGES
214 *
215 ******************************************************************************/
216
bumps(VECTOR EPoint,TNORMAL * Tnormal,VECTOR normal)217 static void bumps (VECTOR EPoint, TNORMAL *Tnormal, VECTOR normal)
218 {
219 VECTOR bump_turb;
220
221 /* Get normal displacement value. */
222
223 DNoise (bump_turb, EPoint);
224
225 /* Displace "normal". */
226
227 VAddScaledEq(normal, Tnormal->Amount, bump_turb);
228 }
229
230
231
232 /*****************************************************************************
233 *
234 * FUNCTION
235 *
236 * INPUT
237 *
238 * OUTPUT
239 *
240 * RETURNS
241 *
242 * AUTHOR
243 *
244 * POV-Ray Team
245 *
246 * DESCRIPTION
247 * Dents is similar to bumps, but uses noise() to control the amount of
248 * dnoise() perturbation of the object normal...
249 *
250 * CHANGES
251 *
252 ******************************************************************************/
253
dents(VECTOR EPoint,TNORMAL * Tnormal,VECTOR normal)254 static void dents (VECTOR EPoint, TNORMAL *Tnormal, VECTOR normal)
255 {
256 DBL noise;
257 VECTOR stucco_turb;
258
259 noise = Noise (EPoint, (TPATTERN*)Tnormal);
260
261 noise = noise * noise * noise * Tnormal->Amount;
262
263 /* Get normal displacement value. */
264
265 DNoise(stucco_turb, EPoint);
266
267 /* Displace "normal". */
268
269 VAddScaledEq(normal, noise, stucco_turb);
270 }
271
272
273
274
275 /*****************************************************************************
276 *
277 * FUNCTION
278 *
279 * INPUT
280 *
281 * OUTPUT
282 *
283 * RETURNS
284 *
285 * AUTHOR
286 *
287 * POV-Ray Team
288 *
289 * DESCRIPTION
290 *
291 * Wrinkles - This is my implementation of the dented() routine, using
292 * a surface iterative fractal derived from DTurbulence.
293 *
294 * This is a 3-D version (thanks to DNoise()...) of the usual version
295 * using the singular Noise()...
296 *
297 * Seems to look a lot like wrinkles, however... (hmmm)
298 *
299 * Idea garnered from the April 89 Byte Graphics Supplement on RenderMan,
300 * refined from "The RenderMan Companion, by Steve Upstill of Pixar,
301 * (C) 1990 Addison-Wesley.
302 *
303 * CHANGES
304 *
305 ******************************************************************************/
306
wrinkles(VECTOR EPoint,TNORMAL * Tnormal,VECTOR normal)307 static void wrinkles (VECTOR EPoint, TNORMAL *Tnormal, VECTOR normal)
308 {
309 register int i;
310 register DBL scale = 1.0;
311 VECTOR result, value, value2;
312
313 Make_Vector(result, 0.0, 0.0, 0.0);
314
315 for (i = 0; i < 10; scale *= 2.0, i++)
316 {
317 VScale(value2,EPoint,scale);
318 DNoise(value, value2);
319
320 result[X] += fabs(value[X] / scale);
321 result[Y] += fabs(value[Y] / scale);
322 result[Z] += fabs(value[Z] / scale);
323 }
324
325 /* Displace "normal". */
326
327 VAddScaledEq(normal, Tnormal->Amount, result);
328 }
329
330
331 /*****************************************************************************
332 *
333 * FUNCTION
334 *
335 * quilted
336 *
337 * INPUT
338 *
339 * OUTPUT
340 *
341 * RETURNS
342 *
343 * AUTHOR
344 *
345 * Dan Farmer '94
346 *
347 * DESCRIPTION
348 *
349 * CHANGES
350 *
351 ******************************************************************************/
352
quilted(VECTOR EPoint,TNORMAL * Tnormal,VECTOR normal)353 static void quilted (VECTOR EPoint, TNORMAL *Tnormal, VECTOR normal)
354 {
355 VECTOR value;
356 DBL t;
357
358 value[X] = EPoint[X]-FLOOR(EPoint[X])-0.5;
359 value[Y] = EPoint[Y]-FLOOR(EPoint[Y])-0.5;
360 value[Z] = EPoint[Z]-FLOOR(EPoint[Z])-0.5;
361
362 t = sqrt(value[X]*value[X]+value[Y]*value[Y]+value[Z]*value[Z]);
363
364 t = quilt_cubic(t, Tnormal->Vals.Quilted LESS_MEMORY_PATCH_MO Control0, Tnormal->Vals.Quilted LESS_MEMORY_PATCH_MO Control1);
365
366 value[X] *= t;
367 value[Y] *= t;
368 value[Z] *= t;
369
370 VAddScaledEq (normal, Tnormal->Amount,value);
371 }
372
373 /*****************************************************************************
374 *
375 * FUNCTION
376 *
377 * facets
378 *
379 * INPUT
380 *
381 * OUTPUT
382 *
383 * RETURNS
384 *
385 * AUTHOR
386 *
387 * Ronald Parker '98
388 *
389 * DESCRIPTION
390 *
391 * This pattern is based on the "Crackle" pattern and creates a faceted
392 * look on a curved surface.
393 *
394 * CHANGES
395 *
396 ******************************************************************************/
397
facets(VECTOR EPoint,TNORMAL * Tnormal,VECTOR normal)398 static void facets (VECTOR EPoint, TNORMAL *Tnormal, VECTOR normal)
399 {
400 int i;
401 int thisseed;
402 DBL sum, minsum;
403 VECTOR sv, tv, dv, t1, add, newnormal, pert;
404 DBL scale;
405 int UseSquare;
406 int UseUnity;
407 DBL Metric;
408
409 static int cvc;
410 static int lastseed = 0x80000000;
411 static VECTOR cv[81];
412
413 Metric = Tnormal->Vals.Facets LESS_MEMORY_PATCH_MO Metric[X];
414
415 UseSquare = (Metric == 2 );
416 UseUnity = (Metric == 1 );
417
418 VNormalize( normal, normal );
419
420 if ( Tnormal->Vals.Facets LESS_MEMORY_PATCH_MO UseCoords )
421 {
422 Assign_Vector(tv,EPoint);
423 }
424 else
425 {
426 Assign_Vector(tv,normal);
427 }
428
429 if ( Tnormal->Vals.Facets LESS_MEMORY_PATCH_MO Size < 1e-6 )
430 {
431 scale = 1e6;
432 }
433 else
434 {
435 scale = 1. / Tnormal->Vals.Facets LESS_MEMORY_PATCH_MO Size;
436 }
437
438 VScaleEq( tv, scale );
439
440 /*
441 * Check to see if the input point is in the same unit cube as the last
442 * call to this function, to use cache of cubelets for speed.
443 */
444
445 thisseed = PickInCube(tv, t1);
446
447 if (thisseed != lastseed)
448 {
449 /*
450 * No, not same unit cube. Calculate the random points for this new
451 * cube and its 80 neighbours which differ in any axis by 1 or 2.
452 * Why distance of 2? If there is 1 point in each cube, located
453 * randomly, it is possible for the closest random point to be in the
454 * cube 2 over, or the one two over and one up. It is NOT possible
455 * for it to be two over and two up. Picture a 3x3x3 cube with 9 more
456 * cubes glued onto each face.
457 */
458
459 /* Now store a points for this cube and each of the 80 neighbour cubes. */
460
461 cvc = 0;
462
463 for (add[X] = -2.0; add[X] < 2.5; add[X] +=1.0)
464 {
465 for (add[Y] = -2.0; add[Y] < 2.5; add[Y] += 1.0)
466 {
467 for (add[Z] = -2.0; add[Z] < 2.5; add[Z] += 1.0)
468 {
469 /* For each cubelet in a 5x5 cube. */
470
471 if ((fabs(add[X])>1.5)+(fabs(add[Y])>1.5)+(fabs(add[Z])>1.5) <= 1.0)
472 {
473 /* Yes, it's within a 3d knight move away. */
474
475 VAdd(sv, tv, add);
476
477 PickInCube(sv, t1);
478
479 cv[cvc][X] = t1[X];
480 cv[cvc][Y] = t1[Y];
481 cv[cvc][Z] = t1[Z];
482 cvc++;
483 }
484 }
485 }
486 }
487
488 lastseed = thisseed;
489 }
490
491 /*
492 * Find the point with the shortest distance from the input point.
493 */
494
495 VSub(dv, cv[0], tv);
496 if ( UseSquare )
497 {
498 minsum = VSumSqr(dv);
499 }
500 else
501 {
502 if ( UseUnity )
503 {
504 minsum = dv[X]+dv[Y]+dv[Z];
505 }
506 else
507 {
508 minsum = pow(fabs(dv[X]), Metric)+
509 pow(fabs(dv[Y]), Metric)+
510 pow(fabs(dv[Z]), Metric);
511 }
512 }
513
514 Assign_Vector( newnormal, cv[0] );
515
516 /* Loop for the 81 cubelets to find closest. */
517
518 for (i = 1; i < cvc; i++)
519 {
520 VSub(dv, cv[i], tv);
521
522 if ( UseSquare )
523 {
524 sum = VSumSqr(dv);
525 }
526 else
527 {
528 if ( UseUnity )
529 {
530 sum = dv[X]+dv[Y]+dv[Z];
531 }
532 else
533 {
534 sum = pow(fabs(dv[X]), Metric)+
535 pow(fabs(dv[Y]), Metric)+
536 pow(fabs(dv[Z]), Metric);
537 }
538 }
539
540 if (sum < minsum)
541 {
542 minsum = sum;
543 Assign_Vector( newnormal, cv[i] );
544 }
545 }
546
547 if ( Tnormal->Vals.Facets LESS_MEMORY_PATCH_MO UseCoords )
548 {
549 DNoise( pert, newnormal );
550 VDot( sum, pert, normal );
551 VScale( newnormal, normal, sum );
552 VSubEq( pert, newnormal );
553 VAddScaledEq( normal, Tnormal->Vals.Facets LESS_MEMORY_PATCH_MO UseCoords, pert );
554 }
555 else
556 {
557 Assign_Vector( normal, newnormal );
558 }
559
560 if(opts.Language_Version<=310)
561 VNormalize( normal, normal );
562 }
563
564 /*****************************************************************************
565 *
566 * FUNCTION
567 *
568 * Create_Tnormal
569 *
570 * INPUT
571 *
572 * OUTPUT
573 *
574 * RETURNS
575 *
576 * pointer to the created Tnormal
577 *
578 * AUTHOR
579 *
580 * POV-Ray Team
581 *
582 * DESCRIPTION : Allocate memory for new Tnormal and initialize it to
583 * system default values.
584 *
585 * CHANGES
586 *
587 ******************************************************************************/
588
589
Create_Tnormal()590 TNORMAL *Create_Tnormal ()
591 {
592 TNORMAL *New;
593
594 New = (TNORMAL *)POV_MALLOC(sizeof(TNORMAL), "normal");
595
596 Init_TPat_Fields((TPATTERN *)New);
597
598 New->Amount = 0.5;
599
600 /* NK delta */
601 New->Delta = (float)0.02; /* this is a good starting point for delta */
602
603 return (New);
604 }
605
606
607
608 /*****************************************************************************
609 *
610 * FUNCTION
611 *
612 * Copy_Tnormal
613 *
614 * INPUT
615 *
616 * OUTPUT
617 *
618 * RETURNS
619 *
620 * AUTHOR
621 *
622 * POV-Ray Team
623 *
624 * DESCRIPTION
625 *
626 * CHANGES
627 *
628 ******************************************************************************/
629
Copy_Tnormal(TNORMAL * Old)630 TNORMAL *Copy_Tnormal (TNORMAL *Old)
631 {
632 TNORMAL *New;
633
634 if (Old != NULL)
635 {
636 New = Create_Tnormal();
637
638 Copy_TPat_Fields ((TPATTERN *)New, (TPATTERN *)Old);
639
640 New->Amount = Old->Amount;
641 New->Delta = Old->Delta;
642 }
643 else
644 {
645 New = NULL;
646 }
647
648 return (New);
649 }
650
651
652
653 /*****************************************************************************
654 *
655 * FUNCTION
656 *
657 * Destroy_Tnormal
658 *
659 * INPUT
660 *
661 * OUTPUT
662 *
663 * RETURNS
664 *
665 * AUTHOR
666 *
667 * POV-Ray Team
668 *
669 * DESCRIPTION
670 *
671 * CHANGES
672 *
673 ******************************************************************************/
674
Destroy_Tnormal(TNORMAL * Tnormal)675 void Destroy_Tnormal(TNORMAL *Tnormal)
676 {
677 if (Tnormal != NULL)
678 {
679 Destroy_TPat_Fields ((TPATTERN *)Tnormal);
680
681 POV_FREE(Tnormal);
682 }
683 }
684
685
686
687 /*****************************************************************************
688 *
689 * FUNCTION
690 *
691 * Post_Tnormal
692 *
693 * INPUT
694 *
695 * OUTPUT
696 *
697 * RETURNS
698 *
699 * AUTHOR
700 *
701 * POV-Ray Team
702 *
703 * DESCRIPTION
704 *
705 * CHANGES
706 *
707 ******************************************************************************/
708
Post_Tnormal(TNORMAL * Tnormal)709 void Post_Tnormal (TNORMAL *Tnormal)
710 {
711 int i;
712 BLEND_MAP *Map;
713
714 if (Tnormal != NULL)
715 {
716 if (Tnormal->Flags & POST_DONE)
717 {
718 return;
719 }
720
721 if (Tnormal->Type == NO_PATTERN)
722 {
723 Error("No normal type given.");
724 }
725
726 Tnormal->Flags |= POST_DONE;
727
728 if ((Map = Tnormal->Blend_Map) != NULL)
729 {
730 for (i = 0; i < Map->Number_Of_Entries; i++)
731 {
732 switch (Map->Type)
733 {
734 case PIGMENT_TYPE:
735
736 Post_Pigment(Map->Blend_Map_Entries[i].Vals.Pigment);
737
738 break;
739
740 case NORMAL_TYPE:
741 Map->Blend_Map_Entries[i].Vals.Tnormal->Flags |=
742 (Tnormal->Flags & DONT_SCALE_BUMPS_FLAG);
743
744 Post_Tnormal(Map->Blend_Map_Entries[i].Vals.Tnormal);
745
746 break;
747
748 case TEXTURE_TYPE:
749
750 Post_Textures(Map->Blend_Map_Entries[i].Vals.Texture);
751
752 break;
753
754 case SLOPE_TYPE:
755 case COLOUR_TYPE:
756 case PATTERN_TYPE:
757
758 break;
759
760 default:
761
762 Error("Unknown pattern type in Post_Tnormal.");
763 }
764 }
765 }
766 }
767 }
768
769
770
771 /*****************************************************************************
772 *
773 * FUNCTION
774 *
775 * Perturb_Normal
776 *
777 * INPUT
778 *
779 * OUTPUT
780 *
781 * RETURNS
782 *
783 * AUTHOR
784 *
785 * POV-Ray Team
786 *
787 * DESCRIPTION
788 *
789 * CHANGES
790 * Added intersectin parameter for UV mapping - NK 1998
791 *
792 ******************************************************************************/
793
Perturb_Normal(VECTOR Layer_Normal,TNORMAL * Tnormal,VECTOR EPoint,INTERSECTION * Intersection)794 void Perturb_Normal(VECTOR Layer_Normal, TNORMAL *Tnormal, VECTOR EPoint,INTERSECTION *Intersection)
795 {
796 VECTOR TPoint,P1;
797 DBL value1,value2,Amount;
798 int i;
799 BLEND_MAP *Blend_Map;
800 BLEND_MAP_ENTRY *Prev, *Cur;
801
802 if (Tnormal==NULL)
803 {
804 return;
805 }
806
807 /* If normal_map present, use it and return */
808
809 if ((Blend_Map=Tnormal->Blend_Map) != NULL)
810 {
811 if ((Blend_Map->Type == NORMAL_TYPE) && (Tnormal->Type == UV_MAP_PATTERN))
812 {
813 UV_VECT UV_Coords;
814
815 Cur = &(Tnormal->Blend_Map->Blend_Map_Entries[0]);
816
817 /* Don't bother warping, simply get the UV vect of the intersection */
818 UVCoord(UV_Coords, Intersection->Object, Intersection);
819 TPoint[X] = UV_Coords[U];
820 TPoint[Y] = UV_Coords[V];
821 TPoint[Z] = 0;
822
823 Perturb_Normal(Layer_Normal,Cur->Vals.Tnormal,TPoint,Intersection);
824 VNormalizeEq(Layer_Normal);
825 Assign_Vector(Intersection->PNormal, Layer_Normal); /* -hdf- June 98 */
826
827 return;
828 }
829 else if ((Blend_Map->Type == NORMAL_TYPE) && (Tnormal->Type != AVERAGE_PATTERN))
830 {
831 /* NK 19 Nov 1999 added Warp_EPoint */
832 Warp_EPoint (TPoint, EPoint, (TPATTERN *)Tnormal);
833 value1 = Evaluate_TPat((TPATTERN *)Tnormal,TPoint,Intersection);
834
835 Search_Blend_Map (value1,Blend_Map,&Prev,&Cur);
836
837 if(opts.Language_Version>310)
838 Warp_Normal(Layer_Normal,Layer_Normal, (TPATTERN *)Tnormal, Test_Flag(Tnormal,DONT_SCALE_BUMPS_FLAG));
839 Assign_Vector(P1,Layer_Normal);
840
841 Warp_EPoint (TPoint, EPoint, (TPATTERN *)Tnormal);
842
843 Perturb_Normal(Layer_Normal,Cur->Vals.Tnormal,TPoint,Intersection);
844
845 if (Prev != Cur)
846 {
847 Perturb_Normal(P1,Prev->Vals.Tnormal,TPoint,Intersection);
848
849 value2 = (value1-Prev->value)/(Cur->value-Prev->value);
850 value1 = 1.0-value2;
851
852 VLinComb2(Layer_Normal,value1,P1,value2,Layer_Normal);
853 }
854
855 if(opts.Language_Version>310)
856 UnWarp_Normal(Layer_Normal,Layer_Normal,(TPATTERN *)Tnormal, Test_Flag(Tnormal,DONT_SCALE_BUMPS_FLAG));
857
858 VNormalizeEq(Layer_Normal);
859
860 Assign_Vector(Intersection->PNormal, Layer_Normal); /* -hdf- June 98 */
861
862 return;
863 }
864 }
865
866 /* No normal_map. */
867
868 if (Tnormal->Type <= LAST_NORM_ONLY_PATTERN)
869 {
870 if(opts.Language_Version>310)
871 {
872 Warp_Normal(Layer_Normal,Layer_Normal, (TPATTERN *)Tnormal,
873 Test_Flag(Tnormal,DONT_SCALE_BUMPS_FLAG));
874 }
875 Warp_EPoint (TPoint, EPoint, (TPATTERN *)Tnormal);
876
877 switch (Tnormal->Type)
878 {
879 case BITMAP_PATTERN: bump_map (TPoint, Tnormal, Layer_Normal); break;
880 case BUMPS_PATTERN: bumps (TPoint, Tnormal, Layer_Normal); break;
881 case DENTS_PATTERN: dents (TPoint, Tnormal, Layer_Normal); break;
882 case RIPPLES_PATTERN:ripples (TPoint, Tnormal, Layer_Normal); break;
883 case WAVES_PATTERN: waves (TPoint, Tnormal, Layer_Normal); break;
884 case WRINKLES_PATTERN:wrinkles (TPoint, Tnormal, Layer_Normal);break;
885 case QUILTED_PATTERN:quilted (TPoint, Tnormal, Layer_Normal); break;
886 case FACETS_PATTERN: facets( TPoint, Tnormal, Layer_Normal); break;
887 case AVERAGE_PATTERN: Do_Average_Normals (TPoint, Tnormal, Layer_Normal, Intersection); break;
888 default:
889 Error("Normal pattern not yet implemented.");
890 }
891
892 if(opts.Language_Version>310)
893 {
894 UnWarp_Normal(Layer_Normal,Layer_Normal, (TPATTERN *)Tnormal,
895 Test_Flag(Tnormal,DONT_SCALE_BUMPS_FLAG));
896 }
897 }
898 else
899 {
900 if(opts.Language_Version>310)
901 {
902 Warp_Normal(Layer_Normal,Layer_Normal, (TPATTERN *)Tnormal,
903 Test_Flag(Tnormal,DONT_SCALE_BUMPS_FLAG));
904 }
905
906 Amount=Tnormal->Amount * -5.0; /*fudge factor*/
907 Amount*=0.02/Tnormal->Delta; /* NK delta */
908
909 /* warp the center point first - this is the last warp */
910 if(opts.Language_Version>310)
911 Warp_EPoint(TPoint,EPoint,(TPATTERN *)Tnormal);
912 else
913 Assign_Vector(TPoint,EPoint);
914
915 for(i=0; i<=3; i++)
916 {
917 VAddScaled(P1,TPoint,Tnormal->Delta,Pyramid_Vect[i]); /* NK delta */
918 if(opts.Language_Version<=310)
919 Warp_EPoint(P1,P1,(TPATTERN *)Tnormal);
920 value1 = Do_Slope_Map(Evaluate_TPat((TPATTERN *)Tnormal,P1,Intersection),Blend_Map);
921 VAddScaledEq(Layer_Normal,value1*Amount,Pyramid_Vect[i]);
922 }
923
924 if(opts.Language_Version>310)
925 {
926 UnWarp_Normal(Layer_Normal,Layer_Normal,(TPATTERN *)Tnormal,
927 Test_Flag(Tnormal,DONT_SCALE_BUMPS_FLAG));
928 }
929
930 }
931
932 if(opts.Language_Version<=310)
933 VNormalizeEq(Layer_Normal);
934
935 if ( Intersection )
936 Assign_Vector(Intersection->PNormal, Layer_Normal); /* -hdf- June 98 */
937 }
938
939
940
941 /*****************************************************************************
942 *
943 * FUNCTION
944 *
945 * INPUT
946 *
947 * OUTPUT
948 *
949 * RETURNS
950 *
951 * AUTHOR
952 *
953 * DESCRIPTION
954 *
955 * CHANGES
956 *
957 ******************************************************************************/
958
Do_Slope_Map(DBL value,BLEND_MAP * Blend_Map)959 static DBL Do_Slope_Map (DBL value,BLEND_MAP *Blend_Map)
960 {
961 DBL Result;
962 BLEND_MAP_ENTRY *Prev, *Cur;
963
964 if (Blend_Map == NULL)
965 {
966 return(value);
967 }
968
969 Search_Blend_Map (value,Blend_Map,&Prev,&Cur);
970
971 if (Prev == Cur)
972 {
973 return(Cur->Vals.Point_Slope[0]);
974 }
975
976 Result = (value-Prev->value)/(Cur->value-Prev->value);
977
978 return(Hermite_Cubic(Result,Prev->Vals.Point_Slope,Cur->Vals.Point_Slope));
979 }
980
981
982
983 /*****************************************************************************
984 *
985 * FUNCTION
986 *
987 * INPUT
988 *
989 * OUTPUT
990 *
991 * RETURNS
992 *
993 * AUTHOR
994 *
995 * DESCRIPTION
996 *
997 * CHANGES
998 *
999 ******************************************************************************/
1000
1001 #define S1 UV1[1]
1002 #define S2 UV2[1]
1003 #define P1 UV1[0]
1004 #define P2 UV2[0]
1005
Hermite_Cubic(DBL T1,UV_VECT UV1,UV_VECT UV2)1006 static DBL Hermite_Cubic(DBL T1,UV_VECT UV1,UV_VECT UV2)
1007 {
1008 DBL TT=T1*T1;
1009 DBL TTT=TT*T1;
1010 DBL rv; /* simplified equation for poor Symantec */
1011
1012 rv = TTT*(S1+S2+2.0*(P1-P2));
1013 rv += -TT*(2.0*S1+S2+3.0*(P1-P2));
1014 rv += T1*S1 +P1;
1015
1016 return (rv);
1017 }
1018
1019
1020
1021 /*****************************************************************************
1022 *
1023 * FUNCTION
1024 *
1025 * INPUT
1026 *
1027 * OUTPUT
1028 *
1029 * RETURNS
1030 *
1031 * AUTHOR
1032 *
1033 * DESCRIPTION
1034 *
1035 * CHANGES
1036 * Added intersectin parameter for UV mapping - NK 1998
1037 *
1038 ******************************************************************************/
1039
Do_Average_Normals(VECTOR EPoint,TNORMAL * Tnormal,VECTOR normal,INTERSECTION * Inter)1040 static void Do_Average_Normals (VECTOR EPoint,TNORMAL *Tnormal,VECTOR normal, INTERSECTION *Inter)
1041 {
1042 int i;
1043 BLEND_MAP *Map = Tnormal->Blend_Map;
1044 SNGL Value;
1045 SNGL Total = 0.0;
1046 VECTOR V1,V2;
1047
1048 Make_Vector (V1, 0.0, 0.0, 0.0);
1049
1050 for (i = 0; i < Map->Number_Of_Entries; i++)
1051 {
1052 Value = Map->Blend_Map_Entries[i].value;
1053
1054 Assign_Vector(V2,normal);
1055
1056 Perturb_Normal(V2,Map->Blend_Map_Entries[i].Vals.Tnormal,EPoint, Inter);
1057
1058 VAddScaledEq(V1,Value,V2);
1059
1060 Total += Value;
1061 }
1062
1063 VInverseScale(normal,V1,Total);
1064 }
1065
1066 END_POV_NAMESPACE
1067