1// Persistence of Vision Ray Tracer version 3.5 Include File 2// File: shapes.inc 3// Last updated: 2001.8.13 4// Description: This file contains macros for working with objects, as well 5// as macros for creating special objects, such as bevelled text, 6// height fields, and rounded shapes. 7 8#ifndef(SHAPES_INC_TEMP) 9#declare SHAPES_INC_TEMP = version; 10#version 3.5; 11 12#ifdef(View_POV_Include_Stack) 13 #debug "including shapes.inc\n" 14#end 15 16#include "shapes_old.inc" 17#include "consts.inc" 18#include "transforms.inc" 19#include "strings.inc" 20#include "math.inc" 21 22// These macros are just interfaces to the trace() function. 23// They return values through their parameters: 24// If an intersection is found, they return true and set 25// OPt to the intersection point, and ONorm to the normal. 26// Otherwise they return false, and do not modify OPt or ONorm. 27#macro Isect(Pt, Dir, Obj, OPt) 28 #local Norm = <0,0,0>; 29 #local IPt = trace(Obj, Pt, Dir, Norm); 30 #if (vlength(Norm) > 0) 31 #declare OPt = IPt; 32 #local Return=true; 33 #else 34 #local Return=false; 35 #end 36 (Return) 37#end 38#macro IsectN(Pt, Dir, Obj, OPt, ONorm) 39 #local Norm = <0,0,0>; 40 #local IPt = trace(Obj, Pt, Dir, Norm); 41 #if (vlength(Norm) > 0) 42 #declare OPt = IPt; 43 #declare ONorm = Norm; 44 #local Return=true; 45 #else 46 #local Return=false; 47 #end 48 (Return) 49#end 50 51 52// A shortcut for getting both min and max extents of an object 53#macro Extents(Obj, Min, Max) 54 #declare Min = min_extent(Obj); 55 #declare Max = max_extent(Obj); 56#end 57 58 59// shortcuts for using the CenterTrans and AlignTrans 60// macros with objects. 61#macro Center_Object(Object, Axis) 62 object {Object Center_Trans(Object, Axis)} 63#end 64 65#macro Align_Object(Object, Axis, Pt) 66 object {Object Align_Trans(Object, Axis, Pt)} 67#end 68 69 70// A simple beveled text macro. The parameters are: 71// Font: the name of the font file. 72// String: the text string the text object is composed of. 73// Cuts: the number of times excess material is cut off, to form the bevel. 74// More cuts will give smoother results, but take longer to render. 75// BevelAng: the angle of the bevel. 76// BevelDepth: the depth of the bevelled portion of the text. 77// Depth: the total depth of the text object. 78// Offset: the offset value for the text object. Since the front faces of each 79// letter need to be in the same plane, z values are ignored. 80#macro Bevelled_Text(Font, String, Cuts, BevelAng, BevelDepth, Depth, Offset, UseMerge) 81 #local BBox = text {ttf Font, String Depth, Offset*(x+y)} 82 #if(UseMerge) 83 merge { 84 #else 85 union { 86 #end 87 text {ttf Font, String Depth-BevelDepth, Offset*(x+y)} 88 intersection { 89 #local J=0; 90 #while(J<Cuts) 91 #local A = 2*pi*J/(Cuts); 92 #local CA = cos(radians(BevelAng)); 93 #local SA = sin(radians(BevelAng)); 94 text {ttf Font, String BevelDepth, Offset*(x+y) 95 translate -z*(BevelDepth+J*0.0001) 96 Shear_Trans(x, y, < cos(A)*SA, sin(A)*SA, CA>/CA) 97 } 98 #local J=J+1; 99 #end 100 } 101 translate z*BevelDepth 102 bounded_by {box {min_extent(BBox), max_extent(BBox)}} 103 } 104#end 105 106 107// Constants used for the text macros 108#declare Align_Left = 1; 109#declare Align_Right = 2; 110#declare Align_Center = 3; 111 112/* Text_Space( Font, String, Size, Spacing ) 113Computes the width of a text string, including "white space". It 114returns the advance widths of all n letters. Text_Space gives the 115space a text or a glyph occupies in regard to its surroundings. 116 117Font: The font to use (see the documentation for the text object) 118String: The text for which we want to know the width 119Size: The size to which the text should be scaled 120Spacing: The amount of space to add between the letters. */ 121 122#macro Text_Space(Font, String, Size, Spacing) 123 #local TO = text {ttf Font concat("|",String,"|") 1 Spacing*x scale <Size,Size,1>} 124 #local SO = text {ttf Font "||" 1 Spacing*x scale <Size,Size,1>} 125 ((max_extent(TO).x-min_extent(TO).x)-(max_extent(SO).x-min_extent(SO).x)) 126#end 127 128/* Text_Width( Font, String, Size, Spacing ) 129Computes the width of a text string. It returns the advance widths 130of the first n-1 letters, plus the glyph width of the last letter. 131Text_Width gives the "fysical" width of the text and if you use 132only one letter the "fysical" width of one glyph. 133 134Font: The font to use (see the documentation for the text object) 135String: The text for which we want to know the width 136Size: The size to which the text should be scaled 137Spacing: The amount of space to add between the letters. */ 138 139#macro Text_Width(Font, String, Size, Spacing) 140 #local TO = text {ttf Font String 1 Spacing*x scale <Size,Size,1>} 141 (max_extent(TO).x-min_extent(TO).x) 142#end 143 144// Circle_Text author: Ron Parker 145/* Circle_Text( Font, Text, Size, Spacing, Thickness, Radius, Inverted, 146 Justification, Angle ) 147Creates a text object with the bottom (or top) of the character cells aligned 148with all or part of a circle. This macro should be used inside an object{...} 149block. 150 151 Font: The font to use (see the documentation for the text object) 152 Text: The text string to be created 153 Size: The height of the text string, as you would use to scale a 154 standard text object 155 Spacing: The amount of space to add between the letters. 156 Thickness: The thickness of the letters (see the documentation for the 157 text object) 158 Radius: The radius of the circle along which the letters are aligned 159 Inverted: If this parameter is nonzero, the tops of the letters will 160 point toward the center of the circle. Otherwise, the bottoms 161 of the letters will do so. 162Justification: One of the constants Align_Left, Align_Right, or Align_Center 163 Angle: The point on the circle from which rendering will begin. The 164 +x direction is 0 and the +y direction is 90 (i.e. the angle 165 increases anti-clockwise. */ 166 167#macro Circle_Text(F, T, S, Sp, Th, R, I, J, A) 168 #local FW = Text_Width(F, T, S, Sp); 169 #local TO = text {ttf F T 1 0 scale<S, S, 1>} 170 #local TH = max_extent(TO).y; 171 #local C = array[strlen(T)] 172 #if(FW > 2*pi*R) 173 #error concat("\n\n**** Text string \"", T, "\" is too long for a circle of the specified radius.\n\n\n") 174 #end 175 #local AW = -FW*180/pi/R; 176 #local SA = A; 177 #local EA = A + AW; 178 #if(((J = Align_Right) & !I)|((J = Align_Left) & I)) 179 #local SA = A - AW; 180 #local EA = A; 181 #else 182 #if(J = Align_Center) 183 #local SA = A - AW/2; 184 #local EA = A + AW/2; 185 #end 186 #end 187 188 #local CI = 1; 189 #while(CI <= strlen(T)) 190 #local OE = Text_Width(F, substr(T,CI,1), S, Sp); 191 #local LW = Text_Width(F, substr(T,1,CI), S, Sp) - OE; 192 #local LA = SA + AW*LW/FW + OE/2/FW*AW; 193 #if(I) 194 #local LA = EA - (LA - SA); 195 #end 196 #local TO = text {ttf F substr(T, CI, 1) Th 0 scale<S,S,1>} 197 #if(I) 198 #local C[CI-1] = 199 object {TO 200 rotate 180*z 201 translate <OE/2, TH, 0> 202 rotate -90*z 203 translate R*x 204 rotate LA*z 205 } 206 #else 207 #local C[CI-1] = 208 object {TO 209 translate -OE/2*x 210 rotate -90*z 211 translate R*x 212 rotate LA*z 213 } 214 #end 215 #local CI = CI + 1; 216 #end 217 218 // Create the final object, a union of individual text object letters. 219 union { 220 #local CI=0; 221 #while(CI < strlen(T)) 222 object {C[CI]} 223 #local CI = CI + 1; 224 #end 225 } 226#end 227 228 229#macro Wedge(Angle) 230 #local A = clamp(Angle, 0, 360); 231 #if(A < 180) 232 difference { 233 plane {-x, 0} 234 plane {-x, 0 rotate y*A} 235 } 236 #else 237 #if(A = 180) 238 plane {-x, 0} 239 #else 240 intersection { 241 plane {x, 0} 242 plane {-x, 0 rotate y*A} 243 inverse 244 } 245 #end 246 #end 247#end 248 249 250#macro Spheroid(Center, Radius) 251 sphere { 0, 1 scale Radius translate Center } 252#end 253 254 255#macro Supertorus(RMj, RMn, MajorControl, MinorControl, Accuracy, MaxGradient) 256 #local CP = 2/MinorControl; 257 #local RP = 2/MajorControl; 258 isosurface { 259 function { pow( pow(abs(pow(pow(abs(x),RP) + pow(abs(z),RP), 1/RP) - RMj),CP) + pow(abs(y),CP) ,1/CP) - RMn } 260 threshold 0 261 contained_by {box {<-RMj-RMn,-RMn,-RMj-RMn>, < RMj+RMn, RMn, RMj+RMn>}} 262 #if(MaxGradient >= 1) 263 max_gradient MaxGradient 264 #else 265 evaluate 1, 10, 0.1 266 #end 267 accuracy Accuracy 268 } 269#end 270 271 272// Supercone author: Juha Nieminen 273// A cone object where each end is an ellipse, you specify two radii 274// for each end. 275// SuperCone function: (x^2/a^2+y^2/b^2-1)*(1-z) + (x^2/c^2+y^2/d^2-1)*z = 0 276// 277// camera { location <6,5,-10> look_at 0 angle 35 } 278// light_source { <100,100,-20>,1 } 279// plane { y,-1.5 pigment { checker rgb 1, rgb .5 } } 280// object { SuperCone(<0,-1.5,0>,1,2, <0,1.5,0>,1,.5) 281// pigment { rgb x } finish { specular .5 } 282// } 283#macro Supercone(PtA, A, B, PtB, C, D) 284 intersection { 285 quartic { 286 <0, 0, 0, 0, 0, 0, 0, B*B-2*B*D+D*D, 2*(B*D-B*B), B*B, 287 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 288 0, 0, 0, A*A-2*A*C+C*C, 2*(A*C-A*A), A*A, 0, 0, 0, 0, 289 -(A*A-2*A*C+C*C)*(B*B-2*B*D+D*D), 290 -(2*((B*D-B*B)*(A*A-2*A*C+C*C)+(A*C-A*A)*(B*B-2*B*D+D*D))), 291 -(B*B*(A*A-2*A*C+C*C)+4*(A*C-A*A)*(B*D-B*B)+A*A*(B*B-2*B*D+D*D)), 292 -(2*(B*B*(A*C-A*A)+A*A*(B*D-B*B))), -A*A*B*B> 293 sturm 294 } 295 cylinder {0, z, max(max(abs(A), abs(B)), max(abs(C), abs(D)))} 296 297 bounded_by {cone {0, max(abs(A), abs(B)), z, max(abs(C), abs(D))}} 298 299 #local Dirv = PtB - PtA; 300 scale <1,1,vlength(Dirv)> 301 #local Dirv = vnormalize(Dirv); 302 #if(vlength(Dirv-<0,0,-1>)=0) scale <1,1,-1> 303 #else Reorient_Trans(z, Dirv) 304 #end 305 translate PtA 306 } 307#end 308 309 310// Connect two spheres with a cylinder. 311// Derived from Connect() macro by John VanSickle 312#macro Connect_Spheres(PtA, RadiusA, PtB, RadiusB) 313 #local Axis = PtB - PtA; 314 #local RadDif = RadiusA - RadiusB; 315 #local Len = VDist(PtA, PtB); 316 #local D2 = sqrt(f_sqr(Len) - f_sqr(RadDif)); 317 318 cone { 319 PtA + Axis/Len*RadDif*RadiusA/Len, RadiusA*D2/Len, 320 PtB + Axis/Len*RadDif*RadiusB/Len, RadiusB*D2/Len 321 } 322#end 323 324 325#macro Wire_Box_Union(A, B, WireRadius) 326 Wire_Box(A, B, WireRadius, no) 327#end 328#macro Wire_Box_Merge(A, B, WireRadius) 329 Wire_Box(A, B, WireRadius, yes) 330#end 331#macro Wire_Box(A, B, WireRadius, UseMerge) 332 #local AA = <min(A.x, B.x), min(A.y, B.y), min(A.z, B.z)>; 333 #local BB = <max(A.x, B.x), max(A.y, B.y), max(A.z, B.z)>; 334 335 #local Delta=abs(BB.x-AA.x)/2; 336 #if (Delta<WireRadius) 337 #warning "\nWire_Box() macro called with x-size < Radius,\nresults may not be as expected\n" 338 339 #local AA = <AA.x+Delta, AA.y, AA.z>; 340 #local BB = <BB.x-Delta, BB.y, BB.z>; 341 #else 342 #local AA = <AA.x+WireRadius, AA.y, AA.z>; 343 #local BB = <BB.x-WireRadius, BB.y, BB.z>; 344 #end 345 346 #local Delta=abs(BB.y-AA.y)/2; 347 #if (Delta<WireRadius) 348 #warning "\nWire_Box() macro called with y-size < Radius,\nresults may not be as expected\n" 349 350 #local AA = <AA.x, AA.y+Delta, AA.z>; 351 #local BB = <BB.x, BB.y-Delta, BB.z>; 352 #else 353 #local AA = <AA.x, AA.y+WireRadius, AA.z>; 354 #local BB = <BB.x, BB.y-WireRadius, BB.z>; 355 #end 356 357 #local Delta=abs(BB.z-AA.z)/2; 358 #if (Delta<WireRadius) 359 #warning "\nWire_Box() macro called with z-size < Radius,\nresults may not be as expected\n" 360 361 #local AA = <AA.x, AA.y, AA.z+Delta>; 362 #local BB = <BB.x, BB.y, BB.z-Delta>; 363 #else 364 #local AA = <AA.x, AA.y, AA.z+WireRadius>; 365 #local BB = <BB.x, BB.y, BB.z-WireRadius>; 366 #end 367 368 #local LBF = AA; 369 #local RBF = < BB.x, AA.y, AA.z>; 370 #local RBB = < BB.x, AA.y, BB.z>; 371 #local LBB = < AA.x, AA.y, BB.z>; 372 #local LTF = < AA.x, BB.y, AA.z>; 373 #local RTF = < BB.x, BB.y, AA.z>; 374 #local RTB = BB; 375 #local LTB = < AA.x, BB.y, BB.z>; 376 377 #if(UseMerge) 378 merge { 379 #else 380 union { 381 #end 382 sphere {LBF, WireRadius} 383 384 #if (AA.x != BB.x) 385 sphere {RBF, WireRadius} 386 #end 387 #if ((AA.x != BB.x) & (AA.z != BB.z)) 388 sphere {RBB, WireRadius} 389 #end 390 #if (AA.z != BB.z) 391 sphere {LBB, WireRadius} 392 #end 393 394 #if (AA.y != BB.y) 395 sphere {LTF, WireRadius} 396 #end 397 #if ((AA.x != BB.x) & (AA.y != BB.y)) 398 sphere {RTF, WireRadius} 399 #end 400 #if ((AA.x != BB.x) & (AA.y != BB.y) & (AA.z != BB.z)) 401 sphere {RTB, WireRadius} 402 #end 403 #if ((AA.y != BB.y) & (AA.z != BB.z)) 404 sphere {LTB, WireRadius} 405 #end 406 407 #if (AA.x != BB.x) 408 cylinder {LBF, RBF, WireRadius} 409 cylinder {LBB, RBB, WireRadius} 410 cylinder {LTB, RTB, WireRadius} 411 cylinder {LTF, RTF, WireRadius} 412 #end 413 414 #if (AA.y != BB.y) 415 cylinder {LBF, LTF, WireRadius} 416 cylinder {RBF, RTF, WireRadius} 417 cylinder {RBB, RTB, WireRadius} 418 cylinder {LBB, LTB, WireRadius} 419 #end 420 421 #if (AA.z != BB.z) 422 cylinder {LTB, LTF, WireRadius} 423 cylinder {LBB, LBF, WireRadius} 424 cylinder {RTB, RTF, WireRadius} 425 cylinder {RBB, RBF, WireRadius} 426 #end 427 } 428#end 429 430#macro Round_Box_Union(A, B, EdgeRadius) 431 Round_Box(A, B, EdgeRadius, no) 432#end 433#macro Round_Box_Merge(A, B, EdgeRadius) 434 Round_Box(A, B, EdgeRadius, yes) 435#end 436#macro Round_Box(A, B, EdgeRadius, UseMerge) 437 #local AA = <min(A.x, B.x), min(A.y, B.y), min(A.z, B.z)>; 438 #local BB = <max(A.x, B.x), max(A.y, B.y), max(A.z, B.z)>; 439 440 #local Delta=abs(BB.x-AA.x)/2; 441 #if (Delta<EdgeRadius) 442 #warning "\nRound_Box() macro called with x-size < Radius,\nresults may not be as expected\n" 443 444 #local AA = <AA.x+Delta, AA.y, AA.z>; 445 #local BB = <BB.x-Delta, BB.y, BB.z>; 446 #else 447 #local AA = <AA.x+EdgeRadius, AA.y, AA.z>; 448 #local BB = <BB.x-EdgeRadius, BB.y, BB.z>; 449 #end 450 451 #local Delta=abs(BB.y-AA.y)/2; 452 #if (Delta<EdgeRadius) 453 #warning "\nRound_Box() macro called with y-size < Radius,\nresults may not be as expected\n" 454 455 #local AA = <AA.x, AA.y+Delta, AA.z>; 456 #local BB = <BB.x, BB.y-Delta, BB.z>; 457 #else 458 #local AA = <AA.x, AA.y+EdgeRadius, AA.z>; 459 #local BB = <BB.x, BB.y-EdgeRadius, BB.z>; 460 #end 461 462 #local Delta=abs(BB.z-AA.z)/2; 463 #if (Delta<EdgeRadius) 464 #warning "\nRound_Box() macro called with z-size < Radius,\nresults may not be as expected\n" 465 466 #local AA = <AA.x, AA.y, AA.z+Delta>; 467 #local BB = <BB.x, BB.y, BB.z-Delta>; 468 #else 469 #local AA = <AA.x, AA.y, AA.z+EdgeRadius>; 470 #local BB = <BB.x, BB.y, BB.z-EdgeRadius>; 471 #end 472 473 #local LBF = AA; 474 #local RBF = < BB.x, AA.y, AA.z>; 475 #local RBB = < BB.x, AA.y, BB.z>; 476 #local LBB = < AA.x, AA.y, BB.z>; 477 #local LTF = < AA.x, BB.y, AA.z>; 478 #local RTF = < BB.x, BB.y, AA.z>; 479 #local RTB = BB; 480 #local LTB = < AA.x, BB.y, BB.z>; 481 482 #if(UseMerge) 483 merge { 484 #else 485 union { 486 #end 487 sphere {LBF, EdgeRadius} 488 489 #if (AA.x != BB.x) 490 sphere {RBF, EdgeRadius} 491 #end 492 #if ((AA.x != BB.x) & (AA.z != BB.z)) 493 sphere {RBB, EdgeRadius} 494 #end 495 #if (AA.z != BB.z) 496 sphere {LBB, EdgeRadius} 497 #end 498 499 #if (AA.y != BB.y) 500 sphere {LTF, EdgeRadius} 501 #end 502 #if ((AA.x != BB.x) & (AA.y != BB.y)) 503 sphere {RTF, EdgeRadius} 504 #end 505 #if ((AA.x != BB.x) & (AA.y != BB.y) & (AA.z != BB.z)) 506 sphere {RTB, EdgeRadius} 507 #end 508 #if ((AA.y != BB.y) & (AA.z != BB.z)) 509 sphere {LTB, EdgeRadius} 510 #end 511 512 #if (AA.x != BB.x) 513 cylinder {LBF, RBF, EdgeRadius} 514 cylinder {LBB, RBB, EdgeRadius} 515 cylinder {LTB, RTB, EdgeRadius} 516 cylinder {LTF, RTF, EdgeRadius} 517 #end 518 519 #if (AA.y != BB.y) 520 cylinder {LBF, LTF, EdgeRadius} 521 cylinder {RBF, RTF, EdgeRadius} 522 cylinder {RBB, RTB, EdgeRadius} 523 cylinder {LBB, LTB, EdgeRadius} 524 #end 525 526 #if (AA.z != BB.z) 527 cylinder {LTB, LTF, EdgeRadius} 528 cylinder {LBB, LBF, EdgeRadius} 529 cylinder {RTB, RTF, EdgeRadius} 530 cylinder {RBB, RBF, EdgeRadius} 531 #end 532 533 box {AA-EdgeRadius*x, BB+EdgeRadius*x} 534 box {AA-EdgeRadius*y, BB+EdgeRadius*y} 535 box {AA-EdgeRadius*z, BB+EdgeRadius*z} 536 } 537#end 538 539#macro Round_Cylinder_Union(A, B, Radius, EdgeRadius) 540 Round_Cylinder(A, B, Radius, EdgeRadius, no) 541#end 542#macro Round_Cylinder_Merge(A, B, Radius, EdgeRadius) 543 Round_Cylinder(A, B, Radius, EdgeRadius, yes) 544#end 545#macro Round_Cylinder(A, B, Radius, EdgeRadius, UseMerge) 546 547 #if(UseMerge) 548 merge { 549 #else 550 union { 551 #end 552 553 #if(Radius<EdgeRadius) 554 #warning "\nRound_Cylinder() macro called with Radius < EdgeRadius,\nresults may not be as expected\n" 555 556 #local AA = A + vnormalize(B - A)*Radius; 557 #local BB = B + vnormalize(A - B)*Radius; 558 559 cylinder {AA, BB, Radius} 560 sphere {0, Radius translate AA } 561 sphere {0, Radius translate BB } 562 563 #else 564 565 #local AA = A + vnormalize(B - A)*EdgeRadius; 566 #local BB = B + vnormalize(A - B)*EdgeRadius; 567 568 cylinder {A, B, Radius - EdgeRadius} 569 cylinder {AA, BB, Radius} 570 torus {Radius - EdgeRadius, EdgeRadius translate y*EdgeRadius 571 Point_At_Trans(B - A) 572 translate A 573 } 574 torus {Radius - EdgeRadius, EdgeRadius translate y*(vlength(A - B) - EdgeRadius) 575 Point_At_Trans(B - A) 576 translate A 577 } 578 579 #end 580 } 581#end 582 583 584// Rounded cone with torus edges 585// This shape will fit entirely within a cone given the same parameters. 586#macro Round_Cone_Union(PtA, RadiusA, PtB, RadiusB, EdgeRadius) 587 Round_Cone(PtA, RadiusA, PtB, RadiusB, EdgeRadius, no) 588#end 589#macro Round_Cone_Merge(PtA, RadiusA, PtB, RadiusB, EdgeRadius) 590 Round_Cone(PtA, RadiusA, PtB, RadiusB, EdgeRadius, yes) 591#end 592#macro Round_Cone(PtA, RadiusA, PtB, RadiusB, EdgeRadius, UseMerge) 593 #if(min(RadiusA, RadiusB) < EdgeRadius) 594 #warning "\nRound_Cone() macro called with Radius < EdgeRadius,\nresults may not be as expected\n" 595 #end 596 597 #if(RadiusA > RadiusB) 598 #local RA = RadiusB; 599 #local RB = RadiusA; 600 #local PA = PtB; 601 #local PB = PtA; 602 #else 603 #local RA = RadiusA; 604 #local RB = RadiusB; 605 #local PA = PtA; 606 #local PB = PtB; 607 #end 608 609 #local Axis = vnormalize(PB - PA); 610 #local Len = VDist(PA, PB); 611 #local SA = atan2(RB - RA, Len); 612 613 #if(UseMerge) 614 merge { 615 #else 616 union { 617 #end 618 #local R1 = RA - EdgeRadius*tan(pi/4 - SA/2); 619 #local R2 = RB - EdgeRadius/tan(pi/4 - SA/2); 620 621 torus {R1, EdgeRadius 622 Point_At_Trans(Axis) translate PA + Axis*EdgeRadius 623 } 624 torus {R2, EdgeRadius 625 Point_At_Trans(Axis) translate PB - Axis*EdgeRadius 626 } 627 628 #local D1 = EdgeRadius - EdgeRadius*sin(SA); 629 #local D2 = EdgeRadius + EdgeRadius*sin(SA); 630 631 cone { 632 PA + Axis*D1, R1 + EdgeRadius*cos(SA), 633 PB - Axis*D2, R2 + EdgeRadius*cos(SA) 634 } 635 636 cone {PA, R1, PB, R2} 637 } 638#end 639 640 641// Cones with spherical caps 642// Sphere-capped cone object with spheres centered on end points. 643// Derived from Connect() macro by John VanSickle 644#macro Round_Cone2_Union(PtA, RadiusA, PtB, RadiusB) 645 Round_Cone2(PtA, RadiusA, PtB, RadiusB, no) 646#end 647#macro Round_Cone2_Merge(PtA, RadiusA, PtB, RadiusB) 648 Round_Cone2(PtA, RadiusA, PtB, RadiusB, yes) 649#end 650#macro Round_Cone2(PtA, RadiusA, PtB, RadiusB, UseMerge) 651 #local Axis = PtB - PtA; 652 #local RadDif = RadiusA - RadiusB; 653 #local Len = VDist(PtA, PtB); 654 655 #local D2 = f_sqr(Len) - f_sqr(RadDif); 656 #if(D2<0) 657 #error "Round_Cone2() macro called with parameters that can't be handled correctly" 658 #end 659 #local D2 = sqrt(D2); 660 661 #if(UseMerge) 662 merge { 663 #else 664 union { 665 #end 666 sphere {PtA, RadiusA} 667 sphere {PtB, RadiusB} 668 669 cone { 670 PtA + Axis/Len*RadDif*RadiusA/Len, RadiusA*D2/Len, 671 PtB + Axis/Len*RadDif*RadiusB/Len, RadiusB*D2/Len 672 } 673 } 674#end 675 676// Sphere-capped cone object with spheres moved and resized 677// to fit ends of cone. 678// The cone portion is identical to what you would get using 679// a cone object with the same parameters, but the spheres are 680// not centered on the endpoints of the cone, but are moved 681// to give a smooth transition with the surface 682#macro Round_Cone3_Union(PtA, RadiusA, PtB, RadiusB) 683 Round_Cone3(PtA, RadiusA, PtB, RadiusB, no) 684#end 685#macro Round_Cone3_Merge(PtA, RadiusA, PtB, RadiusB) 686 Round_Cone3(PtA, RadiusA, PtB, RadiusB, yes) 687#end 688#macro Round_Cone3(PtA, RadiusA, PtB, RadiusB, UseMerge) 689 #local Axis = vnormalize(PtB - PtA); 690 #local Len = VDist(PtA, PtB); 691 #local SA = atan2(RadiusB - RadiusA, Len); 692 693 #if(UseMerge) 694 merge { 695 #else 696 union { 697 #end 698 cone {PtA, RadiusA, PtB, RadiusB} 699 sphere {PtA + Axis*tan(SA)*RadiusA, RadiusA/cos(SA)} 700 sphere {PtB + Axis*tan(SA)*RadiusB, RadiusB/cos(SA)} 701 } 702#end 703 704// Two-triangle quad 705// A---B 706// |\ | 707// | \ | 708// | \| 709// D---C 710#macro Quad(A, B, C, D) 711 triangle {A, B, C} 712 triangle {A, C, D} 713#end 714#macro Smooth_Quad(A, NA, B, NB, C, NC, D, ND) 715 smooth_triangle {A, NA, B, NB, C, NC} 716 smooth_triangle {A, NA, C, NC, D, ND} 717#end 718 719 720// HF Macros author: Rune S. Johansen 721// Optimizations by: Wlodzimierz ABX Skiba 722// There are several HF macros in shapes.inc, which generate meshes in various shapes. 723// See more information in the help file. 724 725#macro HF_Square (Function,UseUVheight,UseUVtexture,Res,Smooth,FileName,MnExt,MxExt) 726 #local WriteFile = (strlen(FileName) > 0); 727 #local xRes = (< 1, 1>*Res).x; 728 #local zRes = (< 1, 1>*Res).y; 729 #local UVheight = (UseUVheight=1); 730 #local UVtex = (UseUVtexture=1); 731 #local Smooth = (Smooth=1); 732 733 #local Ext = MxExt-MnExt; 734 735 // CALCULTION OF POINT GRID 736 // Note that the grid extents one element further in all directions 737 // if a smooth heightfield is calculated. This is to ensure correct 738 // normal calculation later on. 739 #local PArr = array[xRes+1+Smooth][zRes+1+Smooth] 740 #local J = 1-Smooth; 741 #while (J<xRes+1+Smooth) 742 #local K = 1-Smooth; 743 #while (K<zRes+1+Smooth) 744 745 #local UV = <(J-1)/(xRes-1),0,(K-1)/(zRes-1)>; 746 747 #local P = (UV*Ext*<1,0,1> + MnExt); 748 749 #if (UVheight) 750 #local H = Function(UV.x, UV.z, 0); 751 #else 752 #local H = Function(P.x, P.y, P.z); 753 #end 754 755 #declare PArr[J][K] = P + H*Ext*y; 756 757 #declare K = K+1; 758 #end 759 #declare J = J+1; 760 #end 761 762 HFCreate_() 763#end 764 765#macro HF_Sphere (Function,UseUVheight,UseUVtexture,Res,Smooth,FileName,Center,Radius,Depth) 766 #local WriteFile = (strlen(FileName) > 0); 767 #local xRes = (< 1, 1>*Res).x; 768 #local zRes = (< 1, 1>*Res).y; 769 #local UVheight = (UseUVheight=1); 770 #local UVtex = (UseUVtexture=1); 771 #local Smooth = (Smooth=1); 772 773 // CALCULTION OF POINT GRID 774 // Note that the grid extents one element further in all directions 775 // if a smooth heightfield is calculated. This is to ensure correct 776 // normal calculation later on. 777 #local PArr = array[xRes+1+Smooth][zRes+1+Smooth] 778 #local J = 1-Smooth; 779 #while (J<xRes+1+Smooth) 780 #local K = 1-Smooth; 781 #while (K<zRes+1+Smooth) 782 783 #local UV = <(J-1)/(xRes-1),0,(K-1)/(zRes-1)>; 784 785 #local Dir = vrotate( vrotate(x,(-89.9999+179.9998*UV.z)*z), -360*UV.x*y ); 786 #local P = Center + Dir * Radius; 787 788 #if (UVheight) 789 #local H = Function(UV.x, UV.z, 0); 790 #else 791 #local H = Function(P.x, P.y, P.z); 792 #end 793 794 #declare PArr[J][K] = P + H*Dir*Depth; 795 796 #declare K = K+1; 797 #end 798 #declare J = J+1; 799 #end 800 801 HFCreate_() 802#end 803 804#macro HF_Cylinder (Function,UseUVheight,UseUVtexture,Res,Smooth,FileName,EndA,EndB,Radius,Depth) 805 #local WriteFile = (strlen(FileName) > 0); 806 #local xRes = (< 1, 1>*Res).x; 807 #local zRes = (< 1, 1>*Res).y; 808 #local UVheight = (UseUVheight=1); 809 #local UVtex = (UseUVtexture=1); 810 #local Smooth = (Smooth=1); 811 812 #local Axis = EndB-EndA; 813 #local Base = VPerp_To_Vector(Axis); 814 815 // CALCULTION OF POINT GRID 816 // Note that the grid extents one element further in all directions 817 // if a smooth heightfield is calculated. This is to ensure correct 818 // normal calculation later on. 819 #local PArr = array[xRes+1+Smooth][zRes+1+Smooth] 820 #local J = 1-Smooth; 821 #while (J<xRes+1+Smooth) 822 #local K = 1-Smooth; 823 #while (K<zRes+1+Smooth) 824 825 #local UV = <(J-1)/(xRes-1),0,(K-1)/(zRes-1)>; 826 827 #local Dir = vaxis_rotate(Base,Axis,-360*UV.x-90); 828 #local P = EndA+Axis*UV.z+Dir*Radius; 829 830 #if (UVheight) 831 #local H = Function(UV.x, UV.z, 0); 832 #else 833 #local H = Function(P.x, P.y, P.z); 834 #end 835 836 #declare PArr[J][K] = P + H*Dir*Depth; 837 838 #declare K = K+1; 839 #end 840 #declare J = J+1; 841 #end 842 843 HFCreate_() 844#end 845 846#macro HF_Torus (Function,UseUVheight,UseUVtexture,Res,Smooth,FileName,Major,Minor,Depth) 847 #local WriteFile = (strlen(FileName) > 0); 848 #local xRes = (< 1, 1>*Res).x; 849 #local zRes = (< 1, 1>*Res).y; 850 #local UVheight = (UseUVheight=1); 851 #local UVtex = (UseUVtexture=1); 852 #local Smooth = (Smooth=1); 853 854 // CALCULTION OF POINT GRID 855 // Note that the grid extents one element further in all directions 856 // if a smooth heightfield is calculated. This is to ensure correct 857 // normal calculation later on. 858 #local PArr = array[xRes+1+Smooth][zRes+1+Smooth] 859 #local J = 1-Smooth; 860 #while (J<xRes+1+Smooth) 861 #local K = 1-Smooth; 862 #while (K<zRes+1+Smooth) 863 864 #local UV = <(J-1)/(xRes-1),0,(K-1)/(zRes-1)>; 865 866 #local Dir = vrotate(vrotate(-x,360*UV.z*z),-360*UV.x*y); 867 #local P = vrotate(Major*x,-360*UV.x*y)+Dir*Minor; 868 869 #if (UVheight) 870 #local H = Function(UV.x, UV.z, 0); 871 #else 872 #local H = Function(P.x, P.y, P.z); 873 #end 874 875 #declare PArr[J][K] = P + H*Dir*Depth; 876 877 #declare K = K+1; 878 #end 879 #declare J = J+1; 880 #end 881 882 HFCreate_() 883#end 884 885// Internal macro - not intended to be called by user. 886#macro HFCreate_ () 887 888 #if(WriteFile) 889 #fopen _HFMACRO_OUTPUT_FILE FileName write 890 #write(_HFMACRO_OUTPUT_FILE,"mesh2 {\nvertex_vectors {",xRes*zRes,",\n", 891 #else 892 mesh2 {vertex_vectors{xRes*zRes, 893 #end 894 895 #local J = 1; 896 #while (J<=xRes) 897 #local K = 1; 898 #while (K<=zRes) 899 PArr[J][K], 900 #declare K = K+1; 901 #end 902 #declare J = J+1; 903 #end 904 905 #if(WriteFile) 906 "}\n") 907 #else 908 } 909 #end 910 911 #if (Smooth) 912 #if(WriteFile) 913 #write(_HFMACRO_OUTPUT_FILE,"normal_vectors {",xRes*zRes,",\n", 914 #else 915 normal_vectors{xRes*zRes, 916 #end 917 918 // CALCULATION OF NORMAL VECTOR 919 // We don't vnormalize the vectors from the current center point 920 // to its neightbor points because we want a weighted average 921 // where bigger areas contribute more. This also means that the 922 // center point can be left out completely of the calculations: 923 #local J = 1; 924 #while (J<=xRes) 925 #local K = 1; 926 #while (K<=zRes) 927 vnormalize(vcross( 928 PArr[J][K+1]-PArr[J][K-1], 929 PArr[J+1][K]-PArr[J-1][K] 930 )), 931 #declare K = K+1; 932 #end 933 #declare J = J+1; 934 #end 935 #if(WriteFile) 936 "}\n") 937 #else 938 } 939 #end 940 #end 941 942 #if (UVtex) 943 #if(WriteFile) 944 #write(_HFMACRO_OUTPUT_FILE,"uv_vectors {",xRes*zRes,",\n", 945 #else 946 uv_vectors{xRes*zRes, 947 #end 948 #local J = 1; 949 #while (J<=xRes) 950 #local K = 1; 951 #while (K<=zRes) 952 <(J-1)/(xRes-1),(K-1)/(zRes-1)>, 953 #declare K = K+1; 954 #end 955 #declare J = J+1; 956 #end 957 #if(WriteFile) 958 "}\n") 959 #else 960 } 961 #end 962 #end 963 964 #if(WriteFile) 965 #write(_HFMACRO_OUTPUT_FILE,"face_indices {",(xRes-1)*(zRes-1)*2,",\n", 966 #else 967 face_indices{(xRes-1)*(zRes-1)*2, 968 #end 969 #local F1 = <0,zRes,zRes+1>; 970 #local F2 = <0,zRes+1,1>; 971 #local J = 0; 972 #while (J<xRes-1) 973 #local A = J*zRes; 974 #while (mod(A+1,zRes)) 975 F1+A, F2+A, 976 #local A = A+1; 977 #end 978 #local J = J+1; 979 #end 980 #if (UVtex) 981 #if(WriteFile) 982 "}\nuv_mapping\n}") 983 #fclose _HFMACRO_OUTPUT_FILE 984 #else 985 } uv_mapping} 986 #end 987 #else 988 #if(WriteFile) 989 "}\n}") 990 #fclose _HFMACRO_OUTPUT_FILE 991 #else 992 }} 993 #end 994 #end 995 996#end 997 998#version SHAPES_INC_TEMP; 999#end//shapes.inc 1000