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