0% found this document useful (0 votes)
12 views

Fractal programming and ray tracing

The document is a book titled 'Fractal Programming and Ray Tracing with C++' by Roger T. Stevens, published in 1990. It covers the principles of ray tracing and fractal programming using C++, including object-oriented programming concepts and mathematical foundations. The book includes various chapters detailing programming techniques, graphics functions, and practical examples related to fractals and ray tracing.

Uploaded by

ls1861464
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views

Fractal programming and ray tracing

The document is a book titled 'Fractal Programming and Ray Tracing with C++' by Roger T. Stevens, published in 1990. It covers the principles of ray tracing and fractal programming using C++, including object-oriented programming concepts and mathematical foundations. The book includes various chapters detailing programming techniques, graphics functions, and practical examples related to fractals and ray tracing.

Uploaded by

ls1861464
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 483

fRACTAl PROGRAMMING

AND RAY TRACING WITH C++


f RA ClAl PROGRAMMING
AND RAY TRACING WITH C++
Roger T. Stevens
M&T Books
A Division of M&T Publishing, Inc.
501 Galveston Drive
Redwood City, CA 94063

© 1990 by M&T Publishing, Inc.

Printed in the United States of America

All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means,
electronic or mechanical, including photocopying, recording, or by any information storage and retrieval sytem,
without prior written pemission from the Publisher. Contact the Publisher for information on foreign rights.

Limits of Liability and Disclaimer of Warranty


The Author and Publisher of this book have used their best efforts in preparing the book and the programs
contained in it. These efforts include the development, research, and testing of the theories and programs to
determine their effectiveness.

The Author and Publisher make no warranty of any kind, expressed or implied, with regard to these programs or
the documentation contained in this book. The Author and Publisher shall not be liable in any event for
incidental or consequential damages in connection with, or arising out of, the furnishing, performance, or use of
these programs.

Library of Congress Cataloging-in-Publication Data

Stevens, Roger T., 1927-


Fractal Programming and Ray Tracing in C ++ I Roger T. Stevens.
p. cm.
Includes index.
ISBN 1-55851-118-0
I. c++ (Computer program language) 2. Fractals--Data Processing.
I. Title
QA76.73.Cl53S74 1990
005.265--dc20
90-13388
CIP

Trademarks:

All products, names, and services are trademarks or registered trademarks of their respective companies.

Cover Design: Lauren Smith Design


Dedication

For Barbara - again

Barbara says that I already have too many computer


books dedicated to her, but who else should I dedicate it to?
When I come up for air out of my computer room, she's always there,
and although I spend a lot of my time alone writing,
I wouldn't feel like doing it if it weren't for her love
and encouragement. She's just as responsible for
this book as I am, and I think she deserves
all the recognition I can give her.
Contents
Why this Book is for You ........................ . ...... ................... ............1 . . . ..

Chapter 1 I ntroduction ..... ................. ...... ....... ...............................3


. . . .

Ray Tracing 3
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Object-Oriented P rog ram mi ng-Myth and Fact 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Newton's Method-An Example of the Power of C++ 7 . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Th ree-Dimensional Vectors 7
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Classes for Ray Tracing 7


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Renderi ng the Screen 8


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Ray Tracing Rendering I nterfaces 8


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Com m u n icating with the Ray Tracer 9


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Using the Language 9


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Fu nctions that Match an Object 9


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Determi n i ng Ray-Object Intersections 9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Tracing the Ray 11


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

P utti ng it All Together 11


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Displaying the Created Scene 11


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Renderi ng Fractal Scenes 11


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Quaternions 12
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Hardware and Software Req u i rements 13 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Expanding You r Horizons 14


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Chapter 2 Object-Oriented Programming: Myth and Fact... ........1 5 .

I n t h e Beg i n n i n g 15
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

N i n e Years Later 16
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Object-Oriented or Conventional-What's the Difference? 16 . . . . . . . . . . . . . . . . . .

The Word is Paradigm 17


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Some P h i losophical Background 18 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

The Non-Aristotel ian World 19. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Some Good Words about C++ 20 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .


Chapter 3 Beyond C with C++: A Newton's Method Example ..... 21

G raph ics Fu nctions 22


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Prog ram for Plotting a Simple Equation Using Newton's Method 22 . . . . . .

The Concept of Classes in C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27


Publ ic, Private, and Protected . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
Ordi nary Fu nctions With i n a Class 33
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Assigning Memory for a C lass 33


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Constructors 34
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Overloading Operators 35
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Output, I n put, and Friends in C++ 36


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Some Complications with Newton's Method 38


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

General ized Newton's Method Display Program 38


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Another Newton's Method Program .42


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

New Di rections 42
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Chapter 4 Three Di mensional Vector Mathematics with C++ ...... 47

Overloading of Vector Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .49


Other Vector Fu nctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

Chapter 5 Ray Tracing Object Structures ...................................... 59

The Concept of Li nked Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71


Lines, Lamps, and Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
Objects and Derived Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
The World According to Ray Tracing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
Additional Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

Chapter 6 Rendering the Scene-An Overview ............................... 79

Mai n Renderi ng Prog ram . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87

Chapter 7 Ray Traci ng Rendering Interfaces ................................ 89

Standard Procedu ral Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89


The RenderMan Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
The ORT Input Lang uage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
Striki ng Out on Ou r Own . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99

Chapter 8 Communicati ng with the Ray Tracer .......................... 1 01

The i nput.cpp File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 01


C reati ng the Parser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 01
Loading the World . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 02
Processing Attri butes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 42
P rocessing Color Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 46
P rocessing Instances . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 46
Processing Bou ndi ng Boxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 46
Processing Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 47
C reating a Sphere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 47
C reati ng a Triangle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 48
C reati ng a Ring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 49
C reating a Parallelogram . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 50
C reati ng a Quadratic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 51
C reating a Cone . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 52
Attac h i ng a Pattern to an Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 52
Processing Pattern Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 53
Transferri ng an Instance to the Object List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 55
Maki ng Bou nding Boxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 56

Chapter 9 Using the Ray Traci ng Defi nition Language .............. 1 59

F ILE_NAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 59
PATTE R N . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 60
COLOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 62
B E G IN_BBOX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 64
B EG IN_INSTANCES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 65
SPHERE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 65
T R IANGLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 66
R ING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 68
PARALLELOG RAM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 70
QUADRATIC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 73
CON E .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 76
SKY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 78
FOC_LENGTH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 79
LAMP .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 79
OBS E RV E R . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 80
XRES .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 80
.

Y R ES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 81
NAME . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 81
Sample Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 81

Chapter 1 0 Functions that Match an Object: The Concept of Virtual


Functions 1 85
........................................................................................

The objects .cpp File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 88


Constructors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 88
. . . . . . . . . . . . . . . . . . .

Destructors . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 88 . . .

Finding the Normal to an Object. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 1


Generati ng Bou nding Boxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 2
. . . . . . . . . . . . . . . .

Changing the Scale of a User-Generated Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 3


Determ i n i ng Position Variables for an Object. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 4
. . . . . .

Chapter 1 1 Finding Where the Ray Hits an Object ..................... 21 5

The Intersect Fu nction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 5


General Intersection Math . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 7
Intersection with a Sphere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 8
I ntersecting a Quad ratic C u rve . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 9
.

I ntersection with a Ring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222


Intersection of the Ray with a Parallelogram . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
I ntersection with a Triangle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
I ntersection with a Bounding Box . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225

Chapter 1 2 Tracing the Ray ........................................................... 227

The Overal l Scene Traci ng Fu nction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227


Tracing a Ray . ...
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
Determ i n i ng the Backg rou nd Color . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 1
Ambient Color .. .
. . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
Specu lar Reflections and Color Emitted by an Object . . . . . . . . . . . . . . . . . . . . . 242
Tracing a Ray through a Transparent Medium . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
Reflections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
Sending a Li ne to the Data File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245
Pattern Effects on Color .. . .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245

Chapter 13 Putting it All Together with the Make Capability .....247

Creating the Ray-Tracing Program with Zortech C++ . . . . . . . . . . . . . . . . . . . . . . 248


R u n n i ng Prog rams with Tu rbo C++ . ... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250
Ray-Tracing Pictures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253

Chapter 1 4 Displaying and Saving Screens ................................ 255

Creati ng a VGA Color Display . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255


Usi ng High- Resolution VGA Cards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
Saving the Display in .PCX Format.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
Viewi ng the . PCX File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287

Chapter 1 5 Rendering Fractal Scenes ......................... ............... 295 .

The Midpoint Displacement Technique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295


Handling a Fractal with Ou r Ray-Traci ng Program . . . . . . . . . . . . . . . . . . . . . . . . . . 297
I m plementing Fractal Processi ng . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297

Chapter 16 Quaternions and Their Mathematics ........................305

History and Defin itions of Quaternions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305


Quatern ion Mathematics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307

Chapter 17 Quaternion Mathematics with C++ ...........................313

Overloading of Quaternion Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 5


Other Quaternion Fu nctions . . . . . . . . . . . . . ... . . . . . .. . .. . ... . ... . .. . . . . ... . . . . . . . ...... . . . . 31 7

Chapter 18 Julia Sets and Dragon Curves in the Quaternions 329 ..

The Header File . . . . . . . . . . . . . . . . . . . .... . . . .... . .... . . . . . ......... . .. . . .............. . . . ........ 330
Input for the Quaternion Prog ram . ... . . . . . . . . .. . .... . .. . . ............... . ...... ...... 330
BACKG ROUND . . . . . . . . . . . .. . ......... . . ................................................... . .. 332
AMB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ....... . . . . . . . .................. . . ......... ..................... . . 338
DIFF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ... . . ......... . . . .. . . .. . . . . . . .......... . . . . . ...... 339
S R E FLECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . ................ . . ... . ........... . . . . ............. 339
R E FLECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . .......... . ................... . . . ....... . . 339
FILE_NAME . . . . . . . . . . . . . . . . . ........ . . . . .... . ......... . . ...... ............................. . . . . . 339
FLIP . . . . . . . . . . . . . . . . . . . . . . . . . .. . .. . . . . . . . ............................... . ................ . ... . ....... 340
LIG HT_P H I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . .. . . . . . . . . . . . .. . . . . . . .... . . ......... . . . ... . .. . ....... 340
LIG HT_TH ETA . . . . . . . . . . . . . . ......... . .................................... . . . . ........ . . .. . .... 34 1
VIEW_PH l . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . .. . . . . . . . .. . . . . . . . . . . . . . . . . . . . ..... . . . . .. . . . . . ... . .. 34 1
XRES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . .. . .. . . . . . . . . . . .. . . . . . ..... . . . . . ... . .. . . . 34 1
Y R ES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ... . . . .. . . . . . . . ...... . . . .... . ............. . . . . ........ . . . . . .. . . . 34 1
XMAX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ... . ....... ................................ . . .. 34 1
XMIN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . ...... . . . . . . . . . . . . . . . . . . . . . . . .. . ....... . . 34 1
YMAX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ... . .. . . . . . . . . ...... . . . . ........................... 342
YMIN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ...... . . . ..... . . . . ........ . . . . . . . ....... . .. . . .... . .. . . . .. . . . . .. . ... 342
ZMAX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . ...... . . . . . ... . ............................. . . . . 342
ZMIN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ........ . ... . . ......... . .. . . . . . . .. . . . . . . . . . . . . 342
QUAT E R N ION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . .. . . . . .. . . . . . . ....... ......... . . . . . . . . . . . . ... 342
MAX_S IZE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .... . . . . . . . ....... . . . . . . . . . .. . ... . . . . . . . . ........ . . . . . 343
MAX_ITE RATIONS . . . . . . . . . . . . . . . . . . . . . . . . ........ . . . . . . . . . . . . . . . . . ........... . .. . .. . .. . . . . . 344
JULIA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . . . .......... . . . . . . . .... . .. . . . .......... . . . . . 344
DRAGON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .... . . . . ......... . . . . . . .. . . . ... . . ............. . . . . . . . . . . . . . 344
Computing the Quaternions ... . . . . . . . . . . .. . .................... . . .. . .. . . .. . .... . ........ 348
Ray Tracing the Object . . . . . . .. . . . . . . . . . . . . . . . . . . . . . . . . . . . ............ . . . . . . . . . . .. . . . . . . ... 349
Determ i n i ng the Color of a Pixel .. . . . . . . . . . . . . . . . . . . . . . . . . . ...... . . . . . . . . . . . . . . . . . . . . . 357
Producing the Color Picture . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . .......... . .... . . . . . . . . . . . . . . 358
Appendix A Data Files for Ray Traced Scenes ........................... 365

File for Plate 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365


File for Plate 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 370
File for Plate 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373
File for Plate 7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375
File for Plate 8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377
File for Plate 9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 8
File for Plate 1 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422
File for Plate 1 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424
File for Plate 1 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426
File for Plate 1 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 428
File for Plate 1 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 430
. .

File for Plate 1 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 1


File for Plate 1 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . : . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . 433

Appendix B Format for .PCX Files ............................................... 435

Appendix C Hardware Requirements ........................................... 441

Index ................................................................................................ 445


Acknowledgements

All of the software in this book was written using Zortech C++ furnished by
Zortech, Inc . , 4-C Gill St., Woburn, MA 0 1 80 1 . It was also checked with Turbo
C++ furnished by Borland International, 4835 Scotts Valley Drive, Scotts Valley,
CA 95066.

Valuable technical information on the format of the .PCX files and a copy of
PC Paintbrush were supplied by Shannon of Z-Soft Corporation, 1 950 Spectrum
Circle, Marietta, GA 30067.

Software was developed and tested on computers using a Vega VGA card
and a Vega VGA 1 024i card both furnished by Headland Technology Inc., 4622 1
Landing Parkway, Fremont, CA 94538. Color pictures were viewed on a NEC
Multisync Plus Color Monitor furnished by NEC Home Electronics (U.S.A.) Inc.

I am also indebted to Peter Watterberg and John Mareda of Sandia National


Laboratories for letting me look at their ray-tracing software.

I am further indebted to Christopher D. Watkins for his contributions to the


quaternion concepts and software used in this book.
Why this Book is for You
It is assumed that the reader of this book will have some knowledge of
programming in the C language and some basic knowledge of computer graphics
on the IBM PC or equivalent. In order to view most of the displays, you will
need a VGA card and monitor. You will also need the Zortech C++ compiler,
version 2.0 or later. Unless you have a lot of time to spare, you will find that a
system with a math coprocessor will be the fastest and best way to work.

This book includes some instruction in how to use C++ that should get
you started with this language and help you to use and/or modify the programs.
The programs have not been fully tested with Turbo C++, but you should be able
to run them with this language with a little ingenuity. Some clues are given as to
differences between Turbo C++ and Zortech C++.

Executable files for rendering ray-traced scenes and julia sets and
dragons in the quartemions are supplied on the disk that accompanies this book
in two forms: one for use with the math coprocessor, and one for use in systems
without a math coprocessor. If you only want to run these programs without
delving any deeper into the programs, you can do so. All information for setting
up data files for your own pictures is given in the book.

If you don 't have a VGA display system, you can still use the program
to render pictures and store them on disk files, but you will not be able to view
the results except on a VGA-equipped computer. However, since rendering can
take hours and viewing requires only a few minutes, you may want to render on
one machine and view on another.

1
CHAPTER 1

Introduction
C++ is the programming language of the future . Every major software
house that now has a C compiler is coming out with a C++ compiler. Within a
few years everyone w i l l be u s ing C++ because i t not only has all of the
capabilities of C, but has object-oriented and operator overloading capabilities
that let you write elegant programs. If you want to get started learning about
C++, here 's your chance. First, forget everything you 've heard about object­
oriented programming being a unique way of thinking that programmers don't
understand. We 're going to use C++ as a natural extension that is required when
objects are important parts of our program. And we ' ll explore a ray-tracing
program, which is at the forefront of PC graphics, and demands that we try some
object-oriented techniques. The result may not be optimum code for the purist,
but will make you familiar with the capabilities of C++ and help you make a
natural transition from a C programming background.

Ray Traci ng
Ray tracing is a technique for creating a two dimensional picture of a three
dimensional world. There are many methods of doing this, some involving very
simple constructive geometry. Ray tracing is different in that it attempts to cause
the computer to duplicate an actual photographic process. This enables us to
specify a scene of simple primitive objects (spheres, parallelograms, triangles,
etc . ) , together w ith patterns to be projected on surfaces, light sources, and
position of the observer. The ray tracer will trace every beam of light, creating
complex shadows and reflections with breath-taking realism.

Let's begin by postulating a scene made of various primitive objects and


light sources. At some point, an observer is looking at this scene through a
translucent screen. Each tiny point on the screen (corresponding to a pixel on a
color monitor) appears to have some color associated with it; the color is of the
ray of light that intersects the screen and strikes the observer 's eye. Now, let's

3
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

project the light ray backwards from observer to screen and then to the nearest
object. The color of the ray at the intersection with this object is what appears
on the screen; we shall build a file of color data in which we assign that pixel on
the screen to the light ray color.

The color of the ray at the object intersection is not something that can be
determined casually. It depends upon what happens to the light ray before it gets
to this point. If the light is totally emitted by the object, and is of a specified
color, our problem is solved. But if the surface is transmitting a color from
within a partially transparent object, reflecting a color, or changing a color that is
originally projected by a light source, we have to follow the path of the light ray
back toward the light sources and sum the various color contributions to
determine the actual ray color at the object intersection.

Obviously this is no trivial task. Figure 1 - 1 shows the geometry of the


situation. This is very simple geometry, to give you the idea of how things are
done. Take a look at Figure 1 -2, where a few additional objects and light sources
have been added, together with shadows and some reflections. You begin to see
how complicated things may be. Remember, however, that in specifying the
scene, we only have to enumerate the very primitive objects of which it is
composed . A l l of the complicated interactions of light and shadow are
performed by the computer program.

A s suming we c an perform a l l of the se ray - tracing tasks w i th i n the


constraints of an IBM PC or compatible, we are then in the picture-generating
business. Bear in mind that we are going to define a scene in terms of primitive
geometric objects. Many of the characteristics that we need to know in the
course of performing ray-tracing computations are unique to particular types of
objects. For example, the normal for a sphere is different from the normal for a
triangle. The point of intersection of the light ray and a sphere requires a
particular set of calculations. The calculations of the intersection of the light ray
with a parallelogram are the same for all parallelograms but different from those
for a sphere. We begin to note a couple of important facts. First, the computer

4
I NTRODUCTION

Lamp

--
--
--

Object

--
--
--
--
--
--
--
--
- --
--
--
--
--
--
--
--
--
--
--
--
- -
--
--
--
--
--

Figu re 1 -1 . Ray Tracing Geometry

operations are computation intensive. Second, the methodology is highly


suggestive of object-oriented programming. In other words, our orientation in
creating the program is to specify what is to be done to various objects letting the
programming language handle the mechanics (it sorts out which object is being
referred to for each operation) appropriately for that object. There are a number
of object-oriented software packages available, but many of them are very poor
at performing extensive mathematical computations. S ince C++ is not only
object oriented, but has all the mathematical capabilities of C, it turns out to be a
natural for programming a ray tracer. In addition, C++ is capable of overloading
the definitions of the mathematical operators, permitting addition, subtraction,
multiplication, etc. of complex numbers.

5
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

Object- Oriented Prog ramming - Myth and Fact


Chapter 2 starts by exposing the myth of object-oriented programming. The
myth is that while object-oriented programming somehow follows the natural
proc e s s e s of h u m an t h o u g h t , i t i s unn atural to e x pe r i e n c e d c o mputer
programmers and mathematicians . This is simply not true. Many computer
languages already include some object-oriented capabilities, and full object­
oriented programming languages are simply a natural extension of existing
capabilities. If some object-oriented languages appear strange to experts, it
could be they lack the tools to do some things we naturally want to do, and thus
require strange and unnatural work-arounds to do what should be simple to
accomplish.

Lamp

{) ..
..
..
Shadow
..
..
..
..
..
..
..
..
..
..
..
..
..
..
..
RAYS

Shadow

Figure 1 -2. A More Complex Ray Trac i n g Diagram

6
INTRODUCTION

Newton's Method - An Example of the Power of C++


Chapter 3 begins by prov iding the methodology for solving a s imple
problem in generating a fractal using Newton's method. It then shows how, if
the equation being operated upon is made more complex and includes more
higher-powered terms, it becomes almost impossible to decompose it. If the C
language is the only tool available, a series of complicated and "unnatural"
functions need to be created to handle the problem and, even then, they don 't do
a very good job. Next, we show how C++, particularly using the overloading of
operators, can set up the class of complex numbers so that they can be treated in
the same way as other number types (floating point and integer, for example).
We then present a generalized program for Newton's method fractals, and show a
typical result.

Th ree- Di mensional Vectors


Three-dimensional vectors are an important tool of ray-tracing. Rays of
light and object positions are defined in terms of three-dimensional cartesian
coordinate s . Vectors between the origin and various pairs of points are
manipulated using conventional vector mathematics to perform the operations
required in ray-tracing. Using ordinary languages, a number of complicated
functions must be developed to perform these ray-tracing tasks. In Chapter 4,
we show how C++ c an define the class of three-dimensional vectors and
overload mathematical operators to perform vector mathematics as simply as the
mathematic s of more traditional types of numbers . In addition, several
special ized functions for handling vectors are prov ided that simplify the
processes used in the ray-tracing program.

Classes fo r Ray Traci ng


The start of the ray-tracing program is a header that includes, among other
things, the definition of the various classes that are used in the process. One of
these is the class of color data, which describes the color characteristics of any
object, such as the ambient lighting, the light diffused by the object, the mirror­
like reflection characteristics, the specular reflection characteristics, and the
transmission and density characteristics if the object is partially or totally

7
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

transparent. Another is the line class which defines the location and direction of
a light ray and includes a flag to indicate whether the ray is within or outside of a
transparent object. Lamp and pattern classes are also defined. Finally, there is a
generic definition of the characteristics of an object, and then derived classes for
each particular primitive object that the program can handle. Figure 1 -3 is a
diagram showing the relationship of these classes. All of these are described in
detail in Chapter 5 . It is important to note that adding another object class in this
header and defining its associated functions in the "objects" part of the program
is all that is necessary to accommodate a new class of object.

Renderi ng the Screen


Chapter 6 describes the main rendering program , which makes use of a
number of functions to perform the ray-tracing tasks. This program first
initializes the default color data and the world, then defines overloading of the
equals operator for color data and object data, opens and closes the output data
file, and prints out some interesting statistics about the ray-tracing process. It
then loads the world, makes bounding boxes, and traces the scene.

Ray Traci ng Rendering Interfaces


One of the most critical aspects of a ray-tracing program is determining an
easy and familar way of generating data files and passing them to the program.
Chapter 7 discusses this problem and describes several interfaces that have been
used for describing objects and techniques to a ray tracer, including the proposed

Class Class Base Class Class Class


color_data Line Object Lamp Pattern

Derived Class Derived Class Derived Class Derived Class


Sphere Parallelogram Ring BBox

Derived Class Derived Class


Triangle Quadratic

Fi g u re 1 -3. Classes Used in Ray-Traci n g Program

8
I NTRODUCTION

RenderMan interface standard. The QRT language is also described.

Com m u n icating with th e Ray Tracer


In Chapter 8, we describe a parser which provides maximum flexibility in
reading the input data file. Next, we describe how the data is handled within the
program, including the use of linked lists to tie the object list together. This
section also includes description and uses of bounding boxes.

Using th e La ng uage
Chapter 9 gives instructions in how to use the language that was created in
order to specify the objects, lamps, observer, and more which make up the scene
to be rendered.

Fu nctions that Match an Object


We have already mentioned that there are a number of functions that we
want to be specific to a particular type of object. These functions include: ray
intersection, determine position, find normal-to-object surface at point of
intersection, find a bounding box around an object, and change-scale of an
object. These functions are described briefly in Table 1 - 1 . Bear in mind that
there is a separate version of the function for each type of object and that C++
automatically keeps track of which version of function to call for a particular
object. Chapter 1 0 shows how using the C++ capability for defining virtual
functions makes it possible to use a single function and have it do the right thing
for whatever object is being treated.

Determ i n i ng Ray - Object Intersections


The set of intersection functions which are listed in Chapter 8 combined with
the overall function for controlling intersection computations found in Chapter
1 1 , make up the capability to determine whether a ray intersects with any of the
objects that are listed in the scene. This is a critical kind of determination that
tells us what the color of light for each pixel will be. Chapter 1 1 covers this
separately from the two files in which it is intermingled.

9
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

Fu n c t i o n De s c r i p t i o n

Con s t ructor ( h a s t h e s a me C reates a n obj ect a nd


n a me a s t h e o b j e c t ) i n i ti a l i zes it.

F i n d No r m Ge n e r a t e s a ve c t o r t h a t i s
n o rma l to the surface of
the obj e c t a t t h e s pe c i f i ed
pos i t i on .

F i n d BB o x C omp u t e s t h e c o o r d i n a t e s o f
the top l eft corner and
b o t t om r i gh t c o r n e r o f a
b o u n d i ng b o x wh i c h e n c l o s e s
t h e o b j ec t .

S c ale - In s t a n c e Sca l es the s i ze of an


o b j e c t wh i c h i s p a r t o f a n
i n s t a n ce as defi ned by x
a n d y mu l t i p l i e r s .

Po s i t i o n C om p u t e s two p o s i t i o n
va r i a b l e s n e e d e d f o r t h e
i n t e r s e c t i o n c omp u t a t i o n .

Col l i s i onTest C omp u t e s t h e t i me o f


i nt e r sect i on of a ray l i ne
wi th t h e s u r f a c e o f t h e
obj ect .

Table 1 -1 . Functions that Match an Ob1ect

10
I NTRODUCTION

Traci n g the Ray


Chapter 1 2 describes the functions used to trace the path of each light ray in
the scene. We discuss in detail how shadows, mirror reflections, specular
reflections, and transmission through a transparent medium are treated. We also
discuss treatment of the sky and how patterns are projected onto a primitive
surface. Finally a number of example scenes are given and pictures shown to
illustrate the characteristics of different scenes.

Putting it Al l Together
Chapter 1 3 shows how the make capability of C++ operates and gives a
listing of the make file used to compile and link the various sections of the ray
tracing program. This eliminates the repeated recompiling of portions of the
program that have not been modified since the previous pass. The output of the
make capability is the completed ray-tracing program, ready to be run.

Displaying the Created Scene


The output of the ray-tracing program is a file containing red, green, and
blue data for each pixel that makes up the scene. The color is defined in up to
262, 1 44 different shades, but the VGA in its maximum color mode can display
only 256 colors. They make a good-looking picture once we figure out the best
256 colors to use. Chapter 14 describes a program that counts the occurrence of
each color in the scene, assigns the 256 most frequently used colors to the 256
VGA palettes, and then assigns the remaining colors in the scene to the nearest
of the 256 selected colors. The chapter also includes a program to convert the
scene to a .PCX file for storage in compressed form.

Rendering Fractal Scenes


Fractal scenes represent the same kind of problem for ray-tracing that was
described in the section above. In my book, Fractal Programming in C, we got
around the prob lem by u s ing the midpoint-di splacement method in two
dimensions and then randomly applying one of two colors to each generated
triangle. By rights, however, we should use the midpoint-displacement method
in three dimensions and then apply ray-tracing to the resulting surface to

11
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

determine the appropriate colors. If we try to do this directly, the number of


computations becomes impossibly large. We can minimize the computations by
using bounding boxes in the same way that we did for reducing the intersection
computations with groups of objects. We first compute all of the triangle patches
that make up a fractal mountain. Then we put a bounding box around each
group of four adjacent patches, and a bounding box around each group of four
bounding boxes, until we end up with one bounding box surrounding the whole
fractal. In tracing the ray to see if it intersects with the fractal, we first check it
against the largest bounding box. If it doesn 't intersect, we are through. If it
does intersect, we check too for intersection with the four bounding boxes at the
next level down. We only need to proceed further with those boxes it intersects,
if any. We proceed with this process until we work our way down to the triangle
patches, reporting back any of those that were intersections. This eliminates a
very large amount of intersect computation -which is the most time-consuming
operation in the process-and brings the time for generating a scene within
reasonable limits. The resulting techniques for generating realistic scenes are
shown in Chapter 1 5 .

Quaternions
Chapter 16 gives a description of quaternions, four-dimensional vectors first
discovered by Lord Hamilton. We describe in detail the uses of quaternions and
the derivation of their mathematics. In Chapter 1 7 , we show how the class and
operator overloading feature s of C++ c an be used to permit handling of
quaternions as if they were just another type of number.

Chapter 1 8 describes the generation of Julia sets and dragons in the


quaternions. A Julia or dragon quaternion needs to be described by a set of
coordinates (quaternions) at a sufficient number of points on its surface so that
there is no ambiguity in transferring a slice of it to two dimensions. If we
attempted the task of checking the intersection of every ray in our ray-tracing
program with every one of these points, millions of operations would be required
and we wouldn ' t have enough computer time to do the j ob on our small
computer. Using a Z buffer technique, we set up a matrix of screen pixels,

12
I NTRODUCTION

giving the height of each point, and compute the color and shading of each pixel
from this data.

Hardware and Software Requirements


What does it take to do all of this? First of all, you need Zortech C++
version 2.06 or greater. That is the software in which all of these programs were
developed. It is excellent, both as a C compiler and as a C++ compiler. It has a
provision for optimizing the code for fastest and most efficient operation, but
you ' ll have to be a little careful if you ' re going to use that feature. I found
several bugs, where the compiler refused to accept perfectly good expressions
when it was in the optimizing mode. These bugs will no doubt be corrected in
future revisions. In the meantime, compile everything in the normal mode and
try optimizing one file at a time to see what happens. Turbo C++ has just been
released by Borland and the ray-tracing program has been tested against it. It is
possible to run the programs with Turbo C++ with some modifications. If you
have come up with another version of C++, you're on your own. Walter Bright,
who developed Zortech C++ maintained frequent communication with Bjame
Stroustrup, the original developer of the C++ language, so this version is quite
close to the originator 's intent. This may not be true of every version of C++.

S ince the ray-tracing routines are computation intensive, it pays to have a


fast computer. You really need a math coprocessor; you can use the ray-tracing
program without it but it may take days to create a single picture file. Also a 286
or 386 machine is desirable; the faster the clock speed, the better. Since the ray
tracer creates a file of picture data, rather than an actual picture, you can generate
files regardless of the kind of display that you have. However, you probably
want to look at them as well as generate them. This requires a VGA display and
VGA color monitor. The 256 color mode is minimal and hopefully there will be
another generation of color displays with more colors. If there are, any scene
files that you have generated with the ray tracer will contain all the color data
you need to take advantage of more color capability.

These programs have been tried on several different computers and have

13
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

worked w ithout difficulty. However, there are many different computer


configurations available at present, and all of them have their own particular
quirks and eccentricities. To help you in case of difficulty, Appendix C gives
some details of the machines on which these programs were tested.

Expand i n g You r Horizons


A tremendous amount of literature has been written about ray-tracing and
many exciting pictures have been published. Unfortunately none of it has
described software which will permit you to do it on your home computer. In
this book, you have the source code to do your own ray-tracing. If you buy the
disk, you '11 be ready to run the program without typing in or debugging. The ray
tracer is a simple one, which doesn 't include a lot of esoteric features such as
advanced shading models and extensive anti-aliasing. Once you get a basic ray
tracer running, you may decide that you want to read up on such features and add
them to your own. Or you may want to add some additional kinds of primitive
objects. The possibilities are limitless, once you have a basic program to serve
as a platform.

14
CHAPTER 2

Object-Oriented
Programming : Myth and
Fact

In the Beg i n n i n g
In August 1 98 1 , Byte M agazine devoted i t s entire issue t o articles o n
Smalltalk, one o f the first object-oriented languages. Smalltalk had been under
development at the Xerox Palo Alto Research Center since 1 97 1 . Byte was
slightly apologetic because there was no version of the language available for
use with personal computers, but was so impressed with the potential of the
language that it thought a special issue was worthwhile and necessary.

Smalltalk was presented as a whole new approach to programming. Instead


of using computer procedures to operate upon data, Smalltalk centered computer
operations upon objects. The information on an object consisted of a description
of the obj ect, together with descriptions of how the object was to accept
messages sent to it and messages it was to provide in response. David Robeson 's
article in that Byte issue, entitled Object-Oriented Software Systems, began by
saying, "Many people who have no idea how a computer works find the idea of
object-oriented systems quite natural . In contrast, many people who have
experience with computers initially think there is something strange about
object-oriented systems." Thus, according to Smalltalk 's developers the object­
oriented approach corresponds much more closely to the way in which humans
normally think and consequently seems natural and easy to use by computer
neophytes. The only ones who were likely to have trouble with Smalltalk were
e xperienced c omputer programmers , who found this method of operation
exceedingly strange.

15
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

Nine Years Later


One might think, then, that the growth of object-oriented languages would
have been inevitable; upon finding a way of programming that appears more
understandable, everyone should gravitate to it. Interestingly enough, however, I
don't know of a single commercially successful piece of software written with
object-oriented language up to this point. Over the nine years since Smalltalk
first appeared on the scene, there have been tremendous improvements in word
processors, spreadsheets, and data base programs, and almost unanimously, these
programs have been written in C rather than in an object-oriented language. This
is not a very good track record. Does this mean that object-oriented languages
are at a dead end? Not at all. But I do think it means that although the newest
versions of object-oriented languages (Turbo Pascal 5.5 and Zortech and Turbo
C++) are being proclaimed as requiring a whole new way of looking at the
world, this approach has not been good for object-oriented programming and has
actually impeded its development.

Object- Oriented or Conventional - What's the difference?


Before proceeding further, we need to understand the difference between
object-oriented and conventional computer languages . According to the
proponents of obj ect-oriented languages , most conventional programming
languages are concerned with data. This data is introduced into a computer
program, processed by various procedures and ultimately yields a result. On the
other hand, an object-oriented language is concerned with objects. Each object
has a number of different, associated responses, so that when you send a
particular message to an object, it provides a unique response. Ultimately, you
do all your programming by defining classes and responses up to the point where
you can send a message to one class and get back the answer to your problem,
whatever it may be.

Let's expand on this a little further. In the first place, an essential quality of
objects is that they hide many of their characteristics. From the outside, you
send a message to the object and it responds. However, you have no idea what is
going on that translates the message to the correct response. In fact, from the

16
O B J E CT-O R I E N T E D P R O G R AM M I N G : M YTH A N D FACT

inside; things begin to look a lot more like conventional computer programming,
with the necessary code to translate an incoming message into an outgoing
response. But all of this is hidden from the user of the object; it can ' t be
tampered with.

Another characteristic of object-oriented languages is the concept of classes.


A class is a description which applies to one or more similar objects. For
example, Lassie is an object which belongs to the sub-class of collies which in
tum belongs to the class of dogs. If you send the message Speak to Lassie, the
object w i l l be appropriately manipulated and Lassie will respond with the
message Arf, mf. Thus, you can define a class, together with many common
messages and responses, and have most of your programming done. All you
need to complete the project is to identify the objects which are specific to the
classes which you have previously defined.

Suppose, however, that one object has all the characteristics of a particular
class, and is unique in that it has additional characteristics or responds differently
to a particular message. (Sandy may respond A lf, arf, but Lassie may respond
Bow, wow, for example . ) To cope with this situation, the object-oriented
language has the characteristic of inheritance. In this situation, a base class is
modified to create another derived class. A derived class inherits all of the
characteristics of its base class, but then may be modified to be different in
content or behavior.

The Wo rd i s Parad i g m
The word most in vogue to promote object-oriented languages is paradigm.
A paradigm is a model. As used in the object-oriented language discussions, you
have a paradigm of the world (which is not the real world, but your model of it).
It is claimed that object-oriented programming is a paradigm of the world very
close to the paradigm we carry around in our heads, and thus we can more easily
program with it. This is patently nonsense. To be sure, you know of an object
Joe and want to send him a message Come. However, it is pretty artificial to say
that we have as an object a set of numbers and that we are going to send them the

17
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

message Sum whereupon they will respond with the answer. Moreover, there is
plenty of reason to believe that rather than selecting a language that corresponds
to our view of the world, our view of the world is largely determined by our
habitual language.

Some Phi losophical Backg round


Alfred Korzybski, founder of General Semantics, says in his book Science
and Sanity:

"We do not realize what tremendous power the structure of an


habitual language has. It is not an exaggeration to say that it enslaves us
through the mechanism of semantic reactions and that the structure
which a language exhibits, and impresses upon us subconsciously, is
' automatically projected ' upon the world around us."

What Korzybski is saying is that our thought processes are dominated by the
language that we are used to, rather than the language being a reflection of a way
of thinking. If this is true, how do we apply it to the implication that object­
oriented languages are "more natural" to computer neophytes, but strange to
computer professionals. (There is something very strange about a philosophy
that says that a product is to be commended because it is liked by those with no
experience in the field but is disliked by the experts.) I think one of the obvious
implications is that the thought patterns most natural to us using English and
other European languages correspond to object-oriented computer languages ,
and the thought patterns o f those versed i n mathematics correspond to traditional
computer languages.

Is there a relation between certain types of language and contributions to the


growth of civilization in general? There 's plenty of room for argument on this
issue. However, it seems clear that the expansion of civilization to its current
level is primarily due to the contributions of mathematicians, scientists, and
engineers. We may not be too happy about what these contributions have done
to the environment. But without the contributions of science, although the

18
O B J E CT-O R I E N T E D P R O G R A M M I N G : M YTH A N D FACT

environment might be less spoiled, world food production could never meet the
global population demands, and many of us would not be here.

The case is much less clear for the contributions of those whose favorite
language is English or a European language . Communication of critical data
appears fuzzy, to say the least. The languages have not lent themselves to
fostering understanding and friendly relations. Korzybski claims that this is
because all of our languages have heavy Aristotelian philosophical roots, which
tend to make us look for solutions to all problems as black or white (yes or no)
i n s t e a d of p e rc e i v i n g s h a d e s of gray i m portant in a c h i e v i n g peacefu l
compromises. We know that both computers and brain cells work i n a binary
(Aristotelian) mode, so perhaps we are incapable of anything but Aristotelian
thinking. At any rate, there doesn 't appear to be any good reason for embracing
a language that has many features in common with languages that have failed to
handle the world's problems to date.

The Non - Aristotelian World


Korzybski claimed that our languages imposed upon us a strong tendency to
seek "Yes" or "No" solutions to all problems. This seems to be just what has
happened in promoting object-oriented languages. We are expected to force all
our problems into one mold or the other, when in reality they can benefit from
the advantages of both approaches . To begin with, let 's note some evident
similarities between the characteristics of an object-oriented language and some
of the conventional computer languages. The C language, for example, has the
class of integers and the class of real numbers (called float). When you use a
plus or minus sign with these different classes of numbers, the internal (hidden)
operations are different so that integer or floating point arithmetic is performed.
Extending this to the realm of mathematics, the same operators (+, , etc.) are -

used to denote operations on such classes as complex numbers and vectors.


Some computer languages can handle these two classes, but not all of them.
Similarly, C has structures, which look a lot like objects, except that you can't do
many things with them that you would like to do with objects. If you are
interested in making the best use of object-oriented programming techniques ,

19
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

you should forget all of this hype about learning a new way of thinking and let
the object-oriented approaches flow when they are needed. This demands a
language that supports both conventional and object-oriented programming
techniques. The best example is C++.

Some Good Words about C++


Now that we 've thoroughly mixed up the concepts of conventional and
object-oriented programming, let's attempt to use a little common sense to bring
the whole subject into perspective. Suppose we forget about this idea of object­
oriented programming being welcomed by the inexperienced and instead look at
what the object-oriented approach can do for us in the way of solving problems.
The most important characteristics are:

1 . The language should make it possible to create classes like complex


numbers, vectors, quaternions, etc. and operate upon them in the way we
operate on ordinary numbers.

2. The language should make it possible to have sets of functions, each set
using a single calling statement that identifies the type of object being
called and executes the proper function for that type of object.

Other object-oriented features such as inheritance and hiding private data are
useful, but not essential . Note that the only object-oriented language that
provides for overloading of a mathematical operator (essential to achieving the
first goal presented above) is C++. When you also consider that C++ has all the
detailed mathematical and data manipulation capabilities included in C, then it
becomes a natural choice for those who want to use object-oriented capabilities
in complicated mathematical programming. The rest of this book assumes that
C++ is the wave of the future, and naturally fits into the problem of creating ray
tracing programs to generate advanced graphics and fractal pictures.

20
CHAPTER 3

Beyond C with C++ :


A Newton 's Method
Example
We begin our examination of the advantages of using C++ for advanced
graphics using Newton 's method. It is an iterated numerical approximation
technique developed by Sir Isaac Newton to obtain solutions of equations that do
not have a closed form. The method works as follows:

1 . Suppose we want the root of the generalized equation which


cannot be solved by ordinary methods:

f(z ) = 0 ( Eq u a t i on 3 - 1 )

where z is a complex number.

2. To begin Newton's method, we make a guess as to a root of this


equation. The guess is =o·

3. Next, we compute the expression:

( Eq u a t i on 3 - 2 )

where f' is the derivative off For the first pass, we have zO on the
right side of the equation and obtain z l on the left.

4. This process is repeated as many times as you desire. Each new


value for z will be a closer approximation to the actual root of the
equation.

21
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

This iteration process is similar to that used to obtain Julia sets and dragon
curves . I n fact, the graph o f the process for a number o f starting values
throughout the complex plane looks like a fractal display, but in this case, there
is an additional mathematical meaning attached to the results.

G raphics Functions
Before showing the first Newton 's method program , we need to address
three simple graphics functions which are used with either C or C++ in all of the
Newton 's method programs that follow. These functions are shown in Figure 3-
1 . They are setMode , els, and plot. If you want to get into the nuts and bolts of
these functions, which make use of the ROM B IOS video services and direct
c a l l s to the v i d e o re g i sters , y o u ' 11 need to l o ok at m y book G rap h ics
Programming in C. However, the functions are simple and the details of how
they work are not important to the application described here. The first function,
setMode, simply sets the mode of the display screen. In the Newton 's method
programs , we shall al ways set to mode 1 6, which is 640 pixel by 350 line
graphics using 1 6 colors. This mode will work equally well with EGA or VGA
adapter boards. The second function, els , works only when the system is in
display mode 1 6. It clears the existing information from the screen and fills the
screen with whatever color (0 to 1 5) is passed to the function as a parameter.
The third function, plot, also works only with mode 1 6. It plots a point on the
screen. The parameters passed to this function are x (display column), y (display
row), and color (pixel color). The function designates location and color to the
pixel.

Program for Plotting a Simple Equation Using Newton's


Method
The program given in the listing of Figure 3-2 is repeated from my book
Fractal Programming in C. It plots the solutions for the equation:

z3 - 1 0 ( Eq u a t i on 3 - 3 )

22
B EY O N D C WITH C++ : A N EWTON'S M ETHOD EXAM P L E

/*
s etMode ( ) Sets V i deo Mode

*I

v o i d s etMode ( i n t mod e )
{
uni on REGS reg ;

reg . h . a h =0;
reg . h . a l = mode ;
i n t86 ( Ox l O , &reg , & reg ) ;

I*
cl s ( ) C l ea rs t h e Screen

*I

voi d cl s ( i nt col or )
{
uni on REGS reg ;

reg . x . a x Ox0600 ;
reg . x . cx 0:
reg . x . dx O x l 84 F ;
reg . h . bh col or ;
i nt86 ( 0x l 0 , & reg , &reg ) ;

I*
pl ot ( ) = Pl ots a poi nt a t ( x , y ) i n col o r
f o r E n h a n c e d G r a p h i c s Ad a p t e r , u s i n g
Turbo C port output functi ons

*/
voi d pl ot ( i nt x , i nt y , i nt col o r )
{
# d e f i n e s e q_o u t ( i n d e x , v a l ) { o u t p ( O x 3 C 4 , i n d e x ) ; \
outp ( Ox3C5 , va l ) ; }
#d e f i n e g r a p h_o u t ( i n d e x , v a l ) { o u t p ( O x 3 C E , i n d e x ) ; \

23
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

outp ( Ox3C F , va l ) ; }
u n s i g n ed i n t o f f s e t ;
i n t m a s k , d u mmy ;
c h a r f a r * m e m_a d d r e s s ;

offset = ( l ong ly * SOL + ( ( l ong l x I 8 L l ;


mem_a d d r e s s = ( c h a r f a r * l O x A O O O O O O O L + o f f s e t ;
ma s k = Ox80 > > ( x % 8 ) ;
g r a p h_o u t ( 8 , m a s k l :
g r a p h_o u t ( 3 , 0 x 0 0 l ;
s e q_o u t ( 2 , 0 x 0 F ) ;
d u mmy = *mem_a d d r e s s ;
*mem_a d d r e s s = O ;
s e q_o u t ( 2 , c o l o r ) ;
*mem_a d d r e s s = O x F F ;
s e q_o u t ( 2 , 0 x 0 F ) ;
g r a p h_o u t ( 3 , 0 ) ;
g r a p h_o u t ( 8 , 0 x F F l ;

Figure 3-1 . Graphics Functions for Newton's Method Programs

The program is written in C. It is fairly simple, because we can decompose


the real and imaginary parts of the underlying equation and compute them with
ordinary mathematics. It begins by determining the distances on the real and
imaginary axes which correspond to the distance between adjacent pixels on the
display. It then goes through a pair of nested loops. At each iteration, the
starting value for the Newton 's method estimate is determined for a particular
pixel location. The Newton 's method computations are repeated until an
additional iteration provides no change in the resulting root. (Note that in the
real world, we often cannot converge to the exact value of a root, but using the
computer, the limitation on the precision of computer numbers causes an
apparent convergence in every case.) Once we get a root, we can plot in 1 6
possible colors. For this equation, we have three possible roots. We allow five
colors each for two of the roots and six for the third. We then cycle through the
colors allowed for each root, using the number of iterations required to obtain the
root as the parameter for determining which color in the group will be used. The

24
B E Y O N D C WITH C + + : A N EWTON'S M ETHOD EXAM P L E

pixel is then plotted on the screen in the appropriate color. Hence, the group of
colors to which the color belongs indicates which root was ultimately targeted,
whereas the color within the group is a measure of the number of iterations
required to get there. Normally, we set up the display palette so that one root has
all shades of a single color (the first root might have shades of green, the second
shades of red, and the third shades of blue, for example).

/*
c n ew t o n 3 MAP OF N EWTON ' S METHOD FOR SOLV I NG z3
*!

#i n c l ude <stdi o . h>


#i ncl ude <ma t h . h >
#i n c l ude <dos . h>
#i n c l ude <proces s . h>
#i n c l ude "tool s . h"

voi d cl s ( i nt col or ) ;
v o i d s etMode ( i n t mode )
voi d pl ot ( i nt x , i nt y , i nt col or )

can s t i n t ma xcol = 639 ;


c a n s t i n t m a x r ow = 3 4 9 ;
c a n s t i n t m a x_ c o l o r s = 1 6 ;

cha r stri ngs [BOJ ;


i n t c o l , row , i ;
i n t m a x_i t e r a t i o n s = 6 4 ;
i n t m a x_s i z e = 4 ;
i n t L I N E W I D T H = l , O P E RA T O R=O , A N G L E , X C E N T E R , Y C E N T E R ;
i n t C U R S O R_X=O , C U R S O R_Y =O ;
u n s i g n ed l on g i n t PATT E RN=Ox F F F F F F F F ;
f l o a t X m a x = 3 . 5 , X m i n = - 3 . 5 , Y m a x=Z . 5 0 , Y m i n = - 2 . 5 0 ;

ma i n ( )
{
doubl e del ta X , del taY . X . Y , Xsqua re , Xol d , Yol d ,

25
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

Y s q u a r e , Y t em p , t e m p l , t e m p 2 , d e n om . t h e t a ;

i n t c o l o r , row . c o l ;

s etMode ( l 6 ) ;
cl s( 7 ) ;
del t a X = ( Xmax - Xmi n ) / ( ma xcol ) ;
d e l t a Y = ( Ym a x - Ym i n ) / ( ma x row ) ;
f o r ( c o l =O ; c o l <=m a x c o l ; c o l ++ )
{
i f ( kbh i t ( ) ! = 0 )
brea k ;
f o r ( r ow=O ; r o w <=m a x r ow ; r ow++ )
{
X = Xmi n + col * del t a X ;
Y = Yma x - row * d e l t a Y ;
Xsqua re = 0 ;
Y squa re = O ;
Xol d = 42 ;
Yol d = 42 ;
f o r ( i =O ; i < m a x_i t e r a t i o n s ; i ++ )
{
Xsqua re = X*X ;
Y squa re = Y*Y ;
d e n om = 3 * ( ( X s q u a r e - Y s q u a r e ) * ( X s q u a r e
Y s q u a re ) + 4* X s q u a re*Y s q u a re ) ;
i f ( d e n om == 0 )
d e n om = . 0 0 0 0 0 0 0 1 ;
t e m p l = . 6 6 6 6 6 6 7 * X + ( X s q u a r e - Y s q u a r e ) / d e n om ;
Y . 6 6 6 6 6 6 7 * Y - 2 * X * Y / d e n om ;
X = templ ;
i f ( ( Xol d X ) & & ( Y o l d == Y ) )
brea k ;
Xol d x ;
Yol d = Y ;

i f ( X>O )
col or i %5 ;
el se
{
i f ( ( X < - . 3 ) && ( Y > O ) )
col o r = ( i %5 ) + 5 ;

26
BEYOND C WITH C++ : A N EWTON'S M ETHOD EXAM PLE

el se
col or = ( i %6 l + 1 0 ;

p l o t ( c o l , r ow . c o l o r ) ;

getc h ( l ;

Figure 3-2. Program to Solve z3 - 1 = 0

If you look at the part of the program which computes the Newton's method
iterations, note that the mathematics is fairly simple for this equation. Consider
what happens, however, when we use a more complex equation having higher
powers of z and more terms. Decomposition is no longer possible. Of course,
we c an create a lot of special purpose functions to attempt to address the
problem, but, using C++, there is a simpler and more elegant way.

The Concept of Classes i n C++


In order to be able to create a simple program for generalized plotting of
Newton 's method solutions to equations, we create a class of complex numbers.
If you are familiar with the concept of structures in the C language, the concept
of classes will not seem strange to you; the class is an extended type of structure
that is unique to C++. A structure, you will remember, is a collection of
variables which may contain any of the variable types that exist in C, as well as
arrays and other structures. The grouping of these into a structure permits them
to be treated collectively as a single unit as well as being accessed as individual
entities . A class differs from a structure in that all data in a structure is available
to the outside world, whereas it is possible to specify for a class which data is
accessible or not. Also there are some interesting ways of relating similar
classes to each other, which will be described later. The class definition begins
with the word class, followed by the name of the class. The second part of the
class definition is the body, which contains the definition of the variables and
functions that make up the class. This body is enclosed in curly brackets and

27
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

terminated by a semicolon, or by a list of objects of the class type.

It is conventional to include the class definition in a file having the extension


.hpp and the listing of the class's functions in a file having the same name but
with the extension . cpp . These files are then linked to the main program .
However, for the simple example given here, you may include all of the
Complex class information at the beginning of the program. Figure 3-3 is a
listing of the code for the class Complex. The class contains two double
prec i s ion floating-point numbers, real and imaginary, which make up the
complex number. Note that for all of the C++ programs in this chapter, the
listings are for use with Zortech C++. The programs will run with Turbo C++,
but you w i l l have to change every instance of #include < s tream . hpp > to
#include < iostream.h>.

I*
C om p l e x c l a s s of comp l ex n umbe r s

*I

#i n c l u d e <stdi o . h>
#i n c l ude <ma t h . h >
#i n c l ude <dos . h>
#i n c l u d e < p roces s . h>
#i n c l ude < s t ream . hpp>
#i n c l ude < c on i o . h > ;

voi d cl s ( i nt col or ) ;
voi d pl ot ( i n t x , i nt y , i nt col or ) ;
v o i d setMode ( i n t mode ) ;

c l a s s C o mp l e x I
d o u b l e r e a l , i m a g i n a ry ;
publ i c :
C om p l e x ( ) ;
Compl ex ( d o u b l e r , d o u b l e i ) ;
Comp l e x ( Comp l ex & ) ;

28
BEYOND C WITH C++ : A N EWTON'S M ETHOD EXAM P L E

C o m p l e x o p e r a t o r + ( C om p l e x & J ;
C om p l e x o p e r a t o r - ( C om p l e x & ) ;
C om p l e x o p e r a t o r= ( C om p l e x & J ;
C om p l e x o p e r a t o r * ( C om p l e x & ) ;
C om p l e x o p e r a t o r * ( f l o a t & ) ;
C om p l e x o p e r a t o r / ( C om p l e x & J ;
C om p l e x o p e r a t o r- ( ) ;
i n t o p e r a t o r ! = ( C om p l e x & J ;
i n t o p e r a t o r== ( C om p l e x & J ;
v o i d p r i n t ( c h a r * n a me = " " ) ;
doubl e r ( ) ;
daub1 e i ( ) ;
f r i e n d o s t r e a m & o p e r a t o r < < ( o s t r e a m& , C o m p l e x & J ;
};

Compl ex : : C omp l e x ( )
{
rea l = 0 ;
i m a g i n a ry O;

C o m p l e x : : C om p l e x ( d o u b l e r , d o u b l e i )
{
rea l = r ;
i m a g i n a ry i ;

C o m p l e x : : C o m p l e x ( C om p l e x & o t h e r c o m p l e x ) {
r e a l = o t h e r c om p l e x . r e a l ;
i m a g i n a ry = o t h e r c om p l e x . i m a g i n a ry ;

C o m p l e x C o m p l e x : : o p e r a t o r+ ( C om p l e x & a r g ) {
C om p l e x r e s u l t ;
res u l t . rea l = rea l + a rg . rea l ;
r e s u l t . i m a g i n a ry i m a g i n a ry + a r g . i m a g i n a ry ;
return resul t ;

C o mp l e x C o m p l e x : : o p e r a t o r - ( C om p l e x & a r g ) {
C om p l e x r e s u l t ;
res u l t . rea l = rea l - a rg . rea l ;

29
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

r e s u l t . i m a g i n a ry i m a g i n a ry - a r g . i m a g i n a ry ;
return resul t ;

C o m p l e x C om p l e x : : o p e r a t o r * ( C o m p l e x & a r g ) {
Comp l ex r e s u l t ;
r e s u l t . r e a l = r e a l * a r g . r e a l - i m a g i n a ry * a r g . i m a g i n a ry ;
r e s u l t . i m a g i n a ry r e a l * a r g . i m a g i n a ry + i m a g i n a ry *
a rg . rea l ;
retu rn resul t ;

Comp l ex Compl ex : : ope r a t o r * ( f l o a t & a rg ) {


Comp l ex r e s u l t ;
resu l t . rea l = rea l * a rg ;
r e s u l t . i m a g i n a ry i m a g i n a ry * a r g ;
return res ul t ;

C o m p l e x C om p l e x : : o p e r a t o r / ( C o m p l e x & a r g ) {
doubl e temp ;
C om p l e x r e s u l t ;
t e m p = a r g . r e a l * a r g . r e a l + a r g . i m a g i n a ry * a r g . i m a g i n a ry ;
r e s u l t . r e a l = ( r e a l * a r g . r e a l + i m a g i n a ry *
a r g . i m a g i n a ry ) / t e m p ;
r e s u l t . i m a g i n a ry = ( i m a g i n a ry * a r g . r e a l - r e a l *
a r g . i m a g i n a ry ) / t e m p ;
return resul t ;

C o m p l e x C o m p l e x : : o p e r a t o r- ( v o i d ) {
doubl e temp ;
C om p l e x r e s u l t ;
t em p = r e a l * r e a l + i m a g i n a ry * i m a g i n a ry ;
r e s u l t . r e a l = r e a l / t emp ;
r e s u l t . i m a g i n a ry = - i m a g i n a ry / t e m p ;
return resul t ;

C o m p l e x C o m p l e x : : o p e r a t o r= ( Com p l e x & r v a l u e ) {
rea l = rva l ue . rea l ;
i m a g i n a ry = r v a l u e . i m a g i n a ry ;
return *thi s ;

i n t C o m p l e x : : o p e r a t o r== ( C om p l e x & r v a l u e )

30
B E Y O N D C WITH C + + : A N EWTO N'S M ETHOD EXAM P L E

i f ( ( fa b s ( r v a l ue . rea l - rea l ) < 0 . 0 1 ) &&


( f a b s ( r v a l u e . i m a g i n a ry i m a g i n a ry ) < 0 . 0 1 ) )
return l ;
el se
return 0 ;

i n t C om p l e x : : o p e r a t o r ! = ( C om p l e x & r v a l u e )
{
i f ( f l o a t ( r v a l u e . r e a l - r e a l ) == f l o a t ( r v a l u e . i m a g i n a ry -
i m a g i n a ry ) )
return O ;
el se
return l ;

o s t r e a m & o p e r a t o r < < ( o s t r e a m& s , C o m p l e x & a r g )


{
i f ( a r g . i m a g i n a ry > 0 )
s < < " ( " < < a r g . r e a l < < " + " < < a r g . i ma g i n a ry
..
« "i ) ;
el se
s < < " ( " < < a r g . r e a l < < " " < < a r g . i m a g i n a ry
« i ) .. ;
..

return s ;

d o u b l e C om p l e x : : r ( )
{
doubl e temp ;
temp = rea 1 ;
ret u r n temp ;

doubl e Compl ex : : i ( )
{
d o u b l e t em p ;
t e m p = i m a g i n a ry ;
r e t u r n t em p ;

Figure 3-3. Class Complex for Complex Numbers

31
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

Publ ic, Private, and Protected


The C++ language has the capability of hiding data within a class. By
tradition, the keywords are public , private, and protected. However, everything
not specified in a class definition is private by default, so it is seldom necessary
to use the private keyword. If you look at the definition of the Complex class in
Figure 3-3, you ' 1 1 see that the variables making up a complex number (real and
imaginary) are private by default. This means that these variables can only be
accessed by members of the Complex class (namely those functions that form the
rest of the class definition) or by friends of the Complex class. (We ' ll discuss
friends l ater. ) They cannot be accessed by any external function or even by
functions of a class derived from the specified class. You can see that it is
possible to have everything about a class private, but that would be useless, since
there would be no way of accessing class results.

The protected keyword identifies members of a class that are hidden from
external functions but appear as public to classes that are derived from the
specified class. There are no derived functions for the complex number class
(we ' ll speak more about derived functions in later chapters) so there is no need
for any members to be protected.

The public keyword indicates that designated members of the class are
accessible from anywhere within the C++ program where a class object is within
scope. If you are trying to achieve maximum data protection, all of your class
variables will be private and the only access to them from the outside world will
be through various functions that are public. On the other hand, it is perfectly
acceptable to have the entire contents of a class be public . (We ' l l see some
examples of this in later chapters.) You gain in flexibility but pay the price of
losing data protection from the outside world. Note that all of the functions used
by the Complex c l ass are public . In order to permit needed access to the
individual hidden variables the functions r and i were created. They wouldn ' t

32
B E Y O N D C WITH C + + : A N EWTO N ' S M ETHOD EXA M P L E

have been needed if the two variables had been public. Things were left in this
form to demonstrate an alternate method of access.

Ord i n ary Fu nctions with i n a Class


Look at the last two functions within the complex class definition. These are
ordinary functions called in a manner similar to that used for structures.

In other words, if we have a variable temp of the class Complex, and a


variable real of type float, we can write

rea l = temp . r ( ) ;

which will cause the function to return the real part of the complex number to
real. The two ordinary functions used with the Complex class are quite simple.
The function r returns the value of the real part of the complex number and the
function i returns the value of the imaginary part. Instead of making the real and
imaginary parts public, this technique enables us to get the values of the real
and/or imaginary parts for external use but does not permit us to modify them by
direct external action.

Assi g n i n g Memory for a Class


In the C language, variables and structures that are defined globally (not
within a function) are automatically assigned the proper amount of memory and
continue to own that memory for the duration of the program. Variables and
structures defined within a function are automatically assigned the proper
amount of memory each time they come within scope (when the function is
called) and the assigned memory is automatically returned to free memory when
they pass out of scope (the function terminates). When the address of a structure
or variable is defined, only the memory space for the address is allocated; one of
the family of malloc functions must be used to allocate the memory for the
variable or structure itself. The same is true for C++ as far as variables are
concerned. For structures or classes, the situation is somewhat different. When
a member of a structure or class is defined, memory is automatically assigned to

33
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

it, and this memory remains allocated to it until explicitly freed. There is a
special C++ function called a destructor, which, if defined by the programmer
for a class, will automatically be called whenever the class member goes out of
scope. This can be used to delete the memory assigned to a member as well as
any other housekeeping that is necessary. In the case where only the structure or
class address is defined, as in C, only the memory for the address is allocated.
However, C++ has the function new which can be called to allocate the memory
for a class or structure. Fortunately, C++ knows just how much memory to
allocate for a particular structure or class. There is also a companion function
delete, which is used to deallocate the memory assigned by new. If memory is
assigned by new, it will not be deallocated by the destructor; the delete function
must be used. The C++ language also has a function called a constructor. This
function is used to initialize a newly created object in any desired way.

Constructors
The constructor is a special function which is identified by the fact that it has
the same name as the class itself. This function provides for the initialization of
a class object. It is invoked by the compiler whenever a new object of the class
is created. The C++ language supports the concept of function overloading,
which means that you can have more than one definition of a function, providing
the parameters passed to the function are different for each instance. As you can
see in the listing of Figure 3-3, right after the public: statement, we have made
use of this capability to define three constructors. The first constructor is used
when we create a new instance of Complex without passing any parameters. In
the second case, we pass two numbers of type double to the new instance. In the
third case, we pass another complex number to the constructor. Looking down a
little further, you will come to the place where these constructors are defined.
Prototypes of all associated functions must be included w i thin the class
definition, but the actual body of code may be developed separately. The format
for creating a constructor is to begin with the type of data that is to be returned
(in this case Complex, followed by a double colon, followed by the class name,
which for a constructor is identical to the function name). The body of the
function for the first constructor simply sets the real and imaginary parts of the

34
B E Y O N D C WITH C + + : A N EWTO N ' S M ETHOD EXAM P L E

complex number to zero. This is the default case when no parameters are
specified. The second constructor sets the real and imaginary parts of the
complex number to the two numbers that are passed as parameters.

Overload i n g Operators
One of the most important capabilities of C++ is the capability to overload
operators. We have found it quite easy to define the class of complex numbers,
but what makes all of this worthwhile is the fact that we will be able to handle
operations of complex numbers arithmetic just as easily as arithmetic for integers
or floating point numbers. For the complex class, we have overloaded the +, -,
=, * , /, -, = = , and ! = operators. Now let's see how this is done. Look at the
definition for overloading the + operator in Figure 3 - 3 . The format for the
function definition begins like any class function with the type of variable to be
returned, followed by the class name and two colons. Next comes the keyword
operator followed by the function to be overloaded (in this case + ). Next, in
parentheses, are the arguments to be passed to the function. Note that you can't
p a s s j u s t any v ariab l e s . The number of v ariables that c an be passed i s
determined b y the operator that you select. More about that later. We see then
that in the case of the + operator, we are passing one complex number's pointer
to the function, and the function already has access to its own native complex
number. The body of the function definition sets up a complex number to
contain the result, adds the real and imaginary parts of the two complex numbers
separately, and returns the result. Thus when you write

c = a + b;

where a, b, and c are all complex numbers, the new definition of the + function
for complex numbers applies. Its native complex number is a and the complex
number b is passed to it. The addition is performed, returned, and c is set equal
to it. This implies something , however; that the = operator is capable of
performing its function for complex numbers. The definitions of C++ state that
the = operator is automatically overloaded for each class created.

35
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +

The Zortech C++ compiler is sometimes unable to handle this and returns a
compiler error. We have defined our own overload for this operator that sets real
and imaginary parts of the native complex number equal to their counterparts in
the complex number passed to the function. S imilarly, the operators for
subtraction, multiplication, and division are overloaded to properly perform
these operations on complex numbers. The operator - takes only one argument;
we have used it to represent the reciprocal of a complex number.

The == and ! = operators are needed in performing comparisons of complex


numbers in the Newton's method programs. The way we have overloaded them
shows both the flexibility and the dangers inherent in C++. For the ! = test, we
do not want to check for exact equality, since this is either not achieved, or the
whole solution blows up as we try to zero in too closely, due to the limited
precision of computers. Consequently we have chosen to convert the double
precision numbers to floating-point numbers before performing the test. The
result in this test returns false when the double precision numbers are not exactly
equal to each other, but fall within a tolerance range that makes their truncated
floating point equivalents equal. This is very useful for us. But if we used this
method to define an operator overload for a totally generalized complex number
class, programmers that used the class would have an unexpected result. This is
even truer for the == class, where the tolerance for equality has been made even
larger. We are using this operator to determine which of several roots we have
approached most closely. It is very appropriate for this use, but in other cases,
serious problems might occur.

Output, Input, and Friends in C++


Most implementations of the C++ language include an excellent example of
overloading of operators as part of the standard library supplied. These are the
functions used for handling input and output . Here, we will just concern
ourselves with output to the screen. Bear in mind that there are much wider
applications.

This application makes use of cout, a streamlined replacement for the print/

36
BEYOND C WITH C + + : A N EWTON'S M ETHOD EXAM PLE

function using overloading of the shift left (<<) operator. The function begins
with cout < < followed by a string or by any type of variable. The overloading
automatically functions out what type of v ariable is used and displays it
appropriately. Also, the function returns itself, so you may concatenate the left
shift operators into as long a series as you like. For example:

cout << "Th i s i s a t e s t o f " < < v a r i a b l e < < " i tems . \ n " :

is perfectly legal. Note that a semicolon must appear at the end of the series.

Now we are almost ready to consider overloading so that cout can be used
with our Complex class. But first, we need to know about friends. A friend of a
class i s a nonmember of a c l a s s , either a function, a member of another,
previously defined class, or a complete class, which is allowed access to the
nonpublic members of a class. This relationship must be declared within the
class, using the keyword friend.

Now let's see what would happen if we were to overload the double shift
operator within the Complex class in the normal manner. We would have the
prototype:

o s t r e a m& o p e r a t o r < < ( o s t r e a m& ) ;

and some code to define what would be output when the operator was invoked.
However, this invocation (for a complex number temp, for example) would be of
the form:

temp«cout ;

which is very unlike the normal way of using cout for other types of data. What
we need to do is have a prototype of the form:

o s t r e a m& o p e r a t o r < < ( o s t r e a m& , C om p l e x& ) :

37
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

S ince ostream is independent of our class, we cannot include this prototype


in our class. However, it requires access to the private data within the Complex
class. We achieve this by defining it as a friend. Looking at the listing of Figure
3-2, you can see how this is done and the code for performing the operator
overloading. The cout function can now be used with complex numbers in the
same way as with other data types and the Complex class of data can indeed be
concatenated with other data types in the output statement.

Some Compl ications with Newton's Method


Before proceeding further, we need to point out some complications with
Newton 's method. First, it is important to note that Newton used intelligent
guessing of the initial roots. We have chosen to create plots where each pixel
represents the result of starting with a particular number and performing the
Newton 's method iterations. Unfortunately, some numbers are bad places to
start. For example, in Figure 3-2, if we begin with a guess of zero, the derivative
will be zero and when we try to divide by zero, the solution will fail instead of
converging on a real solution. We were lucky that the program worked because
we didn't hit zero exactly as one of our initial guesses. As we describe the more
generalized programs below, note that if there is a coefficient of z, the program
can always be run safely, since there will always be a derivative other than zero.
B u t if the first power of the v ariable is m i s sing, singularities c an occur.
Therefore, we have used tests involving the inequality operator and also limited
the number of iterations to attempt to prevent such disasters (which are usually
recognized by the program quitting with a floating-point overflow message). If
you look at Plate 3, you ' ll see that for this solution of Newton's method, there is
a white circle right in the center of the picture. This represents an area where
these singularities prevent the method from zeroing in on one of the roots.

General ized Newton's Method Display Prog ram


Now that we have complex numbers under control, we are ready to look at
the program for generating generalized Newton 's method d i splay s . This
program is listed in Figure 3-4. First this program gives the user the opportunity
to enter ten coefficients, corresponding to the coefficients of the powers of z

38
B EYON D C WITH C + + : A N EWTON'S M ETHOD EXAM PLE

from 0 to 9. The next few lines of code are very much like the Newton's method
program of Figure 3-2, setting up the values associated with each pixel location
and going into a double loop to compute for each pixel. When we get to the
arithmetic, it is all done with complex numbers and can be simply written for
these possibly complex equations as the arithmetic for the simple equation used
in Figure 3- 2. Note how we initially define z as a complex number. We first
enter a loop which puts together the values of f and f' , power-by-power from the
zeroeth to the next-to-last. We then add in the last power for f (there isn't one
for f'). The expression to compute the new Newton estimate is a single line. We
then compare the old and new values of the complex root and quit if they are the
same, or continue if they are not. (Note that it would be a little more convenient
to use the equality test here, but because of the way we have overloaded the
operators, we have to use the inequality test to obtain the tolerance that we
want.) As for determining the colors to plot, in this case we haven't tried to
assign groups to different roots, since determining all of the roots would be too
complicated. Instead, we cycle through the available colors based upon the
number of iterations it took to find a root. This program is an example of C++ at
its best and at its worst. It is at its best because you can see how simple it is to
write the software; the most difficult part is writing the functions and definitions
for the complex number class. Once you have done this, the actual program is
simple, and since this same complex class can be used again whenever you
encounter a complex number problem, the next program will be even simpler.
(Watch out if you use our peculiar inequality and equality overload functions in a
different application, however.) This is C++ at its worst because the few simple
and elegant lines of code that make up the program conceal a whole lot of
mathematical operations. The result is that this program will require days to
generate a display even with a fast computer and a math coprocessor, so don't
use it unless you have a lot of patience. If you do, you will be rewarded by
interesting displays like that shown in Plate 3, which is the plot of the equation:

z6 - 2z5 + 4z4 - z - 1 0 ( Eq u a t i on 3 - 4 )

39
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

/*

n ew t g e n P r o g r a m t o m a p t h e g e n e r a l i z e d N ew t o n ' s m e t h o d

#i n c l ude <stdi o . h>


#i n c l ude <dos . h>
#i n c l ude < i ost ream . h>
#i n c l ude <ma t h . h >
#i n c l ude <con i o . h>

voi d cl s ( i nt col or ) ;
voi d pl ot ( i nt x , i nt y , i nt col o r ) ;
v o i d s etMode ( i n t mode l ;

i n t c o l , row , i , j ;
i n t m a x_i t e r a t i o n s = 6 4 ;
i n t m a x_s i z e = 4 ;
f l o a t X m a x= 2 . 0 , X m i n = - 2 . 0 , Y m a x= l . 2 0 , Y m i n = - 1 . 2 0 , d e l t a X , d e l t a Y ;
C o m p l e x z , o l d_z ;
C o m p l e x f , f_p r i m e , z_p owe r ;
f l o a t a r g u me n t s [ l O J ;
f l o a t temp ;
c o n s t i n t ma x c o l = 639 ;
c o n s t i n t m a x r ow = 3 4 9 ;
c o n s t i n t m a x_c o l o r s = 1 6 ;

ma i n ( )
{
i n t c o l o r . r ow . c o l . d e g r e e ;

f o r ( i =O ; i < l O ; i ++ )
{
a rg umen t s [ i ] = O ;
cout < < "\nEnter " << << " t h coeffi c i en t : "
c i n > > a r g um e n t s [ i ] ;

s etMode ( l 6 ) ;
f o r ( i =9 ; i >=O ; i - - )

40
B E Y O N D C WITH C + + : A N EWTON'S M ETHOD EXAM P L E

i f ( a r g umen t s [ i ] ! = O J
I
deg ree = i ;
brea k ;

cl s ( l l ;
d e l t a X = ( Xm a x - Xm i n ) / ( ma xc o l + l ) ;
d e l t a Y = ( Y ma x - Ym i n ) / ( ma x row + l ) ;
o l d_z = C om p l e x ( 4 2 , 4 2 ) ;
f o r ( c o l =O ; c o l < =m a x c o l ; c o l ++ )
I
i f ( kbhi t ( ) ! = O J brea k ;
f o r ( r ow=O ; r ow < =m a x r ow ; r o w++ )
I
z = C omp l e x ( Xm i n + c o l * d e l t a X , Y m a x - row * d e l t a Y ) ;
i = 0;
w h i l e ( i < m a x_i t e r a t i o n s )
I
f = 0;
f_p r i m e = O ;
z_p o w e r = l ;
f o r ( j =O ; J < d e g r e e ; j ++ )
I
f = f + z_powe r * a r g u m e n t s [ j ] ;
f_p r i me = f_p r i me + ( z_powe r * a r g umen t s [ j +l ] ) *
( fl oa t ) ( j +l l ;
z_p ow e r = z * z_powe r ;

f = f + z_p owe r * a r g ume n t s [ d e g r e e J ;


z = z - f / f_p r i m e ;
i f ( z ! = o l d_z )
I
o l d_z = z ;
i ++ ;

el se
brea k ;

col or = i %16 ;
p l ot ( c o l , row . co l o r ) ;

41
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

getch ( ) :

Figure 3-4. General ized Newton's Method Program

Another Newton's Method Prog ram


In Figure 3-5, we list a Newton's method program which handles equations
from degree three to ten, but only for the simple equation:

zn - 1 = 0 ( Eq u a t i on 3 - 5 )

We are able to simplify the mathematics somewhat and create a switch


statement to optimize the iterated multiplications needed for solving equations of
a higher degree. This provides a considerable speed-up of the program. In
addition, for this equation, the roots are known to be spaced equally around a
unit circle in the complex plane, so that we can offer two color options; either the
cyclical colors used in the previous program, or pairs of colors associated with
each root, which are determined by comparing the root obtained by the Newton 's
method solution w i th the actual roots to see which one is most closely
approached. The results of using this program are shown in Plate 1 for a fifth
degree equation and Plate 2 for a seventh degree equation.

New Di rections
Now that we 've been exposed to creating classes and using them to simplify
programming, we ' ll go on to the next chapter, where we ' ll look at the functions
and definitions needed to treat three-dimensional vectors. This will eventually
lead us into using these vector operations in the ray tracing program.

42
B EY O N D C WITH C + + : A N EWTON'S M ETHOD EXAM P L E

/*

newton P rogram to sol ve zn - 1 0

*/

con s t i n t maxcol = 639 ;


c o n s t i n t m a x r ow = 3 4 9 ;
c o n s t i n t m a x_ c o l o r s 16 ;
=

i n t m a x_i t e r a t i o n s = 64 ;
d o u b l e X m a x= 2 . 0 , X m i n = - 2 . 0 . Y m a x= l . 2 0 . Y m i n= - 1 . 2 0 , d e l t a X . d e l t a Y ;
C o m p l e x z . o l d_z . z_p owe r , z_p ow e r 2 . z_s q ;
Comp l ex r o o t s [ l O J ;
i n t deg ree ;

ma i n ( )
{
i n t i , j , co l o r . row . c o l . f l a g ;
d o u b l e a , b , t w o p i =6 . 2 8 3 1 8 5 3 ;

s etMode ( 1 6 ) ;
cout « " E n t e r degree of equa t i on ( 3 - 1 0 ) : " ;
c i n » deg ree ;
c o u t « " \ n E n t e r ' 0 f o r cy c l i c a l c o l o r s ; \ n "
·

< < " ' l ' f o r c o l o r s a s s o c i a ted wi t h root : "


c i n » fl ag ;
i f ( deg ree < 3 )
degree 3;
i f ( degree > 1 0 )
degree 10 ;
i f ( fl ag < 0 )
fl ag 0;
i f ( fl ag > 1 )
fl ag 1:
a = 1 . 0 / ( fl o a t ) deg ree ;
b = 1 - a;
f o r ( i =O ; i < d e g r e e ; i ++ )
{
r o o t s [ i ] = C om p l e x ( c o s ( i * t wo p i / ( f l o a t ) d e g r e e ) .
s i n ( i * two p i / ( f l o a t ) d e g r e e ) ) ;

43
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

cl s ( 7 ) :
d e l t a X = ( X m a x - X m i n ) / ( ma x c o l + 1 ) :
d e l t a Y = ( Ym a x - Ymi n ) / ( ma x row + 1 ) :
f o r ( c o l =O : c o l <=ma x c o l : c o l ++ )
{
i f ( kbh i t ( ) ! = 0 ) brea k :
f o r ( r ow=O : r o w <=ma x r ow : r o w++ )
{
z = C o m p l e x ( X m i n + c o l * d e l t a X , Y m a x - r ow * d e l t a Y ) :
o l d_z = C o m p l e x ( l 0 0 0 0 , 1 0 0 0 0 ) ;
i = 0:
w h i l e ( ( z ! = o l d_z ) && ( i < 6 4 ) )
{
o l d_z = z ·
z_s q = z * z :
swi tch ( deg ree )
{

case 3:
z _powe r z _s q :
ca se 4 :
z_powe r z * z_ s q :
brea k :
case 5 :
z_p owe r z_s q * z_s q :
brea k :
case 6 :
z _powe r z * z_ s q *z_s q :
brea k :
ca s e 7 :
z _powe r z_s q * z_s q * z_s q :
brea k :
case 8 :
z _powe r
z_s q * z_s q * z_s q * z :
brea k :
ca s e 9:
z _powe r z_s q * z_s q :
z_powe r z_p owe r * z_powe r :
brea k :
case 10 :

44
B E Y O N D C W I T H C + + : A N EWTO N ' S M ET H O D E X A M P L E

z_powe r = z_s q * z_s q :


z_powe r = z_p owe r * z :
brea k :

z_p o w e r = -z_p owe r ;


i f ( z_powe r ! = C o m p l e x ( ) )
z z * b + ( z_pow e r ) * a :
el se
z o l d_z :
i ++ ;

i f ( f l a g == 1 )
{
col or = 1 5 :

f o r ( j =O ; j < d e g r e e : j ++ )
{
i f ( z == r o o t s [ j ] )
c o l o r = 1 + j % 8 + 8* ( i % 2 ) ;

el se
col or = i %16 :
p l o t ( c o l , r ow . c o l o r ) :

getch ( ) ;

Figure 3-5. Another Newton's Method Program

45
CHAPTER 4

Three Dimensional
Vector Mathematics with
C++

In this chapter, we are going to look in some detail at using C++ to define
the class Vector of three dimensional vectors. All of the information needed to
define these vectors for use in the ray tracing program is included in two files.
The first of these, vmath .hpp, is a header file which contains the definition of the
class. It is listed in Figure 4- 1 . The second file, vmath.cpp, contains the detailed
definitions of all of the functions that are contained within the class. It is listed
in Figure 4-2.

First, look at Figure 4- 1 . The class of three dimensional vectors is defined


as containing three floating-point variables, one for each of the three coordinates
of a Cartesian coordinate system. Two things should be observed about how this
definition is structured. First, the keyword public appears at the very beginning
of the class definition, so all members of the class are completely available to
external functions. Second, there are three constructors; one for use when no
parameters are passed at initialization, another for use when three floating-point
variables are passed, and a third for use when another vector is passed. Thus we
can have the statement:

c = Vector ( 6 , 7 , 8 )

where c as a vector takes on the x,y,z values of 6, 7 , and 8 respectively, and we


can also have:

c = Vector ( )

where c as a vector takes on the x, y, z values of 0, 0, and 0.

47
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

I*

v m a t h . h p p=H e a d e r F i l e f o r T h r e e D i me n s i o n a l V e c t o r M a t h e m a t i c s

*I

#i n c l ude < s t ream . hpp>


#i n c l ude <ma t h . h >

cl a s s Vector I
publ i c :
fl oat x , y , z ·

Vector ( ) ;
Vector ( fl oat xl , fl oat y l , fl oat zl ) ;
Vector ( Vector & ) ;
V e c t o r o p e r a t o r+ ( V e c t o r & ) ;
Vector ope r a t o r - ( Vector & ) ;
Vector ope r a t o r - ( ) ;
V e c t o r o p e r a t o r= ( V e c t o r & ) ;
Vector opera tor* ( Vector & ) ;
Vector ope r a t o r* ( fl oat ) ;
Vector ope r a t o r l ( fl oa t ) ;
fl oat ope r a t o r% ( V ector & l ; I I Dot p roduct
Vector ope rator� ( Vector & ) ; II C ro s s p roduct
V e c t o r o p e r a t o r- ( ) ; I I N o rm a l i z e v e c t o r
Vector mi n ( Vector & ) ;
V e c t o r ma x ( V e c t o r & ) ;
V e c t o r Rot a t e ( f l o a t c o s l , f l o a t s i n l , f l o a t c o s 2 . fl o a t s i n 2 ) ;
V e c t o r R e v_Ro t a t e ( f l o a t c o s l , f l o a t s i n l , f l o a t c o s 2 . f l o a t
s i n2 ) ;
f r i e n d o s t r e a m & o p e r a t o r < < ( o s t r e a m& . V e c t o r & ) ;
v o i d g e t_v e c t o r ( ) ;
};
Figure 4-1 . Vector Mathematics Header File

48
T H R E E D I M E N S I O N A L V E C T O R M AT H E M AT I C S W I T H C + +

Overload ing of Vector Operators


First, we are going to look at the details of the operator overloading for the
Vector class. Refer to Figure 4-2 for the listings. The first two, addition ( +) and
subtraction (-) of two vectors, are very simple. For the first, the values of each
pair of like coordinates are added together. For the second, the value of each
coordinate for the second vector is subtracted from the value of the like
coordinate for the first vector. Now, look at the next function, which i s
overloading o f - fo r a single vector only. This occurs i n expressions like:

c = - a ;

where both c and a are vectors. This will only work because the - operator is
already defined in C++ as being applicable to a single variable as well as the
difference between two variables. Note that if, for some reason, we decided to
use the operator I as the operator for subtraction, we could only use it to define
subtraction between two vectors, since there is no single variable variation of /.

Now, let's look at multiplication (*). We have two overloading definitions of


multiplication. The first is multiplication of two vectors. Each of the three new
vector coordinates is the product of the like coordinates of the two vectors being
operated upon. The second type of multiplication occurs when a vector is
multiplied by a floating-point number. In this case, the new vector coordinates
are the products of the floating-point number with each of the respective
coordinates of the original vector. Note that you can only use expressions like:

a = b * c;

where b is the vector and c is the floating-point number. This won't work if b is
the floating-point number and c is the vector, since we haven 't provided for
overloading in this way. To do so, we would have to overload the multiplication
operator for the class float. Unfortunately, C++ won 't recognize standard
number types as classes, even though they have a lot in common. Next, look at
the operator for defining the dot product of two vectors. The dot product is a

49
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

scalar (floating-point number) obtained by multiplying corresponding pairs of


coordinates for two vectors and taking the sum of these products. In regular C
language mathematics, there is no operator for the dot product, so we have to
select an existing operator that is suitable which we won 't use for something
else. We choose the % operator, ordinarily used for modulus arithmetic. We
won't use any modulus arithmetic with vectors, so it is available for overloading.
It also operates upon two inputs, so it is satisfactory for this operation. Similarly,
we need an operator that we can overload to produce the vector cross-product,
which has no corresponding operation in ordinary arithmetic. We choose the "
operator, which is ordinarily used as a bitwise exclusive or operator by C. We
won 't be doing any exclusive or ' s on vectors, so it is available, and since it
handles two variables, it is suitable for the vector cross product. Look at the
listing of the overload of the " function to see how the vector cross product is
calculated, or refer back to your old book on vector analysis.

*/

#i n c l ude " re n d e r . h pp "

e x t e r n c h a r s t r i n g_b u f [ 3 2 J ;

/*
Vector Constructors

*/

Vecto r : : Vecto r ( )
{
x O;
=

y 0;
z 0;

50
TH REE D I M E N S I O N A L V E C T O R M AT H E M AT I C S W I T H C + +

Vector : : Vector ( fl oat xl , fl oat yl , fl oat zl )


{
x xl ;
=

y yl ;
z z1 ;
=

Vector : : Vecto r ( Vector & otherVector )


{
x othe rVector . x ;
y othe rVector . y ;
z othe rVecto r . z ;
=

/*
Vector Overl oad of + Ope rator

*/

V e c t o r V e c t o r : : o p e r a t o r+ ( V e c t o r & a r g )
{
Vector resul t ;
resul t . x x + a rg . x ;
res u l t . y =
y + a rg . y ;
res u l t . z =
z + a rg . z ;
retu rn res u l t ;

/*
V e c t o r O v e r l oad o f - Ope r a t o r ( a - b )

*/

V e c t o r Vect o r : : op e r a to r - ( Vector & a rg )


{
Vector res u l t ;
res u l t . x x - a rg . x ;
res u l t . y y - a rg . y ;
=

res u l t . z =
z - a rg . z ;
retu rn resul t ;

51
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

/*

I
Vector Ove r l oad of - Ope r a t o r ( - a )

*/

Vector Vector : : ope rato r - ( )


I
Vector res u l t :
resul t . x - x:
res u l t . y=- y;
res u l t . z=- z:
return resul t :

/*
11 "' ° C t o r O v e r l o a d o f * O p e r a t o r ( V e c t o r T i me s a V e c t o

*/

Vector Vector : : ope r a t o r* ( Vector & a rg )


I
Vector res u l t :
resul t . x x * a rg . x :
res u l t . y= y * a rg . y ;
re s u l t . z
= z * a rg . z ;
return resul t :

/*
V e c t o r O v e r l oad of * Ope r a t o r ( Ve c t o r T i mes a F l oa t )

*/

Vector Vector : : ope r a t o r* ( fl oat a rg )


I
Vector resul t :
res u l t . x x * a rg ;
res u l t . y=y * a rg ;
res u l t . z=z * a rg ;
return res u l t :

52
T H R E E D I M E N S I O N A L V E C T O R M AT H E M AT I C S W I T H C + +

/*
V e c t o r O v e r l o a d o f I O p e r a t o r ( V e c t o r D i v i d e d by a F l o a t )

*/

V e c t o r Vecto r : : ope r a t o r / ( fl o a t a rg )
{
Vecto r res u l t ;
res u l t . x x I a rg ;
res u l t . y = y I a rg ;
re s u l t . z = z I a rg ;
return res ul t :

/*
Vector Overl oad of Ope r a t o r

*/

V e c t o r V e c t o r : : o p e r a t o r= ( V e c t o r & r v a l u e )
{
x = rva l ue . x :
y rva l ue . y ;
z rva l ue . z ;
return *thi s ;

/*
V e c t o r O v e r l o a d o f % O p e r a t o r ( D o t P r o d u c t o f Two V e c t o r s )

*/

fl o a t V e c t o r : : ope r a t o r % ( V e c t o r & a rg )
{
fl oat resul t ;
res u l t = x*a rg . x + y*a rg . y + z*a rg . z :
return resul t ;

/* ctor Overl oad of A O p e r a t o r ( C ro s s P r o d u c t o f Two V e c t o r s )

53
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

*/

Vector Vector : : ope ratorA C Vector & a rg )


{
Vector resul t ;
res ul t . x y*a rg . z z*a rg . y ;
res u l t . y = z*a rg . x x*a rg . z ;
res u l t . z = x*a rg . y y*a rg . x ;
retu rn resul t ;

I*
V e c t o r O v e r l o a d o f - O p e r a t o r ( N o rm a l i z e a V e c t o r )

*/

V e c t o r V e c t o r : : o p e r a t o r- ( )
{
Vector resul t ;
fl oat l ;

l = *thi s % *thi s ;
l = s q rt ( l ) ;
resul t . x x/l ;
resul t . y = y / l ;
res ul t . z = z / l ;
return resul t ;

I*
max Re t u r n t h e m a x i m u m o f t w o v e c t o r s

*/

Vector Vecto r : : ma x ( Vector & a rg )


{
Vector resul t ;

resul t . x MAX ( x , a rg . x ) ;
resul t . y MA X ( y , a r g . y ) ;
resul t . z MA X C z , a r g . z ) ;
ret u rn res ul t ;

54
T H R E E D I M E N S I O N A L V E C T O R M AT H E M AT I C S W I T H C + +

/*
mi n R e t u r n t h e m i n i m u m o f two v e c t o r s

*/

Vector Vecto r : : mi n C Vector & a rg l


{
Vector resul t ;

re s u l t . x M I N C x , a rg . x ) ;
resul t .y M I N C y , a rg . y ) ;
resul t . z M I N C z , a rg . z l ;
return resul t ;

/*
Rot a t e a Vector

*/

Vector Vecto r : : Rotate ( fl o a t c o s l , fl o a t s i n l , fl oat cos2 , fl oat


si n2 )

V e c t o r t emp , re s u l t ;

resul t . x = x * cos l + z * -sinl ;


temp . y = y;
temp . z = x * sinl + z * cos l ;
re s u l t . y = temp . y * - co s 2 + temp . z * s i n 2 ;
resul t . z = temp . y * - s i n 2 + temp . z * - co s 2 ;
return ( resul t ) ;

/*
Re v e r s e R o t a t e a V e c t o r

*/

V e c t o r V e c t o r : : R e v_R o t a t e C f l o a t c o s l , f l o a t s i n l , f l o a t c o s 2 ,
fl oat s i n 2 l

55
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

Vector temp , r e s u l t :

temp . x x·
resul t .y = y * cos2 + z * -sin2 :
temp . z = y * s i n2 + z * cos2 ;
re s u l t . x= temp . x * - c o s l + t em p . z * s i n l :
re s u l t . z= temp . x * - s i n l + temp . z * - cos l :
return ( res u l t ) ;

I*
Pri nt Out Vector Contents

*/

o s t r e a m & o p e r a t o r < < ( o s t r e a m& s , V e c t o r & a r g )


{
s < < " ( " < < a rg . x < < << a rg . y < < " , " << a rg . z << " ) " ;
return s :

/*
G e t V e c t o r f r om i n p u t f i l e

*/

v o i d V e c t o r : : g e t_v e c t o r ( )
{
g e t_s t r i n g ( s t r i n g_b u f ) ;
x = a t o f ( s t r i n g_b u f ) ;
g e t_s t r i n g ( s t r i n g_b u f ) ;
y = a t o f ( s t r i n g_b u f ) ;
g e t_s t r i n g ( s t r i n g_b u f ) ;
z = a t o f ( s t r i n g_b u f ) ;

Figure 4·2. Vector Mathematics Function File

56
T H R E E D I M E N S I O N A L V E C T O R M AT H E M AT I C S W I T H C + +

Next look at the operator used to normalize a vector. In this case, we want
an operator that accepts only one input parameter. The - normally gives the user
the complement of an integer, but is also overloaded to be the destructor for an
object. U sing it for the normali ze operati on means that we won ' t have a
destructor for vectors, but this doesn 't really present a problem, since we aren't
going to be creating a lot of vectors that have to be removed from memory at
some later point. Normalization simply divides all components of the vector by
its magnitude so that the resulting vector has a magnitude of one.

Other Vector Functions


We now come to some functions that are a part of the Vector class, but don't
make use of operators. The first two are the max and min functions. If you are
thinking in strictly mathematical terms, you may be wondering exactly what is
meant by the m a x i m um of two vectors or the minimum of two vectors .
However, the use to which we put these two functions in the ray tracing program
i s such that what we want for the max function i s a vector each of whose
coordinates is the maximum of that coordinate in the two vectors being tested -
and similarly for the min function, a vector each of whose coordinates is the
minimum of that coordinate for the two vectors being tested. That is what these
functions provide.

Next we have two rotation functions. The first rotates the vector a specified
angle around the y axis and then another specified angle around the x axis. The
second rotates in the reverse direction, first by a specified angle around the x
axis and then by a specified angle around the z axis.

The print function is an overload of the << operator of the ostream class to
make it possible to use cout, for example, with vectors as well as other types of
data.

The form in which the vector is output is a starting parenthesis, followed by


the three floating-point coordinates (separated by commas), followed by a close
parenthesis. How this type of overloading is done was explained in the previous
chapter.

57
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

Finally, there is a special function called get_vector. This function reads


three strings from the incoming data stream. How these strings are read will be
discussed in Chapter 8 . Each string is converted to a floating-point number and
is then assigned to a vector coordinate in order. Thus this function concludes
with having set the designated vector to the three values read from the file.

58
CHAPTE R 5

Ray Tracing Object


Structures
At this point, we have learned enough about C++ so that we are ready to
begin creating a ray tracing program. We first need to decide how we are going
to handle object information and then set up some mechanisms for doing this
handling. Traditionally, such information is kept in a header file. The header file,
which is called render.hpp, will be a part of every ray tracing file. This header
file is listed in Figure 5 - 1 .

The header begins with a number of #define statements. These are strictly
for convenience in understanding the software. When we get into the subject of
communicating with the ray tracer (Chapter 8 ) we ' ll see that the heart of
communication is reading a string from a data file and comparing it with all
acceptable strings and a s s i gn i n g a type . The type i s simply a number
corresponding to the position of the matching string in the array. As we proceed
further with the input process, we often set up switch statements that take
different actions depending upon which type a string is. If the switch statement
simply provided different actions for different type numbers , it would be
obscure. We would have to go back to the string array each time to determine
which type of object we were dealing with. To clarify this whole process, for
each type we have defined a title that essentially matches the original kind of
string to be equal to the type number (the position in the array). Thus in a switch
statement, we can give this title instead of the number, and the user can identify
what type of string is being processed.

Next, we define some constants that will be used throughout the program.
Most of them are self-evident. A few need to be set up in the main program; we
list them here as extern so that they will be passed as global variables.

59
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

/*
Heade r Fi l e for Ray T ra c i ng P rogram
By R o g e r T . S t e v e n s 3/1 /90
-

*/
#i n c l ude <stdl i b . h>
#i n c l ude <stdi o . h>
#i n c l ude <ma t h . h >
#i n c l ude "vmath . hpp"

I*
Obj ect Defi n i t i on s

*/

#de f i n e P A T T_H E A D E R 0
#d e f i n e L I NE 1
#d e f i n e SPHERE 2
#de f i n e P A RA L L E L O G RAM 3
#d e f i n e T R I ANGLE 4
#d e f i n e LAM P 5
#d e f i n e O B S E RV E R 6
#d e f i n e G RO U N D 7
#d e f i n e S KY 8
#d e f i n e BBOX 9
#de f i n e R I NG 10
#d e f i n e Q U A D RAT I C 11
#d e f i n e B E G I N_B B O X 12
#d e f i n e E N D_B B O X 13
#d e f i n e B E G I N_ I N S T A N C E S 14
#d e f i n e E N D_ I N S T A N C E S 15
#d e f i n e AMB 16
#d e f i n e D I FF 17
#d e f i n e M I RROR 18
#d e f i n e TRANS 19
#d e f i n e D E N S I TY 20
#d e f i n e I NDEX 21
#d e f i n e D I TH E R 22
#d e f i n e SREFLECT 23
#de f i n e REFLECT 24
#d e f i n e LOC 25
#d e f i n e RAD I U S 26

60
R AY T R A C I N G O B J E C T ST R U CT U R E S

#d e f i n e PAt t e r n 27
#d e f i n e REMO V E 28
#d e f i n e XMU LT 29
#d e f i n e YMU LT 30
#d e f i n e NAME 31
#d e f i n e D I ST 32
#d e f i n e L O O KAT 33
#de f i n e Vl 34
#de f i n e V2 35
#d e f i n e Z E N I TH 36
#d e f i n e HOR I Z 37
#d e f i n e R A D_ l 38
#d e f i n e R A D_2 39
#d e f i n e A 40
#d e f i n e B 41
#d e f i n e c 42
#d e f i n e D 43
#d e f i n e E 44
#d e f i n e XMAX 45
#d e f i n e YMAX 46
#d e f i n e ZMAX 47
#d e f i n e XM I N 48
#d e f i n e YM I N 49
#d e f i n e ZM I N 50
#d e f i n e DIR 51
#d e f i n e FOC_L E N GTH 52
#d e f i n e F I R S T_S C A N 53
#de f i n e D E FA U L T 54
#d e f i n e F I L E_ N A M E 55
#de f i n e L A S T_S C A N 56
#d e f i n e XRES 57
#d e f i n e YRES 58
#d e f i n e X_S I Z E 59
#d e f i n e Y_S I Z E 60
#d e f i n e S T A R T_ X 61
#d e f i n e S T A RT_Y 62
#d e f i n e E N D_X 63
#d e f i n e E N D_Y 64
#d e f i n e P A REN 65
#d e f i n e N O_S H A D O W 66
#d e f i n e N O_ L A M P 67
/td e f i n e THRESHOLD 68

61
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

#d e f i n e UP 69
#d e f i n e I N STAN C E O F 70
#d e f i n e SCALE 71
#d e f i n e RE CTAN G L E 72
#d e f i n e C I RC L E 73
#d e f i n e PO LYGON 74
#d e f i n e CO LOR 75
#d e f i n e PO I NT 76
#d e f i n e CONE 77
#d e f i n e H E I GHT 78
#d e f i n e F R AC T A L 79
#d e f i n e D I MENS I ON 80
#d e f i n e SCA LAR 81
#d e f i n e NUl l 82
#d e f i n e l a s t_n o 83

I*
U s e f u l Con s t a n t s

*I

#d e f i n e T R U E 1
#d e f i n e FA L S E 0
#d e f i n e S M A L L 0 . 00 1
#d e f i n e A S P E C T 1 .0 II a s pect rati o
#d e f i n e C N U M 63 II n umber o f s h a d e s of c o l o r mi n u s o n e
#d e f i n e M A X_ I X 4 II maxi mum x i n t e r p o l a t i on
#d e f i n e M A X_ I Y 4 II maxi mum y i n t e r p o l a t i on
#d e f i n e m a x_p i x e l 800 II m a x o f R G B a r r a y s i z e ( d o t s p e r r ow )
extern i nt XS I ZE ;
extern i nt YSI ZE ;
extern i n t C ENTERX ;
e x t e r n i n t C E N T E RY ;
e x t e r n i n t X S I Z E4 ;

I*
Col o r Data Defi n i t i on s

*I

62
R AY T R A C I N G O B J E C T S T R U CT U R E S

c l a s s c o l o r_d a t a
{
publ i c :
Vector amb , I I amb i e n t l i g h t i n g
d i ff . I I d i ff u s e l i g h t i ng
mi rror . I I % l i g ht refl ected
trans . I I % l i g h t t r a n s m i t t ed
d e n s i ty ; I I d e n s i ty
fl oat refl ect . I I p e r c e n t s p e c u l a r l y refl ec ted
i ndex ; I I i n dex i f refract i on
short s refl ect , I I s pecu l a r refl coeffi c i ent
di ther ; I I col o r di theri ng
c o l o r d a t a o p e r a t o r= C c o l o r_d a t a & ) ;
l ;

I*
C l a s s defi n i t i on for Li ne

*I

cl ass Li ne
{
publ i c :
Vector l oc , d i r ;
i nt fl ag ;
l ;

I*
C l a s s defi n i t i on f o r Lamp

*I

c l a s s Lamp
{
publ i c :
Vector l oc ;
fl oat radi us . di stance ;
L a m p * n e x t_ l a m p ;
l ;

I*

63
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

Cl a s s defi ni ti on for a Pattern

*I

cl ass Pattern
{
publ i c :
short type : II type of pattern
fl oat xsi ze . II pattern s i ze i n x d i rect i on
ysi ze , II pattern s i ze i n y d i rect i on
sta rtx , II x c o o rd i n a te s t a r t i n g po s i t i on
s t a rty , II y coord i n a te s t a rt i ng pos i t i on
endx , II x c o o rd i n a t e en d i ng po s i t i on
e n dy , II y c o o rd i n a te end i ng po s i t i on
radi us ; II radi us of ci rcl e pattern
c o l o r_d a t a c o l _d a t a : II c o l o r i n forma t i on
char n a me [ 3 2 J ; II n a me o f p a t t e r n
Pattern *chi l d ,
*s i bl i ng ,
*l i n k :
};

I*
C l a s s Defi n i t i on s for Obj ect

*I

c l a s s Obj ect
{
publ i c :
unsi gned c h a r type , I I obj ect type
fl ag :
cha r n a me [ l 6 J ; I I o b j e c t n a me
Vector l OC , I I obj ect l oc a t i on
vectl , I I t h ree vectors
vect2 ,
vect3 .
l ow e r , I I l owe r b o u n d
uppe r , I I uppe r bound
n o rm :
fl oat c t e rm , I I u s ed for q u a d r a t i c

64
R AY T R A C I N G O B J E CT S T R U C T U R E S

II s u r f a c e s on l y
xm u l t . II x mul t i pl i e r for
II patterns
ymul t , II y mu l t i p l i e r f o r
II pattern
nl , II p r e c om p u t e d v a l u e s
l en 1 ,
l en2 ,
cosl .
sin1 ,
cos2 ,
si n2 :
c o l o r_d a t a * c o l _d a t a : I I c o l o r i n f o rma t i o n
Obj ect *nextobj , I I addr o f next obj ect i n l i st
*c h i l d : I I add res s of c h i l d for
II bound i ng boxes
Pattern *pattern , I I a d d r of pattern s t ructure
* r em o v e : I I a d d r e s s o f s t r u c t t o r e mo v e
I I obj s e c t i on
O b j e c t o p e r a t o r= ( O b j e c t & ) :
v i r t u a l v o i d F i n d N o r m ( V e c t o r * n o rma l , V e c t o r * p o s i t i o n ) :
v i rtua l v o i d Po s i t i on ( f l oa t * po s l , fl oat *pos 2 , Vector
*l ocat i on ) :
v i r t u a l i n t Col l i s i onTes t ( Li ne * l i ne , f l oat *t ) :
v i rtua l v o i d F i nd Bbox ( Vector * v l . Vector * v2 ) :
v i r t u a l v o i d S c a l e_ I n s t a n c e ( V e c t o r *mu l t , i n t f f l a g ) ;
}:

c l a s s Sphere : publ i c Obj ect


{
publ i c :
Sphere ( ) :
v o i d F i n d N o r m ( V e c t o r * n o rma l , V e c t o r * p o s i t i o n ) ;
v o i d P o s i t i o n ( f l o a t * po s l , f l o a t * p o s 2 , V e c t o r * l o c a t i o n ) ;
i n t Co l l i s i onTe s t ( Li n e * l i n e . fl oat *t ) ;
voi d Fi ndBbox ( Vector * v l . Vector * v2 ) ;
v o i d S c a l e_ I n s t a n c e ( V e c t o r * m u l t , i n t f f l a g ) ;
l :

c l a s s T r i a n g l e : publ i c Obj ect


{
publ i c :

65
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

Tri angl e( ) :
v o i d F i n d N o rm ( V e c t o r * n o rm a l , V e c t o r * p o s i t i o n ) ;
v o i d Pos i t i on ( f l o a t * pos l , f l o a t *po s 2 . Vector * l oca t i on ) :
i n t Col l i s i onTest ( L i n e * l i ne , fl oat *t ) ;
voi d Fi ndBbox ( Vector * v l , Vector * v 2 ) ;
v o i d S c a l e_ I n s t a n c e ( V e c t o r *m u l t , i n t f f l a g ) ;
}:

c l a s s Pa ra l l e l ogram : publ i c Obj ect


{
publ i c :
Para l l el ogram( ) ;
v o i d F i n d N o r m ( V e c t o r * n o rm a l . V e c t o r * p o s i t i o n ) :
v o i d P o s i t i o n ( f l o a t * po s l , f l o a t * p o s 2 , V e c t o r * l o c a t i on ) :
i n t Col l i s i onTes t ( Li ne * l i ne , fl oat *t ) ;
v o i d Fi ndBbox ( Vector * v l , Vector * v 2 ) :
v o i d S c a l e_I n s t a n c e ( V e c t o r *m u l t , i n t f f l a g ) ;
}:

c l a s s Ri ng : publ i c Obj ect


{
publ i c :
Ri ng ( ) ;
v o i d F i n d N o r m C V e c t o r * n o rma l , V e c t o r * p o s i t i o n ) ;
v o i d P o s i t i o n ( f l o a t * p o s l , f l o a t * p o s 2 , V e c t o r * l o c a t i on ) :
i n t Col l i s i onTest ( L i n e * l i ne , fl o a t *t ) :
voi d Fi ndBbox C Vector * v l , Vector * v 2 ) :
v o i d S c a l e_ I n s t a n c e ( V e c t o r *m u l t , i n t f f l a g ) ;
}:

c l a s s Quad ra t i c : publ i c Obj ect


{
publ i c :
Quad rati c ( ) ;
v o i d F i n d N o r m C V e c t o r * n o rm a l , V e c t o r * p o s i t i o n ) ;
v o i d Po s i t i on ( fl o a t * pos l , fl o a t *pos 2 , Vector * l oca t i on ) ;
i n t Col l i s i onTe s t C L i ne * l i ne , fl oat *t ) ;
voi d Fi nd Bbox C Vector * v l , Vector * v2 ) ;
v o i d S c a l e_ I n s t a n c e C V e c t o r *m u l t , i n t f f l a g ) ;
}:

c l a s s BBox : publ i c Obj ect

66
R AY T R A C I N G O B J E C T S T R U C T U R E S

i n t C ol l i s i onTe s t ( L i n e * l i n e , fl oat *t ) ;
voi d Fi ndBbox ( Vector * v l , Vector * v2 ) ;
I ;

I*
Structure for the Worl d

*I

ty p e d e f s t r u c t wo r l d
{
Obj ect * stack , II l i s t of obj e c t s i n
II pi cture
* i nstances ; II l i st of user defi ned
II pri mi ti ves
Lamp * l amps ; II l i s t o f l a mp s
Li ne * l i ne ;
i nt obj count . II n um b e r o f o b j e c t s
l a mp c o u n t , II n umbe r o f l amps
f i r s t_s c a n , II fi rst scan l i ne
l a s t_s c a n ; II l ast scan l i ne
l ong r a y_ i n t e r s e c t s , II stati sti cs
p r i m a ry_t r a c e d ,
t o_ l a m p ,
r e f l _t r a n s .
b b o x_i n t e r s e c t s .
i n t e r s e c t_t e s t s ,
p i x e l s_h i t ,
p a t t e r n_ma t c h e s ;
Vector obs ri ght , II obs e r v e r r i ght d i rect i on
obsup , II observer u p di recti on
obsl oc , II l ocati on o f observer
obsdi r , II di recti on i n whi ch observer
II l oaks
s ky c o l o r_h o r i z , II s ky c o l o r a t h o r i z o n
s ky c o l o r_z e n i t h ; II s ky c o l o r a t z e n i t h
fl oat s ky_d i t h e r ;
Pattern * pa tl i st ; I I l i s t o f pattern add res s e s
fl oat fl ength . 11 fo c a l l e n g t h
g l obi ndex ; 1 1 g l oba l i ndex of
II refra c t i on

67
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

cha r outfi l e[32J : I I o u t p u t f i l e n a me


FI LE *fi l ept : I I output fi l e poi nter
fl oat t h reshol d :
fl oat i n t_t h r e s h o l d ,
f r a c t a l _d i m ,
f r a c t a l _s c a l a r :
i nt l evel :

Wo r l d :

I*
M a t h Defi n i t i on s

*I

#d e f i n e MIN(x,y) ( (x)<(y) ? (x) (y ) )


#d e f i n e MA X ( x , y ) ( ( x ) > ( y ) ? (x) (y ) )
#d e f i n e M a x ( x , y , z ) ( x >y & & x>z ? x ( y>z ? y z))
#d e f i n e M i n ( x , y , z ) ( x <y && x<z ? x : ( y<z ? y z))

I*
S t r u c t u r e of Defa u l t V a l ues

*I

t y p e d e f s t r u c t d e f_s t r u c t
{
c o l o r_d a t a c o l _d a t a : II defa u l t col o r i n fo
short s h a d ow : II c o mp u t e s h a d ow s ?
fl oat th reshol d : II cutoff poi n t for mi n refl ,
II refl rays
short i threshol d : II i n teger v e r s i on o f a bove

DEF ;

I*
Setup of V a r i abl es

68
R AY T R A C I N G O B J E C T S T R U C T U R E S

*I

exte r n Wo r l d WORLD : I I t h e wo r l d o f o b j e c t s i n t h e s c e n e
ex t e r n D E F def : I I d e f a u l t v a l u e s f o r s ome p a r a m e t e r s
extern i n t l i n e n umbe r : I I l i ne counter

I*
Funct i on Prototypes for RENDER . C

*I

voi d i n i t_w o r l d ( v o i d ) :
voi d i n i t_c o l o r ( v o i d ) :
voi d W o r l d_S t a t s ( v o i d ) :
voi d O p e n_ F i l e ( ) ;
voi d C l o s e_ F i l e ( ) :
voi d s c a n ne r ( Obj ect * test ) ;

I*
F u n c t i o n P r o t o ty p e s f o r I N P U T . C

*I

P a t t e r n * A t t a c h_ P a t t e r n ( ) ;
i n t G e t A t t r i b ( i n t t y p e . c h a r s t r i n g_b u f [ J ) :
P a t t e r n * G e t_C i r c l e_P a t t e r n ( ) ;
i n t g e t_c o l o r_d a t a ( i n t t y p e , c o l o r_d a t a * c o l _d a t a ) ;
O b j e c t * g e t_d a t a ( ) :
i n t Ge t la mp ( ) ;
i nt LoadWo r l d ( ) :
O b j e c t * G e t_O b j e c t ( i n t t y p e . O b j e c t * q u e u e ) :
Obj ect * Get P a ra l l el ogram( ) :
i nt Get Pattern ( ) :
P a t t e r n * G e t_P o l y_P a t t e r n ( ) ;
P a t t e r n * G e t_ R e c t_ P a t t e r n ( ) :
Obj ect * GetRi ng ( ) :
Obj ect * GetSphere ( ) ;
i n t g e t_s t r i n g ( c h a r s t r i n g_b u f [ J ) :
P a t t e r n * G e t_S u b P a t t e r n ( i n t t y p e ) ;

69
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

Obj ect * GetT r i a n g l e ( ) ;


O bj e c t * GetQ u a d r a t i c ( ) ;
v o i d M a k e_B b o x ( O bj e c t * n o d e ) ;
O b j e c t * N a me_ F i n d ( O b j e c t * o b j . c h a r * n a me ) ;
O b j e c t * M o v e_ I n s t a n c e ( O b j e c t * o b j , i n t f f l a g ) ;
v o i d O f f s e t_ I n s t a n c e ( O b j e c t * o b j . V e c t o r * o f f s e t . i n t f f l a g ) ;
O b j e c t * G e t_ I n s t a n c e_O f { ) ;
v o i d F r a c t a l _c om p < T r i a n g l e * n ew o b j ) ;
O b j e c t * M a k e_f r a c t a l _t r i a n g l e s ( V e c t o r l a c , V e c t o r v e c t l , V e c t o r
vect2 . Vector vect3 , Obj ect * queue , i n t l evel ) ;

/*

*/
l�
I =====�
F u n c t i o n P r o t o ty p e s f o r RAY . C

v o i d T r a c e_S c e n e ( ) ;
v o i d D i f f u s e C o l o r ( V e c t o r * c o l o r , c o l o r_d a t a * c o l _d a t a . V e c t o r *
n o rm . V e c t o r * l a c ,
Li ne * ol i ne ) :
v o i d D u mp_ L i n e ( i n t l i n e n o , c h a r r [ J , c h a r g [ J . c h a r b [ J ) :
v o i d Amb i entC o l o r ( V e c t o r * c o l o r . c o l o r_da t a * c o l _d a t a , V e c t o r * n o rm ,
Vector * l ac ) :
v o i d T r a n s p a r e n t C o l o r < V e c t o r * c o l o r . c o l o r d a t a * c o l _d a t a ,
Vector *
n o rm . V e c t o r * l a c ,
Li n e * l i n e . fl o a t i nmu l t ) :
v o i d R e f l e c t C o l o r ( V e c t o r * c o l o r , c o l o r_d a t a * c o l _d a t a . V e c t o r *
n o rm . Vector * l ac ,
L i n e * l i n e . fl o a t i nmu l t ) ;
v o i d S ky C o l o r ( L i n e * l i n e . V e c t o r * c o l o r ) :
voi d Di the r ( Vector * col or . fl oat di ther ) :
v o i d D i t h e r ( V e c t o r * c o l o r , c o l o r_d a t a * c o l _d a t a ) :
O bj e c t * I n t e r s e c t ( Obj e c t * C u r rObj , L i n e * l i n e . f l o a t * s h o r t e s t_t i me .
s h o r t s h a d ow_f l a g , s h o r t i n i t_f l a g , V e c t o r * a t t e n ) :
i n t T r a c e_ R a y ( L i n e * l i n e . V e c t o r * c o l o r . f l o a t m u l t i p l i e r ) :
i n t F i n d_C o l o r ( O b j e c t * o b j . P a t t e r n * p a t t e r n . V e c t o r * l o c a t i o n ,
c o l o r_d a t a * c_d a t a , f l o a t x_m u l t , f l o a t y_m u l t ) :

Figure 5·1 . The render. hpp Header File

70
R AY T R A C I N G O B J E C T S T R U C T U R E S

We ' re now ready to think about handl ing data within the ray trac ing
program. The first C++ class we are going to set up is color_data. This is not a
very intere sting c l a s s , since it c ontains only one embedded function. It
represents all color characteristics that are likely to be associated with an object.
A number of these are defined as vectors, which permits them to be treated with
vector mathematics, although in this case, the three vector components refer to
values of red, green , and blue that make up the color rather than to position data.
All of these values are assumed to vary between zero and the maximum color
value (63).

The first color to be defined is that for ambient light that falls upon the
object. The second color is the diffused color, i.e. , the inherent color of the
object (the color that it is painted, if you will). If you look around at various
objects, you can recognize that you do not actually see the diffuse color of an
object at any point on the object, but rather one that depends upon how the object
is lighted. The next defined color is the mirror color, which is the proportion of
each color reflected by the object. If this is (63, 63, 63), you have a perfectly
reflecting mirror; if it is (0,0,0), which is the default value, the object has no
mirror-like quality. Other values can cause partial or colored mirror reflection.
The next color is the transparency value. It defines the percentage of each color
transmitted through a transparent object. Next comes the density factor, which
determines how light of each color is attenuated as it passes through a semi­
transparent object. These are all of the color vectors associated with an object.

In addition, the color-data class contains a floating-point number which is


the percentage of light specularly reflected from an object, and a floating-point
number which is the index of refraction. There are also short integers which
give the specular reflection coefficient and the dithering value. These will be
discussed in Chapter 9.

The Concept of Li nked Lists


Before we continue, we need to discuss the concept of linked lists, which is
essential to an understanding of how to handle lines, objects, light sources, etc.
Let's look at linked lists in the context of how we are going to list objects, so that

71
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

later on the ray tracing program can scan them and determine what to do about
intersecting a ray with each object.

We begin by having a list containing no objects, indicated by a variable


called WORLD .stack containing a NULL. We now create an object by setting up
the data space for it and filling in some data values. Then we take the content of
WORLD.stack and put it into a variable in the object containing the address of
the next object. After that, we put the address of the beginning of the data area
for our first object into WORLD.stack. We repeat this process until we generate
all the objects we need.

Now let's see what happens when we want to retrieve data from this list of
objects. We first go to the address specified by WORLD.stack. There, we find
the data for the last object we generated and process that. Then, we go to the
address specified by the next_object variable in this object. There we find the
data for the next-to-last object we created and process it. We continue this
process until, after we have processed data for the first object generated, we find
that the next object variable contains a NULL, which is a signal for us to quit
since we have come to the end of the list. This is basically how a linked list
works.

However, sometimes things are a little more complicated. Suppose there are
several objects we only want to process if a certain criterion is met. For
example, in attempting to intersect arrays with objects, we often draw a box
around several objects. The data for the box are in our main list. If a light ray
intersects this box, we want to go ahead and process the list of objects that are
within the box; otherwise, we want to ignore them and continue down the main
list. We get around this by having a variable for each object called child.

Now, when we get to the point where we generate the box object, we put the
address of the next main object in the next_object variable as usual, but we put a
NULL in the child address variable. Then we process each of the objects that are
enclosed in the box, each time taking the address from the child address variable

72
R AY T R A C I N G O B J E C T S T R U C T U R E S

and putting it into the next_object address of the current object. We take the
address of the current object and put it into the child address variable of the box.
Now when we process data, each time we meet some preestablished criterion, we
take the address from the associate child address variable and process the data
from that object. We then proceed normally through the list of objects in the
box. But when we come to a NULL, which indicates that we are through with
them, we don 't quit, but go back to the box that had the original child address
and p i c k up the addre s s in the n ext_ object v ariabl e . We then continue
processing.

This procedure adds a nice technique for branching in the list scanning
process. How this all works out for the ray tracing program is shown in Figure
5-2. We pick up the address of the first object in the variable WORLD.stack.
After processing it, we get the next object address from next_object. This
process continues until we come to a bounding box. This has an address in
child. We then branch off and continue the usual process until we hit a NULL
address. We then go back up to the bounding box and pick up its next_object.
When we come to a NULL address in the main stream, the entire process
terminates.

Li nes, Lamps, and Patterns


The next class defined in the header is the Line class. It is one of the simpler
classes, simply containing vectors representing the location and direction of a
light ray, a flag to indicate whether it is inside or outside of a transparent object,
and variables to contain the next line and child addresses.

Following this, the Lamp class is defined. This is used for all of the light
sources that are illuminating the scene. It consists simply of vectors defining the
location of the light source, the radius of the light source, and an address for the
next lamp, to permit this to be a linked list. The radius is actually an overkill,
since we won't be concerned about the radius of the light source in this version
of the ray tracing program. For one thing, in all of the demonstration pictures we
are careful to define all of the light sources so that they are located outside of the

73
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

picture. In the future, we might want to include lamps within the picture itself,
in which case more details of the lamp characteristics would have to be included
and treated by the program.

Next is the class definition of a Pattern. The pattern can be a rectangle, a


circle, or a polygon. Its parameters include type, size, starting/ending points in
the x and y directions, radius (if a circle), complete color data, name, and child,
sibling and link address v ariables to permit linked lists. The pattern is a
definition of a surface which is projected onto one of the objects described in the
next paragraph.

Objects and Derived Classes


The next class, the Object class, is the most complex and most important
class of all. First, if you are familiar with other object-oriented languages, note
that this is a class of geometric objects, and is not to be confused with standard
root Object found in Smalltalk and some other object-oriented languages. We
start with the base class, all of whose members are public. It begins with the
type of obj e c t , then a m i s c e l l aneous fl ag , then a n ame ( w h i c h i s u sed
infrequently), then the vector defining the location of the object, then three
vectors which are used differently for different kinds of objects to define the
object extent and shape, then upper and lower bounds of the object, and finally
an object normal vector. Following this are four floating-point numbers, cterm
and yterm used only by quadratic objects, and the x and y multipliers which are
applied to a pattern before it is mapped to the surface of the object. Following
this are a series of floating-point variables that are used in rotating the object or
intersecting it with a ray of light. All of these variables have a fixed value for a
particular object which doesn't vary for different light rays. Consequently, they
are calculated as soon as the object is entered into the data base and stored in the
object structure. Next comes the address of the color data for the object and then
address variables for the next object and child to complete the linked list. Finally
are addresses for the pattern to be applied to this object and for any part of the
object that is to be removed.

74
R AY T R A C I N G O B J E C T ST R U CT U R E S

The next line is a prototype for the overloading of the = operator to apply to
objects. As previously mentioned, it should not be necessary to overload the =
operator; this should be done automatically for each class that i s created.
However, a current bug in the Zortech C++ compiler makes it necessary to do
this overloading. Then comes a list of prototype virtual functions.

A virtual function is defined for the base class, but it can be redefined for
each class that is derived from the base class. The function can be called as if we
were calling the base class function, and yet the compiler automatically selects
whichever redefined version of the function is appropriate to the derived class
that we are concerned with.

Now, you're wondering what a derived class is. A derived class is a new
class which inherits all of the data members and member functions from one or
more classes that have been previously defined. It is set up in C++ in this
manner;

c l a s s Sphere : publ i c Obj ect


{
. . . addi t i ona l contents of cl a s s
} ;

In this case, Sphere is the new class. It has all the member variables and
member functions of the class Object, which has already been defined. If you
look at Figure 5- 1 , you ' ll see that we have defined six new derived classes, one
for each of five types of primitive objects and one for bounding boxes. Each
derived class has all of the characteristics of the base class. In addition, within
each class description you will see prototypes for each redefinition of each
virtual function that is redefined for this class. In Chapter 8, we will list these
redefinitions and describe how these functions are used in further detail.

The Wo rld Accord ing to Ray Tracing


The next section of the header file contains a definition of the World
structure. The world, as far as ray tracing is concerned, contains the addresses

75
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

WORLD.stack

I
PARALLELOG RAM
child
next_object

I
SPHERE
child
next_object

I
BBOX
child
next_object

I
QUAD RATIC TRIANGLE
child child
next_object next_object

I
PARALLELOG RAM SPHERE
child child
next_object next_object

I
N U LL N U LL

Figure 5-2. Linked List for Ray Tracing Program

76
R AY T R A C I N G O B J E C T S T R U CT U R E S

for the beginning of the stack (which is the list of objects), the address for the
beginning of instances (which will be described in Chapter 6), the beginning of
the list of lamps and the beginning of the list of lines. A count of the number of
objects and lamps is also kept. Next are variables to store a number of statistics
that are collected during the course of rendering a particular scene and data on
the observer and the sky. This is followed by a list of the addresses of all
patterns. Finally comes the focal length, a global index of refraction, the output
file name and pointer, and two threshold parameters . The focal length is
supposed to be set up to be similar to a 35 millimeter camera, so that if you enter
50 (a 50 mm lens is a normal lens) you will get a normal perspective of the
scene.

Add itional Parameters


Continuing with the header fi l e , we have a couple of definitions for
obtaining the maximum and minimum of two numbers, then a structure of some
default values. This is followed by the actual world and default structures and
the definition of linenumber, which counts the number of lines of input data read
into the program. Finally, the header includes prototypes of all of the functions
that are created in each section of the ray tracing program. C++ is more picky
about prototype definition than C, and this is all for the good, since intermixing
methods of declaring a function prototype c an yield some weird results.
Anyway, it's good programming practice to put all the prototypes in the header,
which supplies a place to look when you know a function name but not its
location.

77
CHAPTER 6

Rendering the
Scene An Overview
In this chapter, the contents of the file render.cpp are described. The file
principally contains the main program for rendering scenes using the ray tracing
technique . This file is listed in Figure 6- 1 . It gives an overview of the ray
tracing program. Once we have the overview we will look in more detail at the
functions that do the detailed processing. This takes place in later chapters. At
the very beginning of the render.cpp file, a few parameters are initialized. These
include the parameters XSIZE and YSIZE which define the size of the display
screen in pixels. These are default values; you can override them by putting in
new parameters for XRES and YRES in your scene data file. You will want to do
this if you are using a standard VGA card, since the VGA resolution is 320 by
200 pixels, whereas the default values in the program are for a high resolution
super VGA mode of 640 by 480 pixels.

Next we define the function init_world. This function simply provides


default values for the parameters of the WORLD structure. Following this is
init_color, which prov ides defau lt v alues for the color data parameters .
Remember from the previous chapter that these default values are used for any
color parameters not specified in a particular object definition. Remember also
that using the COLOR string in your data file can change any of the default color
parameters.

The code for overloading the = operator for the class Object.next appears
next in this file. You 've already encountered the format for overloading of
operators in Chapters 3 and 4. To overload the = operator we simply set each
parameter of one object equal to the corresponding parameter in the other. This
permits us to have a statement like:

79
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

a = b

where a and b are both objects and have the contents of one automatically
transferred to the other. S ince this is a generic overload for the base class object,
it is inherited by all of the classes derived from this base class. If you use it with
a derived class, however, you should be careful to make sure that both a and b
are of the same derived class. In other words, if a is of class Sphere then b must
be of class Sphere also. If this isn't the case, (if a is of class Sphere and b is of
class Parallelogram) you will get a diagnostic telling you that the classes are not
the same and the program won't run. This overloading function is followed by a
similar overloading function for the class of color_data. This overload function
makes it possible to transfer all the color data information from one class
member to another with a simple = statement. It doesn ' t do any harm to
overload the = operator, but it shouldn't be necessary since this is supposed to be
done automatically. With my copy of Zortech C++ the function had to be
specifically overloaded for proper compilation.

/*
R a y t r a c e = S i mp l i f i e d R a y T r a c i n g P r o g r a m
B y Ro g e r T . S t e v e n s - 1 / 6 / 9 0

*/

u n s i g n ed _s t a c k = 3 0 0 0 0 ;
#i n c l ude " rende r . hpp"
#i n c l u d e <dos . h>
#i n c l ude <stri ng . h>

e x t e r n c h a r s t r i n g_ty p e s [ l 2 8 ] [ 3 2 J ;

#d e f i n e MA X X 800
i n t X S I Z E = 640 ;
i n t Y S I Z E = 480 ;
i nt CENTERX XSIZE/2 ;
i n t C E N T E RY YSIZE/2 ;
i n t X S I Z E4 XSIZE/4 ;
i nt i ;

80
R E N D E R I N G T H E S C E N E-AN O V E R V I EW

Worl d WORLD ; I I A l l o f t h e d a t a to be p r o ce s s ed
DEF def ; I I col o r defa u l ts
i nt l i n e n umbe r ;

I* lI�

=====-===II
i n i t worl d ( ) I n i t i a l i z e t h e WO R L D

*I
v o i d i n i t_w o r l d ( v o i d )
{
WO R L D . s t a c k NULL ;
WO R L D . i n s t a n c e s NULL ;
WO R L D . p a t l i s t NULL ;
WO R L D . o u t f i l e [ O ] NULL ;
WO R L D . l a m p s NULL ;
WO R L D . l i n e NULL ;
WO R L D . o b j c o u n t O;
WO R L D . l a m p c o u n t O;
WO R L D . f l e n g t h 250 ;
W O R L D . f i r s t_s c a n 0;
W O R L D . l a s t_s c a n YSIZE- 1 ;
WO R L D . ob s u p = V e c t o r ( 0 , 1 , 0 ) ;
WO R L D . ob s l o c = V e c t o r ( 5 0 , 7 0 , 1 1 5 ) ;
W O R L D . s ky c o l o r_z e n i t h = V e c t o r ( ) ;
W O R L D . s ky c o l o r_h o r i z =V e c t o r ( ) ;
W O R L D . s ky_d i t h e r = O ;
W O R L D . r a y_i n t e r s e c t s
W O R L D . p i x e l s _h i t
W O R L D . p r i m a ry_t r a c e d
W O R L D . t o_ l a m p
WO R L D . refl t r a n s
WO R L D . bbox i n t e r s e c t s
W O R L D . p a t t e r n_m a t c h e s
W O R L D . i n t e r s e c t_t e s t s 0;
WO R L D . g l o b i n d e x = 1 . 00 ;
WO R L D . t h re s h o l d = . l ;
W O R L D . i n t_t h r e s h o l d = WO R L D . t h r e s h o l d * C N U M ;
WO R L D . f r a c t a l _d i m = 0 . 9 ;
WO R L D . l e v e l = 4 ;
W O R L D . f r a c t a l _s c a l a r = 0 . 0 0 2 ;

81
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

/*
i n i t_c o l o r ( ) Sets up defa u l t col o r d a t a

*/

v o i d i n i t_c o l o r ( v o i d )
{
def . col data . trans Vector ( ) :
d e f . c o l _d a t a . m i r r o r Vector ( ) :
d e f . c o l _d a t a . a m b Vector ( 25 , 25 , 25 ) :
def . col data . d i ff Vecto r ( 48 , 2 7 , 9 ) ;
d e f . c o l _d a t a . d e n s i ty Vecto r ( . 01 . . 01 . . 01 ) :
d e f . c o l _d a t a . i n d e x CNUM ;
def . col data . di ther 3:
def . col data . refl ect 0:
def . col data . s refl ect 10 :
d e f . s h a d ow = T RU E :

/*
O v e r l o a d of ' = ' ope r a t o r fo r Obj e c t c l a s s

*/

O b j e c t O b j e c t : : o p e r a t o r= ( Q b j e c t & r v a l u e )
{
ty p e = r v a l u e . ty p e ;
s t r c py ( n a m e , r v a l u e . n a me ) :
l oc = rva l ue . l oc :
vectl rva l ue . vectl ;
vect2 rva l ue . vect2 :
vect3 rva l ue . vect3 :
l ow e r r v a l u e . l ow e r :
uppe r r v a l ue . uppe r :
n o rm = r v a l u e . n o rm :
c t e rm r v a l u e . c t e rm :
y t e rm r v a l u e . y t e rm :
xm u l t r v a l u e . xm u l t :
ymu l t rv a l ue . ymu l t :
n l = rval ue . n l :

82
R E N D E R I N G T H E S C E N E-AN OVERV I EW

l en l rval ue . l en l :
l en2 rva l ue . l en2 :
cos l rval ue . cosl :
sinl rval ue . s i n l :
cos2 rval ue . cos2 :
si n2 rva l ue . s i n2 :
c o l _d a t a = r v a l u e . c o l _d a t a :
n extobj = r v a l u e . n ext obj :
chi l d = rval ue . chi l d :
pattern = rva l ue . pattern :
r e mo v e = r v a l u e . r e m o v e :
ret u rn *thi s :

/*
Overl oad of ' = ' operator for col o r data cl a s s

*/

c o l o r_d a t a c o l o r_d a t a : : o p e r a t o r= ( c o l o r_d a t a & r v a l u e )


{
a m b = r v a l u e . a mb :
d i ff = rval ue . d i ff :
mi r r o r = rva l ue . mi rror :
trans = rva l ue . trans :
d e n s i ty = r v a l u e . d e n s i ty ;
refl ect = r v a l ue . refl ect :
i ndex = rva l ue . i ndex :
s refl ect = r v a l ue . s refl ect :
di ther = rval ue . di ther :
retu rn *thi s :

/*
F u n ct i on to d i s p l ay ray t r a c i n g s t a t i s t i c s

*/

v o i d W o r l d_S t a t s ( )
{
pri ntf(
..
\n ) :
pri ntf(
..
" II 1 1 \n l :
83
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +

pri ntf(
" II Worl d Stat i s t i cs 1 1 \n" l :
pri ntf(
.. 1 1 ..
1 1 \n l :
pri ntf(
" II Obj e ct s : %4d l l \n" .
WORLD . obj count ) ;
pri ntf(
" II Lamp s : %4d l l \n" ,
WO R L D . l a m p c o u n t ) ;
pri ntf(
" II I ntersect tests : %8l d l l \n" .
WO R L D . i n t e r s e c t_t e s t s ) ;
pri ntf(
" II T ot a l i n t e r s e ct i o n s : %8l d l l \n" ,
WO R L D . r a y_i n t e r s e c t s + W O R L D . b b ox_i n t e r s e c t s ) ;
pri ntf(
" II Obj ect i n t e r s e ct i on s : %8 l d l l \n" .
WO R L D . r a y_i n t e r s e c t s ) ;
pri ntf(
" II Boundi ng B o x i ntersect i ons : %8l d ll \n" .
W O R L D . b b ox_i n t e r s e c t s ) ;
pri ntf(
" 11 Rays t r a ced : %81 d 1 1 \n" .
W O R L D . p r i ma ry_t r a c e d + W O R L D . t o_l a m p +WO R L D . r e f l _t r a n s ) ;
pri ntf(
" II P r i m a ry : %8l d ll \n" ,
W O R L D . p r i m a ry_t r a c e d ) ;
pri ntf(
" II To l amps : %8l d ll\n" ,
W O R L D . t o_l a m p ) ;
pri ntf(
" II Re f l e c t e d o r T r a n s m i t t e d : % 8 1 d 1 1 \n" .
WO R L D . r e f l _t r a n s ) ;
pri ntf(
" II P a t t e r n ma t c h e s : %8l d 11 \n" .
WO R L D . p a t t e r n_m a t c h e s ) ;
pri ntf(
" II Data set to fi l e : %12s 1 1 \n" .

84
R E N D E R I N G T H E S C E N E-AN OVERVIEW

WO R L D . o u t f i l e ) ;
pri ntf(
.. 1 1 ..
11 \n l ;
p r n t f
.. l!::
I ======================::!lh n .. ) ;

/*

F u n ct i on t o open f i l e a n d e n t e r i ma g e s i z e

*/

v o i d O p e n_ F i l e ( )
{
i f ( ( W O R L D . f i l e p t= f o p e n ( W O R L D . o u t f i l e , "w b " ) ) ==N U L L )
{
cout << "Unabl e to open output fi l e" ;
ex i t ( l ) ;

fputc ( ( u n s i gned cha r ) ( XS I ZE & Oxff ) , WO R L D . f i l e p t ) ;


fput c ( ( u n s i g n ed cha r ) ( XS I ZE >> 8) , WO R L D . f i l e p t ) ;
fputc ( ( unsi gned cha r ) ( YS I ZE & Oxff l , WO R L D . f i l e p t ) ;
fputc ( ( u n s i g n ed cha r ) ( YS I Z E >> 8) , WORLD . fi l ept ) ;

/*
Funct i on to c l ose output fi l e

*/

v o i d C l o s e_ F i l e ( )
{
i f ( f c l o s e ( WO R L D . f i l e p t l l
{
cout << "Unabl e to cl ose output fi l e" ;
exi t ( l ) ;

85
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

/*

Ma i n Prog ram for R a y T r a ce r

*/

ma i n ( )
{
Obj ect *test , *test2 ;

cout «

II
1 1 \n" :
cout «
" II 1 1\n" :
cout «
" II S i mp l i f i ed Ray T r a c i n g P r o g r a m 1 1\n" :
cout «
" II 1 1\n" :
cout «
" II By R o g e r T . S t e v e n s - J a n u a ry 6 , 1 9 9 0 1 1 \n" :
cout «
" II 1 1 \n" :
cout «
" II C omma n d L i n e : r e n d e r < f i l e n a me 1 1 \n" :
cout «
" II 1 1\n" :
cout «
II 1 1 \n" :

i n i t_w o r l d ( ) ;
i n i t_c o l o r ( ) ;

86
R E N D E R I N G T H E S C E N E-AN OVERVIEW

i f ( ! LoadWor l d ( ) )
{
c o u t < < " Sy n t a x e r r o r i n l o a d i n g w o r l d \ n " :
ex i t ( l ) ;

M a k e_B b o x ( W O R L D . s t a c k ) : /* make bboxes */


fcl ose ( stdi n ) :
c o u t < < " \ n l m a g e s i z e : " < < X S I Z E < < " p i x e l s h o r i z o n t a l by "
« Y S I Z E « " p i xe l s v e rt i c a l . \ n " :
c o u t < < " \ n F i l e n a me i s : " < < WORLD . ou t f i l e < < " \ n " :
O p e n_ F i l e ( ) ;
T r a c e_S c e n e ( ) :
C l o s e_ F i l e ( ) ;
W o r l d_St a t s ( ) :
fcl ose ( s tdout ) ;
return ( NU L L ) ;

Figure 6-1 . Listing of render.cpp

Following this, we have the function World_Stats, used to print out some
statistics about the ray tracing process. These statistics are gathered during the
rendering process and are printed out at the completion of the rendering
program.

The function Open _File opens the data file for the output data. The file
name is that which was read in from the input data. If the file cannot be opened
an error message i s displayed and the program terminates. Otherwise, we
immediately write to the file the information on the pixel size of the display in
the x and y directions.

Next comes the function Close_File, which simply closes the data file. If it
cannot be closed, an error message is displayed and the program terminates.

Main Renderi ng P rog ram


Finally, we come to the main rendering program, which controls the calling
of all other functions to render the scene. It begins by displaying a header that

87
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

shows how the program should be called up. Next, the functions init_world and
init_color are called to provide initialization. The LoadWorld function is then
called to load in all of the information about the scene from the data file.

Following this, we call the function Make_Bbox. This function creates the
bounding boxes, wherever one was called for by the input data. After making
the boxes, the input data file is closed. The program displays pixel size and the
name of the file used to store the output data. The size information is the latest
received from the input data file, if such information existed; otherwise the
default values will be displayed. Next Open_File is called to open the output
data file. The function Trace_Scene is then called. This function supervises all
of the ray tracing activity, including storing the final data to the output file.
When the ray tracing has been completed, Close_File i s called to close the
output data file. We then call World_Stats to display the statistics that were
collected during the ray tracing process. After this, the program terminates.

88
CHAPTER 7

Ray Tracing
Rendering Interfaces
The first maj or problem that i s encountered i n designing a ray tracer i s
determining the proper method of communicating the data describing the scene
to the program . Thi s includes descriptions of primitive objects (spheres,
parallelograms and quadratics), information on patterns applied to surfaces, a
description of background or sky, a definition of light sources which illuminate
the picture, and the position of the camera or observer. It would certainly be
ideal if there was a standard adopted for every interface with a ray tracing
program. Unfortunately, this is not the case. There seem to be about as many
ways of defining the data for a scene as there are ray tracing programs. We will
discuss a few of the different interface methods used and then go on to develop
our own interface software.

Standard Proced u ral Database


A good place to start is with the Standard Procedural Database. This was
proposed by Eric Haines in an article "A Proposal for Standard Graphics
Environments" in the November 1 987 issue of IEEE Computer Graphics and
Applications. Haines suggests that various rendering programs can be compared
for quality and efficiency through testing on a number of standard scenes. He
has prepared software to generate data files for each of the standard scenes. An
MS-DOS format disk containing this software is available for $5 .00 from:

Micro Doc
c/o F. W. Pospeschil
3 1 08 Jackson Street
Bellevue, Nebraska 68005

89
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

Some of these standard displays are beyond the capabilities of the simple ray
tracer described in thi s book. (They were designed for use with ray tracers
associated with work stations, minicomputers, or mainframes.) However, many
of the standard displays can be simplified enough to produce workable data files
for our ray tracing program. One good aspect of Haines software is that source
code is provided in C and can be easily modified to create a data file in whatever
format you decide is necessary for interfacing. I wrote a program to transform
one of these data files to the format used in the ray tracer described in this book.
The resultant data listing required some message to produce Plate 8. Right now,
we are interested in the format that Haines creates with his software. A partial
listing of one of his data files is given in Figure 7 - 1 . This format is fairly
obscure. You can guess that the first few lines define the observer's position and
that each line beginning with an s defines a sphere . However, if you are
attempting to look at the data file and determine something about the scene, you
may find it rough sledding.

The RenderMan Interface


Pixar of S an Rafael, California has developed the RenderMan interface,
which is a comprehensive interface for use between data files and ray tracing
programs. They propose this as an industry standard, and already the standard
has had considerable acceptance among designers of graphics programs for work
station use. A copy of the interface documentation is available for $ 1 5 .00 from:

Pixar
3240 Kerner Blvd.
San Rafael, California 9490 1

The current implementation of the RenderMan interface i s a set of C


language functions which cover just about anything you might want to transfer
to a ray tracing program. Figure 7-2 is a list of the RenderMan functions. Each
function passes some set of parameters to the ray tracing program . These
parameters are defined in detail in the RenderMan interface documentation.

90
R AY T R A C I N G R E N D E R I N G I N T E R FA C E S

v
f r om 2 . 1 1 . 3 1 . 7
at 0 O O
up O 0 1
angl e 45
hi ther 1
resol u t i on 5 1 2 5 1 2
b 0 . 078 0 . 36 1 0 . 753
1 4 3 2
1 1 -4 4
1 -3 1 5
f 1 0 . 7 5 0 . 33 1 0 0 0 0
p4
12 12 - 0 . 5
- 12 1 2 - 0 . 5
- 12 - 12 - 0 . 5
12 - 12 -0.5
f 1 0.9 0.7 0.5 3 0 0
s 0 0 0 0.5
s 0 . 2 7 2 1 66 0 . 2 7 2 1 6 6 0 . 544331 0 . 1 66667
s 0 . 4 2 0 3 1 4 0 . 4 2 0 3 1 4 0 . 6 1 84 0 5 0 . 0 5 5 5 5 5 6
s 0 . 4 6 1 84 4 0 . 3 0 4 7 0 9 0 . 4 3 3 2 2 0 . 0 5 5 5 5 5 6
s 0 . 3 0 4 0 7 9 0 . 4 6 1 8 44 0 . 4 3 3 2 2 0 . 0 5 5 5 5 5 6
s 0 . 230635 0 . 387 7 7 0 . 7 2 9 5 1 6 0 . 0555556
s 0 . 1 1 50 3 1 0 . 4293 0 . 544331 0 . 0 5 5 5 5 5 6
s 0 . 082487 0 . 239622 0 . 6 55442 0 . 0555556
s 0 . 38 7 7 7 0 . 230635 0 . 7 29 5 1 6 0 . 0555556

Figure 7·1 . Partial Listing of a Ray Tracing Data File

It turns out that the RenderMan interface has found a solid niche in the realm
of work stations, particularly in interfacing between programs like AutoCad and
ray tracing programs designed to convert the graphics outputs into realistic three­
dimensional scenes. When one closely examines the RenderMan interface, it
does a fine job in this particular area. However, it doesn 't claim to provide all
the three-dimensional functions which might be appropriate to a large mainframe
with higher speeds and more memory than in a work station. On the other hand,
P i x ar i n s i s t s that a R e n derMan program i n c o rporate a l l aspects of the

91
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

RenderMan interface, which is pushing the limits of a PC. Pixar believes that
rendering programs using their interlace should be able to handle complicated
scenes with 1 0,000 to 1 ,000 , 000 primitives. Your ordinary PC is just not going
to be able to do this.

R i A t m o s p h e r e ( n a m e , p a r a me t e r l i s t ) s e t s t h e a tmo s p h e r e
shader .
R i A r e a L i g h t S o u r c e ( n a me , p a r a m e t e r l i s t ) c reates a n a rea l i g ht .
Ri Att r i buteBeg i n ( ) pushes c u r rent set of
attri butes .
Ri Att r i buteEnd ( ) pops c u r rent set of
attri butes .
Ri Ba s i s ( u ba s i s , v ba s i s ) s e t s the ba s i s ma t r i ces
that defi ne patches .
R i B e g i n ( n a me ) beg i n s the g r a ph i cs
state .
Ri Bound ( bound ) sets the bound for a
bound i ng box .
Ri C l i ppi ng ( nea r . fa r ) sets nea r and fa r
cl i ppi ng pl anes .
R i C o l o r S a m p l e s ( n , n RG B , R G B n ) s e t s n um b e r o f c o l o r
c om p o n e n t s u s e d i n
s p e c i fy i n g c o l o r s .
Ri Col o r ( col or ) sets a n obj ect col o r .
Ri C on c a t T r a n s f o rm ( t r a n s form ) c o n c a t e n a t e t r a n s f o rm
onto the c u r rent
t r a n s f o rm a t i o n .
Ri Con e ( h e i g h t , r a d i u s , t h e t a ma x , s e t s p a r a me t e r s f o r a
p a r a me t e r l i s t ) cone .

R i C o o r d i n a t e Sy s t em ( s p a c e ) establ i s hes a spec i a l


c o o r d i n a t e s y s t em .
R i C r o pW i n d ow ( x m i n , xm a x , ym i n , y m a x ) renders onl y a
s ubrectang l e of the i mage .
R i Cy l i n d e r ( r a d i u s , z m i n , z m a x , t h e t a m a x . s e t s p a r a me t e r s f o r a
pa ramete rl i s t ) cy l i n d e r .

92
R AY T R A C I N G R E N D E R I N G I N T E R FA C E S

R i De c l a r e ( n a me , d e c l a r a t i o n ) d e c l a r e s n a me a n d ty p e
of a vari abl e .
R i D e f o r m a t i o n ( n a m e , p a r a me t e r l i s t ) c o n c a t e n a t e t h e n a med
d e f o rm a t i o n s h a d e r o n t o
the c u r rent
t r a n s forma t i on .
Ri Dept hOfFi e l d ( fstop , foca l l ength , sets the camera l ens
foca l d i sta n ce ) p a r amete rs .
R i Det a i l Ra n g e ( mi n v i s i b l e , sets the c u r rent deta i l
l owe r t r a n s i t i o n , ra nge .
uppe r t r a n s i t i on , ma xv i s i bl e )
R i Det a i 1 ( b o u n d ) sets the c u r rent deta i l
t o the a rea of the
bound i ng box .
R i D i s k ( h e i g h t , r a d i u s , t h e t a ma x , s e t s t h e p a r a me t e r s f o r
pa rameter l i s t ) a di sk.
R i D i s p l a c eme n t ( n a me , p a r a me t e r l i s t ) sets the cur rent
d i s p l a c eme n t s h a d e r .
R i D i s p l a y ( n a m e , ty pe , mo d e ) s e t s d i s p l a y n a me , t y p e
and mode .
Ri End ( ) end of g raphi cs state .
R i E r r o rM od e ( mode , h a n d l e r ) sets the e r ror handl i ng
mode .
R i E x p o s u r e ( g a i n , g a mm a ) c o n t r o l s s e n s i t i v i ty
a n d n o n - l i n e a r i ty o f
expos u re p roce s s .
R i E x t e r i o r ( n a me , p a r a me t e r l i s t ) sets c u r rent exte r i o r
v o l ume s h a d e r .
R i F o rm a t ( x r e s o l u t i o n , y r e s o l u t i o n , sets resol u t i on and
p i xel a s pectra t i o ) a s pect r a t i o .

R i F r ameA s p e c t Ra t i o ( f r amea s p e c t r a t i o ) s e t s f r a me a s p e c t
rati o .
R i F r a me B e g i n ( f r a m e ) s t a r t of f rame .
Ri FrameEnd ( ) end of f rame .
Ri Gen e ra l P o l y g on ( n l oops , n v e r t s , defi ne genera l concave
p a r a me t e r l i s t ) pol ygon .

93
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

R i G e o me t r i c Ap p r o x i m a t i o n ( ty p e , v a l u e ) method of a p p r ox i ma t i n g
a sma l 1 s u rface
e l emen t .
R i G e o m e t ry ( ty p e , p a r a m e t e r l i s t ) defi nes an
i mp l e me n t a t i o n ­
s p e c i f i c g e om e t r i c
pri mi ti ve .
R i H i d e r ( ty p e , p a r a m e t e r l i s t ) con t rol s h i dden s u rface
a l gori thm .
R i Hy p e r b o l o i d ( p o i n t l , p o i n t 2 , t h e t a m a x , defi nes a hype rbol oi d .
p a r a me t e r l i s t )
R i I d e n t i ty ( ) s e t c u r rent
t r a n s f o rm a t i o n t o
i d e n t i ty .
Ri I l 1 umi n a t e ( 1 i g h t , onoff ) a d d o r r e mo v e a n a r e a
l i ght source to the
1 i st .

R i l m a g e r ( n a me , p a r a m e t e r l i s t ) s e l e c t a n i ma g e r
fun c t i on .
Ri l n t e r i o r ( n ame , pa ramete r l i s t ) sets the current
i n t e r i o r v o l ume s h a de r .
R i l i g h t S o u r c e ( n a me , p a r a m e t e r l i s t ) add a non - a rea l i g h t
sou rce to the l i s t .
Ri Ma k e B ump ( p i c t u ren ame , tex t u ren ame , convert a hei ght fi el d
swra p , twra p , f i l terfunc , swi dth , i m a g e i n t o a b um p m a p
twi d t h , pa ramete r l i s t ) fi l e .

R i M a k e C u b e F a c e E n v i r o n m e n t ( p x , n x , py , p r o j e c t e n v i r o n me n t
ny , pz , n z , tex t u r e f i l e , fov , on t o s i x c u be f a c e s .
f i l t e r f u n c , s w i d t h , tw i d t h ,
pa ramete r l i s t )

R i M a k e l a t t l o n g E n v i r o n me n t ( p i c t u r e f i l e , c o n v e r t a n i ma g e i n to a
textu refi l e , f i l terfunc , swi d t h , l a t i tude - l o n g i tude ma p .
t w i d t h , p a r a me t e r l i s t )
R i M a k e S h a d ow ( p i c t u r e f i l e , t e x t u r e f i l e , c on v e r t a depth
pa ramete r l i st ) i ma g e f i l e

94
R AY T R A C I N G R E N D E R I N G I N T E R FA C E S

i n t o a s h a d ow m a p .
Ri Ma keTex t u r e ( p i c t u ren ame , texturen ame , c o n v e r t a n i ma g e
s w r a p . tw r a p . f i l te rf u n c . swi d t h . i n to a texture fi l e .
twi d t h , pa ramete r l i s t )
Ri Matte ( ) i ndi cates that
s u bsequent obj ects a re
matte obj ects .
Ri Moti onBegi n ( n , tO , t l , . . . , tn ) s t a rt the defi n i t i on of
a mov i ng p r i mi t i v e .
Ri Mot i on End ( ) end t h e defi n i t i on o f a
mov i n g p r i mi t i v e .
R i N u P a t c h ( n u , u o r d e r . u k n o t , um i n , c re a t e a B - s p l i n e
umax , n v , v o rd e r , v k n o t , vm i n , vma x , surface patch .
pa rameterl i st .
Ri Obj ectBeg i n ( ) s t a r t obj ect
defi n i ti on .
Ri Obj e c t E n d ( ) end obj ect defi n i t i on .
R i O p a c i ty ( c o l o r ) set the c u r rent col o r .
R i O p t i o n ( n a me , p a r a me t e r l i s t ) s e t i mp l eme n t a t i o n ­
speci fi c opt i on .
Ri O r i enta t i on ( o r i enta t i on ) s e t s o r i e n t a t i on to
r i g h t - h a n ded o r l ef t ­
h a n ded .
Ri P a r a b o l o i d ( rma x , zm i n , zma x , t h e tamax , defi nes a p a r a bol o i d .
p a r a me t e r l i s t )
R i P a t c h M e s h ( ty p e , n u . u w r a p , n u s t e p , n v , s pe c i f i e s a
v w r a p , n v s t e p , p a r a me t e r l i s t ) q u a d ra l a t e r a l mes h of
patches .
R i P a t c h ( ty p e , p a r a me t e r l i s t ) defi nes a s i ngl e patch .
Ri P e r s pe c t i v e ( fo v ) concatenates a
p e r s pe ct i v e
t r a n s f o rm a t i o n o n t o t h e
c u r r e n t t r a n s fo rm a t i o n .
R i P i x e l F i d e l i ty ( v a r i a t i o n ) s e t s t h e a mo u n t i ma g e
v a l u e s c a n d e v i a t e f r om
t rue v a l ues .

95
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

R i P i x e l F i l t e r ( f i l t e r f u n c , xw i d t h , sets anti a l i a s i ng
ywi d t h ) fi l te r .
Ri P i xe l Sampl es ( xs ampl es , y s ampl es ) sets s ampl i n g rate .
Ri Poi n tsGen e r a l Po l ygon s ( npol y s , n l oops , defi nes general
nverts , verts , pa rameter l i s t ) pol ygon s .
Ri Poi n t s Po l ygons ( n pol y s , nverts , verts , defi nes pol ygon s .
p a r a me t e r l i s t )
R i P o l y g o n ( n v e r t s , p a r a me t e r l i s t ) sets no . of v e r t i ces
for pol ygon
R i P r o c ed u r a l ( d a t a , b o u n d , s u b d i v i d e f u n c , defi nes a p rocedu r a l
f reefun c ) f u n c t i on .

R i P r o j e c t i o n ( n a me , p a r a m e t e r l i s t ) s e t s ty p e o f
p roj e c t i on .
R i O u a n t i z e ( ty p e , o n e . m i n , m a x , s e t s t h e q u a n t i z a t i on
ddi therampl i tude ) p a r amete r s .
R i Re l a t i v e D e t a i l ( r e l a t i v e d e t a i l ) sets rel a t i ve l evel of
deta i l .
R i Re v e r s eO r i e n t a t i o n ( ) c a u s e s c u r rent
o r i en tati on to be
toggl ed .
R i Ro t a t e ( a n g l e , d x , dy , d z ) conca ten a tes a rota t i on
onto the current
t r a n s f o rm a t i o n .
Ri Sca l e ( s x , sy , s z ) concatenates a sca l i ng
onto the c u r rent
t r a n s f o rm a t i o n .
R i S c r e e n W i n d ow ( l e f t , r i g h t , t o p , b o t t om ) d e f i n e s a w i n d ow .
R i S h a d i n g i n t e r p o l a t i o n ( ty p e ) control s shadi ng .
Ri Shadi ngRate ( s i ze ) sets c u r rent shadi ng
rate .
Ri S h u t te r ( mi n . ma x ) sets ti mes t h a t s h utter
open s and c l oses .
Ri S i des ( s i des ) dete rmi nes wh e t h e r
s u rfaces a re one o r
t wo - s i d e d .
R i S k ew ( a n g l e , d x l , dy l , d z l , d x 2 , dy 2 , d z 2 ) c o n c a t e n a t e s a s k ew
96
R AY T R A C I N G R E N D E R I N G I N T E R FA C E S

onto the c u r rent


t r a n s f o rm a t i o n .
Ri Sol i dBeg i n ( ope r a t i on ) defi nes begi n n i ng of a
sol i d .
Ri Sol i d End ( ) defi nes end of a
sol i d .
Ri S p h e re C r a d i u s , zm i n , zma x , thetamax , defi nes a sphere .
p a r a me t e r l i s t )
R i S u r f a c e ( n a me , p a r a me t e r l i s t ) sets the surface
shade r .
Ri T ex t u r e C o o rd i n a te s ( s l , t l , s 2 , t 2 , s 3 , t3 , sets the c u r rent set of
s 4 , t4 ) t e x t u r e c o o rd i n a t e s .
Ri T o ru s ( ma j o r r a d i u s , mi n o r r a d i u s , ph i mi n , defi nes a torus .
p h i m a x , t h e t a m a x , p a r a me t e r l i s t )
R i T r a n s f o rm B e g i n ( ) s a ves the current
t r a n s f o rm a t i o n .
R i T r a n s f o rm E n d ( ) resto res the l a s t
t r a n s f o rm a t i o n t h a t w a s
sa ved .
R i T r a n s f o rm P o i n t s C s p a c e , p o i n t s , n ) t r a n s f o rm s a n a r r ay o f
p o i n t s f r om t h e
c o o rd i n a t e s y s t e m s p a c e
to t h e c u r rent
c o o rd i n a te sys tem .
R i T r a n s f o rm ( t r a n s f o rm ) s ets the c u r rent
t r a n s f o rm a t i o n .
R i T r a n s l a t e ( d x , dy , d z ) concatena tes a
t r a n s l a t i on onto the
c u r r e n t t r a n s f o rm a t i o n .
R i T r i mC u r v e ( o r d e r , k n o t , m i n , ma x , n , u , v , w ) sets the current tri m
curve .
Ri Wo r l dBeg i n ( ) beg i n s the
rende r i ng p roces s .
Ri Wo r l d E nd ( ) ends the renderi ng
p roces s .

Figure 7-2. The RenderMan Interface Procedures

97
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +

When setting up a standard, it is not a good idea to try to make the standard
be all things to all people. Pixar is wise in not trying to make the RenderMan
interface equally applicable to PC 's and mainframes. Pixar does have a piece of
software called PhotoRealistic RenderMan, which works on a PC, but it requires
a 386 machine having a 387 math coprocessor and at least two megabytes of
memory. Not everyone has such a high-powered computer readily available. In
any case, the RenderMan interface seems to be overkill for the simple ray tracer
described in this book. Furthermore, casting everything in the C language fails
to take advantage of the natural improvements available for thi s type of
operation using C++. So we need to look further.

The QRT I nput Language


Steve Koren has developed a Quick Ray Tracing (hence QRT) program for
the IBM and compatible PC, which is available on many bulletin boards. This
program includes an input language which is simple and highly descriptive.
Figure 9- 1 is a sample data file using the QRT input language. It is fairly easy to
understand w i thout studying the detai l s . S ince Koren has several good
demonstrations available with his package, it seemed like a good idea to develop
an interface program capable of reading his data files. However, there are some
problems with the way the QRT program reads the data. In particular, the parser
is so designed that it goes bananas if it encounters a non-displayable character.
One example of this is that all spacings in the QRT data, while completely
flexible, must be defined by space characters. If you attempt to use a tab, the
parser will reject it as an illegal character. Also, in order to use C++, we need to
treat the data in an entirely different way when we get it into the program.
However, our goal is to retain enough compatibility to be able to read QRT data
files.

Striking Out on Our Own


Having looked at a few interface techniques, it is time to design our own. In
the main, we shall attempt reading the QRT language, but will make the format
requirements of our parser less stringent than those used by QRT. And we won't

98
R AY T R A C I N G R E N D E R I N G I N T E R FA C E S

hesitate to add additional commands to make things easier. Finally, since the
number of primitive objects that are defined is small, the techniques used
together with the characteristics of the C++ language make it easy for you to add
additional objects and include them as part of the new descriptive language. In
the following chapter, we will describe our technique for reading in scene data.

99
CHAPTER 8

Communicating with the


Ray Tracer
Having looked at the advantages and disadvantages of various techniques for
transferring data to a ray-tracing program, we can create our own techniques for
handling this data to provide maximum flexibility without getting into overkill
for the simple ray tracer developed in future chapters. Most of the programs for
this job are found in the file called input.cpp.

The input.cpp File


The input.cpp file contains functions used to read and pre-process data from
a data file for use in ray-tracing operations. The functions are set up so all data
is read from a data file specified when the program is called. The technique is to
simply run the program with a command like this:

r e n d e r f i l e n a me

where render is the name of our ray-tracing program and filename is the name of
the file containing the data for the scene you want to render. For convenience,
we have assigned the extension ray to all files containing scene data, but this is
not essential. The input.cpp file is listed in Figure 8- 1 .

Creating the Parser


When one analyzes the content of the QRT input language, it becomes
evident that only a few basic parts of each expression are necessary. All of the
commas, equals signs , and some of the parentheses, while they contribute to
readability, are not needed to properly extract the file content. We distill what
has to be checked and produce the parser which forms the function get_string,
which is listed as part of input.cpp in Figure 8- 1 . The function begins by getting

1 01
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

a character from the input data file. It converts this character to upper case
lettering. If the comment flag is zero, it checks to see if the character is a letter, a
number, a decimal point, a minus sign, or a right parenthesis. These are the only
acceptable characters for the beginning of a string. The letters and numbers can
be the beginning of a name ; the decimal point and minus sign can be the
beginning of a numeric quantity. If an acceptable character is encountered, it is
placed as the first character in the string buffer; if the character is not acceptable,
it is ignored. Two other characters are checked, the right and left curly brackets.
If the left curly bracket is encountered, the comment flag is set to one; if the
right, zero. Once the flag is set, all characters are ignored until the flag is reset,
so that any comments between curly brackets are ignored.

Once an acceptable starting character is encountered, the function loops to


read up to 30 more characters. If the initial character was a right parenthesis, the
string is terminated. Each character read is converted to upper case and checked
to see if it is a letter, a number, an underscore, or a period. These are the only
acceptable characters for the part of a string other than the first character. If the
character is acceptable, it is added to the string; if not, the string is terminated.

Next, the function checks the string it has created against an array of
acceptable strings. If a match is encountered, the function terminates, returning
the number of the matching string in the array. If no match is found, the last
number (which doesn 't correspond to any matching string location) is returned.

Finally, there is a display message of the string and its type. This message is
normally commented out, but if you are having real trouble getting a data file to
read, you can recompile with this message in the program and locate exactly
where your difficulty is.

Load i ng the World


Now that we have a working parser, we are ready to load the computer 's
world.

1 02
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R

At the beginning of the input.cpp file, you will see the function LoadWorld,
but it is not very interesting. All it does is call the function get_data, place the
return address from this function in WORLD .stack, and return a TRUE.

The get_data function scans right down through the entire scene data file,
collecting inputs and processing them, until an error occurs or the file comes to
an end. The first thing that this function does is to return a NULL if the file end
has already been encountered (the file is empty). If there is some file data, the
function goes into a while loop and begins its work by using the parser to read
the first data string from the file. It then sets the parameter found to FALSE.

As we progress through the remainder of this loop, we check to determine


whether the type of string we obtained corresponds to any of the recognized
types that we expect to see. Whenever we encounter a match, found is set to
TRUE. If we get to the end of the loop and found is still FALSE, we print out a
syntax error message and exit from the program. We have already pointed out
that we are going to quit this loop i f we come to the end of the data file.
However, we will sometimes be us ing get_data when we want it to cease
operation before we hit the end of file. In this case, we place a NULL at the
appropriate place in the data file. So the first thing we do after getting a string
with the parser is check whether it is a NULL string. If it is, we return from the
get_data function immediately.

The get_data function is going to process four different kinds of inputs. The
first of these i s attribute . This type of input includes lamp characteristics ,
observer characteristics, patterns, etc. The second type o f input is an instance.
An instance is a user-defined object, consisting of a group of primitive objects
used at different places in the scene. The third kind of data concerns bounding
boxes. When the data specifies a bounding box, the program must generate a
box around all the objects listed within the box . The fourth kind of data is
objects. These are the primitives that compose the scene.

1 03
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

Figure 8-1 . The i nput.cpp File*

/*
i n p u t . c p p = F u n c t i o n s t o r e a d d a t a f r om d i s k f i l e

By R o g e r T . S t e v e n s - 3 / 22 /90

*/

#i n c l ude < c ty p e . h >


#i n c l ude <stri ng . h>
#i n c l ude <stdi o . h>
#i n c l ude <stdl i b . h>
#i n c l ude <ma t h . h >
#i n c l ude <con i o . h>
#i n c l ude " rende r . hpp"

c h a r s t r i n g_ty p e s [ l 2 8 J [ 3 2 J
{ " P ATT_H E A D E R " , " L I N E " , " S P H E R E " , " P A RA L L E L O G RA M " , " T R I A N G L E " , " LAM P " ,
" O B S E R V E R " , " G RO U N D " , " S KY " , " B B O X " , " R I N G " , " Q U A D RAT I C " , " B E G I N_B B O
" , " E N D_B B O X " , " B E G I N_ I N S T A N C E S " , " E N D_ I N S T A N C E S " , " A M B " , " D I F F " ,
" M I R RO R " , " T RA N S " , " D E N S I T Y " , " I N D E X " , " D I T H E R " , " S R E F L E C T " ,
" R E F L E C T " , " L O C " , " RA D I U S " , " P ATT E R N " , " R E MO V E " , " X M U L T " , " Y M U L T " ,
" N A M E " , " D I S T " , " L O O KA T " , " V l " , " V 2 " , " Z E N I T H " , " H O R I Z " , " RA D_l " ,
" RA D_2 " , " A " , " B " , " C " , " D " , " E " , " X M A X " , " Y MA X " , " Z M A X " , " X M I N " , " Y M I N "
, " Z M I N " , " D I R " , " F O C _ L E N G T H " , " F I R S T_S C A N " , " D E FA U L T " , " F I L E_NAM E " ,
" LA S T_S C A N " , " X R E S " , " Y R E S " , " X_S I Z E " , " Y_S I Z E " , " S T A RT_X " , " S TA R T_Y
" , " E N D_X " , " E N D_Y " , " ) " , " N O_S H A D OW " , " N O_ L AM P " , " T H R E S H O L D " , " U P " ,
" I N S T A N C E_O F " , " S C A L E " , " R E C T A N G L E " , " C I RC L E " , " P O L Y G O N " , " C O L O R " ,
" P O I N T " , " C O N E " , " H E I G H T " , " F RA C T A L " , " D I M E N S I O N " , " S C A L A R " , N U L L } ;

c h a r s t r i n g_b u f [ 3 2 J ;
c h a r n a me [ 3 2 J :
F I LE *fget ;

/*
Loa dWo r l d ( ) L o a d s t h e W o r l d w i t h d a t a f r om s t d i n

*I

1 04
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R

extern i n t l i nen umbe r ;

i n t Loa dWo r l d ( )
{
f g e t = f o p e n ( f i l e_i n , " r b " ) ;
WO R L D . s t a c k= g e t_d a t a ( ) ;
return ( TRUE ) ;
fcl ose ( fget ) ;

/*
g e t_d a t a ( ) G e t s d a t a f r om s t d i n a n d p l a c e s i t i n Wo r l d

*/

O b j e c t * g e t_d a t a ( )
{
Obj ect * queue . * temp ;
B B ox * n ewobj ;
V e c t o r l o c . r a d , d , v 3 . u p p e r . l owe r ;
i n t found . type ;
n a m e [ O ] = N U L L ; q u e u e= N U L L ;
1 o c = Vector ( ) ;
rad = Vector ( ) ;
d = Vector ( ) ;
v3 = Vector ( ) ;
upper = Vector ( ) ;
1 owe r = V e c t o r ( ) ;
i f ( feof ( fget ) ) return ( NU L L ) ;
w h i l e ( ! fe o f ( fget ) )
{
t y p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
i f ( s t r c m p ( s t r i n g_b u f , N U L L ) ==O )
retu rn ( queue ) ;
found = FA LS E ;
i f ( G e t A t t r i b ( ty p e , s t r i n g_b u f ) )
{
found = T RU E ;
i f ( n a m e [ O ] == N U L L )
conti nue ;

1 05
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

ty p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
i f ( ty p e ! = B E G I N_B B O X )
{
c o u t < < " E r r o r : N a me m u s t b e f o l l owed < < " by
' B E G I N_B B O X ' \ n " ;
exi t ( l ) ;

s w i t c h ( ty p e )
{
c a s e B EG I N I N STANC E S :
found = T RU E ;
W O R L D . i n s t a n c e s = g e t_d a t a ( ) ;
brea k ;
c a s e E N D_ I N S T A N C E S :
found = TRU E ;
return ( queue ) ;
brea k ;
c a s e E N D_B B O X :
found = T RU E ;
return ( queue ) ;
brea k ;
c a s e B E G I N_B B O X :
n ew o b j = n e w B B o x ;
s t r c py ( n ew o b j - > n a me , n a me ) ;
n e w o b j - > ty p e = B B O X ;
n ew o b j - > c h i l d = g e t_d a t a ( ) ;
n ew o b j - > n e x t o b j = q u e u e ;
q u e u e = n ew o b j ;
found = T RU E ;
brea k ;

i f ( ty p e == F RA C T A L )
{
i f ( ( t emp=G e t_O b j e c t ( t y p e , q u e u e ) ) ! = N U L L )
{
found TRU E ;
queue temp ;

el se

1 06
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R

i f ( ( t e mp=G e t_O b j e c t ( t y p e , q u e u e ) ) ! = N U L L )
{
found = T RU E :
t e m p - > n e x t o b j =q u e u e :
queue = temp ;

i f ( ! found && ! fe o f ( fget ) )


{
c o u t < < " Sy n t a x e r r o r i n r e a d i n g i n p u t d a t a : " < <
s t r i n g_b u f < < " \ n " :
ex i t ( l ) ;

return ( queue ) ;

g e t_s t r i n g ( ) Re a d s a s t r i n g o f d a t a f r om f g e t

*/

i n t g e t_s t r i n g ( c h a r s t r i n g_b u f [ J )
{
char ch ;
i n t fl ag = O , i . resul t . test ;

s t r i n g_b u f [ O J = N U L L :
r e s u l t = l a s t_n o ;
w h i l e ( ! fe o f ( fget ) )
{
c h = touppe r C fgetc ( fget ) ) ;
i f ( f l a g == 0 )
{
i f ( ( i s a l num ( c h ) ) 1 1 ( c h . . . l 1 1 ( ch .-.l I I
( c h == · ) ) ) ·

s t r i n g_b u f [ O J = c h ;
brea k ;

1 07
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

el se
{
i f ( c h == ' { ' )
fl ag = l ;

el se
i f ( c h == } ) . .

fl ag = 0 ;

f o r ( i = l ; i < 3 2 ; i ++ )
{
i f ( c h == ' ) ' )
{
s t r i n g_b u f [ l ] NULL ;
brea k ;

ch touppe r ( fgetc ( fget ) ) ;


i f ( ( i s a l n um ( c h ) ) I I ( c h == ' _ ' ) I I ( c h · . ' ))
s t r i n g_bu f [ i ] = c h ;
el se
{
s t r i n g_b u f [ i ] NU LL ;
brea k ;

f o r ( i =O ; i < l a s t_n o ; i ++ )
{
i f ( s t r c mp ( s t r i n g_b u f , s t r i n g_ty p e s [ i ] ) 0)
{
res ul t = i ;
brea k ;

}
II c o u t < < " S t r i n g b u f fe r c o n t a i n s : < < s t r i n g_b u f < <

II · wh i c h i s type " << r e s u l t < < " \ n " ;

return ( resul t ) ;

1 08
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R

I*

G e t_A t t r i b ( ) G e t s a t t r i b u t e o t h e r t h a n o b j e c t f r om f g e t

*I

i n t G e t A t t r i b ( i n t Ty p e . c h a r s t r i n g_b u f [ J )
!
i n t i , ty p e=O , n o_p a r a m=O . f o u n d =T R U E
Vector l oc , l ook ;
fl oat radi us . di stance ;
Lamp * l amps ;

s w i t c h ( Ty p e )
!
c a s e S KY :
found = T RU E ;
w h i l e ( ty p e ! = P A R E N && ! feof ( fget ) )
!
ty p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
s w i t c h ( ty p e )
!
c a s e Z E N I TH :
W O R L D . s ky c o l o r_z e n i t h . g e t_v e c t o r ( ) ;
WO R L D . s ky c o l o r_z e n i t h =
W O R L D . s ky c o l o r_z e n i t h * ( f l o a t ) C N U M ;
brea k ;
case HORI Z :
W O R L D . s ky c o l o r_h o r i z . g e t_v e c t o r ( ) ;
W O R L D . s ky c o l o r_h o r i z =
W O R L D . s ky c o l o r_h o r i z * ( f l o a t ) C N U M ;
brea k ;
c a s e D I TH E R :
g e t_s t r i n g ( s t r i n g_b u f ) ;
WO R L D . s ky_d i t h e r =
f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
case PAREN :
brea k ;
defa u l t :
f o u n d = FA L S E ;

1 09
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

brea k ;
c a s e C O LO R :
w h i l e ( ty p e ! = P A R E N & & ! f e o f ( f g e t ) )
{
t y p e = g e t_ s t r i n g ( s t r i n g_b u f ) ;
f o u n d = g e t_c o l o r_d a t a ( ty p e , & d e f . c o l _d a t a ) ;
i f ( ty p e == P A R E N )
{
found = TRU E ;
brea k :

i f ( ! found )
{
c o u t < < " U n d e f i n e d p a r a me t e r " < < s t r i n g_b u f
< < "wh i l e l oa d i ng col o r d a t a i n
' i n p u t . c p p "' ;
ex i t ( l ) ;

brea k ;
c a s e F O C L E N GT H :
g e t_s t r i n g ( s t r i n g_b u f ) ;
WO R L D . f l e n g t h = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
W O R L D . f l e n g t h *= 5
brea k ;
c a s e F I L E_NAM E :
g e t_s t r i n g ( s t r i n g_b u f ) ;
s t r c py ( W O R L D . o u t f i l e , s t r i n g_b u f ) ;
brea k ;
c a s e L AM P :
d i stance = 1 50 ;
w h i l e ( ty p e ! = P A R E N & & ! f e o f ( f g e t ) )
{
ty p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
found = T RU E ;
s w i t c h ( ty p e )
!
c a s e LOC :
l o c . g e t_v e c t o r ( ) ;
n o_p a r a m I = l ;
brea k ;

110
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R

c a s e RA D I U S :
g e t_s t r i n g ( s t r i n g_b u f ) ;
r a d i u s = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e D I ST :
g e t_s t r i n g ( s t r i n g_b u f ) ;
d i s t a n c e = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
case PAREN :
brea k ;
defa ul t :
found FALS E ;

i f ( ! found )
{
c o u t < < " U n d e f i n e d p a r a me t e r " < < s t r i n g_b u f
< < " w h i l e l o a d i n g l a mp i n
' i nput . cpp ' " ;
exi t ( l ) ;

i f ( n o_p a r a m < 1 )
{
c o u t < < " T o o few p a r a m e t e r s f o r l a mp i n
' i nput . cpp ' " ;
exi t ( l ) ;

l a m p s = n ew L a m p ;
l amps - > l oc = l oc ;
l amps - > radi u s = radi us ;
l amps - >d i s tance = d i stance ;
l a m p s - > n e x t_l a mp = W O R L D . l a m p s ;
WORLD . l amps = l amps ;
W O R L D . l a m p c o u n t++ ;
brea k ;
c a s e O B S E RV E R :
l ook = Vector ( 200 , 50 , 0 ) ;
found = TRU E ;
w h i l e ( ty p e ! = P A R E N & & ! f e o f ( f g e t ) )
{
t y p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
s w i t c h ( ty p e )

111
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

case LOC :
W O R L D . o b s l o c . g e t_v e c t o r ( ) ;
n o_p a r a m I = l ;
brea k ;
c a s e L O O KAT :
l o o k . g e t_v e c t o r ( ) ;
n o_p a r a m I = 2 :
brea k ;
case UP:
W O R L D . o b s u p . g e t_v e c t o r ( ) ;
brea k ;
case PAREN :
brea k ;
defa ul t :
found FA LS E ;

i f ( ! found )
{
c o u t < < " U n d e f i n ed p a r a me t e r " < < s t r i n g_b u f
<< " wh i l e l oa d i n g obs e rv e r i n
' i n put . cpp ' " ;
ex i t ( l ) ;

WO R L D . o bs d i r l oo k - WORLD . ob s l oc ;
WORLD . obsdi r -WO R L D . o b s d i r ;
W O R L D . ob s r i g h t = WO R L D . ob s u p A W O R L D . ob s d i r ;
WO R L D . o b s u p = WO R L D . ob s d i r A WO R L D . ob s r i g h t ;
W O R L D . o b s u p = -WO R L D . o b s u p ;
W O R L D . o b s r i g h t = -WO R L D . o b s r i g h t ;
i f ( n o_p a r a m ! = 3 )
{
c o u t < < " T o o few p a r a m e t e r s f o r o b s e r v e r " < < " i n
' i nput . cpp ' " ;
exi t ( l ) ;

brea k ;
c a s e PAttern :
Get Pattern ( ) ;
brea k ;

112
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R

case XRES :
g e t_s t r i n g ( s t r i n g_b u f ) ;
XSIZE = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
CENTERX =XSIZE I 2 ;
X S I Z E4 = XSIZE I 4 ;
brea k ;
case Y RES :
g e t_s t r i n g ( s t r i n g_b u f ) ;
YSIZE = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
W O R L D . l a s t_s c a n YSIZE - l ;
C E N T E RY =YSIZE I 2 ;
brea k ;
c a s e N AM E :
g e t_s t r i n g ( n a me ) ;
brea k ;
defa ul t :
found = FALS E ;

return ( found ) :

g e t_c o l o r_d a t a G e t s t h e c o l o r i n f o r m a t i o n f r om a f i l e

*I

i n t g e t_c o l o r_d a t a ( i n t t y p e , c o l o r_d a t a * c o l _d a t a )


{
i nt found = TRUE ;
c h a r s t r i n g_b u f [ 3 2 J ;
s w i t c h ( ty p e )
{
c a s e AMB :
c o l _d a t a - > a mb . g e t_v e c t o r ( ) ;
col data - >amb c o l d a t a - >amb * ( fl oat ) C NUM :
brea k ;
case D I FF :
c o l _d a t a - > d i f f . g e t_v e c t o r ( ) ;
c o l _d a t a - > d i f f = ( c o l _d a t a - > d i f f ) * ( f l o a t ) C N U M ;
brea k ;

113
F R A CTA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +

c a s e M I R RO R :
c o l _d a t a - >m i r r o r . g e t_v e c t o r ( ) ;
c o l _d a t a - > m i r r o r c o l _d a t a - > m i r r o r * ( f l o a t ) C N U M ;
brea k ;
c a s e T RA N S :
c o l _d a t a - > t r a n s . g e t_v e c t o r ( ) ;
c o l _d a t a - > t r a n s c o l _d a t a - > t r a n s * ( f l o a t ) C N U M ;
brea k ;
c a s e D E N S I TY :
c o l _d a t a - > d e n s i ty . g e t_v e c t o r ( ) ;
c o l _d a t a - > d e n s i ty = c o l _d a t a - > d e n s i ty * ( f l o a t ) C N U M ;
brea k ;
case I NDEX :
g e t_s t r i n g ( s t r i n g_b u f ) ;
c o l _d a t a - > i n d e x = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e D I TH E R :
g e t_s t r i n g ( s t r i n g_b u f ) ;
c o l _d a t a - > d i t h e r = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e S R E F L ECT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
c o l _d a t a - > s r e f l e c t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e RE F L ECT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
c o l _d a t a - > r e f l e c t = a t o f ( s t r i n g_b u f ) * C N U M ;
brea k ;
defa ul t :
found = FALSE ;

retu rn ( found ) ;

/ *r.=====�
G e t S p h e r e ( ) = L o a d a s p h e r e f r om f g e t a n d r e t u r n p o i n t e r t o i t

*/

Obj ect * GetSphere ( )


{

114
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R

S p h e r e * n ew o b j ;
i n t t y p e=O , n o_p a r a m 0 , found ;
f l o a t temp ;

n ew o b j = n ew S p h e r e ;
n ew o b j - > c o l _d a t a = n e w c o l o r_d a t a ;
* n e w o b j - > c o l _d a t a = d e f . c o l _d a t a ;
w h i l e ( ty p e ! = P A R E N & & ! f e o f C f g e t ) )
{
t y p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
f o u n d = g e t_c o l o r_d a t a ( ty p e , n ew o b j - > c o l _d a t a ) ;
i f ( f o u n d == T RU E )
conti nue ;
f o u n d = T RU E ;
swi t c h C type )

c a s e LOC :
n e w o b j - > l o c . g e t_v e c t o r ( ) ;
n o_p a r a m I = l ;
brea k ;
c a s e RA D I U S :
g e t_s t r i n g ( s t r i n g_b u f ) ;
t e m p = f a b s C a t o f C s t r i n g_b u f ) ) ; n ew o b j - > v e c t l
Vecto r C temp , 0 , 0 ) ;
n o_p a r a m I = 2 ;
brea k ;
c a s e PAtte rn :
n ew o b j - > p a t t e r n=At t a c h_P a t t e r n ( ) ;
brea k :
case REMOV E :
n ew o b j - > r e m o v e=A t t a c h_P a t t e r n ( ) ;
brea k ;
c a s e X M U LT :
g e t_s t r i n g ( s t r i n g_b u f ) :
n ew o b j - > xm u l t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e Y M U LT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - >y m u l t = f a b s C a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e NAM E :
g e t_s t r i n g ( n ew o b j - > n a me ) ;

115
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

brea k ;
case PAREN :
brea k :
defa u l t :
found FALS E :

i f ( ! found )
{
c o u t < < " U n d e f i n e d p a r a m e t e r " < < s t r i n g_b u f < < " w h i l e
l oadi ng sphere i n ' i nput . cpp ' " ;
ex i t ( l ) ;

i f ( n o_p a r a m ! = 3 )
{
c o u t < < "Too few p a ramete r s f o r s p h e r e i n ' i n p u t . c pp ' " :
ex i t ( l l :

n ew o b j - > n l = n ew o b j - > v e c t l . x * n ew o b j - > v e c t l . x ;


W O R L D . o b j c o u n t++ :
r e t u r n ( n ew o b j ) ;

/* ===�
n=
GetT r i a n g l e ( ) L o a d a t r i a n g l e f r om f g e t a n d r e t u r n
poi nter to i t

*/

Obj ect * GetT r i a n g l e ( )


{
T r i a n g l e * n ew o b j :
i n t t y p e= O , n o_p a r a m 0 , found ;
f l o a t temp :

n ew o b j = n ew T r i a n g l e :
n ew o b j - > c o l _d a t a = n ew c o l o r_d a t a :
* n ew o b j - > c o l _d a t a = d e f . c o l _d a t a ;
w h i l e ( ty p e ! = P A R E N & & ! f e o f ( f g e t l l
{
t y p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
f o u n d = g e t_c o l o r_d a t a ( ty p e , n ew o b j - > c o l _d a t a l ;

116
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R

i f ( f o u n d == T RU E )
cont i nue ;
f o u n d = T RU E ;
s w i t c h ( ty p e )
(
c a s e LOC :
n e w o b j - > l o c . g e t_v e c t o r ( ) ;
n o_p a r a m i = l ;
brea k ;
case Vl :
n ew o b j - > v e c t l . g e t_v e c t o r ( ) ;
n o_p a r a m i = 2 ;
brea k ;
case V2 :
n ew o b j - > v e c t 2 . g e t_v e c t o r ( ) ;
n o_p a r a m i = 4 ;
brea k ;
c a s e PAtt e r n :
n e w o b j - > p a t t e r n=A t t a c h_ P a t t e r n ( ) ;
brea k ;
c a s e R E MO V E :
n e w o b j - > r e m o v e=A t t a c h_ P a t t e r n ( ) ;
brea k ;
c a s e XMU LT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n e w o b j - > xm u l t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e YMU LT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n e w o b j - >y m u l t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e NAM E :
g e t_ s t r i n g ( n ew o b j - > n a m e ) ;
brea k ;
c a s e PA R E N :
brea k ;
defa u l t :
found FA L S E ;

i f ( ! fo u n d )
{

117
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +

c o u t < < " U n d e f i n e d p a r a me t e r " < < s t r i n g_b u f < <


" w h i l e l oa d i n g t r i a n g l e i n ' i n p u t . c pp ' " ;
ex i t ( l ) ;

i f ( n o_ p a r a m ! = 7 )
(
c o u t < < "Too few pa r ame t e r s f o r t r i a n g l e i n ' i n p u t . c pp ' " ;
exi t ( l ) ;

n ew o b j - > n o rm n ew o b j - > v e c t l A n ew o b j - > v e c t 2 ;


n ew o b j - > n o rm - n ew o b j - > n o rm ;
n ew o b j - > n l = n ew o b j - > n o r m % n ew o b j - > l o c ;
n ew o b j - > l e n l = n ew o b j - > v e c t l % n ew o b j - > v e c t l ;
n ew o b j - > l e n 2 = n ew o b j - > v e c t 2 % n ew o b j - > v e c t 2 ;
W O R L D . o b j c o u n t++ ;
retu rn ( newobj ) ;

/ * rr======;i
GetRi ng ( ) L o a d a r i n g f r om f g e t a n d r e t u r n p o i n t e r t o i t

*/

Obj ect * Get R i n g ( )


(
R i n g * n ew o b j ;
i n t t y p e=O , n o_p a r a m 0 , found ;
fl o a t temp ;

n ew o b j = n ew R i n g ;
n ew o b j - > c o l _d a t a = n ew c o l o r_d a t a ;
* n ew o b j - > c o l _d a t a = d e f . c o l _d a t a ;
w h i l e ( ty p e ! = P A R E N & & ! f e o f ( f g e t ) )
(
t y p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
f o u n d = g e t_c o l o r_d a t a ( ty p e , n e w o b j - > c o l _d a t a ) ;
i f ( f o u n d == T R U E )
conti nue ;
found = T RU E ;
s w i t c h ( ty p e )

118
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R

c a s e LOC :
n ew o b j - > l o c . g e t_v e c t o r ( ) ;
n o_p a r a m I = l ;
brea k ;
case Vl :
n ew o b j - > v e c t l . g e t_v e c t o r ( ) ;
n o_p a r a m I = 2 ;
brea k ;
case V2 :
n e w o b j - > v e c t 2 . g e t_v e c t o r ( ) ;
n o_p a r a m i = 4 ;
brea k ;
c a s e R A D_ l :
g e t_ s t r i n g ( s t r i n g_b u f ) ;
n e w o b j - > v e c t 3 . x = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
n o_p a r a m I = 8 ;
brea k ;
c a s e RA D_2 :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > v e c t 3 . y = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
n o_p a r a m i = 1 6 ;
brea k ;
c a s e PAtt e r n :
n ew o b j - > p a t t e r n=At t a c h_ P a t t e r n ( ) ;
brea k ;
c a s e REMOV E :
n ew o b j - > r e m o v e=At t a c h_ P a t t e r n ( ) ;
brea k ;
c a s e XMU LT :
g e t_ s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > xm u l t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e YMU LT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - >y m u l t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e NAM E :
g e t_s t r i n g ( n ew o b j - > n a me ) ;
brea k ;
case PAREN :
brea k ;

119
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

defa u l t :
found FALSE ;

i f ( ! found )
(
c o u t < < " U n d e f i n e d p a r a me t e r " < < s t r i n g_b u f < <
" wh i l e l oa d i ng r i ng i n ' i nput . cpp ' " ;
exi t ( l ) ;

i f ( n o_ p a r a m ! = 3 1 )
{
c o u t < < "Too few p a r amet e r s f o r r i n g i n ' i n p u t . c pp ' " ;
exi t ( l ) ;

n ew o b j - > v e c t 3 . z O;
n ew o b j - > v e c t l = - n e w o b j - > v e c t l ;
n ew o b j - > v e c t 2 = - n ew o b j - > v e c t 2 ;
n ew o b j - > n o rm = n e w o b j - > v e c t l A n ew o b j - > v e c t 2 ;
n ew o b j - > n o r m = - n e w o b j - > n o rm ;
n ew o b j - > n l = n ew o b j - > n o rm % n e w o b j - > l o c ;
n ew o b j - > l e n l = n ew o b j - > v e c t l % n ew o b j - > v e c t l ;
n e w o b j - > l e n 2 = n ew o b j - > v e c t 2 % n ew o b j - > v e c t 2 ;
W O R L D . o b j c o u n t++ ;
retu rn ( newobj ) ;

G e t P a r a l l e l o g r a m ( ) = L o a d a p a r a l l e l o g r a m f r om f g e t a n d
r e t u r n po i n t e r to i t

*/

Obj ect * Get Pa ra l l el og r a m ( )


I
P a r a l l e l o g r a m * n ew o b j ;
i n t t y p e=O , n o_p a r a m = 0 , f o u n d ;
f l o a t temp ;

n ew o b j = n e w P a r a l l e l o g r a m ;
n ew o b j - > c o l _d a t a = n e w c o l o r_d a t a ;
* n ew o b j - > c o l _d a t a = d e f . c o l _d a t a ;

1 20
C O M M U N I C AT I N G W I T H T H E R AV T R A C E R

w h i l e ( ty p e ! = P A R E N & & ! f e o f ( f g e t ) )
{
t y p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
f o u n d = g e t_c o l o r_d a t a ( ty p e , n e w o b j - > c o l _d a t a ) ;
i f ( found == T RU E )
cont i nue ;
found = T RU E ;
s w i t c h ( ty p e )
I
c a s e LOC :
n ew o b j - > l o c . g e t_v e c t o r ( ) ;
n o_p a r a m I l ;=

brea k ;
case Vl :
n e w o b j - > v e c t l . g e t_v e c t o r ( ) ;
n o_p a r a m I 2 ; =

brea k ;
case V2 :
n e w o b j - > v e c t 2 . g e t_v e c t o r ( ) ;
n o_p a r a m I 4 ; =

brea k ;
c a s e PAtt e r n :
n ew o b j - > p a t t e r n =A t t a c h_P a t t e r n ( ) ;
brea k ;
c a s e REMOV E :
n ew o b j - > r e m o v e=At t a c h_ P a t t e r n ( ) ;
brea k ;
c a s e XMU LT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n e w o b j - > xm u l t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e YMU LT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - >y m u l t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e NAM E :
g e t_s t r i n g ( n ew o b j - > n a m e ) ;
brea k ;
case PAREN :
brea k ;
defa ul t :
found = FALSE ;

1 21
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

i f ( ! fo u n d )
(
c o u t < < " U n d e f i n e d p a r a m e t e r " < < s t r i n g_b u f < <
" wh i l e l oa d i ng pa ra l l e l ogram i n ' i nput . cpp ' " ;
ex i t ( l ) ;

i f ( n o_p a r a m ! = 7 )
(
c o u t < < "Too few pa r a met e r s f o r pa r a l l e l o g r a m i n ' i n p u t . cpp ' " ;
ex i t ( l ) ;

n e w o b j - > n o rm = n ew o b j - > v e c t l A n ew o b j - > v e c t 2 ;


n ew o b j - > n o r m = - n ew o b j - > n o r m ;
n ew o b j - > n l = n ew o b j - > n o r m % n ew o b j - > l o c ;
n ew o b j - > l e n l = n e w o b j - > v e c t l % n ew o b j - > v e c t l ;
n ew o b j - > l e n 2 = n ew o b j - > v e c t 2 % n e w o b j - > v e c t 2 ;
W O R L D . o b j c o u n t++ ;
r e t u r n ( n ew o b j ) ;

I*

GetCone ( ) L o a d a c o n e f r om f g e t a n d r e t u r n p o i n t e r t o i t

*/

Obj ect *GetCone ( )


(
Q u a d r a t i c * n ew o b j ;
i n t ty pe=O , n o_p a r a m 0 , found ;
f l o a t t emp ;
V e c t o r n ewd i r ;

n ew o b j = n e w Q u a d r a t i c ;
n ew o b j - > c o l _d a t a = n e w c o l o r_d a t a ;
* n ew o b j - > c o l _d a t a = d e f . c o l _d a t a ;
n ew o b j - > v e c t l = V e c t o r ( 0 , 1 , 0 ) ;
w h i l e ( ty p e ! = P A R E N && ! f e o f ( f g e t ) )
(
t y p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
f o u n d = g e t_c o l o r_d a t a ( ty p e , n ew o b j - > c o l _d a t a ) ;

1 22
C O M M U N I C AT I N G W I T H T H E R AV T R A C E R

i f ( f o u n d == T R U E )
cont i nue ;
found = T RU E ;
swi t c h ( type )
(
c a s e LDC :
n ew o b j - > l o c . g e t_v e c t o r ( ) ;
n o_p a r a m I = l ;
brea k ;
c a s e RA D I U S :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > v e c t 2 . x = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m I = 2 ;
brea k ;
c a s e H E I GHT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > v e c t 2 . z = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m I = 4 ;
brea k ;
case DIR:
n ew o b j - > v e c t l . g e t_v e c t o r ( ) ;
brea k ;
c a s e PAt t e r n :
n ew o b j - > p a t t e r n=A t t a c h_P a t t e r n ( ) ;
brea k ;
c a s e REMOV E :
n ew o b j - > r e m o v e=A t t a c h_ P a t t e r n ( ) ;
brea k ;
c a s e XMU LT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > xm u l t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
ca s e YMU LT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - >y m u l t = f a b s ( a t o f ( s t r i n g_ b u f ) ) ;
brea k ;
c a s e NAM E :
g e t_s t r i n g ( n ew o b j - > n a m e ) ;
brea k ;
c a s e PA R E N :
brea k ;

1 23
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

defa ul t :
found FALSE ;

i f ( ! found )
!
c o u t < < " U n d e f i n e d p a r a m e t e r " < < s t r i n g_b u f < <
" whi l e l oadi ng cone i n ' i nput . cpp ' " ;
exi t ( 1 ) ;

i f ( n o_p a r a m ! = 7 )
!
c o u t < < " T o o few p a r a me t e r s f o r c o n e i n ' i n p u t . c p p ' " ;
ex i t ( l ) ;

n ew o b j - > c t e rm O;
n ew o b j - > l ow e r . x - n ew o b j - > v e c t 2 . x ;
n ew o b j - > l ow e r . z - n ew o b j - > v e c t 2 . x ;
n ew o b j - > l ow e r . y - n ew o b j - > v e c t 2 . z ;
n ew o b j - > u p p e r . x n ew o b j - > v e c t 2 . x ;
n ew o b j - > u p p e r . z n ew o b j - > v e c t 2 . x ;
n ew o b j - > u p p e r . y O;
n ew o b j - > v e c t 2 . x n ew o b j - > v e c t 2 . x * n ew o b j - > v e c t 2 . x ;
n ew o b j - > v e c t 2 . z n ew o b j - > v e c t 2 . z * n ew o b j - > v e c t 2 . z ;
n ew o b j - > v e c t 2 . y - n e w o b j - > v e c t 2 . x * n ew o b j - > v e c t 2 . x ;
n ew o b j - > v e c t 2 . x n ew o b j - > v e c t 2 . x * n ew o b j - > v e c t 2 . z ;
n ew o b j - > v e c t 2 . z n ew o b j - > v e c t 2 . x ;
n ew o b j - > v e c t l = - n ew o b j - > v e c t l ;
t em p = n ew o b j - > v e c t l . x * n ew o b j - > v e c t l . x + n e w o b j - > v e c t l . z *
n ew o b j - > v e c t l . z ;
i f ( t e m p == 0 )
n ew o b j - > c o s l l;
el se
n ew o b j - > c o s l n ew o b j - > v e c t l . z / s q r t ( t e mp ) ;
n ew o b j - > s i n l s q r t ( l - n ew o b j - > c o s l * n ew o b j - > c o s l ) ;
n ewd i r . x = n ew o b j - > v e c t l . x * n ew o b j - > c o s l + n ew o b j - > v e c t l . z *
- newobj - > s i n l ;
n ewd i r . y = n ew o b j - > v e c t l . y ;
n ewd i r . z = n ew o b j - > v e c t l . x * n ew o b j - > s i n l +
n ew o b j - > v e c t l . z * n ew o b j - > c o s l ;
t em p = n ewd i r . y * n ewd i r . y + n ewd i r . z * n ewd i r . z ;
i f ( t e m p == 0 )

1 24
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R

n ew o b j - > c o s 2 l;
el se
n ew o b j - > c o s 2 n ewd i r . y / s q r t ( t em p ) ;
n e w o b j - > s i n 2 = s q r t ( l - n ew o b j - > c o s 2 * n ew o b j - > c o s 2 ) ;
W O R L D . o b j c o u n t++ ;
r e t u r n ( n ew o b j ) ;

/* rr=
====;i
GetQuadrati c ( ) L o a d a q u a d r a t i c s u r f a c e f r om f g e t a n d
return po i n ter to i t

*/

Obj ect *GetQuadrat i c ( )


{
Q u a d r a t i c * n ew o b j ;
i n t t y p e=O , n o_p a r a m 0 , found ;
f l o a t t em p ;
V e c t o r n ewd i r ;

n ew o b j = n e w Q u a d r a t i c ;
n ew o b j - > c o l _d a t a = n ew c o l o r_d a t a ;
* n ew o b j - > c o l _d a t a = d e f . c o l _d a t a ;
n ew o b j - > v e c t l = V e c t o r ( 0 , 1 , 0 ) ;
w h i l e ( ty p e ! = P A R E N & & ! f e o f ( f g e t ) )
{
t y p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
f o u n d = g e t_c o l o r_d a t a ( ty p e , n ew o b j - > c o l _d a t a ) ;
i f ( f o u n d == T R U E )
con t i n u e ;
found = T RU E ;
s w i t c h ( ty p e )
{
c a s e LOC :
n e w o b j - > l o c . g e t_v e c t o r ( ) ;
n o_p a r a m I = l ;
brea k ;
case A:
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > v e c t 2 . x = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m I = 2 ;

1 25
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

brea k ;
case B :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > v e c t 2 . y = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m I = 4 ;
brea k ;
case C :
g e t_s t r i n g ( s t r i n g_b u f ) ;
newobj - > v e c t 2 . z = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m I = 8 ;
brea k ;
case D :
g e t_ s t r i n g ( s t r i n g_b u f ) ;
n e w o b j - > c t e rm = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m I = 1 6 ;
brea k ;
case E :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n e w o b j - >y t e rm = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m i = 3 2 ;
brea k ;
case XMI N :
g e t_ s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > l o w e r . x = a t o f ( s t r i n g_b u f ) ;
brea k ;
c a s e X MA X :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > u p p e r . x = a t o f ( s t r i n g_b u f ) ;
brea k ;
case YMI N :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > l ow e r . y = a t o f ( s t r i n g_b u f ) ;
brea k ;
c a s e Y MA X :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > u p p e r . y = a t o f ( s t r i n g_b u f ) ;
brea k :
case ZM I N :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > l owe r . z = a t o f ( s t r i n g_b u f ) ;
brea k :

1 26
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R

c a s e ZMAX :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > u p p e r . z = a t o f ( s t r i n g_b u f ) ;
brea k ;
case D I R :
n ew o b j - > v e c t l . g e t_v e c t o r ( ) ;
brea k ;
c a s e PAt t e r n :
n ew o b j - > p a t t e r n =A t t a c h_P a t t e r n ( ) ;
brea k ;
c a s e REMOV E :
n ew o b j - > r e mo v e=At t a c h_P a t t e r n ( ) ;
b r ea k ;
c a s e X M U LT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > x m u l t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e YMU LT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - >y m u l t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e N AM E :
g e t_s t r i n g ( n e w o b j - > n a me ) ;
brea k ;
case PAREN :
brea k ;
defa u l t :
found FALSE ;

i f ( ! found )
{
c o u t < < " U n d e f i n e d p a r a me t e r " < < s t r i n g_b u f < <
" w h i l e l oa d i ng q u a d r i c i n ' i nput . cpp ' " ;
ex i t ( l ) ;

i f ( ( n o_p a r a m ! = 6 3 ) & & ( n o_p a r a m ! = 5 9 ) )


{
c o u t < < " T o o f e w p a r a me t e r s f o r q u a d r i c i n ' i n p u t . c p p ' " ;
ex i t ( l ) ;

n ew o b j - > v e c t l - n ew o b j - > v e c t l ;

1 27
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

t e m p = n e w o b j - > v e c t l . x * n ew o b j - > v e c t l . x + n e w o b j - > v e c t l . z *


n ewobj - > v e c t l . z ;
i f ( temp == 0)
n ew o b j - > c o s l l;
el se
newobj - >cos l n ew o b j - > v e c t l . z / s q r t ( t e m p l ;
newobj - > s i n l = s q r t ( l - n ew o b j - > c o s l * n ew o b j - > c o s l l ;
n ewd i r . x = n ew o b j - > v e c t l . x * n e w o b j - > c o s l + n ew o b j - > v e c t l . z *
- n ewo b j - > s i n l ;
n ewd i r . y = n ew o b j - > v e c t l . y ;
n ewd i r . z = n ew o b j - > v e c t l . x * n ew o b j - > s i n l +
n ew o b j - > v e c t l . z * n ew o b j - > c o s l ;
t em p = n e wd i r . y * n ewd i r . y + n ewd i r . z * n ewd i r . z ;
i f ( t e m p == 0 )
newobj - >c o s 2 l;
el se
newobj - > c o s 2 n e wd i r . y / s q r t ( t em p l ;
n ewobj - > s i n 2 = s q r t ( l - n ew o b j - > c o s 2 * n ew o b j - > c o s 2 l ;
W O R L D . o b j c o u n t++ ;
r e t u r n ( n ew o b j l ;

/ * rr=====;i
Get Fracta l ( ) L o a d a f r a c t a l f r om f g e t a n d r e t u r n
po i nt e r to i t

*/

Obj ect * Get F r a c t a 1 ( Obj ect *queue )


I
T r i a n g l e * n ew o b j ;
i n t t y p e=O , n o_p a r a m 0 , found ;
Vector temp ;

n ew o b j = n ew T r i a n g l e ;
n ew o b j - > c o l _d a t a = n e w c o l o r_d a t a ;
* n ew o b j - > c o l _d a t a = d e f . c o l _d a t a ;
w h i l e ( ty p e ! = P A R E N & & ! f e o f ( f g e t ) )
I
t y p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
f o u n d = g e t_c o l o r_d a t a ( ty p e , n e w o b j - > c o l _d a t a ) ;
i f ( f o u n d == T R U E )

1 28
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R

cont i nue ;
found = T RU E ;
swi tch ( type )
{
c a s e LOC :
n ew o b j - > l o c . g e t_v e c t o r ( ) ;
n o_p a r a m I = l ;
brea k ;
case Vl :
n ew o b j - > v e c t l . g e t_v e c t o r ( ) ;
n o_p a r a m I = 2 ;
brea k ;
case V2 :
n ew o b j - > v e c t 2 . g e t_v e c t o r ( ) ;
n o_p a r a m I = 4 ;
brea k ;
case DI MENS I ON :
g e t_s t r i n g ( s t r i n g_b u f ) ;
W O R L D . f r a c t a l _d i m = a t o f ( s t r i n g_b u f ) ;
brea k ;
c a s e S C A LA R :
g e t_ s t r i n g ( s t r i n g_b u f ) ;
W O R L D . f r a c t a l _s c a l a r = a t o f ( s t r i n g_b u f ) ;
brea k ;
c a s e PAtte rn :
n ew o b j - > p a t t e r n =At t a c h_P a t t e r n ( ) ;
brea k ;
c a s e REMOV E :
n ew o b j - > r e m o v e=A t t a c h_P a t t e r n ( ) ;
brea k ;
c a s e XMU LT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > x m u l t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e YMU LT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - >y m u l t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e N AM E :
g e t_s t r i n g ( n ew o b j - > n a me ) :
brea k :

1 29
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

case PAREN :
brea k ;
defaul t :
found FA LS E ;

i f ( ! found )
{
c o u t < < " U n d e f i n e d p a r a m e t e r " < < s t r i n g_b u f < <
" whi l e l oadi ng fracta l t r i angl e i n ' i nput . cpp ' " ;
exi t ( l ) ;

i f ( n o_p a r a m ! = 7 )
{
c o u t < < " T o o few p a r a m e t e r s f o r f r a c t a l t r i a n g l e i n ' i n p u t . c p p ' " ;
ex i t ( l ) ;

F r a c t a l _c om p ( n ew o b j ) ;
q u e u e = M a k e_f r a c t a l _t r i a n g l e s ( n ew o b j - > l o c , n ew o b j - > v e c t l ,
n ew o b j - > v e c t 2 , n ew o b j - > v e c t 3 , q u e u e , WO R L D . l e v e l ) ;
W O R L D . o b j c o u n t++ ;
ret u rn ( queue ) ;

/* r.=====�

G e t_O b j e c t ( ) = L o a d a n o b j e c t f r om f g e t
and return po i nt e r to i t

*/

O b j e c t * G e t_O b j e c t ( i n t t y p e , O b j e c t * q u e u e )
{
O b j e c t * n ew o b j ;
n ew o b j = N U L L ;
s w i t c h ( ty p e )
{
case SPHERE :
n ew o b j =Ge t S p h e r e ( ) ;
b r ea k ;
c a s e P A RA L L E L O G RAM :
n ew o b j =G e t P a r a l l e l o g r a m ( ) ;

1 30
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R

brea k ;
c a s e T R I ANGLE :
n ew o b j = G e t T r i a n g l e ( ) ;
brea k ;
case RING:
n ew o b j = G e t R i n g ( ) ;
brea k ;
c a s e Q U A D RAT I C :
n ew o b j =G e t O u a d r a t i c ( ) ;
brea k ;
c a s e CON E :
n ew o b j =G e t C o n e ( ) ;
brea k ;
c a s e F RA C TA L :
n ew o b j = G e t F r a c t a l ( q u e u e ) ;
brea k ;
c a s e I N S T A N C E_O F :
n ew o b j =G e t_ I n s t a n c e_O f ( ) ;
brea k ;

r e t u r n ( n ew o b j ) ;

/* ===�
rr=
A t t a c h_ P a t t e r n ( ) = F i n d s p a t t e r n m a t c h i n g o b j e c t p a t t e r n
n ame a n d ret u r n s po i n t e r to i t

*/

P a t t e r n * A t t a c h_P a t t e r n ( )
{
Pattern * pat ;

g e t_s t r i n g ( s t r i n g_b u f ) ;
p a t=WO R L D . p a t l i s t ;
w h i l e ( pa t ! =N U L L )
{
i f ( s t r c m p ( s t r i n g_b u f , p a t - > n a m e ) ==O )
brea k ;
p a t=p a t - > s i b l i n g ;

i f ( p a t == N U L L )

1 31
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

cout << "Pa ttern not found \ n " :


exi t ( 1 ) :

ret u rn ( pa t ) ;

/*
G e t_C i r c l e_P a t t e r n ( ) Loa d s a c i r c l e s u b - pattern

*/

P a t t e r n * G e t_C i r c l e_ P a t t e r n ( )
I
i n t t y p e=O , n o_p a r a m = 0 , found ;
Pattern *pa ttern :
c o l o r_d a t a c o l _d a t a ;

p a t t e r n= n e w P a t t e r n :
p a t t e r n - > n a me [ O J = NULL :
pattern - >c h i l d = NULL ;
pattern - > s i bl i ng = N U L L :
pattern - >l i n k = N U L L ;
p a t t e r n - >type = C I RC L E :
c o l _d a t a = d e f . c o l _d a t a :
w h i l e ( ty p e ! = P A R E N & & ! f e o f ( f g e t ) )
{
t y p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
f o u n d = g e t_c o l o r_d a t a ( ty p e , & c o l _d a t a ) :
i f ( ty p e == RA D I U S )
I
g e t_s t r i n g ( s t r i n g_b u f ) :
pattern - > radi us =a b s ( a t o f ( s t r i n g_b u f ) ) ;
n o_ p a r a m I 1 ;
=

found = TRU E ;

i f ( ty p e == P A R E N )
I
found = T RU E :

i f ( ! fo u n d )
I

1 32
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R

c o u t < < " U n d e f i n e d p a r a me t e r " < < s t r i n g_b u f < <


" i n gett i ng c i rcl e pattern \ n " ;
exi t ( l ) ;

i f ( n o_p a r a m ! = 1 )
{
c o u t < < "Too few p a ramet e r s i n g e t t i n g c i r c l e p a t t e rn \ n " ;
exi t ( l ) ;

p a t t e r n - > c o l _d a t a c o l _d a t a ;
retu rn ( pattern ) ;

/ * n=======;i
G e t_ R e c t_ P a t t e r n ( ) Load a rectangl e sub- pattern

*/

P a t t e r n * G e t_ R e c t_ P a t t e r n ( )
{
i n t t y p e=O , n o_p a r a m =O , f o u n d ;
Pattern *pattern ;
c o l o r_d a t a c o l _d a t a ;

p a t t e r n=new P a t t e rn ;
p a t t e r n - > n a me [ O J = N U L L ;
pattern - >chi l d = NU L L ;
pattern - >s i bl i ng = NULL ;
pattern - > l i n k = N U L L ;
patte r n - >type = RECTANGL E ;
c o l _d a t a = d e f . c o l _d a t a ;
w h i l e ( ty p e ! = P A R E N & & ! f e o f ( f g e t ) )
{
t y p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
f o u n d = g e t_c o l o r_d a t a ( ty p e , & c o l _d a t a ) ;
i f ( f o u n d == F A L S E )
f o u n d = T RU E ;
el se
conti nue ;
swi t c h ( type )
{

1 33
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

c a s e S T A RT_X :
g e t_s t r i n g ( s t r i n g_b u f ) ;
p a t t e r n - > s t a r t x = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m I = l ;
brea k ;
c a s e S T A RT_Y :
g e t_ s t r i n g ( s t r i n g_b u f ) ;
p a t t e r n - > s t a r ty = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m I = 2 ;
brea k :
c a s e E N O_X :
g e t_s t r i n g ( s t r i n g_b u f ) ;
p a t t e r n - > e n d x = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m I = 4 ;
brea k :
c a s e E N D_Y :
g e t_ s t r i n g ( s t r i n g_b u f ) ;
p a t t e r n - > e n dy = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m I = 8 :
brea k ;
case PAREN :
brea k ;
defa ul t :
found FALS E ;

i f ( ! found )
{
c o u t < < " U n d e f i n e d p a r a me t e r " < < s t r i n g_b u f < <
" i n gett i ng rectang l e pattern \ n " :
ex i t ( l ) ;

i f ( n o_p a r a m ! = 1 5 )
{
c o u t < < "Too few p a r amet e r s f o r r e c t a n g u l a r p a t t e rn " :
ex i t ( l ) ;

p a t t e r n - > c o l _d a t a c o l _d a t a :
return ( pa ttern ) :

1 34
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R

G e t_P o l y_ P a t t e r n ( ) Load a pol ygon pattern

*I

P a t t e r n * G e t_P o l y_P a t t e r n ( )
{
i n t t y p e=O , n o_p a r a m = 0 , f o u n d ;
Pattern *pattern , *poi ntpatt ;
c o l o r_d a t a c o l _d a t a ;
patte rn=new P a t t e r n ;
p a t t e r n - > n a me [ O J = N U L L ;
pattern - >chi l d = NULL ;
pattern - > s i bl i ng = NULL ;
pattern - > l i n k = NU L L ;
p a t t e r n - > t y p e = P O L Y GO N ;
c o l _d a t a = d e f . c o l _d a t a ;
w h i l e ( ty p e ! = P A R E N & & ! f e o f ( f g e t ) )
{
found = FALSE ;
t y p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
f o u n d = g e t_c o l o r_d a t a ( ty p e , & c o l _d a t a ) ;
i f ( f o u n d == T RU E )
con t i n u e ;
i f ( ty p e == P O I N T )
{
poi ntpatt = new Pattern ;
g e t_s t r i n g ( s t r i n g_b u f ) ;
p o i n t p a t t - > s t a r t x = a t o f ( s t r i n g_b u f ) ;
g e t_s t r i n g ( s t r i n g_b u f ) ;
p o i n t p a t t - > s t a r ty = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m += l ;
poi n t p a tt - > l i n k = p a t t e rn - > l i n k ;
pattern - > l i n k = poi ntpatt ;
f o u n d = T RU E ;

i f ( ty p e == P A R E N )
brea k ;
i f ( ! found )
{
c o u t < < " U n d e f i n e d p a r ame t e r < < s t r i n g_b u f < <
"

"i n gett i ng pol ygon pattern \ n " ;

1 35
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

ex i t ( l ) ;

i f ( n o_p a r a m < 3)
{
cout << " T o o few p a ramet e r s f o r p o l y g o n p a t t e rn · ;
ex i t ( l ) ;

p a t t e r n - > c o l _d a t a c o l _d a t a ;
retu rn ( pattern ) ;

I * ===================================== = ======
� - === = ====n
G e t_ S u b P a t t e r n ( ) Loa d a s ub pa tte rn

11
*
/

P a t t e r n * G e t_S u b P a t t e r n ( i n t t y p e )
{
s w i t c h ( ty p e )
{
c a s e RECTANG LE :
r e t u r n ( G e t _ R e c t_ P a t t e r n ( ) ) ;
c a s e C I RC L E :
r e t u r n ( G e t_ C i r c l e_ P a t t e r n ( ) ) ;
c a s e PO LYGON :
r e t u r n ( G e t_ P o l y_ P a t t e r n ( ) ) ;
defa ul t :
retu rn ( NU L L ) ;

====;!
*
/ �=
Ge t P a t t e r n ( ) Load a pattern i nto pattern l i st

*
/

i n t Ge t P a t t e r n ( )
{
i n t ty p e=O , n o_p a r a m = 0, f o u n d= T RU E ;
Pattern *pattern , *spa t :
p a t t e r n = n ew P a t t e r n :

1 36
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R

p a t t e r n - > n a me [ O J = N U L L ;
pattern - >chi l d = NULL ;
pattern - >si bl i ng = NULL ;
pattern - > l i n k = N U L L ;
p a t t e r n - > t y p e = P A T T_H E A O E R ;
w h i l e ( ty p e ! = PA R E N && ! feof ( fget ) )
(
t y p e = g e t_ s t r i n g ( s t r i n g_b u f ) ;
s w i t c h ( ty p e )
(
c a s e X_S I Z E :
n o_p a r a m I= l;
g e t_s t r i n g ( s t r i n g_b u f ) ;
p a t t e r n - > x s i z e = a t o f ( s t r i n g_b u f ) ;
brea k ;
c a s e Y _S I Z E :
g e t_ s t r i n g ( s t r i n g_ b u f ) ;
p a t t e r n - > y s i z e = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m I= 2;
brea k ;
c a s e NAM E :
g e t_ s t r i n g ( p a t t e r n - > n a m e ) ;
n o_p a r a m I= 4;
b rea k ;
defa ul t :
f o u n d = FA LS E ;

i f ( ( s p a t = G e t_S u b P a t t e r n ( ty p e ) ) ! = N U L L )
(
s p a t - > s i b l i n g=p a t t e r n - > c h i l d ;
p a t t e r n - > c h i l d=s p a t ;
n o_p a r a m I= 8; found = T RU E ;

i f ( t y p e == P A R E N )
{
f o u n d = T RU E ;

i f ( ! found )
{
cout << " U n d e f i n ed pa rameter " << s t r i n g_ b u f <<
" i n getti ng pattern \ n " ;
exi t ( l ) ;

1 37
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

i f ( n o_p a r a m ! = 15)
{
cout << " T o o few p a r a me t e r s i n g e t t i n g p a t t e r n \ n " :
ex i t ( l ) ;

p a t t e r n - > s i b l i n g=WO R L D . p a t l i s t :
W O R L D . p a t l i s t =p a t t e r n :
return ( T RU E ) :

I*

*I I
!!:::= ==
M a k e Bbox l l C r e a t e a bound i n g box

=�

*
v o i d M a k e_B b o x ( O b j e c t node )
{
*
Obj ect t n od e :
Vector v l , v2 :
i f ( n ode - > c h i l d ! =N U L L )
M a k e_B b o x ( n o d e - > c h i l d ) :
i f ( n ode - > n e x t o b j ! =N U L L )
M a k e_B b o x ( n o d e - > n e x t o b j ) :
i f ( n o d e - > ty p e== B B O X )
{
t n o d e= n o d e - > c h i l d :
n o d e - > l owe r = V e c t o r ( 3e 3 0 , 3 e 3 0 , 3 e 30 ) :
node - > uppe r = Vector ( - 3e30 , - 3e30 , - 3e30 ) :
w h i l e ( t n o d e ! =N U L L )
{
t n od e - > F i n d B box ( &v l , & v 2 ) :
n o d e - > l owe r = v l . m i n ( n o d e - > l owe r ) ;
node - >upper = v 2 . ma x ( node - >uppe r ) ;
t n ode=t n od e - > n ex t o bj :

1 38
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R

*
/
N a me F i n d ( ) F i n d s o b j e c t i n s t a c k w i t h a g i v e n n a me

*
/

O b j e c t * N a me_ F i n d ( O b j e c t * o b j . c h a r * n a me )
{
Obj ect *temp ;

i f ( o b j == N U L L )
return ( NU LL ) ;
i f ( obj - > n ame ! = NU LL)
if ( s t r cmp ( n a me , obj - > n a me ) Ol
retu rn ( obj ) ;
i f ( obj - > c h i l d ! = NU L L )
if ( ( t e m p = N a m e_ F i n d ( o b j - > c h i l d , n a m e ) ) ! = NU LL)
r e t u r n ( temp ) ;
i f ( obj - > n ex t o bj != NULL )
i f ( ( t e m p = N a m e_ F i n d ( o b j - > n e x t o b j , n a m e ) ) ! = NU LL)
r e t u r n ( temp ) ;
return ( NU LL l ;

Get I n s t a n ce ( ) Loa d s a n i n stance of a set of obj ects

*
/

O b j e c t * G e t_ I n s t a n c e_O f ( )
{
c h a r n a me [ 3 2 J ;
i n t t y p e = O , n o_ p a r a m = 0, f o u n d =T R U E ;
Vector offset . mul t ;
Obj ect * sou rce . * dest ;

mu l t = Vec t o r (1,1,1);
w h i l e ( ty p e &&
! = PA R E N ! fe o f ( fget ) )
{
ty p e = g e t_ s t r i n g ( s t r i n g_b u f ) ;
s w i t c h ( ty p e )
{

1 39
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

c a s e NAM E :
g e t_s t r i n g ( n a m e ) :
n o_p a r a m I= 1 :
brea k :
c a s e LOC :
o f f s e t . g e t_v e c t o r ( ) ;
n o_p a r a m I= 2:
brea k :
c a s e SCA L E :
m u l t . g e t_v e c t o r ( ) :
brea k :
case PAREN :
brea k :
defa ul t :
found FA L S E :

i f ( ! found )
(
cout << " U n d e f i n ed pa ramet e r " << s t r i n g_b u f <<
" i n gett i ng I n stance" ;
ex i t ( l ) ;

i f ( n o_p a r a m ! = 3)
(
cout << " T o o few p a r a me t e r s i n g e tt i n g I n s t a n c e " ;
exi t ( l ) :

i f ( ( s o u r c e = N a m e_F i n d ( W O R L D . i n s t a n c e s , n a m e ) ) == N U L L )
(
cout << " U n d e f i n e d i n s t a n c e n a me : " << n a me << "\n" :
ex i t ( l ) ;

d e s t = M o v e_ I n s t a n c e ( s o u r c e , T R U E ) ;
d e s t - > S c a l e_ I n s t a n c e ( & m u l t , T R U E ) ;
O f f s e t_ I n s t a n c e ( d e s t , & o f f s e t , T R U E ) ;
W O R L D . o b j c o u n t ++ ;
return ( dest ) ;

1 40
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R

/
* ..,... ======-======-=======--=========-==============;i
...........

M o v e_ I n s t a n c e ( ) = M o v e s u s e r d e f i n e d p r i m i t i v e f r om
W O R L D . i n s t a n c e to W O R L D . s t a c k

*I

O b j e c t * M o v e_ I n s t a n c e ( O b j e c t * o b j , i nt ffl ag )
{
O b j e c t * n ew o b j ;
i f ( o b j == N U L L )
retu rn ( NU L L ) ;
s w i t c h ( o b j - > ty p e )
{
case SPHERE :
n ewobj = n ew S p h e r e ;
brea k ;
case T R I ANGLE :
n ew o b j = n ew T r i a n g l e ;
brea k ;
case RING:
n ew o b j = n ew R i n g ;
brea k ;
c a s e P A RA L L E L O G R A M :
n ewobj = n ew P a r a l l e l og r a m ;
brea k ;
c a s e Q U A D RAT I C :
n ewobj = n ew Q u a d r a t i c ;
brea k ;
case BBOX :
n ewobj n ew B B o x ;
brea k ;
defa ul t :
n ewobj n ew O bj e c t ;

* n ewobj = * obj ;
n ew o b j - > c h i l d = M o v e_ I n s t a n c e ( o b j - > c h i l d , F A L S E ) ;
i f ( ! ffl a g )
n ewo bj - > n ex t o b j M o v e_ I n s t a n c e ( o b j - > n e x t o b j , F A L S E ) ;
el se
n ewobj - > n e x t o b j NU L L ;
r e t u r n ( n ewobj ) ;

1 41
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

/*
Offset I n stance ( ) O f f s e t s a u s e r d e f i n e d p r i m i t i v e by
vector · offset '

*/

v o i d Offs et_I n s t a n c e ( Obj ect *obj , V e c t o r *offset . i n t ffl ag )


{
i f ( o b j ==N U L L )
return ;
obj - > l oc = obj - > l oc + *offset ;
s w i t c h ( o b j - > ty p e l
{
case SPHERE :
obj - >n l = obj - > vec t l . x * obj - >vect l . x ;
brea k ;
c a s e P A RA L L E L O G RAM :
case T R I ANG L E :
case R I NG :
obj - > n l = obj - > n o rm % obj - > l oc ;

O f f s e t_ I n s t a n c e ( o b j - > c h i l d , o f f s e t , F A L S E ) ;
i f ( ! ffl ag )
O f f s e t_ I n s t a n c e ( o b j - > n e x t o b j , o f f s e t , F A L S E ) ;

We will now describe how these kinds of data are treated.

Processi n g Attributes
The first type of data checked by the get_data function is attributes. This is
accomplished by calling the GetAttrib function. This function consists of a large
switch statement, which provides the proper actions for every attribute type that
might have been returned by the parser. As the function is entered, the local
found parameter is set to TRUE. At the end of the switch statement is the
default case, which is entered only if there is no match for any of the other cases.
The default case changes found to FALSE. Upon returning, the function returns
the value of found.

1 42
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R

The first type of attribute checked is sky data. If a match i s found, the
function enters a loop which uses the parser to read strings and processes each
with a switch statement until a right parenthesis is encountered, at which point
the loop terminate s . There are three acceptable strings (besides the right
parenthesis) for sky data. For the first two, ZENITH and HORIZ, a vector is
read into the appropriate place in the WORLD data. For the third kind of string,
DITHER, a string is read in, converted to a floating-point number, and the
absolute value entered into the WORLD .sky_dither parameter. This parameter
should always be positive. If a negative number is encountered, we might
choose to declare this an error, print an error message, and exit. Instead, by
taking the absolute value , we ignore the minus sign and assume that the
numerical value is correct.

Within the loop for sky parameters, we set the found parameter to TRUE
before entering the loop and then set it to FALSE if we ever get to the default
case. This means that when we exit the loop, if any string encountered within
the loop is unacceptable. found will be FALSE; otherwise it remains TRUE.

Next is the COLOR attribute. There are two different ways of assigning
color information to an object. One is a default array of color data stored in the
program. Whenever an object is created, all of the color information starts out
with the default color v alues. Then, as object data is entered from the file,
various items of color information may be entered; if they are, they replace the
default values . The COLOR attribute permits changing of the default color
values. Thus, you may enter default color values without object color values and
all following objects take on the default values. When you want a different
colored object, you change the default values before you define the next object.
Alternately, you can leave the default values alone and specify particular color
values for each object. This attribute is processed by a repeated loop until an end
of file is encountered, or a string is read which is a right parenthesis. The loop
begins by getting a string w i th the parser. The string i s then sent to the
get_color_data function, which checks for legitimate color data and processes it.
This function is described below. It returns a TRUE if the item was correct color

143
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

data or a FALSE. If the string was not a legitimate color parameter, an error
mes sage i s printed out and the program terminate s . Otherw i s e the loop
continues processing color data until it terminates.

If the attribute is FOC_LENGTH, the parser gets the focal length string from
the data file. It is converted to a floating-point number, the absolute value of this
taken (since negative focal lengths are impossible) and multiplied by five. The
result is stored in WORLD flength . The focal length parameter is used as a
multiplier to scale the perspective of the scene. With the mathematics in the ray­
tracing functions, a parameter five times the focal length of the lens gives the
proper perspective for a 35 millimeter camera. We won 't go deeply into optics,
but be aware that a "normal" lens (which gives the kind of photograph we are
used to viewing), has a different focal length for each different film size. If you
go above the "normal" value, objects appear closer, but also more compressed.
This is the telephoto lens. If you go below the "normal" value, you have a wide­
angle lens, which crams more into the picture, but creates distortion. We have
set up the mathematics so that the focal length inputs correspond to a 35 mm
camera, because it is so widely used and many people are familiar with the
photographic effects of the different lenses.

If the attribute i s FILE_NAME, the parser reads the next string and it is
copied to the parameter WORLD .outfi/e, used in opening the output data file.

The next attribute defines a lamp. Lamps are processed with a loop similar
to sky data. Only one parameter is required of a lamp, namely its location.
Another parameter, distance, is set to a default parameter of 1 50 for each new
lamp source, but may be changed by data from the file. In addition, a radius
parameter may be entered (to remain compatible with QRT), but it is otherwise
not essential. When the loop ends, the parameter noyaram will have a value of
one if the location has been entered. If not, an error message will be displayed
and the program terminated. This loop also uses the found parameter to generate
an error message and terminate the program if an undefined parameter i s
encountered. Once a lamp has successfully been defined, a new lamp structure

1 44
C O M M U N I C AT I N G W I T H T H E R AV T R A C E R

i s c r e a t e d and the d a t a tran s ferred to i t . The addre s s of the c urrent


WORLD . lamps is placed in the lamp variable next_lamp and the address of the
new lamp structure is placed in WORLD .lamps.

Getting observer information is the next attribute. It is processed in a


manner similar to sky data, with a loop that gets strings and processes them
through a switch statement. In addition to the right parenthesis which terminates
the loop, there are three vectors that define the observer position. They are the
observer 's location , direction of v iew, and the direction that is "up" to the
observer. A vector is obtained from the data stream for each of these, and stored
in the proper place in the WORLD . We use the same procedure with the found
variable, previously described, to terminate the program with an error message if
an incorrect parameter is encountered. The observer "up" direction has an
original default value, so it is not absolutely necessary to supply this parameter.
However, the other parameters must be specified if the program is to work
correctly. Hence we have included a parameter noyaram which is zeroed at the
start of the GetA ttrib function. It has various bits ored to it for each parameter
read. When we finish reading observer data, if both parameters have been read,
this test parameter should have a v alue of 3 . If it does not, the program
terminates and prints an error message.

The GetA ttrib function next processes the PATTERN attribute. This i s
handled b y the GetPattern function, which will be described later.

The function then processes the XRES and YRES attributes. It uses the
parser to read a string for each of these, converts it to a floating-point number,
takes the absolute value of this number, and places it in the appropriate WORLD
parameter.

Finally, if the attribute is NAME, the parser gets the next string and places it
in the variable name.

1 45
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

Processing Color Data


The get_color_data function performs checking and processing for all valid
color data parameters with a switch statement. The first characteristics to be
processed are for ambient lighting, diffuse color, mirror, transmission, and
density. Each is a vector. These vectors are specified in the data file as having
red, green, and blue components between zero and one . Actually, in the
program, they are expected to vary between zero and the maximum number of
colors (CNUM).

Hence, each one is processed by using the get_vector function to read the
data from the stream and convert it into a vector. The vector is then multiplied
by CNUM to obtain the proper color range. Color data is stored in a color data
array, with address specified by a parameter passed to the function. Next, three
floating-point parameters are processed: index of refraction, dither value, and the
specular reflection coefficient. These are all positive numbers, so that the string
obtained from the data stream by the parser is converted from a floating-point
number into an absolute value.

Finally, the reflection coefficient is processed. This is a floating-point


number which must be multiplied by CNUM, after the incoming value has been
converted to a floating point from the string obtained by the parser.

Processing Instances
All of the instances defined in a file must be placed in a single block which
starts with BEGIN_INSTANCES and ends with END_INSTANCES. When this
first string is encountered, the get_data function is recalled recursively. This
results in the generation of a separate list of objects similar to the main list
described below. The get_data function terminates at the END_INSTANCES
string, whereupon the address of the last object added to the linked list is placed
in WORLD .instances.

Processi n g Bou nding Boxes


When you want a bounding box to surround a set of objects, the string

1 46
C O M M U N I C AT I N G W I T H T H E R AV T R A C E R

BEGIN_BBOX is placed before the data of the first set of objects in the data file
and the string END_BB OX is placed after the end of the data of the last set of
objects. The reason for using a bounding box is to accelerate computations.
Instead of checking whether each ray intersects each nearby object, we can first
check to see if the ray intersects the bounding box. If it does not (as will happen
in most cases), we are through. Only for the few rays that intersect the bounding
box do we need to test against each of the enclosed objects for an intersection.
When the BEGIN_BBOX string is encountered, we first create an object of the
BBOX type. We then copy the current name to its name parameter. We then run
get_data recursively, putting all of the objects encountered into a separate linked
list until the string END_BBOX is encountered. At this point we terminate
get_data and place the address of the last object entered into the linked list in the
child of the box we are creating.

Processing Objects
Next, get_data calls the function Get_Object if the string indicates that
object data is to be processed. This function uses a switch statement to call the
proper function for the object to be created.

Creating a Sphere
If a sphere is to be created, we first allocate memory space. (The call to new
for class Sphere not only assigns the proper amount of memory, but also assures
that this object is always of class Sphere.) Next the function begins a while loop,
where it remains until the file ends or a right parenthesis is encountered. At the
beginning of each iteration of this loop, the parser gets a string. The parameter
found is set to TRUE. A switch statement is then run to see if the string matches
any parameters for the class Sphere. Except for the PATTERN string, which we
will describe later, each acceptable string generates a vector or number from the
data and stores it in the appropriate object variable location.

Some of these variables are optional; others are essential to the creation of a
sphere. When an essential variable is processed, the no_yaram variable has a bit
set in it so that when the loop is terminated, the parameter will contain a 3 if the

1 47
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +

essential parameters have been read. If the parameter does not contain a 3 when
the loop is finished, an error message is displayed and the program terminates.
As in processing several of the attributes, the default for the switch statement is
to set the found parameter to FALSE. So, upon leaving the loop, i f thi s
parameter is FALSE, i t indicates that an incorrect string was encountered. I n this
situation, the program displays an error message and terminates. Otherwise, the
function proceeds to precompute any parameters that do not change for the
sphere and are needed in the process of computing ray intersection s . B y
computing them at this point and storing them i n the object data structure, only
one c o m p u t a t i o n i s req u i re d ( rather than one for e v e r y ray t e s t e d fo r
intersection). In the case of the sphere, the only parameter that is computed is
nl . Finally, WORLD .objcount is incremented, which keeps count of the total
number of objects in the scene.

Creating a Triangle
As with a sphere, we allocate the memory space for a triangle by calling new
(for class Triangle) which not only assigns the proper amount of memory, but
assures that this object is always of class Triangle. Next, the function begins a
while loop, where it remains until the fi le ends or a right parenthe s i s i s
encountered. A t the beginning o f each iteration of this loop, the parser gets a
string. The parameter found is set to TRUE and a switch statement runs to see if
the string matches any of the acceptable parameters for the class Triangle .
Except for the PATTERN string, each acceptable string causes a vector or
number to be read from the data and stored in the appropriate object variable
location . S ome of these variables are optional ; others are essential to the
creation of a triangle. When an essential variable is processed, the no_yaram
variable has a bit set in it in such a manner that when the loop is terminated, the
parameter will contain a 7 if the essential parameters have been read in. If the
parameter does not contain a 7 when the loop is finished, an error message is
displayed and the program terminates. As in processing several of the attributes,
the default for the switch statement is to set the found parameter to FALSE. So,
on leaving the loop, if this parameter is FALSE, it indicates that an incorrect
string was encountered. In this situation, the program displays an error message

1 48
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R

and terminates. The critical parameters for the triangle are: loc, which is the
location of one of the vertices of the triangle in system coordinates; vl (stored as
vectl ), which is in a coordinate system centered at the first vertex; and v2 (stored
as vect2 ) , the third vertex of the triangle which is also in a coordinate system
centered at the first vertex. The triangle processing function precomputes norm,
nl , lenl , and len2 , which are used in the intersection computations. Finally, this
function also increments the object count.

Creating a Ring
If a ring is to be created, we first allocate the memory space for a ring. (The
call to new for class Ring not only assigns the proper amount of memory, but
also assures that this object is forevermore known to be of class Ring.) Next, the
function begins a while loop, in which it remains until the file ends or a right
parenthesis is encountered. At the beginning of each iteration of this loop, the
parser is used to get a string. The parameter found is set to TRUE. A switch
statement i s then run to see i f the string m atches any of the acceptable
parameters for the class Ring. Except for the PATTERN string, which we will
describe later, each acceptable string causes a vector or number to be read from
the data and stored in the appropriate object variable location. Some of these
variables are optional; others are essential to the creation of a ring. When an
essential variable is processed, the no_yaram variable has a bit set in it in such a
manner that when the loop is terminated, the parameter will contain a 3 1 if the
essential parameters have been read in. If the parameter does not contain a 3 1
when the loop i s finished, an error message i s displayed and the program
terminates.

As in processing several of the attributes, the default for the switch statement
is to set the found parameter to FALSE. So, upon leaving the loop, if this
parameter is FALSE, it indicates that an incorrect string was encountered. In this
situation, the program displays an error message and terminates. The ring
processing function precomputes norm, nl , lenl , and len2 , which are used in the

1 49
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +

intersection computations. It also sets v e c t3 . z to zero and


normalizes vectl and vect2 . Finally, this function also increments the object
count.

Creating a Paral lelog ram


If a parallelogram is to be created, we first allocate the memory space for a
parallelogram. (The call to new for class Parallelogram not only assigns the
proper amount of memory, but also assures that this object is forevermore known
to be of class Parallelogram.) Next the function begins a while loop, in which it
remains until the fi le ends or a right parenthes i s is encountered. At the
beginning of each iteration of this loop, the parser is used to get a string. The
parameter found is set to TRUE. A switch statement is then run to see if the
string matches any of the acceptable parameters for the class Parallelogram .
Except for the PATTERN string, which we will describe later, each acceptable
string causes a vector or number to be read from the data and stored in the
appropriate object variable location. Some of these variables are optional; others
are essential to the creation of a parallelogram. When an essential variable is
processed, the no_yaram variable has a bit set in it in such a manner that when
the loop is terminated, the parameter will contain a 7 if the essential parameters
have been read in. If the parameter does not contain a 7 when the loop is
finished, an error message is displayed and the program terminates. As in the
processing of several of the attributes, the default for the switch statement is to
set the found parameter to FALSE. So, upon leaving the loop, if this parameter is
FALSE, it indicates that an incorrect string was encountered. In this situation,
the program displays an error message and terminates. The critical parameters
for the parallelogram are loc , which is the location of the first vertex of the
parallelogram in system coordinates; vi (stored as vectl ), which is a vertex of
the parallelogram adjacent to the first vertex in a coordinate system centered at
the first verte x ; and v2 ( stored as vect2 ) , which i s the other vertex of the
parallelogram that is adjacent to the first vertex in a coordinate system centered
at the first vertex. From these three vertices, the function computes the location
of the fourth vertex and stores the information necessary to be able to make a test
of whether an intersection between a ray and the parallelogram occurs. If you

1 50
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R

modify the software so that a fourth vertex can be entered as an input, the
parallelogram object can become a generalized quadralateral. The parallelogram
processing function precomputes norm, nl , lenl , and len2 , which are used in the
intersection computations. Finally, this function also increments the object
count.

Creating a Quad ratic


If a quadratic is to be created, we first allocate the memory space for a
quadratic. (The call to new for class Quadratic not only assigns the proper
amount of memory, but also assures that this object is forevermore known to be
of class Quadratic. ) Next the function begins a while loop, in which it remains
until the file ends or a right parenthesis is encountered. At the beginning of each
iteration of this loop, the parser is used to get a string. The parameter found is
set to TRUE. A switch statement is then run to see if the string matches any of
the acceptable parameters for the class Quadratic. Except for the PATTERN
string, which we will describe later, each acceptable string causes a vector or
number to be read from the data and stored in the appropriate object variable
location.

Some of these variables are optional; others are essential to the creation of a
quadratic. When an essential variable is processed, the no_yaram variable has a
bit set in it in such a manner that when the loop is terminated, the parameter will
contain a 3 1 if the essential parameters have been read in. If the parameter does
not contain a 3 1 when the loop is finished, an error message is displayed and the
program terminates. As in the processing of several of the attributes, the default
for the switch statement is to set the found parameter to FALSE. So, upon
leaving the loop, if this parameter is FALSE, it indicates that an incorrect string
was encountered. In this situation, the program displays an error message and
term inate s . The quadratic preprocessing function normalizes vectl and
precomputes cos] and sin] . It then computes the direction vector newdir, using
vectl and cos] and sin] . Using this new vector, it precomputes cos2 and sin2 .
Finally, this function also increments the object count.

1 51
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +

Creating a Cone
The function for creating a Quadratic can produce a wide variety of shapes,
depending on the coefficients assigned to the terms of the equation. However,
the coefficient values needed for a shape are not always evident. Consequently,
you may w ant to create some new shape names , which use the quadratic
equation. A cone is an example of how such functions are created.

To begin w ith, you need to add the shape name at the beginning of the
input.cpp listing, and an appropriate define statement in the header file.

You need to do this for any new parameter names you will use. Now look at
the GetCone function to see how it is written. It is similar to the other functions
for getting objects except that it creates a new object of class Quadratic. The
terms processed within the switch statement used to define the cone are: radius
(at the base of the cone), cone height, and direction (which is the same as the
curve direction used in getting a quadratic).

After all input data is collected, we convert the radius and height parameters
into the proper coeffic ients for the quadratic equation to produce a cone.
Nothing else has to be done; all of the additional parts of the ray-tracing program
treat this cone in the same way as any other object of class Quadratic. You can
use this technique to create any shapes defined by a quadratic, such as a cylinder.

Attach i ng a Pattern to an Object


The PATTERN string can occur in two contexts: preceding the definition of
the pattern characteristics, or within the definition of an object (to indicate the
name of the pattern associated with this object). It is the latter situation that we
are discussing here.

When the PATTERN string is encountered within an object, the function


Attach_Pattern is called. This function first uses the parser to get the next string,
which is the name of the pattern, then the address of the pattern at the top of the
pattern list, WORLD.patlist. A while loop begins by comparing the name of this

1 52
C O M M U N I C AT I N G W I T H T H E R AV T R A C E R

pattern with the name of the pattern that was read in for the object. If there is a
match, the function terminates and the address of the pattern is returned to the
object function where it is saved as part of the object data structure. If there is
no match, the function obtains the address of the next pattern in the list and
reiterates the loop. If a NULL address is obtained, it indicates that the entire list
has been read without a match being found. In this case, an error message is
displayed and the program terminates.

Processing Pattern Data


When the PATTERN string is outside of an object definition, the GetAttrib
function calls GetPattern to process the data. The data for a pattern must first
specify three parameters: the pattern name, and size in the x and y directions.
Then data for at least one of three acceptable pattern types (rectangle, circle, and
polygon) must appear. The function begins by creating a new pattern variable
and initializing its parameters. Then a while loop reiterates until the file ends or
until a right parenthesis is encountered. At the beginning of each loop iteration,
the function uses the parser to get the next data string. A switch statement
determines if the string is an acceptable one for pattern data; if it is, the next
string is read, converted to a floating-point number if it's not a name, and put
into the appropriate data slot in the pattern structure. The function makes use of
noyaram, as was done with objects, to assure that all of the required parameters
exist.

The found parameter is used a little differently. It starts out as TRUE. After
passing through the switch statement, if the string is not one of the three that
must occur initially in the pattern definition, the default case sets it to FALSE.
After leaving the switch statement, the function calls the Get_SubPattern
function to process data for one of three pattern types. If this function i s
successful, the n oyaram parameter has the appropriate bit added to it, the found
parameter is reset to TRUE, and the address of the sub-pattern put into a list
pointed to by the child parameter.

1 53
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

When the loop i s completed, the function displays an error message and
terminates the program if found is false. Otherwise, it checks the value of
no_param to make sure all required parameters were read from the file. If so,
the parameter should be 1 5 . If not, an error message is d isplayed and the
program terminates. Otherwise, the pattern address is linked to the pattern list
and the function ends.

The Get_SubPattern function is simply a switch statement which calls the


appropriate function to process one of three types of pattern data or returns a
NULL if the type is not one of three acceptable ones.

The Get_Circle_Pattern function processes pattern data for a circle pattern.


It sets up a new pattern and initializes the parameters. A while loop begins,
which is iterated until the end of file occurs or a right parenthesis is encountered.
Then the parser gets the next string. The only acceptable ones are RADIUS, one
of the color data strings, or the right parenthesis. If RADIUS is encountered, the
string is converted to the absolute value of a floating-point number and stored in
the pattern radius parameter. When the loop is complete, the appropriate error
message is displayed if the radius was not found or if an undefined parameter
occurs, and the program terminates. Otherwise, the color data is transferred to
the pattern structure and the function returns the address of the sub-pattern.

The Get_Rect_Pattern function processes pattern data for a rectangle. It sets


up a new pattern and initializes the parameters. A while loop begins, which is
iterated until end of file occurs or a right parenthesis is encountered. The parser
is then used to get the next string . The acceptable strings are START_X,
START_Y, END_X, END_Y, the color data strings, and the right parenthesis.
For each acceptable p arameter ( o ther than the color data and the right
parenthesis) the next string is read, converted to a floating-point number, and
stored in the appropriate variable in the sub-pattern data structure. When the
loop is complete, the appropriate error message is displayed if the rectangular
coordinates were not found or if an undefined parameter occurs, and the program

1 54
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R

terminates. Otherwise, the color data is transferred to the pattern structure and
the function returns the address of the sub-pattern.

The Get_Poly_Pattern function processes pattern data for a polygon. It first


sets up a new pattern and initializes the parameters. Then a while loop is begun,
which is iterated until the end of file occurs or a right parenthesis is encountered.
The parser is then used to get the next string. The only acceptable strings are
POINT, the color data strings , and the right parenthesis. For each POINT
parameter a new pattern is created. Then the next two strings are read by the
parser, c on v erted to fl oating-point numbers , and stored as the x and y
coordinates of a point on the polygon in the new pattern data structure. This
pattern is added to the pattern linked list by properly setting up the addresses in
the pointpatt- > link and pattern->link variables. The no_yaram variable is also
incremented. If the type was not POINT or a right parenthesis, an error message
i s d i splayed and the program terminate s . When the right parenthe s i s i s
encountered, the loop terminates. When the loop is complete, there must be at
least three points defined for a polygon to have been created. Thus if no_yaram
is less than 3 , there aren 't enough points so an error message is displayed and the
program is terminated. Otherwise, the color data is copied to the pattern color
data and the function ends, returning the pattern address.

Transferri ng an Instance to the Object List


When the string INSTANCE_OF i s encountered in the data stream , the
function Get_Instance_Of is called. The first thing that this function does is to
set the multiplier vector mutt to a default value of ( 1 , 1 , 1 ). Next, a while loop
iterates until the file ends or a right parenthesis is encountered. Each iteration of
the loop begins by the parser reading a string from the data stream.

Two parameters are mandatory : the name of the instance, and the location at
which the instance is to be generated. A switch statement is used to check for
these mandatory parameters (using the no_yaram variable to assure that both
occur) for the multiplier vector (which is optional), and for the right parenthesis.
The found parameter is used to cause the program to display an error message

1 55
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +

and terminate if an undefined parameter is encountered. At the completion of


the loop, if both mandatory parameters are not present, the program displays an
error message and terminates. Otherwise, the function Name_Find is called.

This function checks the name just read against every instance name in the
list of instances. If no match occurs, an error message is displayed and the
program terminates. If a match does occur, the function calls Move_Instance.
This function first sets up a new object to match the object in the instances file.
It copies all of the data for that object from the instances file to the new object.
It then calls itself recursively to perform the same operations for any child
objects or succeeding objects in the instances list that are part of the named
instance. Then, the Get_Instance_Of function calls the Scale_Instance function
to apply the multiplier vector to the object. Thi s function differs for each
different type of object under consideration. It will be discussed in detail in
Chapter l 0. Finally, the Get_Instance_Of function calls the Offset_Instance
function which moves the object location from that specified in the instance to
that read in above for this particular instance. It recursively does the same for all
objects associated with this instance.

Making Bou nding Boxes


We have completed loading the world and will return to the main rendering
program (described in Chapter 6). You will note, however, that while we created
a bounding box each time the BEGIN_BBOX string was encountered, and set up
the list linking to the bounding box, we did not establish any parameters for the
size of the bounding box. Consequently, before anything else, the main program
needs to run the function Make BBox to establish these bounds. This function
runs recursively for every object contained in the bounding box. It starts out
with a high value for the lower bound and a low value for the upper bound, then
runs the function FindBbox. This function, which differs for each type of object,
sets an upper and lower bound for the box surrounding the object.

The Make_BBox function then applies the minimum function to the object
lower bounding box and the new lower bound and the maximum function to the

1 56
C O M M U N I C AT I N G W I T H T H E R AV T R A C E R

object upper bound and the new upper bound. Here, minimum and maximum
mean that we take the minimum or maximum of each coordinate to create a new
set of coordinates. When the process is completed, all objects are encompassed
within the bounding box.

1 57
CHAPTER 9

Using the Ray Tracing


Definition Language
Now that we have described how this part of the program creates a scene, we
will regress a bit and describe how to write a data file containing scene data.
First, take a look at the sample data files given in Appendix A. These are
formatted s i m i l ar to the Q RT input language , but are simplified without
violating the relaxed requirements of the parser developed above. Note that the
use of parentheses, equals signs, etc. provide a clear understanding of what is
being done. However, the program described in this chapter is more flexible in
the data structure it requires. In the sections that follow, you ' ll see the bare
minimum that must be included in each data file for the particular property
being described. You can insert any optional characters you desire to enhance
program readability. Furthermore, you can add any comments you need by
enclosing them in curly brackets. (Note that the parser converts all letters of the
alphabet to upper case so you can use any combination of upper and lower case
to enhance readability. They are treated the same, and will end up as capital
l e t t e r s a fte r b e i n g p a r s e d . ) S tr i n g t y p e c h aracters are defi n e d as a l l
alphanumerics plus the underscore character(_) and the decimal point(.). The
minus( - ), and right parenthesis ()) characters are also considered string type
characters, but only if they are at the beginning of a string.

FILE NAM E
In order to specify the name of the output file for the scene data, the string
FILE_NAME must appear in the data stream. It must be followed by at least one
non- string type character and may be followed by as many non- string type
characters as desired. The next string must be an MS-DOS compatible type file
name.

1 59
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +

PATTERN
The PATTERN string is used to initiate the description of a pattern. (The
pattern is projected onto the surface of whatever object has a pattern of this
name.) The string must be followed by at least one string type character and
may be fol l owed by as many non- string type characters as desired. The
following strings may follow the PATTERN string:

X_SIZE This denotes the size of the pattern in the x direction. It must be
followed by one or more non-string type characters, followed by a number
representing the x pattern size, then followed by one or more non-string type
characters.

Y_SIZE This denotes the size of the pattern in the y direction. It must be
followed by one or more non-string type characters, followed by a number
representing the y pattern size, and followed by one or more non-string type
characters.

NAME This denotes the name of the pattern. It must be followed by one or
more non-string type characters, followed by a string giving the pattern name,
which must be followed by one or more non-string type characters.

The above three strings are mandatory for the PATTERN description .
Follow ing them one or more group s of strings must occur to prov ide a
description of the pattern. The first entry in each group must be one of the
following three strings RECTANGLE, which denotes a rectangle pattern,
CIRCLE, which denotes a circle pattern, or POLYGON, which denotes a
polygon pattern. The string must be followed by one or more non-string type
characters. Following all of the information that makes up one of these three
types of patterns, a right parenthesis must occur to complete the pattern data.

The following strings may follow the RECTANGLE string.

1 60
U S I N G T H E R AY T R A C I N G D E F I N I T I O N L A N G U A G E

START_X This denotes the beginning x position of the rectangle pattern. It


must be followed by one or more non-string type characters, which must be
followed by a number corresponding to the x pattern beginning position, which
must be followed by one or more non-string type characters.

START_Y This denotes the beginning y position of the rectangle pattern. It


must be followed by one or more non-string type characters, which must be
followed by a number corresponding to the y pattern beginning position, which
must be followed by one or more non-string type characters.

EN D_X This denotes the end x position of the rectangle pattern. It must be
followed by one or more non-string type characters, which must be followed by
a number corre sponding to the x pattern ending position, which must be
followed by one or more non-string type characters.

E N D_Y This denotes the end y position of the rectangle pattern. It must be
followed by one or more non-string type characters, which must be followed by
a number corre sponding to the y pattern ending position, which must be
followed by one or more non-string type characters.

Color I nformation Any of the items which make up the color data may be
specified in the rectangle pattern data. These are described in the next section.
Note that there is no specific order in which the acceptable strings need to be
listed. You may arrange them at your convenience. After all information for the
rectangle has been supplied, a right parenthesis must occur to terminate the
rectangle pattern data.

The following strings may follow the CIRCLE string.

RADIUS This denotes the radius of the circle pattern. It must be followed
by one or more non-string type characters, which must be followed by a number
corresponding to the x pattern beginning position, which must be followed by
one or more non-string type characters.

1 61
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +

Color I nformation Any of the items which make up the color data may be
specified in the circle pattern data. These are described in the next section. Note
that there is no specific order in which the acceptable strings need to be listed.
You may arrange them at your convenience. After all information for the circle
has been supplied, a right parenthesis must occur to terminate the rectangle
pattern data.

The following strings may follow the POLYGON string.

POI NT This denotes that the coordinates of one point of the polygon pattern
will follow. It must be followed by one or more non-string type characters,
which must be followed by a number corresponding to the x coordinate of the
polygon, which must be followed by one or more non-string type characters,
which must be followed by a number corresponding to the y coordinate of the
polygon, which must be followed by one or more non-string type characters.
The POINT string and its associated numbers must occur at least three times to
define a polygon.

Color Information Any of the items which make up the color data may be
specified in the polygon pattern data. These are described in the next section.
Note that there is no specific order in which the acceptable strings need to be
listed. You may arrange them at your convenience. After all information for the
polygon has been supplied, a right parenthesis must occur to terminate the
rectangle pattern data.

COLOR
Color information may be supplied in two ways. First, there is a default set
of color information which will be used for an object or pattern if other color
information is not furnished. This default color information may be set by
placing the s tring COLOR in the data fi l e . Any of the items of c o l or
information shown below may then occur. When all color information is
complete, the color section must be completed by a right parenthesis. The other
way of supplying color information is to include it in the description of an

1 62
U S I N G T H E R AY T R A C I N G DEFINITION LANGUAGE

object or pattern. Any of the color information items shown below may be
included in an object or pattern description and will then supersede the default
information for this object or pattern only. The strings that may be included as
color information are as follows (the order is immaterial):

AMB This denotes the character of the ambient light impinging upon the
object or pattern. It must be followed by one or more non-string type characters,
which must be followed by three numbers (separated by one or more non-string
type c h arac ters) w h i c h make up the ambient l ight red , green, and blue
components. The last number must be followed by one or more non-string type
characters.

DIFF This denotes the character of the light diffused by the object or
pattern. It must be followed by one or more non-string type characters, which
must be followed by three numbers (separated by one or more non-string type
characters) which make up the diffused light red, green, and blue components.
The last number must be followed by one or more non-string type characters.

M I R ROR This denotes the amount of light directly reflected by the object
or pattern. It must be followed by one or more non-string type characters, which
must be followed by three numbers (separated by one or more non-string type
characters) which make up the reflecting red, green, and blue characteristics.
The last number must be followed by one or more non-string type characters.

TRANS This denotes the light transmission characteristics of a transparent


or semi-transparent object or pattern. It must be followed by one or more non­
string type characters, which must be followed by three numbers (separated by
one or more non-string type characters) which make up the transmission red,
green, and blue components. The last number must be followed by one or more
non-string type characters.

DEN SITY This denotes the density characteristics of an object or pattern. It


must be followed by one or more non-string type characters, which must be

1 63
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

followed by three numbers (separated by one or more non-string type characters)


which make up the density red, green, and blue components. The last number
must be followed by one or more non-string type characters.

I N D EX This denotes the index of refraction of the object or pattern. It must


be followed by one or more non-string type characters which must be followed
by a floating-point number which is the index of refraction, which must be
followed by one or more non-string type characters.

DITH ER This denotes the dither to be applied to an object or pattern. It


must be followed by one or more non-string type characters which must be
followed by a floating-point number which is the amount of dither between two
different colors , which must be followed by one or more non-string type
characters.

$RE FLECT This denotes the specular reflection coefficient for an object or
pattern. It must be followed by one or more non-string type characters which
must be followed by a floating-point number which is the specular reflection
coefficient, which must be followed by one or more non-string type characters.

REFLECT This denotes the specular reflection for an object or pattern. It


must be followed by one or more non-string type characters, which must be
followed by a floating-point number that is the specular reflection, which must
be followed by one or more non-string type characters.

BEGIN BBOX
The BEGIN_BBOX string marks the beginning of a box that will enclose
several objects. It must be followed by at least one non-string type character. It
is followed by descriptions of all of the objects which are to be enclosed within
the box. The box is terminated by the string END_BBOX, which is followed by
one or more non-string type characters.

1 64
U S I N G T H E R AY T R A C I N G D E F I N I T I O N LANGUAGE

BEGIN_INSTANCES
The BEGIN_INSTANCES string marks the beginning of an object or group
of objects that are to appear as a group at several places throughout a scene. It
must be followed by one or more non-string type characters. This must be
followed by the descriptions of one or more objects which make up the instance.
The instance description is terminated by the string END_INSTANCE S ,
followed b y one o r more non-string type characters. The BEGIN_INSTANCES
and END_INSTANCES strings may occur only once in a data file. All instances
to be used in the scene must be included between these two strings in their one
occurrence.

SPHERE
The S PHERE string denotes data for an object which is a sphere. It is
followed by one or more non-string type characters. This is followed by any of
the sphere descriptive items shown below. Finally, the sphere description is
terminated by a right parenthesis. The legitimate strings for a sphere are:

LOC This denotes the location of the sphere. It must be followed by one or
more non-string type characters, which must be followed by three numbers
( separated by one or more non- string type characters) which make up the
location vector. The last number must be followed by one or more non-string
type characters.

RADIUS This denotes the radius of the sphere. It must be followed by one
or more non-string type characters, which must be followed by a floating-point
number which is the sphere radius, which must be followed by one or more non­
string type characters.

PATTERN This denotes that a pattern is to be applied to the surface of the


sphere. It must be followed by one or more non-string type characters, which are
followed by a string which is the name of the pattern to be used, which must be
followed by one or more non-string type characters.

1 65
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

REMOVE This denotes a type of pattern that is used to remove a part of an


object. It must be followed by one or more non-string type characters, which are
followed by a string which is the name of the remove pattern to be used, which
must be followed by one or more non-string type characters.

X M U LT This denotes a multiplier for the size of the sphere. It must be


followed by one or more non-string type characters, which must be followed by
a floating-point number which is the x multiplier, which must be followed by
one or more non-string type characters.

Y M U LT This denotes a multiplier for the size of the sphere. It must be


followed by one or more non-string type characters, which must be followed by
a floating-point number which is the y multiplier, which must be followed by
one or more non-string type characters.

NAME This denotes a name for the sphere. It is used only when the sphere
is part of an instance. It must be followed by one or more non-string type
characters , which are followed by a string which is the name of the sphere,
which must be followed by one or more non-string type characters.

PA R E N T h i s i s the r i g h t parenthe s i s w h i c h term i nates the sphere


description.

Color I nformation Any of the items which make up the color data may be
specified in the sphere object data. These are described in the previous section.
Note that there is no specific order in which the acceptable strings need to be
listed. You may arrange them at your convenience. After all information for the
sphere has been suppl ied , a right parenthesis must occur to terminate the
rectangle pattern data.

TRIANG LE
The TRIANGLE string denotes data for an object which is a triangle. It is
followed by one or more non-string type characters. This is followed by any of

1 66
U S I N G T H E R AY T R A C I N G D E F I N I T I O N L A N G U A G E

the triangle descriptive items shown below. Finally, the triangle description is
terminated by a right parenthesis. The legitimate strings for a triangle are:

LOC This denotes the location of the triangle. It must be followed by one or
more non-string type characters, which must be followed by three numbers
( separated by one or more non-string type characters) which make up the
location vector. The last number must be followed by one or more non-string
type characters.

V1 This denotes one of the apexes of the triangle. It is assumed that the
first apex of the triangle is indicated by the location vector. This is the second
apex. Its position is given with respect to the first apex. It must be followed by
one or more non-string type characters , which must be fol lowed by three
numbers (separated by one or more non-string type characters) which make up
the apex coordinates. The last number must be followed by one or more non­
string type characters.

V2 This denotes one of the apexes of the triangle. It is assumed that the
first apex of the triangle is indicated by the location vector. This is the third
apex. Its position is given with respect to the first apex. It must be followed by
one or more non-string type characters, which must be followed by three
numbers (separated by one or more non-string type characters) which make up
the apex coordinates. The last number must be followed by one or more non­
string type characters.

PATTERN This denotes that a pattern is to be applied to the surface of the


triangle. It must be followed by one or more non-string type characters, which
are followed by a string which is the name of the pattern to be used, which must
be fol lowed by one or more non-string type characters.

R EMOVE This denotes a type of pattern that is used to remove a part of an


object. It must be followed by one or more non-string type characters, which
are followed by a string which is the name of the remove pattern to be used,

1 67
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

which must be followed by one or more non-string type characters.

X M U LT This denotes a multiplier for the size of the triangle. It must be


followed by one or more non-string type characters, which must be followed by
a floating-point number which is the x multiplier, which must be followed by
one or more non-string type characters.

This denotes a multiplier for the size of the triangle. It must be


Y M U LT
followed by one or more non-string type characters, which must be followed by
a floating-point number which is the y multiplier, which must be followed by
one or more non-string type characters.

NAME This denotes a name for the triangle. It is used only when the sphere
is part of an instance. It must be followed by one or more non-string type
characters, which are followed by a string which is the name of the triangle,
which must be followed by one or more non-string type characters.

PA R E N Thi s i s the right parenth e s i s which terminates the triangle


description.

Color I nformation Any of the items which make up the color data may be
specified in the triangle object data. These are described in a previous section.
Note that there is no specific order in which the acceptable strings need to be
listed. You may arrange them at your convenience. After all information for the
triangle has been supplied, a right parenthesi s must occur to terminate the
triangle pattern data.

RING
The RING string denotes data for an object which is a ring. It is followed by
one or more non-string type characters. This is followed by any of the ring
descriptive items shown below. Finally, the ring description is terminated by a
right parenthesis. The legitimate strings for a ring are:

1 68
U S I N G T H E R AV T R A C I N G D E F I N I T I O N L A N G U A G E

LOC This denotes the location of the ring. It must be followed by one or
more non-string type characters, which must be followed by three numbers
( separated by one or more non-string type characters) which make up the
location vector. The last number must be followed by one or more non-string
type characters.

V1 This denotes one of two vectors which define the plane of the ring. Its
position is given with respect to location vector. It must be followed by one or
more non-string type characters , which must be followed by three numbers
(separated by one or more non-string type characters) which make up the vector.
The last number must be followed by one or more non-string type characters.

V2 This denotes the second of two vectors which define the plane of the
ring. Its position is given with respect to location vector. It must be followed
by one or more non-string type characters , which must be followed by three
numbers (separated by one or more non-string type characters) which make up
the vector. The last number must be followed by one or more non-string type
characters.

RAD_1 This denotes the inner radius of the ring. It must be followed by
one or more non-string type characters, which must be followed by a floating­
point number which is the inner ring radius, which must be followed by one or
more non-string type characters.

RAD_2 This denotes the outer radius of the ring. It must be followed by
one or more non-string type characters, which must be followed by a floating­
point number which is the outer ring radius, which must be followed by one or
more non-string type characters.

PATTERN This denotes that a pattern is to be applied to the surface of the


ring. It must be followed by one or more non-string type characters, which are
followed by a string which is the name of the pattern to be used, which must be
followed by one or more non-string type characters.

1 69
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +

R EMOVE This denotes a type of pattern that is used to remove a part of an


object. It must be followed by one or more non-string type characters, which
are followed by a string which is the name of the remove pattern to be used,
which must be followed by one or more non-string type characters.

X M U LT Thi s denotes a multiplier for the size of the ring . It must be


followed by one or more non-string type characters, which must be followed by
a floating-point number which is the x multiplier, which must be followed by
one or more non-string type characters.

Y M U LT Thi s denotes a multiplier for the size of the ring . It must be


followed by one or more non-string type characters, which must be followed by
a floating-point number which is the y multiplier, which must be followed by
one or more non-string type characters.

NAME This denotes a name for the ring. It is used only when the ring is
part of an instance. It must be followed by one or more non-string type
characters, which are followed by a string which is the name of the ring, which
must be followed by one or more non-string type characters.

PAR E N This is the right parenthesis which terminates the ring description.

Color Information Any of the items which make up the color data may be
specified in the ring object data. These are described in a previous section. Note
that there is no specific order in which the acceptable strings need to be listed.
You may arrange them at your convenience. After all information for the ring
has been supplied, a right parenthesis must occur to terminate the ring pattern
data.

PARALLELOG RAM
The PARALLELOGRAM string denotes data for an object which is a
parallelogram. It is followed by one or more non-string type characters. This is
followed by any of the parallelogram descriptive items shown below. Finally,

1 70
U S I N G T H E R AY T R A C I N G D E F I N I T I O N L A N G U A G E

the parallelogram description is terminated by a right parenthesis. The legitimate


strings for a parallelogram are:

LOC This denotes the location of the parallelogram. It must be followed by


one or more non- string type characters , which must be followed by three
numbers (separated by one or more non-string type characters) which make up
the location vector. The last number must be followed by one or more non-string
type characters.

V1 This denotes one of the comers of the parallelogram. It is assumed that


the first comer of the parallelogram is indicated by the location vector. This is
the next adjacent comer on one side of the first comer. Its position is given with
respect to the first comer. It must be followed by one or more non-string type
characters, which must be followed by three numbers (separated by one or more
non-string type characters) which make up the comer coordinates. The last
number must be followed by one or more non-string type characters.

V2 This denotes another of the comers of the parallelogram. It is assumed


that the first comer of the triangle is indicated by the location vector and an
adj acent comer to the first comer by V I . This is the adjacent comer on the other
side of the first comer. Its position is given with respect to the first comer. It
must be followed by one or more non-string type characters, which must be
followed by three numbers (separated by one or more non-string type characters)
which make up the comer coordinates. The last number must be followed by
one or more non-string type characters.

PATTERN This denotes that a pattern is to be applied to the surface of the


parallelogram. It must be followed by one or more non-string type characters,
which are followed by a string which is the name of the pattern to be used, which
must be followed by one or more non-string type characters.

1 71
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

R EMOVE This denotes a type of pattern that is used to remove a part of an


object. It must be followed by one or more non-string type characters, which
are followed by a string which is the name of the remove pattern to be used,
which must be followed by one or more non-string type characters.

This denotes a multiplier for the size of the parallelogram. It must


X M U LT
be followed by one or more non-string type characters, which must be followed
by a floating-point number which is the x multiplier, which must be followed by
one or more non-string type characters.

Y M U LT This denotes a multiplier for the size of the parallelogram. It must


be followed by one or more non-string type characters, which must be followed
by a floating-point number which is the y multiplier, which must be followed by
one or more non-string type characters.

NAME This denotes a name for the parallelogram. It is used only when the
parallelogram is part of an instance. It must be followed by one or more non­
string type characters, which are followed by a string which is the name of the
paral l e l ogram , which m u s t be fo l l owed by one or more non- s tring type
characters.

PAR E N This is the right parenthesis which terminates the parallelogram


description.

Color I nformation Any of the items which make up the color data may be
specified in the parallelogram object data. These are described in a previous
section. Note that there is no specific order in which the acceptable strings need
to be listed. You may arrange them at your convenience. After all information
for the parallelogram has been supplied, a right parenthesis must occur to
terminate the parallelogram pattern data.

1 72
U S I N G T H E R AV T R A C I N G D E F I N I T I O N L A N G U A G E

QUADRATIC
The QUADRATIC string denotes data for an object which is expressed by a
quadratic equation. The equation to denote this object is: A x 2 + B y2 + C z2 +
Ez = D (Equation 9- 1 ). The string is followed by one or more non-string type
characters. This is followed by any of the quadratic descriptive items shown
below. Finally, the quadratic description is terminated by a right parenthesis.
The legitimate strings for a quadratic are:

LOC This denotes the location of the quadratic. It must be followed by one
or more non-string type characters, which must be followed by three numbers
(separated by one or more non- string type characters) which make up the
location vector. The last number must be followed by one or more non-string
type characters.

A This denotes the coefficient of x2 in the quadratic equation. It must be


followed by one or more non-string type characters, which must be followed by
a floating-point number which i s the A coefficient value, which must be
followed by one or more non-string type characters.

8 This denotes the coefficient of y2 in the quadratic equation. It must be


followed by one or more non-string type characters, which must be followed by
a floating -point number which i s the B coeffic ient value, which must be
followed by one or more non-string type characters.

C This denotes the coefficient of z2 in the quadratic equation. It must be


followed by one or more non-string type characters, which must be followed by
a floating-point number which i s the C coefficient value, which must be
followed by one or more non-string type characters.

D Thi s denotes the constant term in the quadratic equation. It must be


followed by one or more non-string type characters, which must be followed by
a floating-point number which is the D constant value, which must be followed
by one or more non-string type characters.

1 73
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

E This denotes the coefficient of y in the quadratic equation. It must be


followed by one or more non-string type characters, which must be followed by
a floating-point number which i s the C coeffic ient value, which must be
followed by one or more non-string type characters. Note that the program does
not allow the equation to contain both a y and a y 2 term for any given object. If
you try to include both, the program will terminate with an error message.

XMIN This denotes the minimum value for the x coordinate in the quadratic
equation. It must be followed by one or more non-string type characters, which
must be followed by a floating-point number which is the minimum x value,
which must be followed by one or more non-string type characters.

XMAX This denotes the maximum value for the x coordinate in the
quadratic equation. It must be followed by one or more non-string type
characters, which must be followed by a floating-point number which i s the
maximum x value, which must be followed by one or more non-string type
characters.

YMIN This denotes the minimum value for the y coordinate in the quadratic
equation. It must be followed by one or more non-string type characters, which
must be followed by a floating-point number which is the minimum y value,
which must be followed by one or more non-string type characters.

YMAX This denotes the maximum value for the y coordinate in the
quadratic equation. It must be followed by one or more non-string type
characters, which must be followed by a floating-point number which is the
maximum y value, which must be followed by one or more non-string type
characters.

ZMIN This denotes the minimum value for the z coordinate in the quadratic
equation. It must be followed by one or more non-string type characters, which
must be followed by a floating-point number which is the minimum z value,
which must be followed by one or more non-string type characters.

1 74
USING THE R AV T R A C I N G DEFINITION LANGUAGE

ZMAX This denotes the maximum value for the z coordinate in the quadratic
equation. It must be followed by one or more non-string type characters, which
must be followed by a floating-point number which is the maximum z value,
which must be followed by one or more non-string type characters.

DIR This denotes a vector which indicates the direction of the axis of the
quadratic. It must be followed by one or more non-string type characters, which
must be followed by three numbers (separated by one or more non-string type
characters) which make up the direction vector. The last number must be
followed by one or more non-string type characters.

PATTERN This denotes that a pattern is to be applied to the surface of the


quadratic. It must be followed by one or more non-string type characters, which
are followed by a string which is the name of the pattern to be used, which must
be followed by one or more non-string type characters.

R EMOVE This denotes a type of pattern that is used to remove a part of an


object. It must be followed by one or more non-string type characters, which are
followed by a string which is the name of the remove pattern to be used, which
must be followed by one or more non-string type characters.

X M U LT This denotes a multiplier for the size of the quadratic. It must be


followed by one or more non-string type characters, which must be followed by
a floating-point number which is the x multiplier, which must be followed by
one or more non-string type characters.

Y M U LT This denotes a multiplier for the size of the quadratic. It must be


followed by one or more non-string type characters, which must be followed by
a floating-point number which is the y multiplier, which must be followed by
one or more non-string type characters.

NAME Thi s denotes a name for the quadratic. It is used only when the
quadratic is part of an instance. It must be followed by one or more non-string

1 75
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

type characters , which are followed by a string which i s the name of the
quadratic, which must be followed by one or more non-string type characters.

PA R E N This is the right parenthes i s which terminates the quadratic


description.

Color i nformation Any of the items which make up the color data may be
specified in the quadratic object data. These are described in a previous section.
Note that there is no specific order in which the acceptable strings need to be
listed. You may arrange them at your convenience. After all information for the
quadratic has been supplied, a right parenthesis must occur to terminate the
quadratic pattern data.

CON E
The CONE string denotes data for an object which i s expressed by a
quadratic equation of the form :

where r is the radius of the cone at its base and h is the height of the cone. The
string is followed by one or more non-string type characters. This is followed by
any of the cone descriptive items shown below. Finally, the cone description is
terminated by a right parenthesis. The legitimate strings for a cone are:

LOC This denotes the location of the cone. It must be followed by one or
more non-string type characters, which must be followed by three numbers
(separated by one or more non- string type characters) which make up the
location vector. The last number must be followed by one or more non-string
type characters.

This denotes the radius of the cone at its base. It must be followed
RADIUS
by one or more non-string type characters , which must be followed by a
floating-point number which is the radius value, which must be followed by one

1 76
USING THE R AY T R A C I N G DEFINITION LANGUAGE

or more non-string type characters.

This denotes the height of the cone. It must be followed by one or


H E I G HT
more non-string type characters, which must be followed by a floating point
number which is the height value, which must be followed by one or more non­
string type characters.

DIR This denotes a vector which indicates the direction of the axis of the
cone. It must be followed by one or more non-string type characters, which must
be followed by three numbers (separated by one or more non-string type
characters) which make up the direction vector. The last number must be
followed by one or more non-string type characters.

R EMOVE This denotes a type of pattern that is used to remove a part of an


object. It must be followed by one or more non-string type characters, which are
followed by a string which is the name of the remove pattern to be used, which
must be followed by one or more non-string type characters.

· X M U LT This denotes a multiplier for the size of the cone. It must be


followed by one or more non-string type characters, which must be followed by
a floating-point number which is the x multiplier, which must be followed by
one or more non-string type characters.

Y M U LT This denotes a multiplier for the size of the cone. It must be


followed by one or more non-string type characters, which must be followed by
a floating-point number which is the y multiplier, which must be followed by
one or more non-string type characters.

NAME This denotes a name for the cone. It is used only when the cone is
part of an instance. It must be followed by one or more non-string type
characters, which are followed by a string which is the name of the cone, which
must be followed by one or more non-string type characters.

1 77
F R A C TA L P R O G R A M M I N G A N D R A Y T R A C I N G W I T H C + +

PAREN This is the right parenthesis which terminates the cone description.

Color I nformation Any of the items which make up the color data may be
specified in the quadratic object data. These are described in a previous section.
Note that there is no specific order in which the acceptable strings need to be
listed. You may arrange them at your convenience. After all information for the
cone has been supplied, a right parenthesis must occur to terminate the cone
pattern data.

S KY
The SKY string denotes data for color of the sky. It is followed by one or
more non-string type characters. This is followed by any of the sky descriptive
items shown below. Finally, the sky description is terminated by a right
parenthesis. The legitimate strings for the sky are:

This denotes the color of the sky at the zenith. It must be followed
ZEN ITH
by one or more non-string type characters, which must be followed by three
numbers (separated by one or more non-string type characters) which make up
the red, green, and blue components of the color. The last number must be
followed by one or more non-string type characters.

HORIZ This denotes the color of the sky at the horizon. It must be followed
by one or more non-string type characters, which must be followed by three
numbers (separated by one or more non-string type characters) which make up
the red, green, and blue components of the color. The last number must be
followed by one or more non-string type characters.

Thi s denotes the dither to be applied to the sky. It must be


D I TH E R
followed by one or more non-string type characters which must be followed by a
fl oating-point number wh ich i s the amount of d i ther between two type
characters.

PAREN This is the right parenthesis which terminates the sky description.

1 78
USING THE R AY T R A C I N G DEFI NITION LANGUAGE

FOC_LENGTH
The FOC_LENGTH string denotes the focal length of a 35 millimeter lens to
give the equivalent perspective to the picture. It must be followed by one or
more non-string type characters, which are followed by a floating-point number
giving the focal length of the lens, which is followed by one or more non-string
type characters.

LAM P
The LAMP string denotes data fo r a light source. I t i s followed by one or
more non-string type characters. This is followed by any of the lamp descriptive
items shown below. Finally, the lamp description is terminated by a right
parenthesis. The legitimate strings for the lamp are:

LOC This denotes the location of the light source. It must be followed by
one or more non-string type characters , which must be followed by three
numbers (separated by one or more non-string type characters) which make up
the location vector. The last number must be followed by one or more non-string
type characters.

RADIUS This denotes the radius of the light source. It must be followed by
one or more non-string type characters, which must be followed by a floating­
point number which is the radius of the light source, which must be followed by
one or more non-string type characters.

DIST This denotes the distance from the light source at which the lighting of
objects will be at a normal intensity. Objects closer than this will be overlit
(washed out) while objects farther away will be darker than normal. The string
must be followed by one or more non-string type characters, which must be
followed by a floating-point number which is the distance of the light source,
which must be followed by one or more non-string type characters.

PA R E N This is the right parenthesis which terminates the light source


description.

1 79
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

OBSERVER The OB SERVER string denotes data for the observer. It is


followed by one or more non-string type characters. This is followed by any of
the observer descriptive items shown below. Finally, the observer description is
terminated by a right parenthesis. The legitimate strings for the observer are:

LOCThis denotes the location of the observer. It must be followed by one


or more non-string type characters, which must be followed by three numbers
( separated by one or more non-string type characters) which make up the
location vector. The last number must be followed by one or more non-string
type characters.

LOOKAT This denotes the direction in which the observer is looking. It


must be followed by one or more non-string type characters, which must be
followed by three numbers (separated by one or more non-string type characters)
which make up the direction vector. The last number must be followed by one or
more non-string type characters.

This denotes the direction for the observer. It must be followed by one
UP
or more non-string type characters, which must be followed by three numbers
(separated by one or more non-string type characters) which make up the UP
vector. The last number must be followed by one or more non-string type
characters.

PA R E N Thi s i s the right parenthe s i s which terminates the observer


description.

XRES
The XRES string denotes the x resolution of the display. It must be followed
by one or more non-string type characters, which are followed by a floating­
point number giving the x resolution, which is followed by one or more non­
string type characters.

1 80
U S I N G T H E R AV T R A C I N G D E F I N I T I O N L A N G U A G E

Y RES
The YRES string denotes the y resolution of the display. It must be followed
by one or more non-string type characters, which are followed by a floating­
point number giving the y resolution, which is followed by one or more non­
string type characters.

NAM E
The NAME string denotes a name. It must be followed by one or more non­
string type characters, which are followed by a string designating a name, which
is followed by one or more non-string type characters.

Sample Fi les
Figure 9- 1 i s a small sample file of data for a scene written in the QRT
language format. This file can be read and processed with the ray-tracing
program described in this book. For comparison, Figure 9-2 lists the same file,
showing the minimum that is required for processing the file with the input
functions described in this chapter. You can see that you have a lot of flexibility
w i th a d d i ng n o n - s tring type c h aracters to create a format that you are
comfortable with and which still can be read with these functions.

F I L E_ N A M E = S p h e r e RAW
.

PATT E R N ( x_s i z e = 60 ,
y_s i z e = 60 ,
n a me = CHECK ,
R E C TA N G L E (
s t a r t_x = 0,
s t a r t_y = 0,
e n d_x = 30 ,
e n d_y = 30 ,
di ff = ( .1,1.0, .1) ,
di ther = O,
)
RECTANG LE (
s t a r t_x 30 ,
s t a r t_y 30 ,

1 81
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

e n d_x = 60 ,
e n d__y = 60 ,
di ff = ( .1,1.0, .1) ,
di ther = 0,
)

PARA L L E L O G RAM l oc = ( - 1 0000 , O , - 1 0000 ) ,


vl = ( 2 0000 , 0 , 0 ) ,
v2 = ( 0 , 0, 20000 ) ,
d i ff = ( .8, .8, 0) ,
di ther = O,
pa t te rn = C H EC K
xmu l t 2
ymul t = 2

SPHERE l oc ( 2 00 ' 9 0 ' 80 ) '


ra d i us = 35 ,
d i ff = ( .3, .3, .8) ,
amb = ( . 32 , . 32 , . 32 ) ,
refl ect = . 60 ,
s refl ect = 20
xm u l t 1.0,
ymu l t = 1.0,

LAMP ( l oc = ( 1 20 , 1 20 , - 50 ) ,
radi us = 5,
di st = 80
)

LAMP ( l oc = ( 1 20 , 1 5 0 , 80 ) ,
ra d i us = 5,
di st = 70
)

S KY ( hori z = ( . 2 , . 2 , . 55 ) ,
zen i t h ( . 1 , . 1 , . 25 ) ,
di ther = 1
)

1 82
U S I N G T H E R AY T R A C I N G D E F I N I T I O N L A N G U A G E

XRES 320
Y RES 200

FOC L E NGTH 80

Figure 9-1 . Sample QRT Data File

F I L E_ N A M E S p h e r e . R A W

P A T T E R N ( x_ s i z e 60
y_s i z e 60
n a me C H E C K
R E C TA N G L E
sta rt x O
s t a r t_y 0
e n d_x 30
e n d_y 30
d i ff . 1 1 . 0 . 1
di ther 0
)
RE CTAN G L E )
s t a r t_x 30
s t a r t_y 30
e n d_x 60
e n d_y 60
d i ff . 1 1 . 0 . 1
di ther O
)

P A RA L L E L O G R A M
l oc - 1 0000 0 - 1 0000
vl 20000 O 0
v2 0 0 20000
d i ff . 8 . 8 0
di ther O
pa t t e r n CH EC K
xm u l t 2
ymu l t 2

1 83
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

SPHERE (
l Qc 200 90 80
radi us 35
di ff . 3 . 3 . 8
amb . 32 . 32 . 32
refl ect . 60
s refl ect 20
xmu l t 1 . 0
ym u l t 1 . 0
)

LAMP
l QC 120 1 20 - 50
radi us 5
d i s t 80
)

LAMP
l QC 120 1 50 80
radi us 5
di st 70
)
S KY (
hQri z . 2 . 2 . 55
zen i t h. 1 . 1 . 25
di ther 1
)

XRES 320
YRES 200

F O C_ L E N G T H 80

Figure 9-2. Sample Simpl ified Data File

1 84
CHAPTER 1 0

Functions that Match an


Object: The Concept of
Virtual Functions

One of the most critical things to the philosophy of object-oriented


programming is to have a function that can be applied to objects of several
different classes and w i l l automatically perform the appropriate action for
whatever class the object belongs to. For example, suppose we have the classes
Sphere, Cone , and Cube. We want to have a function Test and be able to say:

object. Test();

Now, if object is a member of class Sphere we want the function to perform


one set of test operations, but if the object is of class Cone we want a different
set of operations performed and if the object is of class Cube, we want another
set performed that is totally different from those performed for either Sphere or
Cone. The C++ language provides the capability for doing this through the use
of Virtual functions. It works in this manner:

First, define a base class.

cl ass S h a pe

. . . c l a s s memb e r d e f i n i t i on s ;

1 85
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

v i rtua l i nt Test ( i nt a, fl oat b ) ;

} ;

The virtual function is a prototype as a part of the class definition. It begins


with the word Virtual, followed by the variable that is to be returned by the
function, followed by the function name which is followed by the types and
names of parameters passed by the function, enclosed in parentheses. Thus,
except for being preceded by the word Virtual the function definition is the same
used for any function. Next, we define a derived class for each type of object we
want available. For example:

cl ass Sphere : publ i c S h a pe

. . . c l a s s membe r d e f i n i t i on s ;

i nt Test ( i nt a , fl oat b ) ;

} ;

The fact that the name of the class is followed by a colon, the word public,
and the name of a previously defined class, makes this class a derived class,
which inherits all of the characteristics of the base class and may include various
special members of its own. If you want to use the common function (Test in the
example) you must include in the definition of Sphere a prototype of the function
which is the same as that for the Virtual function in the base class, except that the
word Virtual is omitted. The same procedure for the definition of the classes is
the Cone and Cube.

Next, you must have a definition for each of the functions. This includes a
definition for the function for the base class, which must be defined, even if there
is nothing in it. For example,

1 86
F U N C T I O N S T H AT M AT C H A N O B J E C T: V I R T U A L F U N C T I O N S

i nt Shape Test ( i nt a , fl oat b )


{ } ;

i nt Sphere : : Tes t ( i nt a . fl oat b )


{
ope ra t i on a :
ope ra t i on b ;

i nt Cone : : Tes t ( i n t a . fl oat b )

ope ra t i on c ;
ope ra t i on d :

i n t C u be : : Te s t ( i n t a. f l oa t b )

ope ra t i on e :
ope ra t i on f ;

Note the format for the first line of each function definition. The type of the
variable returned by the function comes first. It must be the same as it was in the
prototype definition. Next comes the name of the particular class for which the
function is being defined. It is followed by two colons, the name of the function
and the variables that are passed by it. This part of the definition must be the
same for each definition of the function and match the prototype definition.
Finally comes the body of the definition which may be different for each of the
definitions. Once you have done this groundwork, you can use this function
throughout your program as we discussed at the beginning of the chapter. Call
the function by preceding the normal function call with the name of an object,
followed by a dot. The function will have access to the members of the named

1 87
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

object. The program will automatically look at the object, determine to what
class it belongs, and use the definition of the function which matches that class
to perform the function operations.

The objects.cpp File


In the ray-tracing program, all the functions that make use of the virtual­
function technique to provide different actions for each class of objects are
grouped in the file called objects . cpp . Thi s file is l isted in Figure 1 0- 1 .
Although the functions are used at various places throughout the program, they
are all described in this chapter.

Constructors
The constructor is a special kind of function automatically called by the
program to initialize an object, each time an object is defined. It is identified by
the same name as the class. Thus, a typical constructor would look like:

Sphe re : : Sphe re ( )
{
membe r d e f i n i t i o n s . :

The objects.cpp file begins with the definition of a constructor for each of
the five different types of objects. You can look at them in the listing of Figure
l 0- 1 . There is nothing particularly unusual about them. They simply specify the
initial values the members of the object should have. Mostly they are NULLS .
The type in each case corresponds to the proper number for the type of object.
The multipliers are set to default values of one. The color information is set to
the default values.

Destructors
Whenever you define a class member, the required memory space remains
assigned to that class member forever unless you deallocate it. If you want to
deallocate the memory assigned to this class member when you are through

1 88
F U N C T I O N S T H AT M AT C H A N O B J E C T: V I R T U A L F U N C T I O N S

using it, you must call a destructor function. Similarly, if you assign space for a
class member with new, thi s memory will be reserved forever unless you
deallocate it with the function delete. Since almost all of our class members in
this program are allocated using new, we don't use destructors. If you need them
for your program, refer to the C++ manual for details on how to create them.

Figure 1 0-1 . The objects.cpp File

/*
obj e c t s . c Fun c t i ons bel ong i ng to e a c h of the c l a s ses
d e r i v e d f r om t h e O b j e c t c l a s s .

By R o g e r T. Stevens 3 / 1 /90

* / ll====!I

#i n c l ude " rende r . hpp"

/*

Sphere Constructor

*/

Sphere : : Sphere ( )
{
ty p e = SPHERE ;
nextobj = NULL ;
chi l d = NU LL ;
pattern = NULL ;
remov e = NU L L ;
n a me [ O ] = NU LL ;
xmu l t l;
ymu l t l;
upper Vector ( ) ;
l ow e r Vector ( ) ;

1 89
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

/*

T ri a ng e Const ructor
== l ===!.I
��
============ ====================================

*/

Tri angl e : : Tri angl e ( )


{
type = T R I AN G L E :
nextobj = N U L L :
chi l d = NU L L :
pattern = NULL :
remo v e = N U L L :
n ame [ O ] = N U L L ;
xmu l t 1:
ymu l t 1:
upper Vector ( ) :
1 owe r Vector ( ) :

/*

Ri ng Con st ructor

I�=====================================================!J

*/

Ri ng : : Ri ng ( )
{
ty p e = R I N G :
next obj = NU L L :
chi l d = NULL ;
pa t t e rn = NU L L :
remo v e = N U L L :
n a me [ O ] = N U L L ;
xmu l t 1:
ymu l t l·
uppe r Vector ( ) ;
l owe r Vector( ) ;

1 90
F U N C T I O N S T H AT M AT C H A N O B J E C T: V I R T U A L F U N C T I O N S

*
/

Pa ra l l e l ogram Co n s t ructor

*
/

Pa ra l l e l og ram : : P a r a l l e l ogram( )
{
t y p e = P A R A L L E L O G RA M ;
nextobj = N U L L ;
chi l d = NULL ;
pattern = NULL ;
remov e = NU L L ;
n a me [ O J = N U L L ;
xmu l t l;
ymu l t l;
uppe r Vector ( ) ;
l owe r Vector ( ) ;
vect3 Vector( ) ;
}
*
/

ua at c o t ructor
'
� ====Q===
d=r ==i==C==n=
s===== �I

============ ==============
*/

Qu a d r a t i c : : Quadrat i c ( )
{
t y p e = Q U A D RAT I C ;
nextobj = NU L L ;
chi l d = NULL ;
pattern = NU LL ;
remo v e = N U L L ;
n a me [ O J = N U L L :
c t e rm O;
y t e rm O;
xm u l t l;
ymul t l;
upper Vector( ) ;
l owe r Vector ( ) ;

1 91
F R A C TA L P R O G R A M M I N G A N D R A Y T R A C I N G W I T H C + +

L
I

*
/
No rma l f i nder for gen e r i c obj ect
========"
*
/

v o i d O bj e c t : : F i n d N o rm ( V e c t o r * n o rma l . Vector * po s i t i on )
{
)

*
/
N o rma l fi nder for sphere

*
/

v o i d S p h e r e : : F i n d N o rm ( V e c t o r * n o rma l , Vector * pos i ti on )


{
* n o rma l *pos i t i on - l oc ;
* n o rma l - *n o rma l ;

*
/
N o rma l fi nder for pa ra l l el ogram

*
/

v o i d P a r a l l e l o g r a m : : F i n d N o rm ( V e c t o r * n o rma l , Vector * pos i t i on )


{
*n o rma l = n o rm ;

*
/
N o rma l fi nder for tri angl e

*
/

1 92
F U N C T I O N S T H AT M AT C H A N O B J E C T: V I R T U A L F U N C T I O N S

v o i d T r i a n g l e : : F i n d N o rm ( V e c t o r * n o rma l . Vector * po s i t i on )
{
* n o rm a l = n o rm :

*
/

N o rma l fi nder for ri ng

*
/

v o i d R i n g : : F i n d N o rm ( V e c t o r * n o rma l . V e c t o r * po s i t i on )
{
* n o rma l = n o rm :

L
I =======o!ll
*
/
No rma l fi nder for quadrati c
� ·.

*
/

v o i d O u a d r a t i c : : F i n d N o rm ( V e c t o r * n o rm a l . Vector * pos i t i on )
{
V e c t o r n ew p o s . n ewd i r :

n ewpos = * po s i t i o n - l o c :
i f ( ( v e c t l . x == 0 ) & & ( v e c t l . y 1 ) && ( vectl . z 0) )
{
* n o rm a l v e c t 2 * n ew p o s :
* n o rma l - * n o rma l :

el se
{
n ew p o s = n ew p o s . Ro t a t e ( c o s l . si nl . cos 2 . s i n2 ) ;
n ewd i r = v e c t 2 * n ewp o s :
* n o rma l = n ewd i r . Re v_Rot a t e ( c o s l . si nl . cos2 . s i n2 ) :
I
}

1 93
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

L
I

/*
F i nd Bound i n g Box for Gen e r i c Obj ect

======="

*I

voi d Obj ect : : F i ndBbox ( Vector * v l . Vector * v2 )


{ I

/*
Fi nd Bound i ng Box for Sphere

*/

voi d Sphere : : F i ndBbox ( Vector * v l . Vector * v2 )


{
v l - > x= l o c . x - v e c t l .x;
v 2 - > x= l o c . x+ v e c t l .x;
v l - >y=l o c . y - v e c t l .x;
v 2 - > y = l o c . y+ v e c t l.x;
v l - > z=l o c . z - v e c t l . x ;
v 2 - > z=l o c . z+ v e c t l . x ;

I*
Fi nd Bound i ng Box for Pa r a l l el ogram

*/

voi d P a r a l l el og ram : : Fi ndBbox ( Vector * v l , Vector * v2 )


{
Vector poi nt2 . poi nt3 , poi n t4 ;
poi nt2 l oc + vectl ;
poi nt3 = l oc + vect2 ;
p o i n t4 = po i n t3 + v e c t l ;
v l - > x=M I N ( p o i n t 2 . x , p o i n t 3 . x ) ;
v l - > x=M I N ( v l - > x . p o i n t 4 . x ) ;
v l - > x=M I N ( v l - > x . l o c . x ) ;
v l - > y=M I N ( p o i n t 2 . y , p o i n t 3 . y ) ;
v l - > y =M I N ( v l - > y . p o i n t 4 . y ) ;

1 94
F U N C T I O N S T H AT M AT C H A N O B J E C T: V I R T U A L F U N C T I O N S

v l - > y =M I N ( v l - > y . l o c . y ) ;
v l - > z =M I N ( p o i n t 2 . z . p o i n t 3 . z ) ;
v l - > z =M I N ( v l - > z . p o i n t 4 . z ) ;
v l - > z =M I N ( v l - > z , l o c . z ) ;
v 2 - > x= M A X ( p o i n t 2 . x , p o i n t 3 . x ) ;
v 2 - > x= M A X ( v 2 - > x , p o i n t 4 . x ) ;
v 2 - > x=M A X ( v 2 - > x . l o c . x ) ;
v 2 - >y=MAX ( p o i n t 2 . y , p o i n t 3 . y ) ;
v 2 - > y =M A X ( v 2 - > y . p o i n t 4 . y ) ;
v 2 - >y=MAX ( v 2 - >y , l o c . y ) ;
v 2 - > z =M A X ( p o i n t 2 . z , p o i n t 3 . z ) ;
v 2 - > z=MAX ( v 2 - > z . p o i n t4 . z ) ;
v 2 - > z =M A X ( v 2 - > z . l o c . z ) ;

I*
F i n d B o u n d i n g Box fo r T r i a n g l e

*/

voi d T r i a n g l e : : Fi ndBbox ( Vector * v l , Vecto r * v2 )


{
Vector poi nt2 . poi nt3 ;

poi nt2 = l ac + vectl ;


po i n t3 = l ac + v ec t 2 ;
v l - > x=M I N ( p o i n t 2 . x , p o i n t 3 . x ) ;
v l - > x =M I N ( v l - > x . l o c . x ) ;
v l - > y =M I N ( p o i n t 2 . y , p o i n t 3 . y ) ;
v l - > y =M I N ( v l - > y . l o c . y ) ;
v l - > z =M I N ( p o i n t 2 . z , p o i n t 3 . z ) ;
v l - > z =M I N ( v l - > z , l o c . z ) ;
v 2 - > x=MAX ( p o i n t 2 . x , p o i n t 3 . x ) ;
v 2 - > x= M A X ( v 2 - > x . l o c . x ) ;
v 2 - >y=MA X ( po i n t 2 . y , p o i n t 3 . y ) ;
v 2 - >y=MAX ( v 2 - >y , l o c . y ) ;
v 2 - > z=MA X ( p o i n t 2 . z , p o i n t 3 . z ) ;
v 2 - > z=MA X ( v 2 - > z . l o c . z ) ;

1 95
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

/*
Fi nd Bound i ng Box for Bound i ng Box

*/

v o i d BBox : : F i ndBbox ( Ve c t o r * v l , Vector * v2 )


{
*v l l ow e r ;
*v2 uppe r ;

/*
Fi nd Bound i ng Box for Ri ng

*/

voi d Ri ng : : Fi nd Bbox ( Vector * v l . Vector * v2 )


{
v l - >x l oc . x - vect3 . y ;
v2 - >x l o c . x+v e c t 3 . y ;
v l - >y l oc . y - vect3 . y ;
v 2 - >y l o c . y+v e c t 3 . y ;
v l - >z l oc . z - vect3 . y ;
v2 - >z l oc . z+vect3 . y ;

/*
F i nd Bound i ng Box for Qu a d r a t i c

*/

voi d Qu a d r a t i c : : F i nd Bbox ( Vector * v l , Vector * v2 )


{
*v l l ow e r ;
*v2 upper ;
*v l *v l + l ac ;
*v2 *v2 + l ac ;

1 96
F U N C T I O N S T H AT M AT C H A N O B J E C T: V I R T U A L F U N C T I O N S

/*
C h a n g e s c a l e of u s e r defi ned generi c Obj ect

*/

v o i d O b j e c t : : S c a l e_ I n s t a n c e ( V e c t o r * m u l t , i n t f f l a g )
{
}

I
L
/*
Change s ca l e of u s e r defi ned Sphere

� ========!I

*/

v o i d S p h e r e : : S c a l e_ I n s t a n c e ( V e c t o r * m u l t , i nt ffl ag )
{
fl oat s i ze ;

s i z e = M i n ( m u l t - > x . m u l t - >y , m u l t - > z ) ;


l o c = l o c * *m u l t ;
v e c t l . x *= s i z e ;
c h i l d - > S c a l e_ I n s t a n c e ( m u l t , F A L S E ) ;
i f ( ! ffl a g )
n e x t o b j - > S c a l e_ I n s t a n c e ( m u l t , F A L S E ) ;

I * rr======;i
C hange s c a l e of u s e r defi ned Pa ra l l el ogram

*I

v o i d P a r a l l e l o g r a m : : S c a l e_ I n s t a n c e ( V e c t o r * m u l t , i nt ffl ag )
{

l o c = l o c * *m u l t ;
v e c t l = v e c t l * *m u l t ;
v e c t 2 = v e c t 2 * *m u l t ;
c h i l d - > S c a l e_ I n s t a n c e ( m u l t , F A L S E ) ;

1 97
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

i f ( ! ffl a g )
n e x t o b j - > S c a l e_ I n s t a n c e ( m u l t , F A L S E ) ;

I*
C hange s ca l e of u s e r defi ned Ri ng

*I

v o i d R i n g : : S c a l e_ I n s t a n c e ( V e c t o r * m u l t , i nt ffl ag )
{
fl oat s i ze ;

s i z e = M i n ( mu l t - > x . mu l t - >y , m u l t - > z ) ;


l a c = l a c * *m u l t ;
v e c t l = v e c t l * *m u l t ;
v e c t 2 = v e c t 2 * *m u l t ;
v e c t 3 . x *= s i z e ;
v e c t 3 . y *= s i z e ;
c h i l d - > S c a l e_ I n s t a n c e ( m u l t . F A L S E ) ;
i f ( ! ffl a g )
n e x t o b j - > S c a l e_ I n s t a n c e ( m u l t , F A L S E ) ;

/*
C hange s ca l e of user defi ned Tri angl e

*I

v o i d T r i a n g l e : : S c a l e_ I n s t a n c e ( V e c t o r * mul t . i nt ffl ag )
{

l a c = l a c * *m u l t ;
v e c t l = v e c t l * *m u l t ;
v e c t 2 = v e c t 2 * *m u l t ;
c h i l d - > S c a l e_ I n s t a n c e ( m u l t , F A L S E ) ;
i f ( ! ffl a g )
n e x t o b j - > S c a l e_ I n s t a n c e ( m u l t , F A L S E ) ;

1 98
F U N C T I O N S T H AT M AT C H A N O B J E C T: V I R T U A L F U N C T I O N S

I*
C hange s ca l e of u s e r defi ned Quadra t i c

*/

v o i d Q u a d r a t i c : : S c a l e_ I n s t a n c e ( V e c t o r * m u l t , i nt ffl ag )
{
fl oat s i ze ;

u p p e r = u p p e r * *m u l t ;
l ow e r = l ow e r * *m u l t ;
l o c = l o c * *m u l t ;
c h i l d - > S c a l e_ I n s t a n c e ( m u l t , F A L S E ) ;
i f ( ! ffl ag )
n e x t o b j - > S c a l e_ I n s t a n c e ( m u l t , F A L S E ) ;

/*
D e t e rm i n e p o s i t i o n v a r i a b l e s f o r g e n e r i c obj e c t

*/

voi d Obj ect Pos i t i on ( fl oa t * pos l , fl oat *pos 2 , Vector *


l oc a t i on )

/*
D e t e rm i n e p o s i t i on v a r i a b l e s f o r s p h e re

*I

voi d Sphere Pos i t i on ( fl oa t * pos l . fl oat *pos 2 , Vector *


l oc a t i on )

Vector del ta ;

del t a = * l ocati on - l oc :

1 99
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

*pos l = atan2 ( del ta . x , del ta . y ) * vectl . x ;


*pos2 = atan2 ( sq rt ( ( del ta . x * del ta . x ) + ( del ta . y * del ta . y ) ) ,
del ta . z ) * vectl . x ;

/*
Dete rmi n e pos i t i on v a r i a b l es for t r i a n g l e

*/

voi d Tri angl e Po s i t i on ( f l oa t * po s l , f l o a t *pos 2 , Vector *


l ocati on )

Vector del ta ;
fl oat l ength l , l ength2 ;

del ta * l oc a t i on - l oc ;
l engt h l s q rt ( vectl % vectl ) ;
l ength2 sqrt ( vect2 % vect2 ) ;
*pos l ( del ta % vectl ) l ength l ;
/
*pos2 = ( del ta % vect2 ) l ength2 ;
/

/*
D e t e rm i n e po s i t i on v a r i a b l e s f o r p a r a l l e l og r a m

*/

v o i d Pa r a l l e l o g r a m Pos i t i on ( f l oa t * pos l , fl oat *pos2 . Vector *


l oc a t i on )

Vector del ta ;
fl oat l engthl , l ength2 ;

de l t a * l oc a t i on - l oc ;
l engt h l sqrt ( vectl % vectl ) ;
l ength2 sqrt ( vect2 % vect2 ) :
*pos l ( del ta % vect l ) l ength l ;
/
*pos2 = ( del ta % vect2 ) l ength2 ;
/

200
F U N C T I O N S T H AT M AT C H A N O B J E C T: V I R T U A L F U N C T I O N S

/*
Det e rm i n e po s i t i on v a r i a b l e s for r i ng

*
/

voi d Ri ng : : Pos i t i on ( f l oa t * pos l . f l o a t *pos 2 , Vector *


l oca t i on )

Vector del ta ;
fl oat l engt h l , l ength2 ;

del ta = * l oc a t i on - l ac ;
l eng t h l sqrt ( vectl % vectl ) ;
l ength2 sqrt ( vect2 % vect2 ) ;
*pos l ( de l ta % vect l ) l engt h l ;
/
*pos2 = ( del ta % vect2 ) l ength2 ;
/

/*
Dete rmi ne pos i t i on v a r i a b l es for q u a d ra t i c

*
/

voi d Quadrati c Pos i t i on ( f l oa t * pos l , fl oat *pos2 , Vector *


l oca t i on )

V e c t o r n ewp o s ;

n ew p o s = * l o c a t i o n - l ac ;
*pos l n ewpos . x ;
*pos2 = n ew p o s . y ;

/*
Gen e r i c i n tersect i on test

201
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

*/

i nt Obj ect : : Col l i s i onTes t ( Li ne * l i ne . fl oat *t )


{
return ( O ) ;

/*
Test for i n tersecti on of l i ne wi th sphere

*/

i nt Sphere : : Co l l i s i onTes t ( Li ne * l i ne , fl oat *t )


{
fl oat a , b , c , d , tl ;
V e c t o r t emp ;

t emp = l o c - l i n e - > l o c ;
c ( t emp % t emp ) - n l ;
b - 2 * ( l i n e - > d i r % t em p ) ;
a l i ne - >di r % l i ne - >di r ;
d b*b - 4 . 0*a *c ;
i f ( d <=O )
retu rn ( FALSE ) ;
d = s q r t ( d ) ; * t= ( - b +d ) / ( a + a ) ;
t l= ( - b - d ) I ( a+a ) ;
i f ( * t <=SMA L L && t l <=SMA L L )
retu rn ( FALS E ) ;
i f ( t l > *t )
{
i f ( * t < SMA L L )
*t = t l ;

el se
i f ( t l > SMA L L )
*t = tl ;
r e t u r n ( T RU E ) ;

202
F U N C T I O N S T H AT M AT C H A N O B J E C T: V I R T U A L F U N C T I O N S

/*
Test for i n t e r s ec t i on of l i n e wi th t r i a n g l e

*I

i nt Tri angl e : : C o l l i s i onTe s t ( L i ne * l i ne , fl oat *t )

Vector del ta , l oc a t i on ;
fl oat dot . pos l , pos2 , gu [ 3 J , gv [ 3 J ;
i nt i , j , c r o s s i n g_n o ;

d o t = n o rm % l i n e - > d i r ;
i f ( f a b s ( d o t ) < S MA L L )
ret u rn ( FALS E ) ;
pos l = n l ;
p o s 2 = n o rm % l i n e - > l oc ;
* t= ( p o s l - p o s 2 ) / d o t ;
l oc a t i on = l i ne - > l oc + ( l i ne - >di r * *t ) ;
del ta = l oc a t i on - l ac ;
i f ( ( f a b s ( n o rm . x ) > fa b s ( n o rm . y ) ) && ( fa b s ( n o rm . x ) >
f a b s ( n o rm . z ) ) )

gu [OJ -
del ta . y ;
gv [OJ - del ta . z ;
gu [ l ] vect l . y del ta . y ;
gv [ l ] vectl . z del ta . z ;
gu[2J vect2 . y del ta . y ;
gv [2J vect2 . z del ta . z ;

el se
{
i f ( f a b s ( n o rm . y ) > f a b s ( n o rm . z ) )
{
gu[OJ - del ta . x ;
gv [ O J - del ta . z ;
gu [ l ] vectl . x del ta . x ;
gv [ l ] vectl . z del ta . z ;
gu [ 2 J vect2 . x del ta . x ;
gv [ 2 ] vect2 . z del ta . z ;

203
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

el se
{
gu[OJ - del ta . x ;
gv [OJ - del ta . y ;
gu[ l ] vectl . x - del ta . x ;
gv [ l ] vectl . y - del ta . y ;
gu[2] vect2 . x - del ta . x ;
gv [ 2 J vect2 . y - del ta . y ;

c r o s s i n g_n o = O ;
f o r ( i =O ; i <3 ; i ++ )
{
j = (i + 1) % 3;
i f ( ( ( gv [ i ] < 0 ) && ( g v [ j ] >= 0) ) 1 1 ( ( gv [ j ] < 0 ) && ( gv [ i ]
>= 0) ) )

i f ( ( g u [ i J > =O ) && ( g u [ j ] >= 0) )


c r o s s i n g_n o ++ ;
el se
{
i f ( ( g u [ i J > =O ) I I ( gu[j J >= 0) )
{
i f ( gu [ i ] - gv [ i ] * ( gu[j ] - g u [ i ] ) I
( gv[j ] - gv [ i ] ) > 0 )
c r o s s i n g_n o++ ;

i f ( ( c r o s s i n g_n o % 2 ) == 0)
r e t u r n ( FA L S E ) ;
r e t u r n ( T RU E ) ;

204
F U N C T I O N S T H AT M AT C H A N O B J E C T : V I R T U A L F U N C T I O N S

I*
Te s t f o r i n t e r s e ct i on o f l i n e wi t h pa ra l l e l o g r a m

*/

i nt Pa ra l l el ogram : : Col l i s i onTest ( Li ne * l i ne , fl oat *t )


{
Vector del ta , l o c a t i on ;
fl oat dot , pos l , pos2 , gu [ 4 J , gv [ 4 J ;
i nt i . j . c r o s s i n g_n o ;

d o t = n o rm % l i n e - > d i r ;
i f ( fa b s ( d o t ) < S MA L L )
r e t u r n ( FA L S E ) ;
pos l = n l ;
p o s 2 = n o rm % l i n e - > l oc ;
* t= ( p o s l - p o s 2 ) / d o t ;
l oc a t i on = l i n e - > l oc + ( l i n e - >d i r * *t ) ;
del ta = l ocati on - l ac ;
i f ( ( fa b s ( n o rm . x ) > f a b s ( n o rm . y ) ) && ( f a b s ( n o rm . x ) >
f a b s ( n o rm . z ) ) )

gu [O] - del ta . y ;
gv [OJ - del ta . z ;
gu[ l ] vectl . y del ta . y ;
gv [ l ] vect l . z del ta . z ;
gu[2J vect2 . y + vect l . y - del ta . y ;
gv [2J vect2 . z + vectl . z - del ta . z ;
gu[3J vect2 . y - del ta . y ;
gv[3J vect2 . z del ta . z ;

el se
{
i f ( fa b s ( n o rm . y ) >= f a b s ( n o rm . z ) )
{
gu[OJ - del ta . x ;
gv [OJ - del ta . z ;
gu [ l ] vectl . x del ta . x ;
gv [ l ] vectl . z - del ta . z ;
gu[2J vect2 . x + vect l . x del ta . x ;
gv [2J vect2 . z + vect l . z - del ta . z ;

205
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

gu[3J vect2 . x - del ta . x ;


gv [3J vect2 . z - del ta . z ;

el se
{
gu[OJ -
del ta . x ;
gv [OJ - del ta . y ;
gu [ l ] vectl . x - del ta . x ;
gv [ l ] vectl . y del ta . y ;
-

gu[2J vect2 . x + vectl . x - del ta . x ;


gv [2] vect2 . y + vectl . y - del ta . y ;
gu[3J vect2 . x - del ta . x ;
gv [ 3 J = vect2 . y - del ta . y ;

c r o s s i n g_n o = O ;
f o r ( i =O ; i <4 ; i ++ )
{
j = (i + 1) % 4;
if ( ( (gv[i J < 0 ) && ( g v [ j ] >= 0) ) I I ( ( gv [ j ] < 0 ) &&
( g v [ i ] >= 0) ))

i f ( ( g u [ i J > =O ) && ( gu[j J >= 0) )


c r o s s i n g_n o ++ ;
el se
{
i f ( ( g u [ i ] >=O ) I I ( gu [j ] >= 0) )
{
i f ( gu[ i ] - gv [ i ] * ( gu[ j ]
gu[i ] ) / ( gv [j ] - gv [ i ] )
> O ) c r o s s i n g_n o ++ ;

i f ( ( c r o s s i n g_n o % 2) 0)
r e t u r n ( FA L S E ) ;

206
F U N C T I O N S T H AT M AT C H A N O B J E C T : V I R T U A L F U N C T I O N S

ret u r n ( T RU E ) ;

===;i
I * r.=
Test fo r i n tersect i on of l i ne wi th r i ng

*/

i nt Ri ng : : Co l l i s i onTes t ( Li ne * l i ne , fl oat *t )
{
Vector del ta , l oc a t i on ;
fl oat dot , rad , pos l , po s 2 ;
dot = n o rm % l i n e - > d i r ;
i f ( fa b s ( d o t l < SMA L L )
r e t u r n ( FA L S E ) ;
pos l = n l ;
p o s 2 = n o rm % l i n e - > l oc ;
* t= ( p o s l - p o s 2 ) / d o t :
l oc a t i on = l i n e - > l oc + ( l i n e - >d i r * *t ) ;
del t a = l oc a t i on - l oc ;
rad = sqrt ( del ta % del ta ) ;
i f ( rad< ( vect3 . x ) I I rad> ( vect3 . y ) )
r e t u r n ( FA L S E ) ;
ret u rn ( T RU E ) ;

I*
Te s t f o r i n t e r s e ct i on o f l i n e wi t h q u a d ra t i c

*I

i nt Quadrati c : : C o l l i s i onTe s t ( L i n e * l i n e , fl oat *t l


{
fl oat a , b , c , d , tl ;
V e c t o r l oc a t i on , l ocl , tempd i r ;
L i n e n ew l i n e ;

newl i ne . l oc = l i ne - > l oc - l oc ;
i f ( ( v e c t l . x == O l && ( vectl .y 1 ) && ( vectl . z 0))
n ew l i n e . d i r = l i n e - > d i r ;

207
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

el se
{
n ew l i n e . d i r = l i n e - > d i r . Ro t a t e ( c o s l , sinl , cos2 , s i n2 ) ;
n ew l i n e . l a c = n ew l i n e . l o c . Re v_R o t a t e ( c o s l , sinl , cos2 ,
s i n2 ) ;

i f ( y t e r m == 0 )
{
c = - ( c t e rm ) + v e c t 2 . x * n ew l i n e . l o c . x * n ew l i n e . l o c . x +
v e c t 2 . y * n ew l i n e . l o c . y * n ew l i n e . l o c . y +
v e c t 2 . z * n ew l i n e . l o c . z * n ew l i n e . l o c . z :
b = 2 * ( v e c t 2 . x * n ew l i n e . l o c . x * n ew l i n e . d i r . x +
v e c t 2 . y * n ew l i n e . l o c . y * n ew l i n e . d i r . y +
v e c t 2 . z * n ew l i n e . l o c . z * n ew l i ne . d i r . z ) ;
a = vect2 . x * newl i n e . d i r . x * n ew l i n e . d i r . x +
v e c t 2 . y * n ewl i n e . d i r . y * newl i ne . di r . y +
v e c t 2 . z * n ewl i n e . d i r . z * n ew l i n e . d i r . z ;

el se
{
c - ( c t e rm ) + v e c t 2 . x * n e w l i n e . l o c . x * n ew l i n e . l o c . x -
y t e rm * n ew l i n e . l o c . y +
v e c t 2 . z * n ew l i n e . l o c . z * newl i n e . l o c . z :
b = 2 * ( v e c t 2 . x * n ew l i n e . l o c . x * n ewl i n e . d i r . x -
y t e rm * n ew l i n e . d i r . y +
v e c t 2 . z * n ew l i n e . l o c . z * n ewl i n e . d i r . z ) ;
a = v e c t 2 . x * n ew l i n e . d i r . x * n ew l i n e . d i r . x +
v e c t 2 . z * n ew l i n e . d i r . z * n ew l i n e . d i r . z ;
}
d b * b - 4 . 0*a *c ;
i f ( d<O )
return ( FALSE ) :
d = s q rt ( d ) :
* t = ( - b+d ) / ( a + a ) ;
t l = ( - b - d ) / ( a+a ) ;
l o c a t i o n = n ew l i n e . l a c + ( n ewl i n e . d i r * *t ) ;
l oc l = newl i n e . l ac + ( n ewl i n e . d i r * t l ) ;
i f ( ( l o c a t i o n . x < l owe r . x ) I I
( l oc a t i on . x > u p pe r . x ) I I
( l o c a t i o n . y < l owe r . y ) I I
( l oca t i on . y > uppe r . y ) I I
( l o c a t i o n . z < l owe r . z ) I I

208
F U N C T I O N S T H AT M AT C H A N O B J E C T : V I R T U A L F U N C T I O N S

( l ocati on . z > upper . z l l


*t = - 1 ;
i f ( ( l o c l . x < l owe r . x ) I I
( l ocl . x > upper . x l I I
( l o c l . y < l owe r . y l I I
( l ocl . y > upper . y ) I I
( l o c l . z < l owe r . z ) I I
( l ocl . z > upper . z l )
t1 = - 1 ;
i f ( * t <=SMA L L && t l <=SMA L L )
r e t u r n ( FA L S E ) ;
i f ( tl > *t )
{
i f ( * t < SMA L L )
*t = t 1 ;

el se
i f ( t 1 > SMA L L )
*t = t 1 ;
r e t u r n ( T RU E ) ;

/*
Te s t f o r i n t e r s e ct i on of l i n e wi t h bound i n g box

*/

i n t BBox : : Co l l i s i onTe s t ( Li ne * l i n e , fl oat *t l


{
fl o a t tmi nx , tma xx , tmi ny , t m a xy ,
tmi n z , tma xz , tmi n , tma x , tl , t2 ;

* t= l O ;
i f ( f a b s ( l i n e - > d i r . x ) < SMA L L )
{
i f ( ( l owe r . x < l i n e - > l o c . x ) &&
( upper . x > l i ne - > l oc . x l l
{
tmi nx - 3e30 ;
tma xx 3e30 ;

209
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

el se
r e t u r n ( FA L S E ) ;

el se
{
t l = ( l owe r . x - l i n e - > l o c . x ) / l i n e - > d i r . x ;
t2 = ( uppe r . x - l i ne - > l oc . x ) / l i ne - >di r . x ;
tmi nx = M I N ( t l , t2 ) ;
tma xx = MAX ( t l , t2 ) ;
i f ( tm a x x < O )
r e t u r n ( FA L S E ) ;

i f ( fa bs ( l i n e - >d i r . y ) < SMAL L )


{
i f ( ( l owe r . y < l i n e - > l o c . y ) &&
( uppe r . y > l i ne - > l oc . y ) )

tmi ny = - 3e30 ;
t m a x y =3 e 3 0 ;

el se
r e t u r n ( FA L S E ) ;

el se
{
t l = ( l owe r . y - l i n e - > l o c . y ) / l i n e - > d i r . y ;
t 2 = ( uppe r . y - l i ne - > l oc . y ) / l i ne - >d i r . y ;
tmi ny = M I N ( t l , t 2 ) ;
t m a xy = M A X ( t l , t 2 ) ;
i f ( t m a xy < O )
r e t u r n ( FA L S E ) ;

i f ( fa b s ( l i n e - > d i r . z ) < SMA L L )


{
i f ( ( l owe r . z < l i n e - > l o c . z ) &&
( uppe r . z > l i n e - > l oc . z ) )

tmi nz = - 3e30 ;
t m a x z =3 e 3 0 ;

el se
r e t u r n ( FA L S E ) ;

21 0
F U N C T I O N S T H AT M AT C H A N O B J E C T : V I R T U A L F U N C T I O N S

el se
{
tl = ( l owe r . z - l i n e - > l o c . z ) / l i n e - > d i r . z ;
t2 = ( u ppe r . z - l i ne - > l oc . z ) / l i ne - >d i r . z ;
tmi nz = M I N ( tl , t2 ) ;
tma xz = MA X ( t l , t 2 ) ;
if ( tm a x z < O l
retu rn ( FALS E ) ;

tmi n = M a x ( t m i n x , tm i ny , tm i n z ) ;
tma x = M i n ( t m a x x . t m a xy , t m a x z ) ;
if ( tm a x < tm i n )
retu rn ( FALS E ) ;
r e t u r n ( T RU E ) ;

F i n d i n g the Normal to an Object


Three of the object classes, the Triangle, Ring, and Parallelogram are plane
figures. Their normal at any point is the same; it is the normal to the plane. This
normal is calculated once at the time the figure is read in from the data file and
stored within the object structure. Hence, the function FindNorm for these three
classes of object simply gets the precomputed normal and puts it into the
variable normal. The Sphere class has a normal that differs, depending upon the
point on the sphere where you are located. This position is represented by the
variable position. The normal is a vector drawn from the center of the sphere
(represented by the vector loc) to the position. This has to be normalized.

For the surfaces represented by quadratic equations, things are a little more
complicated. Usually, the quadratic surfaces are oriented around the y axis. If
any other orientation is desired, it is specified in the vector vectl . We first define
a vector newpos, which is the vector from the center (loc) of the object to the
position where we are on the surface. Then check vectl ; if it is a unit vector in
the y direction, the normal vector is the normalized value of a vector which is the
cross product of the vector vect2 (a vector created from the coefficients of x2-, y2,

21 1
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

and z 2 in the quadratic equation) and the vector newpos. If vectl indicates that
the quadric is rotated in some direction other than normal, first rotate the newpos
vector to correspond with the normal orientation of the solid then find the
normal, and reverse rotate it back to get the actual normal for the rotated solid.

Generating Bou nding Boxes


This next series of functions generates bounding boxes that encompass
various objects. The first function is empty for the base class . For the Sphere
class, the bounding box has x, y, and z maximums which are the coordinates of
the sphere center p l u s the rad i u s , and x, y , and z m i n i m u m s which are
coordinates of the sphere center minus the radius. The function passes the
addresses of two vectors, whose contents are changed by the function action.
The first, v 1 , represents the comer of the box corresponding to the minimums,
and the second, v2 , the comer of the box corresponding to the maximums.

The parallelogram is defined by the loc vector, which marks the set of
coordinates for the first comer of the parallelogram, and by two other vectors,
vectl and vect2 , which represent the location of two other corners of the
parallelogram with respect to the first comer. The fourth comer is defined from
the other three and the fact that pairs of sides of the figure are parallel. The
function to find the bounding box computes the second, third, and fourth comers
of the parallelogram in absolute coordinates (not referenced to loc) and then
takes the maximum and minimum values of each of the three coordinates for the
box comers.

The function to find the bounding box for the triangle works exactly the
same as for the parallelogram, except there are only three comers for the figure
instead of four.

The function to find the bounding box for the ring simply adds the outer
radius of the ring to each of the three coordinates to obtain the maximum box
comer and subtracts it from the coordinates to obtain the minimum box comer.
This is not too efficient, since it generates a box which will hold the ring, no

21 2
F U N C T I O N S T H AT M AT C H A N O B J E C T : V I R T U A L F U N C T I O N S

matter which direction it is oriented in. Taking into consideration the actual
orientation of the ring, a much tighter bounding box can be generated. You may
want to attempt this improvement.

For the quadratic, the upper and lower bounds of x, y, and z are specified at
the time when data for the quadratic is entered. These bounds are simply taken
to generate the bounding box.

Chang i n g the Scale of a User- Generated Object


U ser-defined objects are created by the statement BEGIN_INSTANCES
followed by definitions of one or more objects, and ending with the statement
END_INSTANCES. When a named instance is called for by the appropriate
command, its description is first transferred to new objects within the list of
objects processed by the ray-tracing program. The instance may then be
modified, scaled, and/or relocated. Usually, the location for a single-object
instance is given as a Joe vector of (0, 0, 0). When relocation occurs, the Joe
vector is changed to the new location of the object. If an instance consists of
several objects, the center of the group is usually considered to be the location
(0, 0, 0) and the Joe vector for each object shows the displacement of that object
from the center of the group.

An object is scaled by one of the functions Scale_Instance. For each of the


scaling functions, a parameter i s passed to the function which i s a vector
showing the multiplication factors for scaling in each of the three coordinates.
The scaling function for each class of object treats the Joe vector in the same
way, name l y by m u l t i p l y i ng each coordinate by the multiplier for that
coordinate . Scaling of other parameters differs, depending upon the class of
object. For an object of class Sphere , the minimum multiplier for the three
coordinates is used to scale the radius of the sphere, vectl .x. For an object of
class Parallelogram , the vector Joe defines the first comer of the parallelogram,
and the vectors vectl and vect2 define two other comers with respect to the first
corner. The scaling function simply multipl ies these two vectors by the
multiplier vector. For an object of class Triangle, the function is the same as for

21 3
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +

the Parallelogram class. For an object of class Ring, vectors vectl and vect2
define the plane of orientation of the ring, with respect to the toe vector, and
these are multiplied by the multiplier vector. The parameter vect3 .x is the inner
radius of the ring and vect3 .y is the outer radius. Both are scaled by multiplying
by the minimum of the three coordinate multipliers. For an object of class
Quadratic, the upper and lower limits are scaled by multiplying by the multiplier
vector. Finally, each Scale_Instance function recursively calls itself to scale any
child functions and if a flag is passed to the function, it also recursively calls
itself to scale any function addressed in the nextobj parameter.

Determ i n i ng Position Variables for an Object


Once the ray tracing functions described in Chapter 1 2 have established an
intersection between the ray being traced and an object, we need to project a
pattern (if one has been specified) onto the object surface to determine whether
the pattern color should be substituted for the native color of the object. This is
described in detail later. At this point, only two position variables, posl and
pos2 , are required for the process and these variables are different for each type
of object. For the sphere, the angle of the vector from the center of the object
coordinate system to the point of intersection in the x-y plane is multiplied by
the radius of the spher� to give posl . For pos2 , the angle is that between the z
coordinate of the above vector and the projection of it onto the x-y plane. Again,
the angle is multiplied by the radius of the sphere.

For the Ring, Parallelogram, and Triangle objects, the posl value is the
projection of the vector from the center of the object-oriented coordinate system
to the intersection on one of the vectors that defines the plane of the object. Pos2
is the projection of that same vector upon the other vector that defines the object
plane. Finally, for the Quadratic object, posl and pos2 are simply the x and y
coordinates at the point of intersection in the object-oriented coordinate system.

21 4
CHAPTER 1 1

Finding Where the Ray


Hits an Object

Here we describe the ray.cpp file, which traces each ray throughout the
picture. Before doing that, however, we need to discuss how to determine where
a ray actually hits an object. Given that we are working backwards, starting at
the observer 's eye and tracing a ray of light back to the screen, we determine at
some point in our computations exactly where on an object 's surface the ray may
be hitting. A function for this action is found in ray.cpp, while the functions that
determine the exact intersection for each class of object are a part of objects.cpp,
which was described in the previous chapter. However, at that time , we
deliberately neglected these functions, choosing to describe the whole operation
here in a separate chapter.

The Intersect Fu nction


The function Intersect controls the intersect point with an object. It is listed
as part of Figure 1 0- 1 . The principal inputs are the address of line, the current
ray being traced, and the address of CurrObj, the object in the object list that is
being tested for intersection with the ray. This function is going to return the
address of the closest object intersected, which is locally stored in the static
object address Closest_object. It is not destroyed, since it is a static address. The
function loops, calling CollisionTest for each object in the object list. This latter
fun c t i o n u s u a l l y s o l v e s a quadratic equation , saving the closest object
intersection of the two roots obtained. When Intersect finishes, it returns the
address of the closest object intersected. The function also updates a variable
called Shortest_time, which is the time travelled along the ray to the closest

21 5
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

object. The first thing the function does is reinitialize the closest-object address
and the shortest-time variable, if necessary. A value of TRUE in init_flag is the
criterion for reinitialization. The time is initialized to a very large value and the
address of the closest object to a null.

Next, the function starts a loop through every object in the object list. At the
beginning of the loop, we call CollisionTest, which determines whether an
intersection occurs. If there is no intersection, this function returns a FALSE;
otherwise, it returns TRUE and the v ariable t contains the time when the
intersection takes place. (Throughout our consideration of intersections, we use
a parametric method wherein we follow the ray from its beginning along the
direction in which it is oriented until an intersection occurs. Since the ray­
direction vector is normalized, multiplying this vector by the time provides the
coordinates of the position we have reached by following the ray.)

After thi s , we increment a stati stics variable that tracks the number of
intersection tests made. Next, if an intersection occurred, we check to make
sure that the time parameter t returned was not too small. This eliminates a
computation problem that occurs when we start a ray at the surface of some
object, intending to follow reflected or refracted light from that point on. If our
computer had absolute precision, we could compute our next intersection
without a problem. When precision is not absolute, we may find that the next
intersection is very close by, where in fact we are just finding the intersection
that we started from all over again. This not only wastes time, it can become an
infinite loop where we keep finding the same intersection and never escape. To
avoid this, we specify a minimum length of the ray before the intersection is
considered valid. This minimum is greater than the possible computation error,
thus eliminating erroneous cases.

If we have a valid intersection, we next check to see whether the intersection


is with a bounding box. If so, we run Intersect recursively to find the closest
intersection (if any) with an object within the bounding box. If there is a valid
intersection with an object (not a bounding box), we first check to see if the

21 6
F I N D I N G W H E R E T H E R AY H I TS A N O B J E C T

remove parameter for that object i s active. If so, we compute the point of
intersection and put it in the vector toe and call the function Find_ Color.
Normally, this function determines whether a pattern color must be used to
replace the usual color of the object. In this case, the pattern is actually a part of
the object to be removed. If the function returns to a pattern intersection, we
eliminate this object from consideration, set the address of the object to be
checked to the next object in the list, and start another iteration of the loop. If
the remove parameter was not active or if it was active but we intersected a part
of the object that is not to be removed, we increment the statistical variable that
counts the number of ray intersections with objects that are not bounding boxes.

There are two kinds of rays whose intersections may be investigated with the
Intersect function. One of these is called shadow rays, which go from the object
to a light source. The other kind of ray goes from the observer to the screen to
the object. We distinguish between the two cases by passing the parameter
shadow_flag as TRUE for shadow rays and FALSE for the other types of rays.
For the shadow rays, if t is less than one and the transmission characteristics of
the object are all less than the threshold values, we assign this object to be the
closest object and terminate the function. Otherwise, the light-attenuation factor
increases according to the transmission characteristic for the object.

If the ray is from the observer to an object, we compare the value of t


returned for this object with the value in Shortest_time. If t is smaller than the
previously shortest time, we put this value into Shortest_time and put the address
of this object into Closest_object. We then set the object address to that of the
next object in the list and continue with another iteration of the loop. When the
loop is done, an intersection of the ray with every object in the list has been
checked. If any intersections occurred, Shortest_time contains the time to the
closest object and Closest_object contains the address of the closest object. This
address is returned by the function when it terminates.

General Intersection Math


We mentioned in passing that in ray tracing we use the equation of the ray in

21 7
F R A C TA L P R O G R A M M I N G A N D R A Y T R A C I N G W I T H C + +

a parametric form. In particular, the equations for the coordinates of the ray are:

(Equation 1 1 - 1 )

Y = y t t + YO (Equation 1 1 -2)

z = z 1 t + zo (Equation 1 1 -3)

The coordinates (xo , YO · zo ) are the coordinates of the starting point of the
ray; the coordinates (x 1 Y I · z 1 ) represent a unit vector in the direction in which
.

the ray is travelling. The parameter t can be taken as time. Thus, at zero time,
the ray is at its origin. As time passes, the ray travels farther along its path. We
are interested in determining the time at which the ray intersects an object; in
particular, if we scan through a list of objects, we would like to know which
object the ray hits first (the intersection for which t is the smallest). We compute
the intersection of the ray with an object by inserting the ray equation into the
equation for the object's surface and solving the resulting equation. For this
computation, we 'll use a coordinate system that is referenced in some convenient
way to the surface of the object we are testing.

Intersection with a Sphere


The function CollisionTest is different for each type of object for which an
intersection with the ray must be tested. As described in the previous chapter,
using virtual functions, the program automatically selects the proper version of
the function for the type of object being tested. The versions of the function are
listed in Table 1 1 - 1 . For a sphere, we determine the intersection as follows. The
equation of a sphere, centered at (0, 0, 0) and having a radius r, is:

(Equation 1 1 -4)

If we substitute the parametric equations of the ray into this equation (using
for the ray the coordinate system whose origin is the center of the sphere) we
obtain the following:

21 8
F I N D I N G W H E R E T H E R AY H I T S A N O B J E C T

(Equation 1 1 -5)

We begin by converting the line origin to the sphere 's coordinate system and
storing the result in the vector temp. We have precomputed the square of the
sphere 's radius; it is stored in nl . Next, we use some vector mathematics to
determine the coefficients of t2 (a in the function), t (b in the function), and the
constant term (c in the function). We then perform a straightforward solution of
the quadratic equation to obtain two roots, one of which is tl and the other
placed in the space addressed by t. (The address of t is passed to the function so
that the final value is available to the calling program rather than only being
local to this function.)

We are going to return a TRUE if there is a legitimate intersection and a


FALSE if there is not. A legitimate intersection yields at least one root that is
greater than a spec ified minimum value. The minimum protects u s from
thinking that a ray starting at the sphere 's surface (such as a reflected ray) has an
intersection at the surface (t = 0).

We first check to see whether ti i s both greater than the minimum and
smaller than the contents of t. If it meets these conditions, we replace it as the
contents of t, then check that the contents of t are greater than the minimum.
(This check is necessary in case we didn 't make a switch in the above test.) If
the contents meet the condition, we have a legitimate root and we return TRUE,
with the time corresponding to the closest root stored in the location pointed to
by t. Otherwise, we return a FALSE to indicate that there is no legitimate root
and we don 't really care what time it is.

Intersecting a Quadric C u rve


The next consideration is intersecting with a quadric curve. This is similar
to our sphere intersection, since the sphere is a degenerate case of the general
quadric c u rv e . The m o s t common quadric shapes are c y l inder, elliptic
paraboloid, hyperbolic paraboloid, elliptic cone, hyperboloid of one sheet,

21 9
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

hyperboloid of two sheets, and ellipsoid. These shapes are shown in Plate 9. All
of these shapes are represented by the following generalized equation:

ax2 + 2 bxy + 2 cxz + 2dxw + ey2 + 2fyz + 2gyw + hz2 + 2 izw + jw2 = 0

(Equation 1 1 -6)

Although the above equation covers every possible kind of quadric curve, it
is too complex to be handled easi l y by this simple ray-tracing program .
Fortunately, most of the common quadric surfaces can be treated by a subset of
this equation, namely:

A.x2 + By2 Cz2 + Ey = D (Equation 1 1 -7)

Table 1 1 -1 . Parameters of Quadric Shapes

Shape A B c D E Color

Elliptic cone + -
+ 0 -
Cyan

Cylinder + 0 + + -
Green

Elliptic paraboloid + -
+ 0 -
Purple

Hyperbolic paraboloid +
- -
0 -
Blue

Hyperboloid of one sheet + -


+ + -
Orange

Hyperboloid of two sheets - -


+ +
-
Red

Ellipsoid + + + + -
White

220
F I N D I N G W H E R E T H E R AV H ITS A N O B J ECT

We further impose the restriction that only one y term may occur in the equation
for any given surface (there may be either a y term or a y2 term, but not both). Table
1 1 - 1 l i s t s t h e v ar i o u s s h a p e s and g i v e s the s i g n of e a c h c o e ffi c ient
required for that particular shape, along with the color of the shape in Plate 9.

We are going to u se the same technique of substituting the parametric ray


equations into the equation of the quadric and then solving the resulting quadratic
equation. The equation for the quadric containing a y2 term is:

t2 (Ax 1 2 + By 1 2 + Cz 1 2 ) + 2t(Axox 1 + BYOY l + Czoz 1 ) + (Ax o2 + Byo2 +


cz02 _ D) = o
(Equation 1 1 -8)

For the quadric that has y term instead of a y2 term, the corresponding equation
is:

t 2 (Ax 1 2 + Cz 1 2 ) + 2t(Ax 0x 1 - Ey 1 + Czoz 1 ) + (Ax02 - Ey0 + Cz02 ) = O

(Equation 1 1 -9)

Look at the function listed in Table 1 1 - 1 . It first converts the origin of the ray to
the quadric-centered coordinate system and places the result in newline.toe. Next, it
checks the orientation of the quadric by looking at the contents of vectl . If this is a
unit vector pointed in the y direction, the orientation of the quadric is standard, so the
ray direction is placed in newline.dir. If the vector in vectl indicates a different
orientation for the quadric, the ray direction is rotated to correspond to the orientation
of the quadric coordinate system. This is done with the function Rotate , using the
sines and cosines for rotation precomputed for the particular quadric. The result, after
rotation, is placed in newline.dir.

The function next uses vector mathematics to generate the coefficients for the
quadratic equation of the intersection. This equation is then solved to obtain two
roots. Next, the location of each root is computed in terms of the quadric coordinate

221
F R A C TA L P R O G R A M M I N G A N D R A V T R A C I N G W I T H C + +

system. The upper and lower limits for each coordinate of the quadric are stored
in terms of its own coordinate system. The location of each intersection is
compared with these limits. If the root falls within the limits, it is an acceptable
intersection; if not, set the time parameter for that root to - 1 to assure that it will
not be considered a valid intersection in the tests that follow, then proceed with
the testing process. As with the sphere, the goal is to find the smaller of the two
intersection times, providing that the time selected must exceed the threshold
parameter SMALL . The function returns TRUE for a valid intersection and
FALSE if there is no valid intersection. If there is a valid intersection, t points to
the time for that intersection.

Intersection with a Ring


Next, we consider an intersection with a ring. This is the first of three
surfaces that are actually sections of a plane. The first thing the intersection
funCtion, Col/isionTest , does in this case is to determine whether the ray
intersects with the plane containing the ring. The initial step is to take the dot
product of the line (ray) direction vector and the normal to the plane (which was
precomputed and stored in norm). If this is zero or very small, the ray is hitting
the plane on its edge . But a plane doesn ' t really have an edge (the edge is
infinitely thin), so we might as well forget this case and return FALSE to indicate
that an intersection does not take place. The equation for a plane is:

ax + by + cz + d = 0 (Equation 1 1 - 1 0)

The intersection of the ray with the plane i s obtaine d , as before , by


substituting the parametric equations of the ray into the equation of the plane,
giving:

ax()±Jll'.o+cz()_±_d
t = ax + by +cz + d (Equation 1 1 - 1 1 )
1 1 1

This is a general equation, but we use a coordinate system centered at the


middle of the plane so that the parameter d will always be zero. Observe that the
vector (a, b, c) is the normal to the plane. Consequently, the denominator of the

222
F I N D I N G W H E R E T H E R AY H I TS A N O B J E C T

equation is the dot product of the normal to the plane and the line direction. As
for the numerator, it is the dot product of the normal to the plane with the
difference between the origin of the plane coordinate system and the origin of
the line. We have already computed the dot product of the normal and the origin
of the plane coordinate system; it is stored in nl , so all that needs to be done is to
subtract from nl the dot product of the normal to the plane and the line origin,
then plug the results into the intersection equation and obtain a value for the time
until intersection.

Next, determine the point on the ray at which it intersects the plane, called
the location , then find the vector delta , which is the vector from the plane
coordinate origin to the point of intersection. The length of this vector is the
square root of the dot product of the vector and itself. We call this length rad. If
rad falls between the values of the inner radius of the ring and the outer radius of
the ring, we have a valid intersection with the ring and return TRUE. Otherwise,
there is no valid intersection and we return FALSE.

Intersection of the Ray with a Paral lelog ram


The function for determining whether there is a valid intersection with a
parallelogram begins like the function for obtaining an intersection with a ring.
We first reject cases where the ray intersects the edge of the plane, then, for the
remaining cases, determine the intersection of the ray with the plane. Again, we
compute the exact point of intersection of the ray with the plane and store this
location in the vector location. In delta , the location of the intersection is stored
in terms of the parallelogram coordinate system.

We are now ready to determine whether the intersection is actually inside the
parallelogram. This turns out to be a lot more work than determining whether
the intersection with the plane occurs, and more work than doing the same thing
for the ring (which is a rather trivial case). We are going to use the Jordan curve
theorem, which states that if we project a line from the intersection point in an
arbitrary direction and the line has an odd number of intersections with the line
segments that are the sides of the parallelogram, the intersect point is inside the

223
F R A C TA L P R O G R A M M I N G A N D R A Y T R A C I N G W I T H C + +

parallelogram. If there is an even number of intersections, the intersect point is


outside the parallelogram.

To make things easier, we first project both the parallelogram and the
intersect point onto a plane defined by two axes of the coordinate system. We
must decide which of the three coordinate axes should be discarded, namely the
one with the largest value for any of the vertices of the parallelogram. This is
the dominant axis. We then perform the projection onto the plane formed by the
other two coordinates by throwing away the values of the dominant coordinate
for each of the parallelogram's vertices, then compute the location of each vertex
in the new system with respect to the parallelogram coordinate system. The first
vertex is always at (0, 0) by definition.

In the CollisionTest function, we take into consideration the dominant axis


and compute the coordinates of each vertex in terms of a coordinate system
centered at the intersect point. These are stored in (gu[n} , gv[n}), where n is the
vertex number from 0 to 3 . The new coordinate system will have the axes u and
v. We can project the test line in an arbitrary direction; we choose to project it
along the u axi s . We initialize crossing_no , which contains the number of
crossings of a parallelogram line segment, then enter a loop that checks the test
line against the line segment between each pair of adjacent vertices. We can
only have an intersection of the test l ine and the line segment connecting
adjacent vertices if gv[i} and gv[j] have opposite signs. (This puts one vertex on
one side of the u axis and the other on the opposite side, which assures a crossing
of the u axis.)

If both gu[i] and gu[j] are positive, then we know that the crossing of the u
axis is also a crossing of the test line, and we therefore increment crossing_ no.
If one of the vertex u coordinates is positive and the other is negative, we must
compute the value of the u coordinate for the intersection of the line segment
with the u axis. If this is positive, we have an intersection with the test line and
therefore increment the number of crossings; if negative, there is no intersection
with the test line, so the number of crossings is unchanged.

224
P l a t e 1 . Newto n ' s M e t h o d f o r x 5 - 1 = 0

Plate 2. N ewto n ' s M et h o d f o r x 7 - 1 = O


P l a t e 3. Newto n ' s M e t h o d f o r x 6 - 2x 5 + 4 x4 - x - 1 = O

P l ate 4. B r i c k Wa l l a n d S p h e re s
P l a t e 5 . C o n e s a n d M i rro red S p h e res

Plate 6 . New Y o r k Wo r l d ' s Fa i r - 1 9 39


P l ate 7. E g y pt i a n Desert Scene

Plate 8. Indian Story Te l l e r


Plate 9. S h a pes G e n e rated U s i n g t h e Q u a d ra t i c Equation

P l a t e 1 0 . T h e Troj a n H o rse
Plate 1 1 . T h e M i rro red Blimp

Plate 1 2. F racta l M o u nta i n w i t h U FO ' s


Plate 1 3. Quatern i o n Julia Set

P l ate 1 4. Quater n i o n Julia Set


P l ate 1 5. Q u a rte r n i o n J u l ia Set

Plate 1 6. Q u a te r n i o n Dragon C u rve


FINDING WHERE THE R AY H I TS A N O B J E C T

After completing the loop for all adjacent line segment pairs, we take the
value of crossing_no modulo 2, which gives us a zero for an even number of
crossings and a one for an odd number of crossings. If the number of crossings
is odd, we know that the intersection is within the parallelogram and return
TRUE when the function terminates; if the number of crossings is even, there is
no intersection within the parallelogram so we return FALSE when the function
terminates.

This function will work equally well for any quadrilateral. It is restricted to
parallelograms because of the way we handle the input data, namely inputting
the location of the parallelogram (which is one vertex) and then the location of
two other vertices in relation to the first vertex . The fourth vertex of the
parallelogram is computed internally. You might want to create a new type
called QUADRILATERAL, which allows three arbitrary vertices to be entered
rather than two. After input and the proper initial calculations, the new object is
considered a type PARALLELOGRAM.

Intersection with a Triangle


The function Collision_Test for finding the intersection of a ray with a
triangle is exactly the same as the function for finding the intersection of a ray
with a parallelogram except that only three vertices are specified, the loop to
check line segment only tests for three line segments, and the modulus arithmetic
statement that makes sure the second vertex of the pair rolls around to zero on
the last check uses modulo three rather than modulo four. In fact, this whole
method of determining if a line that intersects a plane is also within a figure will
work equally well for any polygon, regardless of the number of sides. You can
set up a more generalized version in which objects of different numbers of sides
are treated; however, you need to make sure you have room to generate the
number of line segments needed to create the polygon.

Intersection with a Bou nd i n g Box


In addition to the intersection tests of the ray with various types of objects,
we need to have a version of the intersection function CollisionTest with the

225
F R A C TA L PROGRAMMING AND R AY T R A C I N G W I T H C++

bounding box, which may be set up around an object or group of objects to


reduce the number of intersection tests needed. The ray-tracing part of the
program is set up so that unless an intersection with the bounding box occurs,
further t e s t s for intersection w i th the obj e c t s contained i n the box are
unnecessary.

The function begins by determining whether the x component of the ray


direction i s greater than the minimum value SMALL . If not, the function
determines whether the ray origin is between the x limits of the box. If so, the
minimum time in this direction is set to a very low value and the maximum to a
very high value; otherwise, the function terminates, reporting no intersection.

If the component exceeds the threshold SMALL, times are calculated for the
ray to hit the upper and lower x limits of the box. If the maximum time is less
than zero, the function termin ate s , reporting no intersection. The same
procedure takes place for the y and z components of the ray. Overall maximum
and minimum times are taken, the maximum time being the minimum of the
three maximum components and the minimum time being the maximum of the
three minimum components. If the overall maximum is less than the overall
minimum, the function terminates and reports no intersection ; otherwise, it
reports that an intersection did occur.

226
CHAPT E R 1 2

Tracing the Ray

We have completed the portions of our ray-tracing program that support the
main task: tracing the path of each ray of light that makes up the picture. This
job is done by the functions that make up the file called ray.cpp. This file is
l isted in Figure 1 2 - 1 . Bear in mind that each l ight source emits rays that
illuminate all of the objects in the picture. The objects, in tum, absorb, reflect, or
refract the light rays, and some return through the viewing screen to the observer.
The rays of light striking the observer 's eyes determine the appearance of the
scene. These rays are a small fraction of the actual light rays in the world. In the
interest of reducing our computer processing to a reasonable amount, rather than
trace each ray of light from the light source, we trace backwards only those rays
that strike the observer's eyes.

We start at the observer's eye and follow a ray to a pixel on the screen. We
then continue to follow the ray in a straight line until it finally hits some object.
Then we follow reflected and refracted rays, as necessary, to their sources and
combine all that information to determine the color that this particular light ray
has when it reaches the eye. In doing ray tracing in this reverse manner, we
avoid the multitude of rays that don't contribute to the light seen by the observer
or to the picture.

The Overal l Scene- Traci ng Function


In Chapter 6, we noted that the main program called Trace_Scene performed
the ray-tracing operation. Of course, it isn 't all that simple: The Trace_Scene
function begins by defining a new line and putting it into the list of lines. It then
g o e s i n t o a fo r l o o p , w h i c h re p e a t s fo r e a c h l i ne of the d i s p l ay from
WORLD first_scan to WORLD. last_scan. Usually these scan limits are the first
and last lines of the display screen. Next, the number of the line being scanned

227
F R A C TA L PROG RAM MING AND R AY T R A C I N G W I T H C + +

is displayed, giving the user some idea of how far the program has progressed,
since ray tracing takes a considerable amount of time. Then the function
determines the parameter yf, which is the y coordinate for the current scan line in
WORLD coordinates. It enters another for loop, which reiterates for each pixel
on the line. At each iteration, this loop begins by calculating xf, which is the
equivalent value of x in WORLD coordinates for the pixel being processed. The
function then computes the vector giving the direction of the ray ( line->dir)
from the observer to the WORLD coordinates of the current pixel at the screen.
The function Trace_Ray is run to follow the ray for the rest of its path and return
the colors of the ray. These are stored in character arrays of red, green , and blue.
After the inner for loop has been completed, the function Dump_Line is called to
send all of the data for the colors of one line to the output file. When the outer
for loop is finished, Trace Scene terminates and returns to the main program.

/*
ray . cpp = Functi ons r e l a ted to r a y t r a c i n g

B y Rog e r T . Stevens 2 - 1 2 - 90

*I

#i n c l ude < s t d l i b . h >


#i n c l ude <ma t h . h >
#i n c l ude " rende r . h p p "

i nt l evel :

I*
Trace Scene ( ) Ray t r a c i n g of en t i re scene

*I

v o i d T r a c e_S c e n e ( )

i nt x , y ;
c h a r r e d [ m a x _p i x e l ] , g r e e n [ m a x _p i x e l ] , b l u e [ m a x_p i x e l ] ;

228
T R A C I N G T H E R AY

Vector col or ;
Li ne l i ne ;
fl oat xf . yf ;

for ( y = W O R L O . f i r s t_ s c a n ; y < = W O R L O . l a s t_s c a n ; y++ )

cout << "Tra c i ng l i ne # : " << y << "\n" ;


y f= ( ( f l o a t l ( C E N T E R Y - y ) ) / ( W O R L D . f l e n g t h l ;
for ( x=O ; x<X S I Z E ; x++ )
(
xf=( ( f l oa t ) ( C E N T E RX - x ) ) / ( WORLD . fl engt h*AS P ECT J ;
l i ne . l ac WORLD . obsl oc ;
l i ne . d i r = WORLD . obsd i r ;
l i ne . d i r = l i ne . d i r + WORLD . obsri ght * x f +
WO R L D . o b s u p * y f ;
l evel = O;
T r a c e_ R a y ( & l i n e , & c o l o r , l . O l ;
W O R L D . p r i m a ry_t r a c e d ++ ;
red [ x ] = c o l o r . x ;
g reen [ x ] = c o l o r . y ;
bl ue[x] = col or . z ;

D u m p_ L i n e ( y , r e d , g r e e n , b l u e l ;
}

I*
T r a c e_ R a y ( ) Ray t r a ce s for a l i ne of d i s p l ay

*I

i n t T r a c e_ R a y ( L i n e * l i n e . V e c t o r * c o l o r . f l o a t m u l t i p l i e r )
(
V e c t o r n e w_p o s i t i o n , n e w_d i r e c t i o n , c l o s e _o b j _ l o c . c l o s e_o b j _n o r m ;
f l o a t S h o r t e s t_t i m e . di v i so r ;
O b j e c t * C l o s e s t _o b j e c t ;
c o l o r_d a t a c o l _d a t a ;

*col or = Vector ( ) ;
l e v e l ++ ;
if ( l evel > 48 )
return ( FALS E ) ;

229
F R A C TA L P R O G R A M M I N G AND R AY T R A C I N G W I T H C++

if ( mu l t i p l i e r < WORLD . t h re s h o l d )
r e t u r n ( FA L S E ) :
C l o s e s t _o b j e c t = l n t e r s e c t ( W O R L D . s t a c k , l i n e , & S h o r t e s t _t i m e , F A L S E .
T RU E , NULL ) ;
i f ( C l o s e s t _o b j e c t ! = N U L L )
{
c l o s e_o b j _ l o c = l i n e - > l o c + ( l i n e - > d i r * S h o r t e s t _t i m e ) :
C l o s e s t _o b j e c t - > F i n d N o r m ( & c l o s e_o b j _n o r m , & c l o s e_o b j _ l o c ) :
i f ( ( c l o s e_o b j _n o r m % l i ne - >d i r ) >O )
c l o s e_o b j _ n o r m = - c l o s e_o b j _n o r m ;
F i n d_C o l o r ( C l o s e s t _o b j e c t , C l o s e s t _o b j e c t - > p a t t e r n ,
& c l o s e_o b j _ l o c , & c o l _d a t a ,
C l o s e s t_o b j e c t - > x m u l t , C l o s e s t _o b j e c t - > y m u l t ) ;
A m b i e n t C o l o r ( c o l o r , & c o l _d a t a , & c l o s e_o b j _n o r m ,
& c l o s e_o b j _ l o c ) :
D i f f u s e C o l o r ( c o l o r , & c o l _d a t a , & c l o s e_o b j _n o r m ,
& c l o s e_o b j _ l o c , l i n e ) ;
T r a n s p a r e n t C o l o r ( c o l o r , & c o l _d a t a , & c l o s e_o b j _n o r m ,
& c l o s e_o b j _ l o c , l i n e , m u l t i p l i e r ) ;
R e f l e c t C o l o r ( c o l o r , & c o l _d a t a , & c l o s e_o b j _n o r m ,
& c l o s e_o b j _ l o c , l i n e , m u l t i p l i e r ) ;
D i t h e r ( c o l o r . & c o l _d a t a ) ;

el se
S ky C o l o r ( l i n e , c o l o r ) ;
i f ( co l o r - > x > C N UM II c o l o r - >y > C N U M II col o r - >z > CNUM )

di vi sor ( f l o a t ) Ma x ( c o l o r - > x , c o l o r - >y , c o l o r - > z ) I


( fl oat ) CNUM :
*col or = *col or I d i v i sor ;

r e t u r n ( C l o s e s t _o b j e c t ! = N U L L ) ;

I*
I ntersect ( ) F i n d s f i r s t o b j e c t h i t by r a y

*I

Obj ect * l n t e r s e c t ( O b j e c t * C u r r O b j , L i n e * l i n e . f l o a t * S h o r t e s t_t i m e .


s h o r t s h a d o w_ f l a g , s h o r t i n i t _f l a g , V e c t o r * a t t e n )

230
T R A C I N G T H E R AY

s t a t i c O b j e c t * C l o s e s t_o b j e c t ;
Vector l oc ;
Obj ect * obj ;
s h o r t c o l l i s i on ;
stat i c s hort stop ;
fl oat t ;
obj = C u r rObj ;
i f ( i n i t _f l a g )
{
* S h o r t e s t_t i m e =3 e 3 0 ;
C l o s e s t_o b j e c t = N U L L ;
s t o p= F A L S E ;

whi l e ( o bj ! =N U L L && ! stop )


{
col l i s i on = obj - >Col l i s i onTest ( l i ne , &t ) ;
W O R L D . i n t e r s e c t_t e s t s ++ ;
if ( c o l l i s i o n & & C t > S MA L L ) )
{
i f C o b j - > t y p e == B B O X )

W O R L D . b b o x_ i n t e r s e c t s ++ ;
I n t e r s e c t ( o b j - > c h i l d , l i n e , S h o r t e s t_t i me ,
s h a d o w_f l a g , F A L S E , a t t e n ) ;

el se
{
i f ( o bj - > r emo v e ! = NU L L )
{
l oc = l i ne - > l oc + l i ne - >d i r * t ;
i f C F i n d_C o l o r ( o b j , o b j - > r e m o v e , &l oc , NU L L , 1.0,
1. 0) )
obj =obj - > n extobj ;
conti nue ;

W O R L D . r a y _ i n t e r s e c t s ++ ;
i f ( s h a d o w_ f l a g & & t < l l
{
i f ( ( o b j - > c o l _d a t a - > t r a n s . x <
W O R L D . i n t_t h r e s h o l d ) & &
( o b j - > c o l _d a t a - > t r a n s . y <
W O R L D . i n t_t h r e s h o l d ) & &

231
F R A C TA L P R O G R A M M I N G AND R AY T R A C I N G W I T H C++

C o b j - > c o l _d a t a - > t r a n s . z <


W O R L D . i n t_t h r e s h o l d ) )

C l o s e s t_o b j e c t = o b j ;
ret u r n C obj ) :

el se

i f ( atten ! = NU L L )

*a tten = *atten *
( o b j - > c o l _d a t a - > t r a n s *
o b j - > c o l _d a t a - > t r a n s )
( f l o a t ) ( C NUM * CNUM ) ;

i f ( ( ! s h a d o w_ f l a g ) && C t < * S h o r t e s t_t i m e ) )


{
* S h o r t e s t t i me t;
C l o s e s t _o b j e c t = o b j ;

o b j =o b j - > n e x t o b j ;

r e t u r n C C l o s e s t_o b j e c t ) ;

I*

Amb i e n t C o l o r ( ) Add ambi e n t c o l o r

*I

v o i d Am b i e n t C o l o r C V e c t o r * c o l o r , c o l o r_d a t a * c o l _d a t a , Vector *
n o rm .
Vector * l ac )

*col or * c o l o r + c o l _d a t a - > a m b * ( c o l d a t a - >d i ff I


fl o a t ) C NUM ) ;

232
T R A C I N G T H E R AY

I*

Di ffuseCol or( ) Comp u t e s s p e c u l a r r e f l e c t i o n s a n d col o r


e m i t t e d by o b j e c t

*I

v o i d D i f f u s e C o l o r ( V e c t o r * c o l o r , c o l o r_d a t a * c o l _d a t a , V e c t o r *
n o rm . V e c t o r * l o c , Li ne * ol i ne )

Li ne l i ne ;
Obj ect * C u r rObj ;
Lamp * l a mp ;
fl oat dot , di stance , t i me , tl , t2 ;
Vector refl ect , attenuate ;

l i ne . l ac = *l oc ;
l amp = W O R L D . l a m p s ;
whi l e ( l a m p ! =N U L L )
(
l i n e . d i r = l a mp - > l o c - *l oc ;
a ttenuate = Vector ( l , 1 , 1 ) ;
C u r r O b j = l n t e r s e c t ( WO R L D . s t a c k , & l i n e , & t i me , T RU E ,
T RU E . & a t t e n u a t e ) ;
W O R L D . t o_ l a m p++ ;
i f C C u r r O b j == N U L L )
(
d i s t a n ce = l i ne . d i r % l i n e . d i r ;
l i ne . di r = - l i ne . di r ;
i f C c o l _d a t a - > d i f f . x > O II c o l _d a t a - > d i f f . y > O II
c o l _d a t a - > d i f f . z > O )

t l = * n o rm % l i n e . d i r ;
i f C t l >O l
(
t 2 = l a mp - >d i s t a n ce* t l / sq r t ( d i s t a n ce ) ;
*col or = *col or + ( ( attenuate *
c o l _d a t a - > d i f f ) * t 2 ) ;

i f ( col d a t a - > s refl ect>O l


(

233
F R A C TA L P R O G R A M M I N G AND R AY T R A C I N G W I T H C++

d o t = l i n e . d i r % * n o rm :
re f l e c t = - l i n e . d i r + * n o rm * d o t + * n o rm * d o t :
t l = - ( refl ect % ol i ne - >di r ) :
i f ( tl>0 . 6 )
{
t 2 = p o w ( t l , c o l _d a t a - > s r e f l e c t )
* l amp - >d i s t a n c e / s q r t ( d i s t a n ce ) :
t 2 *= C f l o a t ) c o l _d a t a - > r e f l e c t :
*col or = *col or + a ttenuate * t2 :

l a m p = l a m p - > n e x t_l a m p :

I*
Transpa rentCol o r ( ) T r a c e s r a y t h r o u g h t r a n s p a r e n t me d i um

*I

voi d Transpa rentCol or( Vector * col or , c o l o r_d a t a * c o l _d a t a , V e c t o r *


n o rm . V e c t o r * l a c , Li ne * l i ne . fl oa t i nmul t )

L i n e n ew l i n e :
Vector col l , refract , di stance , d i s p l a c eme n t , attenua t i on :
f l o a t g l a s s d i s t , c u r r e n t_i n d e x , mul ti pl i e r , si del ;
i n t ma x t r a n s ;
s t a t i c V e c t o r o l d_po s i t i o n ;

i f ( ( c o l _d a t a - > t r a n s . x < W O R L D . i n t _t h r e s h o l d ) & &


( c o l _d a t a - > t r a n s . y < W O R L D . i n t_ t h r e s h o l d ) & &
( c o l _d a t a - > t r a n s . z < W O R L D . i n t _t h r e s h o l d ) )
return :
i f C l i ne - >fl ag )

c u r r e n t _ i n d e x = c o l _d a t a - > i n d e x / W O R L D . g l o b i n d e x ;
d i s p l a c e me n t = * l a c - o l d_po s i t i o n ;
g l a s s d i s t = s q r t ( d i s p l a c eme n t % d i s p l a c eme n t ) :

el se
I

234
T R A C I N G T H E R AY

c u r r e n t_i n d e x = W O R L D . g l o b i n d e x / c o l _d a t a - > i n d e x ;
o l d_p o s i t i o n = * l o c ;

newl i ne . l oc = *l oc ;
s i d e l = * n o rm % ( - l i ne - >di r ) ;
ref r a ct = - ( * n o rm * s i de l ) - l i ne - >di r ;
refract = refract * ( 1 - c u r r e n t_i n d e x l ;
newl i ne . d i r = l i ne - >d i r + refract ;
n ew l i n e . d i r = _ newl i ne . d i r ;
m a x t r a n s = M a x ( c o l _d a t a - > t r a n s . x , c o l _d a t a - > t r a n s . y ,
c o l _d a t a - > t r a n s . z ) ;
newl i ne . fl ag = ! C l i ne - >fl ag ) ;
mul t i p l i e r = i nmu l t * C fl oat lmaxt ran s / C fl oat l CNUM ;
T r a c e_R a y C & n e w l i n e , & c o l l , m u l t i p l i e r ) ;
W O R L D . r e f l _ t r a n s ++ ;
*col or = *col or + col l ;
i f C l i ne - >fl ag )
!
a t t e n u a t i o n = c o l _d a t a - > d e n s i t y * ( * c o l o r * g l a s s d i s t ) ;
*col or = *col or - a t t e n u a t i on . mi n ( * col o r ) ;

/*
Re f l e c t C o l o r ( ) Traces ray boun ced off obj ect

*I

v o i d R e f l e c t C o l o r C V e c t o r * c o l o r , c o l o r_d a t a * c o l _d a t a . V e c t o r *
n o rm . V e c t o r * l oc , Li ne * l i ne . fl oa t i nmul t l

Vector col l ;
L i 11 e n e w l i n e ;
fl oat mul t i p l i e r . dot ;
i nt maxmi rror ;

if ( ( c o l _d a t a - > m i r r o r . x < W O R L D . i n t_t h r e s h o l d l & &


( c o l _d a t a - > m i r r o r . y < W O R L D . i n t_ t h r e s h o l d l & &
C c o l _d a t a - > m i r r o r . z < W O R L D . i n t_t h r e s h o l d l l return ;
n ew l i n e . l o c = * l o c ;
d o t = - ( l i n e - > d i r % * n o rm ) ;
n ew l i n e . d i r = l i n e - > d i r + * n o rm * d o t + * n o rm * d o t ;

235
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +

m a x m i r r o r = M a x ( c o l _d a t a - > m i r r o r . x , c o l _d a t a - > m i r r o r . y ,
c o l _d a t a - > m i r r o r . z ) ;
mul t i pl i e r = i nmul t * ( f l o a t ) ma xm i r r o r / C N U M ;
T r a c e_ R a y ( & n e w l i n e , & c o l l , m u l t i p l i e r ) ;
W O R L D . r e f l _t r a n s ++ ;
*col or = *col or + col l * ( c o l _d a t a - > m i r r o r I ( fl oa t ) CNUM ) ;

I*
S ky C o l o r ( ) C o m p u t e s s ky c o l o r

*/

v o i d S ky C o l o r ( L i n e * l i n e . V e c t o r * c o l o r )

fl o a t l ength . hori z , zen i th ;

l en g t h l i ne - >d i r % l i ne - >d i r ;
zen i t h l i n e - >d i r . y * l i n e - >d i r . y I l ength ;
hori z ( l i ne - >d i r . x * l i ne - >d i r . x + l i ne - >di r . z * l i ne - >di r . z ) /
l ength ;
* c o l o r = * c o l o r + W O R L D . s k y c o l o r_z e n i t h * z e n i t h +
W O R L D . s k y c o l o r_ h o r i z * h o r i z ;
D i t h e r ( c o l o r , W O R L D . s k y_d i t h e r ) ;

I*
Di ther( ) Col o r d i theri ng funct i ons

*I

#de f i n e M I N C O L 1 0

voi d Di ther( Vector * col or . fl oat di the r )


!
fl oat r , g , b ;

if ( d i t h e r ==O ) return ;
if ( di ther>O )
!
r= ( ( f l o a t ) r a n d ( ) / 1 6 3 8 3 ) l ;
g=( ( f l oa t ) ra nd ( ) / 1 6383 ) l ;

236
T R A C I N G T H E R AY

b= ( ( f l o a t ) r a n d ( ) / 1 6 3 8 3 ) - l ;
i f C co l o r - >x<M I NCO L )
r=f a b s ( r ) ;
i f C co l o r - >y<M I NCO L )
g=f a b s ( g ) ;
i f C co l o r - > z < M I NCO L )
b=fa b s C b ) ;
* c o l o r= * c o l o r + V e c t o r ( r * d i t h e r , g * d i t h e r , b* d i t h e r ) ;

v o i d D i t h e r ( V e c t o r * c o l o r , c o l o r_d a t a * c o l _d a t a )

fl oat r , g , b ;
i f C c o l _d a t a - > d i t h e r ==O )
return ;
i f C c o l _d a t a - > d i t h e r > O l
{
r= ( ( f l o a t l r a n d C l / 1 6383 ) l ;
g= ( ( f l o a t ) r a n d ( ) / 1 6 3 8 3 ) l ;
b= C C f l o a t ) r a n d ( ) / 1 6 3 8 3 ) l ;
i f C col o r - >x<M I NCO L l
r=f a b s ( r ) ;
if C c o l o r - >y < M I NCO L )
g=f a b s ( g ) ;
if C col o r - >z<M I NCO L )
b= f a b s C b ) ;
* c o l o r = * c o l o r + V e c t o r ( r * c o l _d a t a - > d i t h e r ,
g * c o l _d a t a - > d i t h e r , b * c o l _d a t a - > d i t h e r ) ;

el se
{
r=C C f l oa t l ra n d C l / 1 6383 ) - l ;
i f C C c o l o r - > x+ c o l o r - > y + c o l o r - > z l > C 3 * M I N C O L ) )
r=f a b s ( r ) ;
* c o l o r = * c o l o r + V e c t o r ( r * c o l _d a t a - > d i t h e r ,
r * c o l _d a t a - > d i t h e r ,
r * c o l _d a t a - > d i t h e r ) ;

237
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

/*

D u m p_ L i n e ( ) Sends a l i ne of data to d i s k fi l e

*/

v o i d D u m p_ L i n e ( i n t l i n e n o , c h a r * red , cha r *g reen . cha r *bl ue )


I
fw r i t e ( & l i n e n o , s i z e o f ( i n t ) , l , W O R L D . f i l e p t ) ;
fw r i t e ( r e d , s i z e o f ( c h a r ) , X S I Z E , W O R L D . f i l e p t ) ;
fw r i t e C g r e e n , s i z e o f ( c h a r ) , X S I Z E , W O R L D . f i l e p t ) ;
fw r i t e C b l u e , s i z e o f ( c h a r ) , X S I Z E , W O R L D . f i l e p t ) ;

/*
Fi nd Col o r ( ) F i nds t h e col o r of a poi n t on a n obj ect
surface , return i n g e i t h e r pattern or
d e f a u l t c o l o r i n f o rma t i o n

*I

i n t F i n d _C o l o r ( O b j e c t * o b j . Pattern *pattern , Vector * l oc a t i on ,


c o l o r_d a t a * c_d a t a , f l o a t x_m u l t , f l o a t y_m u l t )

Pattern *patt ;
fl oat x , y , posl , pos2 ;
i n t modx , mody ;
f l o a t r a d i u s_sq , x_ c i r , y_ c i r , xl , x2 , yl , y2 ;
P a t t e r n * l i n e_ s e g m e n t ;
i n t n umbe r = O ;

i f ( p a t t e r n == N U L L )

* c_d a t a = * ( o b j - > c o l _d a t a ) ;
r e t u r n ( FA L S E ) ;

obj - > Pos i t i on ( &pos l , &pos2 , l ocati on ) ;


pos l / = x_m u l t ;
p o s 2 / = y_m u l t ;
modx = ( i n t ) ( po s l I ( pa ttern - >xs i ze ) ) ;
i f ( pos l <O )
m o d x- ;

238
T R A C I N G T H E R AV

mody = ( i n t l ( p o s 2 I ( pa t t e r n - >y s i z e l l ;
if ( pos2<0 l
m o d y- ;
x = pos l - ( ( f l o a t ) modx * p a t t e rn - > x s i z e ) ;
y = pos2 - ( ( f l o a t ) mody * p a t t e r n - >y s i z e ) ;
patt = pattern - >chi l d ;
whi l e ( p a t t ! =N U L L )
{
W O R L D . p a t t e r n _m a t c h e s ++ ;
swi t c h ( pa t t - >type )
{
c a s e R E C TA N G L E :
if ( ( x>patt - > sta rtx ) && ( x< pa tt - endx ) &&
( y > p a t t - > s t a r ty ) & & ( y < p a t t - > e n dy ) )

* c_d a t a = p a t t - > c o l _d a t a ;
r e t u r n ( T RU E l ;

brea k ;
c a s e C I RC L E :
x ci r = x patt - > rad i us ;
y_c i r = y patt - > radi us ;
r a d i u s_ s q x c i r * x c i r + y_c i r * y_c i r ;
i f ( r a d i u s_sq <= ( p a tt - > ra d i us*pa tt - > rad i us ) )
{
* c_d a t a = p a t t - > c o l _d a t a ;
return ( TRUE l ;

brea k ;
c a s e P O L Y GO N :
whi l e ( l i n e_ s e g m e n t - > l i n k ! = NU L L )
{
x l = l i n e_segme n t - > s t a r t x - x ;
x 2 = l i n e_ s e g me n t - > l i n k - > s t a r t x x;
y l = l i n e_segme n t - > s t a r ty - y ;
y 2 = l i n e_s egme n t - > l i n k - > s t a r ty y;
i f ( ( x l <=O ) && ( x 2 < =0 ) )
{
i f ( ( y l �O ) && ( y 2�0 ) )
n umbe r++ ;
el se

239
F R A C TA L P R O G R A M M I N G A N D R A Y T R A C I N G W I T H C + +

if ( y l *y 2 < = 0)
i f C xl - ( y l * ( x2 - xl ) / ( y 2 - y l l l > 0 )
n u m b e r++ ;

l i n e_s e g m e n t = l i n e_ s e g m e n t - > l i n k :

i f ( ( n umbe r % 2 ) == 0)
brea k ;
el se
!
* c _d a t a = p a t t - > c o l _d a t a ;
r e t u r n ( T RU E ) :

pa t t patt - >si bl i ng ;

* c_d a t a = * ( o b j - > c o l _d a t a l :
ret u r n ( FALS E ) :

Figure 1 2-1 . Listing of the ray.cpp File

Tracing a Ray
The function Trace_Ray performs the actual ray-tracing operation for a
single ray. It begins by zeroing the vector color, which will contain the color
information for this ray. Next, the function looks at the parameter multiplier,
w h i c h h a s b e e n p a s s e d to i t , and c o m p are s it w i t h the thre s h o l d
WORLD.threshold.

The multiplier parameter is set to one when the Trace_Ray function is first
entered. It is used to multiply the color parameters. It darkens the colors during
repeated reflections and transmiss ions through a transparent medium. The
parameter decreases with each reflection or refraction, thereby darkening the
colors. When the parameter is reduced below the threshold, any further ray
contributions are unimportant, so the ray-tracing function ceases. Obviously,
this never happens when the Trace _Ray function is called by Trace_Scene.
However, Trace_Ray is also called recursively by some of the functions that are

240
T R A C I N G T H E R AY

subsequently called in the Trace_Ray function. To reduce computing time, these


need to be omitted when the color contribution is negligible. Next, the function
cal l s Intersect , which scans the l i s t of objects and determines where the
intersection with the nearest object occurs. This was described in Chapter 1 1 . If
objects are identified as being intersected by the ray, the function computes the
location of the closest object. We then find the normal for the closest object at
the point of intersection and, if necessary, reverse it so that it is projecting out
from the intersected surface.

The Trace_Ray function then calls the function Find_Color. This function,
described below, determines whether a pattern is superimposed upon the object
surface. If there is, and our intersection occurs at a point that should be the
pattern color rather than the native color of the object, the function changes the
color accordingly. The functions AmbientColor, DiffuseColor, TransparentColor,
and ReflectColor are then called to trace reflected and refracted rays and add in
their color contributions. Finally, we call the function Dither, which dithers the
color information if necessary. If no intersection with an object is found, the
function calls the function SkyColor and colors the pixel with the appropriate
color for the sky. Finally, the function verifies that none of the color components
exceeds the maximum allowable color number. If so, the color information for
that pixel is scaled within the color limits. The function then terminates.

Determ i n i ng the Backg rou nd Co lor


Observe that at the start of the Trace_Ray function, a color vector for the
pixel was initialized to zero. What happens if the ray from the observer to the
pixel on the screen continues on through the scene without intersecting any
objects at a l l ? When this happens , the function SkyColor is called. The
parameters passed to this function are the address of the object of class Line,
which contains the parameters of the ray being traced and the address of the
vector color. Color represents the pixel color, which, up to this point, is zero.

WORLD stores two colors for the background (or sky), one at the horizon
and one at the zenith (directly overhead). The SkyColor function determines

241
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

from these what color to use for the sky-colored pixel. It squares the length of
the ray being traced (from the observer to the screen), then uses this to normalize
the components of the ray direction in the y and x-z plane directions. The color
for the zenith is multiplied by the square of the y component, horizon color is
multiplied by the square of the x-z component, and the result is added to give the
final background color. Try a few examples to satisfy yourself that if you use the
same color for both horizon and zenith, this process will result in that same
color, regardless of the direction of the normalized direction vector.

The function finally calls Dither with the color vector address and the
World.sky_dither value as parameters. Dither begins with three random numbers
between - 1 and + 1 . For each component of the sky color, if the component is
less than a minimum value of 1 0, the random number is made positive. Finally,
each random number is multiplied by the dither parameter and the results are
added to the three color components.

Ambient Color
Suppose we have a collision between the light ray and an object. At the
moment, our color vector is still set to zero. The first thing we do is call the
function AmbientColor. The ambient color is the general light illuminating the
scene; it does not come from any of the light sources. We multiply this light
color by the diffuse color, which is the natural color of the object, and the result
is scaled to the number of permitted color shades (64). The product is added to
the current color vector value of the pixel.

Specu lar Reflections and Color Emitted by an Object


The function D iffuseColor determines the color emitted by an object
intersected by the ray being traced. This color is influenced by inherent color of
the object itself and by the light striking it from various light sources. This
function begins by creating a line whose origin is the point of intersection of the
light ray and object. Next, the function begins a while loop that scans the list of
light sources (lamps). For each light source, the direction of the new line is set
up to point at the light source.

242
T R A C I N G T H E R AY

The vector attenuate is then set to ( 1 , 1 , 1 ) or no attenuation. Next, the


Intersect function determines whether this new line intersects any of the objects
in the scene. If it does, that object blocks any contribution from the light source
under consideration, so no action is necessary. If there is no intervening object,
the function determines the di stance of the new l ine to the light source,
normalizes the line direction vector, and checks to see whether the color vector
of the object is greater than zero for any of its components. If so, the current
object color is multiplied by the attenuate vector and by a factor representing the
diffuse reflection of the light from the light source being checked by the object
under test. This factor is the cosine of the angle between the normal-to-object
surface and direction-of-light (found by taking the dot product of the line
direction vector and the object normal vector) multiplied by lamp->distance and
divided by distance-to-lamp. The lamp - > distance parameter indicates the
distance from the lamp at which the illumination is considered to be 100 percent.
The overall color obtained from this procedure is added to the color vector.

Specular reflection produces highlights on curved surfaces. It is particularly


noticeable when you look at an i l luminated ball and see a spot of bright,
reflected light. Thi s type of reflection i s sometimes called Phong shading
because the model was first proposed by Phong. The function determines the
cosine of the angle between the surface normal of the object and the direction of
a microfacet of the surface, which would result in perfect specular reflection of
the light in the direction of the observer. We propose to raise this cosine to some
power; for values less than 0.6, any power that we would normally use would
cause the contribution to become negligibly small, so we can ignore it and avoid
making any calculations. If the cosine is greater than 0.6, we raise it to the
sreflect power, where sreflect is a Phong coefficient that is input as part of the
object data. This is then multiplied by lamp - > distance and divided by the
distance from the object to the lamp, giving a light intensity coefficient. We
multiply this coefficient by reflect , the reflection factor that was input for the
object. The product is multiplied by attenuate and that product added to the
color vector.

243
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

This procedure for diffuse and specular color reflection repeats for each light
source in the list. When all light sources are exhausted, the loop terminates and
the function ends.

Traci ng a Ray through a Transparent Med i u m


The function TransparentColor traces a ray through a transparent o r semi­
transparent medium, shifting the ray angle as needed at the junction of surfaces
and attenuating it in accordance with medium characteristics. The function
begins by testing the col_data-> trans vector to see if all components are below a
preset threshold. If they are, the light ray extinguishes. No further processing is
needed, and the function returns to the caller. Otherwise, the function continues
by checking line- >flag , which indicates whether the light ray is currently inside
or outside a transparent object. If it is inside the object, we determine a new
index of refraction and compute glassdist , the distance travelled within the glass.
Otherwise, we c ompute the index of refraction outside the obj ect and set
old_yosition to the current line position.

The function then creates a new line, with its beginning at the point of
intersection. The angle of refraction determines the direction of the line as it
c o n t i n u e s from t h e p o i n t of i n t e rs e c t i on . B a s e d on the transparency
characteristics of the trans vector of the object, a multiplier is computed. The
flag for this new line is the opposite of the current flag. In other words, if the
flag indicates that we are outside a transparent object, we are inside after the
intersection, and vice versa. Trace_Ray is called recursively to trace the new ray.
The returned color information is added to the color vector. Finally, if we have
been travelling inside the transparent object, a new attenuation vector is
calculated as the product of the distance travelled within the transparent object
and the density vector, which is part of the object information.

Reflections
The function ReflectColor determines the reflections on a mirrored surface
and begins by determining whether any of the coefficients of the object 's mirror
vector are above the preset threshold. If none are, there is no reflection and the

244
T R A C I N G T H E R AY

function returns without further action. If there is some reflection, a new line is
set up with its origin at the point of intersection. We then calculate the direction
at which the ray we are tracing reflects off the surface. A multiplier is computed
based upon the maximum mirror coeffic ient of the object. The function
Trace_Ray then recursively traces this new ray. The result, multiplied by the
mirror vector, is added to the color vector.

Sendi n g a Line to the Data Fi le


During the tracing of a scene, one full line of data is accumulated in the
color arrays. When the line is complete, the function Dump_Line is called. This
function first writes the line number out to the data file and then writes a full line
of red data, a full line of green data, and a full line of blue data.

Pattern Effects on Color


The function Find_Color determines whether the application of a pattern
affects the inherent color of an object. It begins by checking if the pattern
address passed to it is a NULL (indicating no pattern) or a legitimate address. If
a NULL is found, the color data to be used by the calling program is set to the
object 's color data, and FALSE is returned by the function to indicate that no
pattern information was used. Otherwise, the Position function for the particular
object is called, returning position data on the object intersection point. This
data i s scaled by the x_m u lt and y_mult parameters to determine x and y
coordinate positions on a pattern. The function then scans the pattern elements,
checks for the type of pattern , and performs the necessary computations to
determine whether the coordinates fall upon a pattern area. If so, the color data
to be used by the calling program is set to the pattern color data and a TRUE is
returned; if not, the color data is set to the object's color data and a FALSE is
returned.

245
CHAPTER 1 3

Putting it All Together


With the Make Capability

We now have all of the files necessary for ray tracing. (An additional file for
fractals is in Chapter 1 5 and is included in the make files discussed in this
chapter, but is not necessary for ordinary scene rendering.) Tying these files
together could be a complicated job but is simplified by u s ing the make
capability that is available in many languages including most versions of C, and
in Zortech C++ and Turbo C++. There is, however, a difference between them.

The advantage of the make capability is that it tracks the date and time when
each file was created. (You need to make sure your system clock is working and
is set to the correct time.) When you use make, the program automatically checks
each object file that you link together to make up the finished program to assure
that it is the latest version. If so, it is linked without recompiling. If you have
performed editing since an object file was last generated, it will be recompiled.
Thus, only the minimum amount of recompiling is necessary. You don 't need to
recompile everything to be safe. If you really want to recompile a file, you first
type :

t o u c h f i l e n a me

where filename is the name of the file you 're interested in recompiling, and a
flag is set that forces recompilation of this file when you next run make. With
our ray-tracing program, render.hpp is a header file associated with every other
file, so if you use touch on it, every file will be recompiled when make is run.

247
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

There are two ways to run make. The first method applies if you intend to
use make on only one set of program data. You may then store all of the data
required by the make facility in a file called makefile, then invoke the capability
by typing :

ma ke

The program automatical ly searches out the makefile and uses the data to
perform its functions. Alternately, if you have several programs that require the
m a k e c a p ab i l i t y , y o u c an g i v e the data fi l e a d i ffe rent n a m e , s u c h as
zraymake.mak. The make capability is then invoked by typing:

ma ke - fz r ayma ke . ma k

where the name following the -f is that of the file where your make data is stored.

Creating the Ray-Tracing Program with Zortech C++


All of the programs in this book were written and debugged using Zortech
C++, version 2.06. They should work well with this compiler. Earlier versions
of Zortech C++ have a bug in the make capability that prevents this program
from compiling. Figure 1 3- 1 is the makefile for use with Zortech C++.

The first line of the file begins by specifying the name of the executable file
to be created, followed by the name of each object file to make up the program.
This data must not exceed 1 27 characters because of DOS limitations. Then
there 's the statement to define l inking of the program . It must be indented;
otherwise, make may think it is part of the previous data. It too is limited to 1 27
characters and begins by blink followed by a space, followed by the names of all
the object files to be linked by + signs. At the end of the line is the option lnoi,
which tells the linker to be case-sensitive. Each object file created by the make
capability is followed by two lines of code. At the beginning of the first line for
each object file is the name of the object file followed by a colon. The .c or .cpp
file is compiled to produce the object file followed by the names of all other
source files. The second line begins with ztc, invoking the compiler, followed by

248
P U TT I N G I T A L L TOG E T H E R W I T H T H E M A K E C A PA B I L I T Y

any desired options and the name of the source file to be compiled.

r e n d e r . exe : r e n d e r . obj vma t h . obj i n p u t . obj obj e c t s . o bj


f r a c t a l . obj ray . obj

b l i n k r e n d e r+ v m a t h + i n p u t + f r a c t a l + o b j e c t s + r a y / n o i

rende r . obj : rende r . cpp render . hpp


ztc - w - -o - c - m l - f rend e r . c pp

vm a t h . obj : vma t h . cpp rende r . hpp


ztc -w- -o -c - m l - f vma t h . cpp

i n put . obj : i n put . cpp rende r . hpp


ztc -w- -o -c - ml - f i nput . cpp

fracta l . obj : f ra c t a l . cpp rende r . hpp


ztcppl fracta l - w - - ml - f
ztc2b fracta l

obj ects . obj : obj ects . cpp render . hpp


ztc - w - - c -ml - f obj ects . cpp

ray . obj : ray . cpp render . hpp


ztc -w- -c -ml - f ray . cpp
Figu re 1 3-1 . Listing of Zortech C++ Make File

Let 's take a look at the options used in compiling programs. The -c option is
needed for each compile statement, since it tells the compiler to compile only
and not link. This is necessary because we will do the linking with a separate
link command l ine once a l l of the neces s ary updated object modu les are
identified by the make facility. The -! option tells the compiler to generate in­
line instructions for the math coprocessor. If you have a math coprocessor, you
need this option for every compile; if not, it should not be included.

The -ml option indicates that the large memory model should be used. This
is necessary for all modules for this program because it is large and complex and

249
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

uses a lot of memory for data storage. The -o option tells the compiler to use the
global optimizer to optimize the code. Ideally, this should be used for every
m o d u l e to o b t a i n o p t i m u m c ode fo r the fi n a l program . H o w e v er, the
complexities of some files caused the global optimizer to become confused and,
for example, reject a simple if statement as illegal. If you use the optimizer
option only for those files shown, you ' l l be safe. You may want to try it on
additional files one at a time, but you do so at your own peril.

Finally, the -w- option turns off warnings from the compiler. S ince the
compiler tends to generate a warning every time it encounters an external
variable, there can be quite a stack of warning messages, most of them useless.
If you get into trouble trying to compile, you may want to remove this option
and display the warning messages for your review.

Look at the instructions for compiling the fractal file. Although this file is
not too big, it has some complicated multiple recursion in it. As a result, if you
use the normal Zortech ztc compile command, you are apt to get an out of
memory message. Zortech has a more complex but slower compiler that must be
invoked in two steps, as shown. This compiler is able to handle the fractal
module without difficulty.

Once you run the make facility, you should have a fully compiled program
that will perform whatever ray tracing you desire.

Ru n n i ng Prog rams with Tu rbo C++


The Newton 's method programs have been compiled and run with Turbo
C++. This is the first version of Turbo C++ released by Borland. The ray
tracing program has also been compiled with Turbo C++ and the wsphere.ray
data file successfully traced. The other data files were not checked with Turbo
C++.

There are some differences that have to be considered for Turbo C++. First,
where Zortech C++ uses the include file stream .hpp, Turbo C++ uses the file

250
P UTTI NG I T A L L T O G E T H E R W I T H T H E M A K E C A PA B I L I T Y

iostream .h, so you will have to go through the files and change this statement
wherever it occurs-hopefully, once, in the render.hpp file. If there were a few
other places I missed, you will find them quickly enough when you try to
compile.) Figure 1 3-2 lists the makefile for Turbo C++. First, look at the linking
command, and note that while the Zortech command line linker automatically
finds any library files needed and links them in, the Turbo C++ command line
linker does not. Instead, you have to specify several of these library files on the
linker command line. The Turbo C++ command line linker doesn 't recognize
any instructions for the location of include or library files in the integrated
environment, so you have to specify the full path for each library file if it is not
in the same directory with the rest of your program. When you installed Turbo
C++, your linker and compiler were put in the sub-directory bin , whereas the
library files were put into the subdirectory lib. Unfortunately, if you include a
full path command for each library file, such as:

c : \tcpl us\l i b\cl

you are likely to find that when you attempt to link, you get an error message
like :

c omma n d l i ne too l ong

because you have exceeded a DOS limitation of 1 27 characters in a single


command line. You can get around this limitation by using a response file to
contain your extra data as described in the Turbo C++ manual, but it's just as
easy to copy the needed library files to your bin directory. That is why there are
no paths given for the library files in the make file.

Note that the compile statements use a compiler tee instead of the zte
compiler used by Zortech. All of the compile options used are the same, except
for the additional ones Y and Yo used by Turbo C++. Now we get to the good
and bad aspects of Turbo C++. The Zortech C++ compiler is apparently much
more e fficient than the Turbo C++ compiler, since the ray tracing program
compiles to a little over l OOk bytes with Zortech while Turbo C++ requires 1 22k

251
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

bytes. Unfortunately, we need all that extra memory consumed by Turbo C++
for our data, so the program runs out of memory. That's the bad side. The good
side is that Turbo C++ has a sophisticated overlay capability that reduces the
amount of memory required by the program at any given time. Note the use of
lo in the link command which separates the program modules that remain
resident at all times from those that may be overlaid. In addition, in the compile
section, -Y is used with each module that is to remain resident and -Yo with each
module that may be overlaid. Once the program is compiled and linked with
these overlay options specified, it is capable of tracing the sample pictures
without difficulty.

rende r . exe : rende r . obj vma t h . obj i n put . obj obj ects . obj
f r a c ta l . obj ray . obj

tl i n k cOl render vma t h o i nout obj ects fracta l


/
r ay , , , ove r l ay emu ma t h l cl

render . obj : rende r . cpp rende r . hpp


tee -c -Y -ml -f rende r . cpp

vma t h . obj : vma t h . cpp rende r . hpp


tee - c -Y - ml -f vma t h . c pp

i n p ut . obj : i n put . cpp rende r . hpp


tee -c -Yo -ml - f i nput . cpp

fracta l . obj : fract a l . cpp rende r . hpp


tee - c - Yo - ml - f fra cta l . cpp

obj ects . obj : obj ects . cpp rende r . hpp


tee -w- -Yo -c -ml - f obj ects . cpp

ray . obj : ray . cpp rende r . hpp


tee - c -Yo -ml - f ray . cpp

Figu re 1 3-2. Listing of Turbo C++ Make File

252
P U TTI N G I T A L L TO G E T H E R W I T H T H E M A K E C A PA B I L I T Y

Ray- Traci ng Pictu res


Pictures generated by the ray-tracing program are shown in Plates 4 to 1 6 in
the color section. The input data used to specify these pictures is l isted in
Appendix A. You should be able to process any one of these pictures and create
the same picture, or modify the data to create a new picture according to your
own design.

253
CHAPTER 1 4

Displaying and Saving


Screens

The result of using the ray-tracing program is a disk file which contains a lot
more detailed color information than we can ever use with the VGA monitor on
a personal computer. Because of the large amount of information in the file, it
takes a lot of space; in fact, we can only get one of these files onto a standard
360k floppy disk. This chapter looks at how we convert from the file generated
by the ray tracer to the best possible VGA display, how that display is stored in a
reasonably sized disk file, and how to restore that disk file to a screen display. If
you ' re lucky enough to have a color printer, you m ay want to make some
printouts of these displays. There is a program commercially available called
Pizazz Plus, which can capture any display screens you will generate and print to
many different color printers with reasonably good quality.

Creating a VGA Color Display


The file generated by the ray tracer provides three bytes of data for each
p i x e l of the c o l or d i s p l ay. Each byte contains a number from 0 to 63
representing a shade of color. One byte gives the shade of red, another the shade
of green, and the third the shade of blue. Together, each set of bytes can
represent 262, 1 44 different shades of color. This is adequate to color any scene
with more precision than the human eye can discern. Unfortunately, the VGA
display card, in the mode which displays the largest number of colors, can only
display 256 different colors at any one time. It might seem hopeless to attempt
to create a realistic scene from our original data file with such a limited number
of available colors. Actually, the situation is not as bad as it appears. In the first
place, most scenes don't even come close to requiring the full range of colors.
The program described below tallies the number of color shades in a scene. The

255
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

number of colors for scenes in this book ranges from 350 to 3500, even when
realistic shading, reflections, and shadows are included. This is a much greater
number than the 256 handled by the VGA, but fortunately many of these colors
are used in shading a surface and are thus very close to each other, so that the
number of colors can be reduced to 256 without major degradation of the picture.
Of course, we could have a prettier, more realistic picture if we had more colors
to work with, but by using a few tricks we can make the VGA display look
pretty good.

The program for this operation is listed in Figure 1 4- l . We first need to


halve the number of color shades from 0 to 63 to 0 to 3 1 . Since we can only
display 256 out of a possible 262, 1 44 colors, it doesn't matter if we cut the
number of possible values of each color in half. Fortunately, this results in a
total maximum number of color shades of 3 2 ,768, which i s a size we can
contain within an array in a C program. Every set of three bytes represents a
color in the file. Each time we encounter a color, we 'II increment the member of
the array representing this color so that when we are finished the array contains
the total number of occurrences for each of the 32,768 shades of color. We sort
these according to the number of occurrences and assign the 256 VGA colors to
the 256 shades that occur most often. This is all very well , but what do we do
about the colors not in the first 256 in frequency of occurrence? It is instructive
to look at the number of occurrences for these remaining colors. If you want to
do this for several typical files, you can modify the program of Figure 1 4- 1 so
that after it completes the sort, it prints out the values in the array instead of
generating the color picture. You ' ll find that many of the colors below the first
256 occur only once, so that if we get them wrong only a single pixel is affected.
Even the ones that occur most frequently do so 20 or 30 times, which is not a
very big section of a picture. Nevertheless, we want to do the best we can, so we
compare each of these colors with the 256 selected for display and assign each
color to whichever of the 256 is closest to the actual color.

256
D I S P L AY I N G A N D S AV I N G S C R E E N S

/*
col p roc P rog ram to P roce s s C o l o r D a t a f o r VGA
*/

#i n c l ude <dos . h >


#i n c l ude < s t d i o . h >

v o i d g o t o xy ( i n t x , i nt y ) ;
v o i d pl ot ( i nt x , i nt y , i nt col or ) ;
v o i d s etMode ( i n t mode ) :
v o i d s e t V GAp a l e t t e ( u n s i g n e d c h a r * b u f f e r ) :
v o i d s o rt ( u n s i gned i n t s t a rt . un s i gned i n t end ) :

ty p e d e f s t r u c t
{
c h a r Red :
cha r G reen ;
c h a r B l ue :

RGB ;

e n um { r e d =O , g r n = l . b l u=2 };

u n i on REGS reg ;
s t ruct S REGS i n reg :

#d e f i n e MA X X R E S 800 s e t max h o r i z coord expected *


/* /

u n s i g n e d i n t C o l _A r r a y [ 2 5 6 ] [ 2 ] ;
u n s i g n e d c h a r P a l _A r r a y [ 2 5 6 J [ 3 J :
RGB Co l o r , C ol o r 2 ;

i n t i , k , x res . y re s . l a s t_c o l o r , s c a n l i n e , r l , r 2 , g l , g 2 , b l , b 2 :
u n s i g n e d c h a r r [ MA X X R E S J , g [ MA X X R E S ] , b [ MA X X R E S J ;
F I L E * f i l e_ l ;
u n s i g n e d c h a r f a r * c o l o r_ h i s t ;
l o n g i n t c o l o r_n o ;
unsi gned i nt j :
u n s i g n e d c h a r f re q u e n cy [ 8 1 9 2 J ;
un s i gned i nt hues [8192 J :

v o i d ma i n ( a rgc , a rg v )

257
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +

i nt a rgc :
char *argv [ J :

i nt i ndex :
i nt rgbi ndex :
i nt yl :
u n s i g n e d i n t d l , t em p_d ;
unsi gned cha r d2 :

s etMode ( 3 ) :
i f ( a rgc ! = 2 )
{
p r i n t f ( " V GA C o l o r P r o c e s s o r by R o g e r S t e v e n s \ n " ) ;
p r i n t f ( " U s a g e : % s f i l e n a m e . RAW \ n " , a r g v [ O J ) :
exi t ( l ) ;

i f ( ( f i l e_ l = f o p e n ( a r g v [ l ] , " r b " ) ) == N U L L )
{
p r i n t f ( "Cou l dn ' t open fi l e %s \ n " , a rg v [ l ] ) :
exi t ( l ) ;

c o l o r_h i s t = f a r m a l l o c ( 3 2 7 6 8 ) :
f o r ( i =O : i < 2 5 6 : i ++ )
{
P a l _A r r a y [ i J [ r e d J O;
P a l _A r r a y [ i J [ g r n J 0:
P a l _A r r a y [ i J [ b l u J 0:
)
f o r ( j =O : j < 3 2 7 6 8 ; j ++ )
c o l o r_h i s t [ j J = 0 :
xres = y res = 0 :
f r e a d ( & x r e s . s i z e o f ( i n t ) . 1 . f i l e_l ) :
f r e a d ( &y r e s , s i z e o f ( i n t ) , l , f i l e_l ) :
p r i n t f ( " V GA c o l o r p o s t - p r o c e s s o r by Ro g e r S t e v e n s \ n " ) :
p r i n t f ( " I m a g e f i l e r e s o l u t i o n i s : % d by % d \ n " , x r e s , y r e s ) :
yl = 0 :
pri ntf( "Col l ecti ng col or data ]") :
w h i l e ( ! f e o f ( f i l e_l ) )
{

258
D I S P L AY I N G A N D S AV I N G S C R E E N S

f r e a d ( & s c a n l i n e , s i z e o f ( i n t ) , l , f i l e_l ) :
i f ( s c a n l i n e >= y r e s )
{
p r i n t f ( " F a u l ty data fi l e . \ n " ) :
ex i t ( l ) ;

g o t o xy ( 2 4 , 3 ) :
p r i n t f ( "%d " , scanl i ne ) ;
f r e a d ( & r [ O J , s i z e o f ( c h a r ) , x r e s . f i l e_l ) ;
f r e a d ( & g [ O J . s i z e o f ( c h a r ) , x r e s , f i l e_l ) ;
f r e a d ( & b [ O J . s i z e o f ( c h a r ) , x r e s , f i l e_l ) ;
f o r ( i n d e x=O ; i n d e x < x r e s ; i n d e x++ )
{
C o l o r . Re d ( r [ i ndexJ & Ox3e ) ;
Col or . Green ( g [ i ndex J & Ox3 e ) ;
Col or . Bl ue ( b [ i ndex ] & Ox3e ) ;
c o l o r_n o = ( C o l o r . R e d > > 1 ) I ( C o l o r . G r e e n
<< 4 ) I ( Col o r . Bl ue << 9 ) ;
i f ( c o l o r_h i s t [ c o l o r_n o ] < 2 5 5 )
c o l o r_h i s t [ c o l o r_n o ] ++ ;

y l += l ;

l a st col or = - 1 ;
f o r ( j =O ; j < 3 2 7 6 8 ; j ++ )
{
i f ( c o l o r_h i s t [ j ] > 0 )
{
l a s t_c o l o r++ ;
h u e s [ l a s t_c o l o r ] j;
f r e q u e n cy [ l a s t_c o l o r ] c o l o r_h i s t [ j ] :

p r i n t f ( " \ n T h e r e a r e % d c o l o r s . " , l a s t_c o l o r ) ;


pri n t f ( " \ n Sta rti ng s o rt . " ) ;
s o r t ( O , l a s t_c o l o r ) :
p r i n t f ( " \ n S o r t c om p l e t e d . " ) ;
p r i n t f ( " \ n M o d i fy i n g e x t r a c o l o r s ]") ;
f o r ( i =O : i < 2 5 6 ; i ++ )
f r e q u e n cy [ i J = i :
f o r ( i =2 5 6 : i < = l a s t_c o l o r : i ++ )
{

259
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

g o t oxy ( 2 5 . 7 ) ;
pri ntf( "%5d" . i ) ;
dl = 32768 ;
f o r ( j =O ; j < 2 5 6 ; j ++ )
{
C o l o r . Red = ( h ue s [ i ] < < 1 ) & Ox3 E ;
Col o r . Green = ( h ue s [ i ] >> 4 ) & Ox3 E ;
C o l o r . B l ue = ( h ue s [ i J >> 9 ) & Ox3 E ;
C o l o r 2 . Red = ( h u e s [ j ] < < 1 ) & Ox3 E ;
C o l o r 2 . Green = ( h ues [ j ] >> 4 ) & Ox3 E ;
Col o r 2 . B l ue = ( h ues [ j ] >> 9 ) & Ox3 E ;
t e m p_d = ( C o l o r . R e d - C o l o r 2 . R e d ) * ( C o l o r . Re d -
C o l o r 2 . Re d ) + ( C o l o r . G r e e n -
Col or2 . Green ) * ( Col o r . Green -
Col o r 2 . G reen ) +
( Co l o r . B l ue - C o l o r2 . B l u e ) * ( Co l o r . B l ue -
Col or2 . Bl ue ) ;
i f ( t em p_d < d l )
{
dl t e m p_d ;
d2 j;

f r e q u e n cy [ i ] = d 2 ;

f o r ( j =O ; j < 2 5 6 ; j ++ )
{
C o l o r . Red = ( h u e s [ j ] < < 1 ) & Ox3 E ;
C o l o r . G reen = ( h ue s [ j ] >> 4 ) & Ox3 E ;
C o l o r . B l ue = ( h ues [ j ] >> 9 ) & Ox3 E ;
P a l _A r r a y [ j ] [ O J C o l o r . Red ;
P a l _A r r a y [ j ] [ l ] Col o r . G reen ;
P a l _A r r a y [ j ] [ 2 ] Col or . Bl ue ;

setMode ( Ox l 3 ) ;
s e t V G A p a l e t t e ( & P a l _A r r a y [ O J [ O J ) ;
f o r ( j =O ; j < 3 2 7 6 8 ; j ++ )
c o l o r_h i s t [ j ] = O ;
f o r ( j =O ; j < = l a s t_c o l o r ; j ++ )
c o l o r_h i s t [ h u e s [ j J J = f r e q u e n cy [ j J ;
r e w i n d ( f i l e_ l ) ;
yl = O ;

260
D I S P L AY I N G A N D S AV I N G S C R E E N S

f r e a d ( & x r e s . s i z e o f ( i n t ) , l , f i l e_l ) :
f r e a d ( &y r e s , s i z e o f ( i n t ) , l , f i l e_l ) :
w h i l e ( ! f e o f ( f i l e_l ) )
{
f r e a d ( & s c a n l i n e , s i z e o f ( i n t ) , l , f i l e_l ) :
i f ( s c a n l i n e >= y r e s )
{
p r i n t f ( " F a u l ty d a t a f i l e . \ n " ) :
ex i t ( l ) ;

f r e a d ( & r [ O J , s i z e o f ( c h a r ) , x r e s , f i l e_l ) :
f r e a d ( & g [ O J , s i z e o f ( c h a r ) , x r e s , f i l e_l ) :
f r e a d ( & b [ O J , s i z e o f ( c h a r ) , x r e s . f i l e_l ) ;
f o r ( i n d e x=O : i n d e x < x r e s : i n d e x++ )
{
C o l o r . Re d ( r [ i ndexJ & Ox3e ) :
Col o r . G reen ( g [ i ndex ] & Ox3e ) ;
Col or . Bl ue ( b [ i ndex ] & Ox3e ) :
c o l o r_n o = ( C o l o r . Re d > > 1 ) I ( C o l o r . G r e e n
<< 4 ) I ( Col o r . Bl ue << 9 ) :
p l o t ( i n d e x , y l , c o l o r_h i s t [ c o l o r_n o J ) ;

y l += 1 :

getc h ( ) ;
setMode ( 3 ) :
f c l o s e ( f i l e_l ) ;

/*
setMode ( ) Sets V i deo Mode
I*

v o i d s etMode ( i n t mode )
{
reg . h . a h 0:=

reg . h . a l = mode :
i nt86 ( Ox l O , & reg , & reg ) ;

261
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

*/
pl ot ( ) F u n c t i o n t o p l o t p o i n t t o V GA 2 5 6 C o l o r S c r e e n

*/

voi d pl ot ( i n t x , i nt y , i nt col o r )
(
uns i gned i nt offset ;
c h a r fa r * a d d r e s s ;
offset = 320 * y + x ;
a d d r e s s = ( c h a r fa r * ) ( OxAOOOOOOOL + offset ) ;
*address = col or ;

/*
setVGApa l ette ( ) Funct i on to set a l l 256 col o r reg i s t e r s

*/

v o i d s e tVGApa l ette ( u n s i gned c h a r *buffe r )


(
reg . x . a x = Ox101 2 ;
seg read ( & i n reg ) ;
i n reg . e s i n reg . d s ;
reg . x . bx 0;
reg . x . cx 256 ;
reg . x . dx ( i n t ) & b u f fe r [ O J ;
i n t86x ( Ox l 0 , & reg , & reg , & i n reg ) ;

/*
sort ( ) Q u i c k s o r t t o s o r t c o l o r s by f r e q u e n cy

*/

voi d sort ( un s i gned i nt sta rt , u n s i gned i nt end )


(
u n s i gned i n t pi v ot , temp2 ;
u n s i g n ed c h a r temp ;

i f ( st a r t < ( end - 1 ) )
(

262
D I S P L AY I N G A N D S AV I N G S C R E E N S

i = sta rt ;
j = end ;
pi vot ( f r e q u e n cy [ i ] + f r e q u e n cy [ j ] +
f r e q u e n cy [ ( i +j ) / 2 ] ) / 3 ;
do
{
w h i l e ( f r e q u e n cy [ i ] > p i v o t )
i ++ ;
w h i l e ( f r e q u e n cy [ j ] < p i v o t )
j-;
if (i < j)
{
t e m p = f r eq u e n cy [ i ] ;
f r e q u e n cy [ i ] = f r e q u e n cy [ j ] ;
f r e q u e n cy [ j ] = t e m p ;
temp2 = hues [ i ] ;
h u e s [ i ++ J = h u e s [ j ] ;
h u e s [ j -J = t e m p 2 ;

wh i l e ( i < j ) ;
i f ( j < end )
{
s o rt ( sta rt , j ) ;
sort ( j+l , end ) ;

i f ( f r e q u e n cy [ e n d J > f r e q u e n cy [ s t a r t J )
{
t e m p = f r e q u e n cy [ s t a r t ] ;
f r e q u e n cy [ s t a r t ] = f r e q u e n cy [ e n d ] ;
f r e q u e n cy [ e n d ] = temp ;
temp2 = hues [ s ta rt J ;
h ues [ s t a rt ] = hues [ end J ;
h u e s [ e n d J = t em p 2 ;
)

v o i d g o t o xy ( i n t x , i n t y )
{
reg . h . a h = 2 ;
reg . h . bh = O ;
reg . h . d h = y - 1 ;

263
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +

reg . h . dl = x-1 :
i n t86 ( 0x l 0 , & reg , & reg ) ;

Figure 1 4-1 . Program to Display t\<o�-"-tracing Data

Now, let's look at the program in detail . First, I should point out that to
make the program independent of graphics routines that differ from one version
of C to another, I have included functions that perform the graphics tasks needed
to create the display. There are three and they are all fairly simple.

The function setMode makes use of the ROM BIOS video services to set the
display mode . The function properly sets up the register contents and then
generates the interrupt that calls the proper ROM BIOS service. We are really
only interested in two display modes, mode 3 which is the normal text mode, and
mode 1 9 ( 1 3H) which is the VGA graphics mode.

The second function is plot, which plots a pixel at the appropriate point on
the display. The VGA memory board contains memory for four color planes. In
many of the modes, color is determined by sending a single bit to the same
address in each of the four memory planes. This requires some complicated
manipulation of registers, since the memory planes cannot be addressed directly.
Fortunately for mode 1 9, a full byte is used to describe the color of each pixel
and each byte is at an adjacent memory address so that all we have to do is
compute the address at which the pixel resides in memory and send the byte to it.
(Actually, inside the VGA card, all sorts of funny things go on, with the bytes
being rotated through the four memory planes so that any one memory plane
only stores every fourth byte with the intervening memory locations being
empty. This is totally invisible to us. From the outside world, it looks as if we
were simply storing data in an ordinary memory array.)

The third function is setVGApalette. The VGA has 256 color registers that
store the color shades to be used for the display. The ROM BIOS video service
that is used in this function takes data from a buffer and stores it in all of these

264
D I S P L AY I N G A N D S AV I N G S C R E E N S

color registers in a single operation. To do this, we first set up the a register to


access the appropriate video service. We then read in the current segment where
the buffer i s and assign it to register es. We put 0 in register bx and 256 in
register ex to indicate the starting register number and the number of registers to
be filled with data. We put the buffer address into register dx. Then we execute
the interrupt to perform the operation.

The final function used by this program is sort. This is a standard Quicksort
algorithm. Since it is described in many computer books including my book,
Graphics Programming in C, I won 't go into any detail. Suffice to say that it
sorts the contents of the array in which the frequency of occurrence of each color
is accumulated. It puts the indexes of this array (which represent the different
shades of color) into a new array in the order of the number of occurrences,
beginning with the most frequently occurring color.

The program starts by checking whether it was called with a file name
specified. If not, a message is printed out (with the display in text mode), which
indicates that a file name must be included to run the program. The program
then exits. If a file name was specified, an attempt is made to open the specified
file. If the file cannot be opened, the program prints out a message to this effect
and then exits. If the file is successfully opened, the program next allocates
memory for the array color_hist , which will be used to store the occurrences of
colors. The array of information for the color registers, Pal_Array , and the
color_hist array are then initialized to all zeroes. The first four bytes of the file,
which are the integer values for xres , the number of display pixels in the x
direction, and yres, the number of display pixels in the y direction, are then read.
The heading and the resolution data are then displayed on the screen. Next, the
program displays the line "Collecting color data [ ]" with a space for the line
number. The program then starts a while loop which will continue until the end
of the file is encountered.

The loop begins by reading the number of the scan line from the file. If it is
greater than the maximum line that was defined, there i s an error and the

265
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

program displays, "Faulty data file" and exits. If the scan line is acceptable, it is
displayed at the proper place on the screen. Next, the program reads first a line
of red data, then a line of green data, and then a line of blue data from the file.
These are stored in r, g, and b arrays. A for loop takes the red, green, and blue
v a l u e s for e a c h p i x e l ( n o t i n c l u d i n g the l e a s t s i g n i fi c an t b i t , thereby
accomplishing the division by two) then shifts and combines them into a unique
color number. This value is used as an index for the color_hist array and the
contents of that address is incremented.

Once the loop is complete, the program runs another for loop which scans
the color_hist array and increments a variable, last_color, each time a color
occurs at least once. The index for this color is placed in an array hues and the
frequency with which it occurs in an array frequency. Each of these arrays is of
size 8 1 92, assuming that there will be no more than 8 1 92 different colors in any
particular picture. If there are more than 8 1 92 colors, the program will probably
bomb. The next thing that happens is that a line is displayed telling how many
colors were in the picture, so if there are too many colors, you may get to see this
before anything goes haywire. Assuming there weren 't too many colors, the
program displays "Starting sort," then runs the sort function, and then displays
"Sort completed."

The frequency of occurrence data is no longer needed; instead we will fill


the frequency array with a color number from 0 to 255 for each color. We begin
by assigning the first 256 colors the numbers 0 to 2 5 5 . Then the program
displays "Modifying extra colors[ ]" with a space for the color number being
processed. The program enters a for loop which it iterates for each of the
additional colors from 256 to the last_color number. Within this loop, first the
number of the color being worked on is displayed. Then another for loop is
entered which is reiterated for each of the 256 initial colors. Within this loop,
each color index for the current color being processed and the current one of the
256 initial colors is decomposed into the original red, green, and blue color data.
The sum of the squares of the difference between red, green, and blue values is
then computed. At each iteration, the smallest sum of squares is saved along

266
D I S P L AY I N G A N D S AV I N G S C R E E N S

with its color number. When the current color has been checked against all 256
initial colors, it is assigned the number of the color for which the sum of the
squares of the differences was smallest.

When the two loops are complete, all of the colors beyond the first 256 have
been assigned color numbers that correspond to the color for which the sum of
the squares of the differences was smallest. The graphics mode is set for the 256
color display and setVGApalette is run to set the VGA color values for the first
256 colors. Then we refill the color_ hist array with the number of the color
associated with each index value or with a zero if that index has no color and we
rewind the file. The file is then read all over again, beginning by reading the
xres and yres values and then entering a while loop that reiterates until the end of
file is encountered. For each iteration, the scan line number is read first followed
by the red, green, and blue data for a complete line. Then a for loop is run for
each pixel of the line. The color data for that pixel is combined into an index
number in the same manner as was done above. The color number for that index
is taken from the color_hist array and the pixel is plotted in that color at the
appropriate point on the screen. When both loops are complete, the full picture
is being displayed. The program waits for a character to be entered at the
keyboard. When this occurs, the screen is reset to the text mode, the file is
closed, and the program terminates.

Using Hig h - Resol ution VGA Cards


Many VGA cards currently being sold have high-resolution modes that
produce much higher quality displays than envisioned when the first VGA
specifications came out. Unfortunately, the methodology for doing this with
each card seems to be different. It would be a great step forward if a standard for
implementing enhanced displays could be agreed upon, but it's unlikely.

Here we are going to give a program for producing a high resolution display
from ray tracing data using the Vega VGA 1 024i display card. This card supports
a number of extended high-resolution modes. The one we are going to use is
800 by 600 pixels with 256 colors. First, go into a ray-tracing data file and

267
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

change the XRES and YRES parameters to 800 and 600, respectively. Then run
render with this file to generate a new raw data file at the improved resolution.
(This is going to take longer than for a 320 by 200 display, since there are now
480,000 elements to process instead of 64,000.)

Run the program l isted in Figure 1 4-2, to convert the raw data file to a
display. The first thing to observe is that this program looks very similar to the
colproc program given in Figure 1 4- 1 . In fact, everything is the same except the
way the graphics mode is set up and the way to write to the screen. First, look at
the setMode function, which is used to set the display mode. Note that this
function now begins with an if statement. For modes less than 32H, the function
is just the same as the one used with the regular display modes. However, for the
extended graphics functions (modes beyond 32H), a different ROM BIOS call is
used, placing the mode in a different register, and sending an initializing output
to one of the VGA registers. Although this function uses the ROM BIOS, this
part of the ROM BIOS is contained in the VGA board, so that for a different
make of VGA board, the results could be completely different.

Let's look at the plot function. Before, we used the x and y pixel values to
create an offset which was added to the basic video memory address to create the
address where the pixel color was sent. Now we begin by creating the offset
(which can be larger because we now have 640 pixels in a line instead of 320).
However, this larger video memory is banked to be able to handle more memory
within the memory space allotted to the VGA. Thus, if the offset is greater than
65 5 3 6 (64k) , we must divide it by 655 3 6 to obtain the bank number. The
remainder is the new value of offset. The function keeps a record of the number
of the last active bank in global memory. If the desired bank is different from the
currently active bank, the function selects the new bank. The new bank number
is stored in active_bank. The function then provides outputs to several of the
VGA registers to select this new bank.

The way this is done is not very straightforward, but should be self-evident
from the program listing. Once the correct memory bank has been selected, the

268
D I S P L AY I N G A N D S AV I N G S C R E E N S

function creates a memory address from the offset and the base memory address,
and sends the pixel color there. (If the correct bank is already selected, the
function can skip all that bank selection stuff and simply create the address and
send the pixel. B asically, these two functions are all that need to be changed to
use the extended 640 pixel by 480 row by 256 color mode.

/*
800proc P r o g r a m t o P r o c e s s 8 0 0 x 6 0 0 C o l o r D a t a f o r V GA
*/

#i n c l ude < d o s . h >


#i n c l ude < s t d i o . h >

voi d g o t o xy ( i n t x , i n t y ) ;
voi d pl ot ( i nt x , i nt y , i nt col or ) ;
voi d s e tMode ( i n t mode ) ;
voi d s e t V GA p a l e t t e ( u n s i g n e d c h a r * b u f f e r ) ;
voi d s o rt ( u n s i gned i nt sta rt . u n s i gned i n t end ) ;

typede f s t ruct
{
c h a r Red ;
cha r Green ;
cha r B l ue ;

RGB ;

e n u m { r e d =O , g r n = l , b l u = 2 } ;

uni on REGS reg ;


s t ruct S R EGS i n reg ;

#d e f i n e MAX X RE S 800 I * s e t m a x h o r i z c o o r d e x p e c t ed * /

u n s i g n e d i n t C o l _A r r a y [ 2 5 6 J [ 2 J ;
u n s i g n e d c h a r P a l _A r r a y [ 2 5 6 ] [ 3 J ;
RGB Col o r , C o l o r 2 ;

i n t i , k , x res . y res .
l a s t_c o l o r . s c a n l i n e . r l , r 2 , g l , g 2 , b l , b 2 , b a n k=O , a c t i v e_b a n k=O ;

269
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +

u n s i g n e d c h a r r [ MA X X R E S J , g [ MA X X R E S J , b [ MA X X R E S J ;
F I L E * f i l e_ l ;
u n s i g n e d c h a r f a r * c o l o r_h i s t ;
l o n g i n t c o l o r_n o ;
unsi gned i nt j ;
u n s i g n e d c h a r f r e q u e n cy [ 8 1 9 2 J ;
u n s i gned i nt h ue s [ 8 1 92 J ;

v o i d ma i n ( a rg c , a rg v )
i nt a rgc ;
c h a r *a rgv [ J ;

i nt i ndex ;
i nt rgbi ndex ;
i nt yl ;
u n s i g n e d i n t d l , t em p_d ;
unsi gned cha r d2 ;

setMode ( 3 ) ;
i f ( a rgc ! = 2 )
I
p r i n t f ( " V GA C o l o r P r o c e s s o r by R o g e r S t e v e n s \ n " ) ;
p r i n t f ( " U s a g e : % s f i l e n a m e . RAW \ n " , a r g v [ O J ) ;
exi t ( l ) ;

i f ( ( f i l e_l = f o p e n ( a r g v [ l ] , " r b " ) ) == N U L L )


I
p r i n t f ( "Cou l dn ' t open fi l e %s \ n " , a rgv [ l ] ) ;
exi t ( l ) ;

c o l o r_h i s t = f a r m a l l o c ( 3 2 7 6 8 ) ;
f o r ( i =O ; i < 2 5 6 ; i ++ )
I
P a l _A r r a y [ i J [ r e d J O;
P a l _A r r a y [ i ] [ g r n ] O;
P a l _A r r a y [ i ] [ b l u ] O;
}
f o r ( j =O ; j < 3 2 7 6 8 ; j ++ )
c o l o r_h i s t [ j ] = O ;
xres = y res = O ;

270
D I S P L AY I N G A N D S AV I N G S C R E E N S

f r e a d ( & x r e s , s i z e o f ( i n t ) , l , f i l e_ l ) ;
f r e a d ( &y r e s , s i z e o f ( i n t ) , l , f i l e_ l ) ;
p r i n t f ( " V GA c o l o r p o s t - p r o c e s s o r by R o g e r S t e v e n s \ n " ) ;
p r i n t f ( " I m a g e f i l e r e s o l u t i o n i s : % d by % d \ n " , x r e s , y r e s ) ;
f o r ( i =O ; i < 2 5 6 ; i ++ )
{
P a l _A r r a y [ i J [ r e d J 0;
P a l _A r r a y [ i J [ g r n J O;
P a l _A r r a y [ i J [ b l u J O;
}
yl = O;
pri ntf( "Col l ecti ng col or data [ ]") ;
w h i l e ( ! f e o f ( f i l e_l ) )
{
f r e a d ( & s c a n l i n e , s i z e o f ( i n t ) , l , f i l e_l ) ;
i f ( s c a n l i n e >= y r e s )
p r i n t f ( " F a u l ty d a t a f i l e . \ n " ) ;
exi t ( l ) ;
}
g o t o xy ( 2 4 , 3 ) ;
p r i n t f ( "%d " , s c a n l i ne ) ;
f r e a d ( & r [ O J . s i z e o f ( c h a r ) , x r e s . f i l e_l ) ;
f r e a d ( & g [ O J . s i z e o f ( c h a r ) , x r e s . f i l e_l ) ;
f r e a d ( & b [ O J , s i z e o f ( c h a r ) , x r e s , f i l e_l ) ;
f o r ( i n d e x=O ; i n d e x < x r e s ; i n d e x++ )
{
C o l o r . Re d ( r [ i ndex J & Ox3e ) ;
Col o r . Green ( g [ i ndex J & Ox3e ) ;
Col or . Bl ue ( b [ i ndex J & Ox3e ) ;
c o l o r_n o = ( C o l o r . Re d > > 1 ) I ( C o l o r . G r e e n
<< 4) I ( Col or . Bl ue << 9 ) ;
i f ( c o l o r_h i s t [ c o l o r_n o ] < 2 5 5 )
c o l o r_h i s t [ c o l o r_n o ] ++ ;

y l += l ;

l ast col or = - 1 ;
f o r ( j =O ; j < 3 2 7 6 8 ; j ++ )
{
i f ( c o l o r_ h i s t [ j ] > 0 )
{
l a s t_ c o l o r++ ;

271
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +

h u e s [ l a s t_c o l o r ] = j ;
f r e q u e n cy [ l a s t_c o l o r ] c o l o r_h i s t [ j ] ;

p r i n t f ( " \ n T h e r e a r e % d c o l o r s . " , l a s t_c o l o r ) ;


pri ntf( " \nSta rti ng sort . " ) ;
s o r t ( O , l a s t_c o l o r l ;
p r i n t f ( " \ n S o r t c om p l e t e d . " ) ;
p r i n t f ( " \ n M o d i fy i n g e x t r a c o l o r s ]") ;
f o r ( i =0 : i < 2 5 6 ; i ++ l
f r e q u e n cy [ i J = i ;
f o r ( i =2 5 6 ; i <= l a s t_c o l o r ; i ++ )
{
g o t o xy ( 2 5 , 7 l ;
pri ntf( "%5d" , i l ;
d l = 32768 ;
f o r ( j =O ; j < 2 5 6 ; j ++ )
{
C o l o r . Red = ( h ue s [ i ] << l l & Ox3 E ;
C o l o r . Green = ( h ue s [ i ] >> 4 ) & Ox3 E :
Col o r . Bl ue = ( h ue s [ i ] >> 9 ) & Ox3 E ;
C o l o r 2 . Red = ( h u e s [ j ] < < l l & Ox3 E ;
Col or2 . Green = ( hues [j ] >> 4 ) & Ox3E :
Col o r2 . B l ue = ( hues [ j ] >> 9 ) & Ox3E ;
t emp_d = ( C o l o r . Re d - C o l o r 2 . Re d ) * ( C o l o r . Re d ­
C o l o r 2 . Re d l + ( C o l o r . G r e e n -
Col o r 2 . Green l * ( Col or . G reen - Col or2 . Green ) +
( Col or . Bl ue - Col or2 . Bl ue ) * ( Col or . Bl ue -
Col or2 . Bl ue l ;
i f ( t e m p_d < d l l
{
dl t e mp_d ;
d2 j;

f r e q u e n cy [ i ] d2 ;

f o r ( j =O ; j < 2 5 6 : j ++ )
{
C o l o r . Re d = ( h u e s [ j ] < < l l & O x 3 E ;
Col o r . Green = ( h ues [ j ] >> 4 ) & Ox3 E ;
C o l o r . Bl ue = ( h ues [ j ] >> 9 ) & Ox3 E ;

272
D I S P L AY I N G A N D S AV I N G S C R E E N S

P a l _A r r a y [ j J [ 0 J C o l o r . Red ;
P a l _A r r a y [ j J [ l J Col o r . Green ;
P a l _A r r a y [ j J [ 2 J Col or . B l ue ;

setMode ( Ox67 ) ;
s e t V GA p a l e t t e ( & P a l _A r r a y [ O J [ O J ) ;
f o r ( j =O ; j < 3 2 7 6 8 ; j ++ )
c o l o r_h i s t [ j ] = O ;
f o r ( j =O ; j < = l a s t_c o l o r ; j ++ )
c o l o r_ h i s t [ h u e s [ j ] J = f r e q u e n cy [ j ] ;
r e w i n d ( f i l e_l ) ;
yl = O ;
f r e a d ( & x r e s , s i z e o f ( i n t ) , l , f i l e_ l ) ;
f r e a d ( &y r e s , s i z e o f ( i n t ) , l , f i l e_ l ) ;
f o r ( y l ; y l < 4 8 0 ; y l ++ )
I
f r e a d ( & s c a n l i n e . s i z e o f ( i n t ) , l , f i l e_l ) ;
i f ( s c a n l i n e >= y r e s )
I
p r i n t f ( " F a u l ty d a t a f i l e . \ n " ) ;
exi t ( l ) ;

f r e a d ( & r [ O J , s i z e o f ( c h a r ) , x r e s , f i l e_l ) ;
f r e a d ( & g [ O J , s i z e o f ( c h a r ) , x r e s . f i l e_l ) ;
f r e a d ( & b [ O J , s i z e o f ( c h a r ) , x r e s . f i l e_l ) ;
f o r ( i n d e x=O ; i n d e x < x r e s ; i n d e x++ )
I
C o l o r . Red ( r [ i ndex J & Ox3e ) ;
Col or . Green ( g [ i ndex J & Ox3e ) ;
Col or . Bl ue ( b [ i ndex J & Ox3e ) ;
c o l o r_n o = ( C o l o r . Re d > > 1 ) I ( C o l o r . G r e e n
<< 4 ) I ( Col o r . Bl ue << 9 ) ;
p l o t ( i n d e x , y l , c o l o r_h i s t [ c o l o r_n o ] ) ;

getch ( ) ;
setMode ( 3 ) ;
f c l o s e ( f i l e_ l ) ;

273
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +

I�
/*
s etMode ( ) Sets V i deo Mode
� ==========!I

*/
v o i d s etMode ( i n t mode )
{
i f ( mode > Ox32 )
{
a c t i v e_b a n k = O ;
reg . x . a x = Ox6 F05 :
reg . h . b l = mode ;
i n t86 ( Ox l O , & reg , &reg ) ;
o u t pw ( O x 3 C 4 , 0 x E A 0 6 ) ;

el se
{
reg . h . a h = 0 ;
reg . h . a l = mode ;
i n t86 ( Ox l O , & reg , & reg ) ;

pl ot ( ) F u n c t i on to p l ot p o i n t t o VGA 2 5 6 C o l o r S c reen

*/

voi d pl ot ( i nt x , i nt y , i nt col o r )
{
l ong i nt offset :
c h a r fa r *addres s ;
i n t temp , t emp2 ;

offset = 640 L * ( l on g ) y + ( l ong ) x ;


a n k = offs et / 65536 L :
offset = offset % 65536 L ;
i f ( ba n k ! = acti ve ban k )
{
a c t i v e_b a n k = b a n k ;

reg . h . a h ba n k & OxOl ;


reg . h . a l OxF9 ;

274
D I S P L AY I N G A N D S AV I N G S C R E E N S

o u t pw ( O x 3 C 4 , r e g . x . a x ) ;
t e m p = i n pw ( O x 3 C C ) ;
t emp = temp & Ox D F :
i f ( ( ba n k & Ox02 ) ! = 0 )
t em p = t e m p I O x 2 0 ;
o u t pw ( O x 3 C 2 . t em p ) ;
outp ( Ox3C4 , 0x F6 ) ;
t e m p = i n pw ( O x 3 C 5 ) ;
t emp = temp & Ox FO :
t emp2 = ( ( ba n k & OxOC ) > > 2 ) I ( ba n k & OxOC ) ;
temp = temp I temp2 ;
outp ( Ox3C 5 , temp ) ;

a d d r e s s = ( c h a r fa r * ) ( OxAOOOOOOO L + offset ) ;
*add ress = col or :

/ *rr=======;i
s e t V GA p a l e t t e ( ) F u n c t i on t o s e t a l l 2 5 6 col o r reg i s t e r s

*I

v o i d s e t V GA p a l e t t e ( u n s i g n e d c h a r * b u f f e r )
{
reg . x . a x = Oxl01 2 :
segread ( & i n reg ) ;
i n reg . es i n reg . d s :
reg . x . bx O;
reg . x . cx 256 ;
reg . x . dx ( i nt ) &buffer [OJ ;
i n t86x ( Ox l 0 , & reg , & reg , & i n reg ) ;

I*

sort ( ) Q u i c k s o r t t o s o r t c o l o r s by f r e q u e n cy

*I

v o i d s o r t ( u n s i g n e d i n t s t a r t . u n s i g n ed i n t end )
{
u n s i gned i n t pi vot , temp2 :
un s i gned c h a r temp ;

275
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

i f ( sta rt < ( end - 1))


{
i = sta rt ;
j = end ;
p i v o t = ( f r e q u e n cy [ i ] + f r e q u e n cy [ j ] +
f r e q u e n cy [ ( i +j ) / 2 ] ) / 3 ;
do
{
w h i l e ( f r e q u e n cy [ i J > p i v o t )
i ++ ;
w h i l e ( f r e q u e n cy [ j ] < p i v o t )
j-;
if (i < j)
{
t emp = f r e q u e n cy [ i ] ;
f r e q u e n cy [ i ] = f r e q u e n cy [ j ] ;
f r e q u e n cy [ j ] = t e m p ;
temp2 = h u es [ i ] ;
h u e s [ i ++ J = h u e s [ j ] ;
h u e s [ j -J = t em p 2 ;

whi l e ( i < j ) ;
i f ( j < end )
{
s o rt ( s t a rt , j ) ;
sort ( j+l , end ) ;

i f ( f r e q u e n c y [ e n d ] > f r e q u e n cy [ s t a r t ] )
{
temp = f r e q u e n cy [ s t a r t ] ;
f r e q u e n cy [ s t a r t ] = f r e q u e n c y [ e n d ] ;
f r e q u e n cy [ e n d ] = t emp ;
t em p 2 = h u e s [ s t a r t ] ;
h ue s [ s t a rt ] = h ues [ e nd ] ;
h ue s [ end ] = temp2 ;

276
D I S P L AY I N G A N D S AV I N G S C R E E N S

v o i d g o t o xy ( i n t x , i n t y )
!
reg . h . a h= 2;
reg . h . bh = O;
reg . h . d h= y-1 ;
reg . h . d l= x-1 ;
i n t86 ( 0x l 0 , & reg , & r eg ) ;

Figure 1 4·2. Program to Generate 800 x 600 Display

Saving the Display in . PCX Format


The .PCX file format was created by ZSoft for use in PC Paintbrush. It has
now become a recognized standard for storing graphics screens. The format for
a .PCX file is given in Appendix B . The program described here takes the file of
raw data from the ray tracer, and uses the same technique described above to
determine the colors needed for the display on the VGA. However, instead of
displaying the file, it converts the resulting information to the .PCX format and
stores it in a .PCX file having the same name as the .RAW file. The program to
do this is listed in Figure 1 4-3.

The program begins exactly like the preceding one, checking to see whether
a file name is specified on the call line and if not, displaying an error message
and exiting. Similarly, it then tries to open the file if one is specified, and if
unsucces sfu l , d i splays an error m e s s age and quits. If the file i s opened
successfully, the program strips off that part of the file name preceding the dot
and appends . PCX to it. It then opens this new file and sends the proper
information for the . PCX format file header to it. Next, the program does
exactly what the preceding program did to collect information on the occurrence
of colors, assign the 256 color register values, and find the least squares fit for
those colors not among the first 256. The program then rewinds the file, reads
the xres and yres values, and enters a while loop that continues until the end of
file is encountered.

At the beginning of each iteration of the loop, the program reads the scan
line number from the file and, if it exceeds the allowable maximum value,
displays an error message and exits. If the scan line value is OK, a line of red,

277
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

green, and blue pixel data is read to the appropriate arrays. For each pixel in the
line, the proper index is created from the color data and used to obtain the pixel
color from the col_hist array. This data is then encoded in the .PCX format.

Essentially, this format simply outputs the byte to the file if it is a single
occurrence and does not have the two most significant bits as ones. Otherwise
two bytes are output. The first has its two most significant bits set to one and the
remaining bits give a count (between 1 and 63) of the number of sequential
occurrences of the same byte value.

/*
pcxgen P rogram to P roce s s C o l o r Data for VGA and
s a v e to a . PC X d i s k fi l e .
I n c l u d e s 3 2 0 x 2 0 0 a n d 6 4 0 x4 8 0 m o d e s

B y Rog e r T . S t e v e n s 5/5/90

*/

#i n c l ude <dos . h>


#i n c l ude <stdi o . h>
#i n c l ude < s t ream . hpp>
#i n c l ude <stdl i b . h>
#i n c l ude <stri ng . h>

voi d g o t o xy ( i n t x , i n t y ) ;
voi d pl ot ( i nt x , i nt y , i n t col o r ) ;
voi d s etMode ( i n t mode ) ;
voi d s e t VGApa l e t te ( un s i gned c h a r *buffe r ) ;
voi d s o rt ( un s i gned i n t s t a rt , u n s i gned i nt end ) ;

ty p e d e f s t r u c t r g b
{
c h a r Red ;
c h a r G reen ;
cha r Bl ue ;

RGB ;

278
D I S P L AY I N G A N D S AV I N G S C R E E N S

#de f i n e red 0
#de f i n e g r n 1
#d e f i n e b l u 2

uni on REGS reg ;


s t ruct S REGS i n reg ;

#de f i n e MAX X RES 800 / * set max h o r i z coord expected */

u n s i g n e d i n t C o l _A r r a y [ 2 5 6 ] [ 2 J ;
u n s i g n e d c h a r P a l _A r r a y [ 2 5 6 J [ 3 J ;
RGB C o l o r , Co l o r 2 ;
i n t i , k , a d d l , a d d 2 , n u m b e r , l i n e_l e n g t h , e n d , s t a r t_l i n e , e n d_l i n e ,
x r e s , y r e s , l a s t_c o l o r , s c a n l i n e , r l , r 2 , g l , g 2 , b l , b 2 ;
u n s i g n e d c h a r P A L E TT E [ l 6 J =

{ 0 , 1 , 2 , 3 , 4 , 5 , 2 0 , 7 , 56 , 5 7 , 58 , 59 , 60 , 6 1 , 6 2 , 63 ) ;
u n s i g n e d c h a r c h , c h l , o l d_c h , n u m_o u t , r e d_p , g r e e n_p , b l u e_p ;
u n s i g n e d c h a r r [ MA X X R E S ] , g [ MA X X R E S ] , b [ MA X X R E S ] ;
F I L E * f i l e_ l , * f s a v e ;
u n s i g n e d c h a r f a r * c o l o r_h i s t ;
l o n g i n t c o l o r_n o , j ;
u n s i g n e d c h a r f r e q u e n cy [ 8 1 9 2 ] ;
u n s i g n ed i n t h ue s [ 8 1 92 J ;
c h a r f i l e n a me [ l 5 J ;

ma i n ( a rgc , a rg v )

i nt a rgc ;
cha r *a rgv [ J ;

i nt i ndex , rgbi ndex , y l , l ength ;


u n s i g n e d i n t d l , t em p_d ;
u n s i g n ed c h a r d 2 ;

s etMode ( 3 ) ;

cout «

279
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

..
" II I I\ n :
cout «
..
" II I I\ n :
cout «
" II P rogram to P roce s s Col o r D a t a f o r VGA a n d I l\ n " ;
cout «
" II s a v e to a . PCX d i s k fi l e . I l\ n " ;
cout «
" II I n c l u d e s 3 2 0 x 2 0 0 a n d 640x480 mod e s I l\ n " ;
cout «
" II I l\ n " ;
cout «

" II By R o g e r T . S t e v e n s 5 / 5 / 90 I l\ n " ;

i f ( a rgc ! = 2 )
{
cout «
..
" II I I\ n :
cout «
..
" II U s e a g e : p c x g e n f i l e n a me . RAW I I\ n :
}
cout «
" II I l\ n " ;
cout «
" II I l\ n " ;

i f ( a rg c ! = 2 )
exi t ( l ) ;
i f ( ( f i l e_ l = f o p e n ( a r g v [ l ] , " r b " ) ) == N U L L )
{
p r i n t f ( "Cou l dn ' t open fi l e % s \ n " , a rg v [ l ] ) ;
exi t ( l ) ;

f o r ( i =O ; i < 2 5 6 ; i ++ )
{
P a l _A r r a y [ i J [ r e d J O;
P a l _A r r a y [ i ] [ g r n ] O;

280
D I S P L AY I N G A N D S AV I N G S C R E E N S

P a l _A r r a y [ i ] [ b l u ] = O ;

c o l o r_h i s t = f a r m a l l o c ( 3 2 7 6 8 ) ;
f o r ( j =O ; j < 3 2 7 6 8 ; j ++ )
c o l o r_h i s t [ j ]
= O;
xres = y res = O ;
f r e a d ( & x r e s , s i z e o f ( i n t ) , l , f i l e_ l ) ;
f r e a d ( &y r e s , s i z e o f ( i n t ) , l , f i l e_ l ) ;
c o u t < < " \ n \ n l m a g e f i l e r e s o l u t i o n i s : " < < x r e s < < " by " < <
y res « " \ n " ;
i f ( ! ( ( ( xres 3 2 0 ) & & ( y r e s == 2 0 0 ) ) I I ( ( x r e s 6 4 0 ) &&
( y r e s == 4 8 0 ) ) ) )

cout << " Does not s upport t h i s resol u t i on . \ n " ;


exi t ( O ) ;

l ength = s t r c s pn ( a rg v [ l ] , " . " ) ;


s t r n c py ( f i l e n a me , a r g v [ l ] , l e n g t h ) ;
s t r c a t ( f i l e n a me , " . p c x " ) ;
fsave = f o p e n ( f i l e n a me , " w b " ) ;
f p u t c ( OxOA , f s a v e ) ;
fputc ( Ox05 , fs a ve ) ;
fputc ( OxOl , fsave ) ;
fpu t c ( Ox08 , fs a ve ) ;
fputc ( O , fs a ve ) ;
fputc ( O , fs a ve ) ;
fputc ( O , fs a ve ) ;
fputc ( O , fs a ve ) ;
x res-;
y res-;
fw r i t e ( & x r e s , s i z e o f ( i n t ) , l , f s a v e ) ;
fw r i t e ( &y r e s , s i z e o f ( i n t ) , l , f s a v e ) ;
x r e s ++ ;
y r e s ++ ;
fw r i t e ( & x r e s . s i z e o f ( i n t ) , l , f s a v e ) ;
fw r i t e ( &y r e s , s i z e o f ( i n t ) , l , f s a v e ) ;
ch = OxOO ;
f o r ( i =O ; i < l 6 ; i ++ )
{
r e d_p = ( ( ( P A L E T T E [ i ] & O x 2 0 ) > > 5 ) I
( ( PA L E T T E [ i ] & O x 0 4 ) > > 1 ) ) * 8 5 ;
g r e e n_p = ( ( ( PA L E T T E [ i ] & O x l O ) > > 4 ) I

281
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

( PA L ETT E [ i ] & Ox02 ) ) * 85 ;


b l u e_p = ( ( ( P A L E T T E [ i ] & O x 0 8 ) > > 3 ) I
( ( PA L E T T E [ i ] & O x O l ) < < 1 ) ) * 8 5 ;
f p u t c ( r e d_p , f s a v e ) ;
f p u t c ( g r e e n_p , f s a v e ) ;
f p u t c ( b l u e_p , f s a v e ) ;

fput c ( OxOO , fs a ve ) ;
fput c ( OxOl , fs a ve ) ;
fput c ( Ox40 , fs a ve ) ;
fput c ( OxOl , fs a ve ) ;
l i n e_l e n g t h = x r e s ;
end = xres ;
f o r ( i =6 8 ; i < l 2 8 ; i ++ )
fputc ( OxOO , fs a ve ) ;
yl = O ;
p r i n t f ( " C o l l e c t i n g c o l o r d a t a f r om s c a n l i n e [ ]") ;
w h i l e ( ! f e o f ( f i l e_l ) )
{
f r e a d ( & s c a n l i n e , s i z e o f ( i n t ) , l , f i l e_ l ) ;
i f ( s c a n l i n e >= y r e s )
{
p r i n t f ( " F a u l ty d a t a f i l e . \ n " ) ;
ex i t ( l ) ;

g o t o xy ( 3 9 , 1 3 ) ;
p r i n t f ( "%3d " , s c a n l i ne ) ;
f r e a d ( & r [ O J , s i z e o f ( c h a r ) , x r e s , f i l e_l ) ;
f r e a d ( & g [ O J , s i z e o f ( c h a r ) , x r e s , f i l e_l ) ;
f r e a d ( & b [ O J , s i z e o f ( c h a r ) , x r e s , f i l e_l ) ;
f o r ( i n d e x=O ; i n d e x < x r e s ; i n d ex++ )
{
C o l o r . Red ( r [ i ndexJ & Ox3e ) ;
Col o r . G reen ( g [ i ndexJ & Ox3e ) ;
Col or . Bl ue ( b [ i ndexJ & Ox3e ) ;
c o l o r_n o = ( C o l o r . Re d > > 1 ) I ( C o l o r . G r e e n
< < 4) I ( Co l o r . Bl ue << 9 ) ;
i f ( c o l o r_h i s t [ c o l o r_n o ] < 2 5 5 )
c o l o r_h i s t [ c o l o r_n o ] ++ ;

y l += l ;

282
D I S P L AY I N G A N D S AV I N G S C R E E N S

l a s t_c o l o r = - 1 ;
f o r ( j =O ; j < 3 2 7 6 8 ; j ++ )
{
i f ( c o l o r_ h i s t [ j ] > 0 )
{
l a s t_c o l o r++ ;
h u e s [ l a s t_c o l o r ] j;
f r e q u e n cy [ l a s t_c o l o r ] c o l o r_h i s t [ j J ;

p r i n t f ( " \ n T h e r e a r e % d c o l o r s . " , l a s t_c o l o r ) ;


pri ntf( "\nSta rti ng sort . " ) ;
s o r t ( O , l a s t_c o l o r ) ;
p r i n t f ( " \ n S o r t c om p l e t e d . " ) ;
p r i n t f ( " \ n M o d i fy i n g e x t r a c o l o r s ]") ;
f o r ( i =O ; i < 2 5 6 ; i ++ )
f r e q u e n cy [ i ] = i ;
f o r ( i =2 5 6 ; i <= l a s t_c o l o r ; i ++ )
{
g o t o xy ( 2 5 , 1 7 ) ;
pri ntf( "%5d" , i ) ;
d l = 3 2 7 68 ;
f o r ( j =O ; j < 2 5 6 ; j ++ )
{
C o l o r . Re d = ( h u e s [ i ] < < 1 ) & O x 3 E ;
Col o r . Green = ( hues [ i ] >> 4 ) & Ox3E ;
C o l o r . B l u e = ( h ue s [ i ] > > 9 ) & Ox3 E ;
C o l o r 2 . Red = ( h u e s [ j ] < < 1 ) & Ox3 E ;
C o l o r 2 . G reen = ( h u e s [ j ] > > 4 ) & Ox3 E ;
C o l o r 2 . B l u e = ( h u e s [ j ] > > 9 ) & Ox3 E ;
t emp_d = ( C o l o r . Red - C o l o r 2 . Red ) * ( C o l o r . Red -
C o l o r 2 . Re d ) + ( C o l o r . G r e e n -
Col or2 . G reen ) * ( Col o r . Green -
Col o r 2 . G reen ) +
( Co l o r . B l u e - C o l o r2 . B l ue ) * ( Co l o r . B l ue -
Col o r2 . Bl ue ) ;
i f ( t em p_d < d l )
{
dl t em p_d ;
d2 j;

283
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

f r e q u e n cy [ i ] = d 2 ;

f o r ( j =O ; j < 2 5 6 ; j ++ )
{
C o l o r . Red = ( h u e s [ j ] < < 1 ) & Ox3E ;
C o l o r . G reen = ( h u e s [ j ] > > 4 ) & Ox3 E ;
C o l o r . Bl ue = ( hues [ j ] >> 9 ) & Ox3 E ;
P a l _A r r a y [ j ] [ O J C o l o r . Red ;
P a l _A r r a y [ j ] [ l ] Col or . Green ;
P a l _A r r a y [ j ] [ 2 J Col o r . Bl ue ;

f o r ( j =O ; j < 3 2 7 6 8 ; j ++ )
c o l o r_h i s t [ j ] = O;
f o r ( j =O ; j <= l a s t_c o l o r ; j ++ )
c o l o r_h i s t [ h u e s [ j ] J = f r e q u e n cy [ j ] ;
r e w i n d ( f i l e_l ) ;
yl = 0 ;
f r e a d ( & x r e s , s i z e o f ( i n t ) , l , f i l e_ l ) ;
f r e a d ( &y r e s , s i z e o f ( i n t ) , l , f i l e_l ) ;
w h i l e ( ! f e o f ( f i l e_l ) )
{
f r e a d ( & s c a n l i n e , s i z e o f ( i n t ) , 1 , f i l e_l ) ;
i f ( s c a n l i n e >= y re s )
{
p r i n t f ( " F a u l ty d a t a f i l e . \ n " ) ;
ex i t ( l ) ;

f r e a d ( & r [ O J , s i z e o f ( c h a r ) , x r e s , f i l e_ l ) ;
f r e a d ( & g [ O J , s i z e o f ( c h a r ) , x r e s , f i l e_l ) ;
f r e a d ( & b [ O J , s i z e o f ( c h a r ) , x r e s , f i l e_l ) ;
C o l o r . Red ( r [ O J & Ox3e ) ;
Col o r . Green = ( g [ O J & Ox3e ) ;
Col o r . Bl ue = ( b [ O J & Ox3e ) ;
c o l o r_n o = ( C o l o r . R e d > > 1 ) ( Co l o r . G reen < < 4 ) I
( Col o r . Bl ue << 9 ) ;
n umbe r = 1 ;
o l d_c h = c o l o r_h i s t [ c o l o r_n o ] ;
f o r ( i n d e x= l ; i n d e x <=x r e s ; i n d e x++ )
{
C o l o r . Red ( r [ i ndexJ & Ox3e ) ;
Col o r . G reen ( g [ i ndex J & Ox3e ) ;
Col o r . Bl ue ( b [ i ndex J & Ox3e ) ;

284
D I S P L AY I N G A N D S AV I N G S C R E E N S

c o l o r_n o = ( C o l o r . Re d > > 1 ) I ( C o l o r . G r e e n


<< 4 ) ! ( Col o r . Bl ue << 9 ) ;
i f ( i n d e x == x r e s )
ch o l d_c h - l ;
el se
ch c o l o r_h i s t [ c o l o r_n o ] ;
i f ( ( c h == o l d_c h ) && ( n u m b e r < 6 3 ) )
n u m b e r++ ;
el se
{
n um_o u t = ( ( u n s i g n e d c h a r ) n um b e r I O x C O l ;
i f ( ( ( o l d_c h & O x C O ) ==
O x C O ) I I ( n um b e r > 1 ) )
f p u t c ( n u m_o u t , f s a v e ) ;
f p u t c ( o l d_c h , f s a v e ) ;
ol d ch ch ;
n umbe r = l ;

y l += l ;

fputc ( OxOC , fs a ve ) ;
f o r ( i =O ; i < 2 5 6 ; i ++ )
f o r ( j =0 ; j < 3 ; j ++ )
f p u t c ( P a l _A r r a y [ i ] [ j ] * 4 , f s a v e ) ;
fcl ose ( fsave ) ;
f c l o s e ( f i l e_ l ) ;
c o u t < < " F i l e t r a n s f o rm a t i o n c o m p l e t e . \ n " ;

I*
s o rt ( ) Q u i c k s o r t t o s o r t c o l o r s by f r e

*/

v o i d s o rt ( u n s i g n e d i n t s t a rt , u n s i g n ed i n t end )
{
un s i gned i nt pi v ot , temp2 ;
u n s i g n e d c h a r t e mp ;

i f ( s t a r t < ( end - 1 ) )
{

285
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

i = sta rt ;
j = end ;
pi vot ( f r e q u e n cy [ i ] + f r e q u e n cy [ j ] +
f r e q u e n cy [ ( i +j ) / 2 ] ) / 3 ;
do
{
w h i l e ( f r e q u e n cy [ i ] > p i v o t )
i ++ ;
w h i l e ( f r e q u e n cy [ j ] < p i v o t )
j- ;
if (i < j)
{
t em p = f r e q u e n cy [ i ] ;
f r e q u e n cy [ i ] = f r e q u e n cy [ j ] ;
f r e q u e n cy [ j ] = t e m p ;
temp2 = h u es [ i ] ;
h u e s [ i ++ J = h u e s [ j ] ;
h u e s [ j -J = temp2 ;

whi l e ( i < j ) ;
i f ( j < end )
{
sort ( sta rt , j ) ;
s o rt ( j +l , end ) ;

i f ( f r e q u e n cy [ e n d ] > f r e q u e n cy [ s t a r t ] )
{
t em p = f r e q u e n cy [ s t a r t ] ;
f r e q u e n cy [ s t a r t ] = f r e q u e n cy [ e n d ] ;
f r e q u e n cy [ e n d ] = t em p ;
temp2 = hues [ st a rt ] ;
hues [ sta rt] = hues [end ] ;
h u e s [ end ] = temp2 ;

v o i d g o t o xy ( i n t x , i n t y )
{
reg . h . a h = 2 ;
reg . h . bh = O ;
reg . h . dh = y - 1 ;

286
D I S P L AY I N G A N D S AV I N G S C R E E N S

reg . h . d l= x-1 ;
i nt86 ( 0x l 0 , & reg , & r eg ) ;

/*
setMode ( ) Sets V i deo Mode
*/

v o i d s etMode ( i nt mode )
{
reg . h . a h = O;
reg . h . a l = mode ;
i nt86 ( 0x l 0 , & reg , &reg ) ;

Figure 1 4-3. Program t o Convert Ray-Tracing Data to a .PCX File

The second byte i s the value of the recurring byte. The program does this by
storing the previous byte value and comparing it with the current one. When
they agree and the number is within bounds, the number counter is incremented.
When they disagree, the information for the count and the previous byte is sent
to the file and the counter reset. When all of the input data is processed, the
information for setting the colors of the color registers is appended to the end of
the . PC X file in the proper format, both files are closed, and the program
term inates. The program works equally well with the standard 320 by 200
resolution or the extended 640 by 480 resolution. We have set things up so that
if anything other than these two specified resolutions is read in from the data file,
the program displays an error message and terminates.

V iewing the . PCX File


There are a number of programs available for viewing .PCX files, but as the
number of types of display adapters and display modes increases, it becomes
increasingly likely that not every program will work with every type of display.
The program listed here will display any .PCX file created by PCXGEN. It is a

287
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

simple barebones program, but if you can create the display with this program,
you know that the basic information is there in .PCX format, so it should work
with any other program that is truly .PCX compatible. The program is listed in
Figure 1 4-4.

/*

z s 256 P r o g r a m to read . pcx fi l e a n d d i s p l ay as


VGA mode 1 3 H ( 320 x 200 x 256col o r s ) o r
extended mode 6 7 H ( 640 x 480 x 2 5 6
col ors ) sc reen .

By R o g e r T . S t e v e n s 5/5/90

*/

#i n c l ude <dos . h>


#i n c l ude <stdi o . h>
#i n c l ude < s t ream . h pp>
#i n c l ude <stdl i b . h>

i n t r e s t o r e_s c r e e n ( c h a r f i l e_n a m e [ J ) ;
v o i d g o t o xy ( i n t x , i n t y ) ;
voi d pl ot ( i nt x , i nt y , i nt col or ) ;
v o i d s etMode ( i n t mode l ;
voi d setVGApa l ette ( un s i gned c h a r *buffer ) ;

uni on REGS reg ;


st ruct SREGS i n reg ;

u n s i g n e d c h a r P a l _A r r a y [ 2 5 6 ] [ 3 J ;
i n t x r e s , y r e s , a c t i v e_b a n k , b a n k ;

ma i n ( a rg c , a rg v )
i nt a rgc ;
cha r *a rgv [ J ;

288
D I S P L AY I N G A N D S AV I N G S C R E E N S

s etMode ( 3 ) ;
i f ( a rg c ! = 2 )
{

c o u t < < " D i s p l a y 2 5 6 C o l o r V GA M o d e 1 3 H o r 6 7 H " < <


" S c reen f rom . PC X F i l e \ n " ;
cout << " By R o g e r T . S t e v e n s \ n " ;
c o u t < < " U s a g e : z s 2 5 6 f i l e n a me . p c x \ n " ;
exi t ( l ) ;

r e s t o r e_ s c r e e n ( a r g v [ l ] ) ;
getch ( ) ;
s e tMode ( 3 ) ;

i n t r e s t o r e_s c r e e n ( c h a r f i l e_n a me [ J )
{
#i ncl ude <dos . h>
#i ncl ude <stdi o . h>

FI LE *fl ;
u n s i g n e d c h a r c h , c h l , r e d , g r e e n , b l u e , c o l o r , l i n e_l e n g t h , e n d ;
i n t l i n e_ e n d , i , j , k , m , p a s s , x l , y l , x 2 , y 2 ;

i f ( ( f l = f o p e n ( f i l e_n a m e , " r b " ) ) == N U L L )


{
p r i n t f ( " \ n C a n ' t f i n d % s . \ n " , f i l e_n a me ) ;
ret u rn ( l ) ;

el se
{
c h = fgetc ( fl ) ;
i f ( c h ! = OxOA )
{
c o u t < < " \ n " < < f i l e_n a m e < <
" i s not a v a l i d Z Soft fi l e . \ n " ;
fcl ose ( fl ) ;
return ( l ) ;

289
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

f s e e k ( f l , - 7 6 9 L , S E E K_ E N D l :
c h = fgetc ( fl ) :
i f ( ch ! = OxOC l
{
c o u t < < " \ n " < < f i l e n a me < < " i s n o t a M o d e 1 9 f i l e . \ n " :
fcl ose( fl ) ;
return ( l ) ;

f o r ( i =O : i < 2 5 6 ; i ++ )
f o r ( j =O ; j < 3 : j ++ )
{
P a l _A r r a y [ i J [ j J fgetc ( fl ) ;
P a l _A r r a y [ i J [ j J P a l _A r r a y [ i ] [ j ] I 4 ;

f s e e k ( f l , 1 2 L , S E E K_S E T ) ;
frea d ( &x res , s i zeof ( i n t ) , l , f l ) ;
f r e a d ( &y r e s , s i z e o f ( i n t ) , l , f l ) ;
i f ( ( x r e s == 3 2 0 ) & & ( y r e s == 2 0 0 ) )
s etMode ( Ox l 3 ) ;
el se
{
i f ( ( x r e s == 6 4 0 ) & & ( y r e s 480 ) )
s etMod e ( Ox67 ) :
el se
{
c o u t < < " \ n " < < f i l e_n a m e < <
" i s not a Mode 13H or Mode 67H fi l e . \n" :
fc l o se ( f l ) ;
return ( l ) ;

s e t V GA p a l e t t e ( & P a l _A r r a y [ O J [ O J ) ;
f s e e k ( f l , 1 2 8 L , S E E K_S E T ) ;
f o r ( k=O ; k <y r e s ; k++ )
{
f o r ( i =O : i < x r e s ; i ++ )
{
c h l = fgetc ( fl ) ;
i f ( ( c h l & OxCO ) ! = OxCO l
{

290
D I S P L AY I N G A N D S AV I N G S C R E E N S

pl ot ( i , k , c h l ) ;

el se
I
c h l &= O x 3 F ;
pa s s = c h l ;
c h = fgetc ( fl ) ;
f o r ( m=O ; m < p a s s ; m++ )
I
p l o t ( i ++ , k , c h ) ;

i-;

fcl ose ( fl ) ;
ret u rn ( Q ) ;

I*
s e t V GA p a l e t t e ( ) F u n ct i on t o set a l l 256 c o l o r reg i s t e r s

v o i d s e t V GApa l e t t e ( u n s i g n e d c h a r *buffe r )
I
reg . x . a x = O x 1 0 1 2 ;
s e g r e a d ( & i n reg ) ;
i n reg . es i n reg . ds ;
reg . x . bx 0;
reg . x . cx 256 ;
reg . x . dx ( i nt ) &buffer [ O J ;
i n t86x ( Ox 1 0 , &reg , & reg , &i n reg ) ;

v o i d g o t o xy ( i n t x , i n t y )
I
reg . h . a h = 2 ;
reg . h . bh = O ;
reg . h . d h = y - 1 ;
reg . h . d l = x - 1 ;
i n t86 ( 0x 1 0 , &reg , & r eg ) ;

291
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

/*
setMode ( ) Sets V i deo Mode

*/
v o i d s etMode ( i n t mode )
{
i f ( mo d e > O x 3 2 )
{
a c t i v e_b a n k = O ;
reg . x . ax = Ox6F05 ;
r e g . h . b l = mo d e ;
i nt86 C Ox l O , & reg , &reg ) ;
o u t pw ( O x 3 C 4 , 0 x E A 0 6 ) ;

el se
{
reg . h . a h = O ;
r e g . h . a l = mo d e ;
i n t86 ( Ox l O , &reg , &reg ) ;

/*
pl ot ( ) F u n ct i on t o p l ot p o i n t to VGA 2 5 6 C o l o r S c reen

*/

voi d pl ot ( i nt x . i nt y , i nt col o r )
{
l ong i nt offset ;
c h a r fa r * a d d r e s s ;
i n t t em p , t e m p 2 ;

offset = ( l ong ) xres * ( l on g l y + C l on g ) x ;


bank = offset/65536 L ;
offset = offset % 65536 L ;
i f ( b a n k ! = a c t i v e_b a n k )
{
a c t i v e_ba n k = b a n k ;

292
D I S P L AY I N G A N D S AV I N G S C R E E N S

reg . h . a h = b a n k & OxOl ;


reg . h . a l = OxF9 ;
o u t pw ( O x 3 C 4 , r e g . x . a x ) ;
t e m p = i n pw ( O x 3 C C ) ;
temp = temp & OxD F ;
i f ( ( b a n k & Ox0 2 ) ! = 0 )
temp = temp I Ox20 ;
o u t pw ( O x 3 C 2 , t em p ) ;
o u t p ( Ox3C4 , 0x F6 ) ;
t em p = i n pw ( O x 3 C 5 ) ;
t em p = t em p & O x F O ;
t em p 2 = ( ( b a n k & O x O C ) > > 2 ) I ( b a n k & O x O C ) ;
t em p = t e m p I t e m p 2 ;
o u t p ( Ox3C5 , temp ) ;

a d d r e s s = ( c h a r fa r * ) ( QxAOOOOOO O L + offset ) ;
*add ress = col or ;

Figu re 1 4-4. Program for Displaying . PCX Flies

293
CHAPTER 1 5

Rendering Fractal Scenes

If you have been carefully observing the programs so far, you have probably
noticed a few references to fractals and wondered why nothing was said about
them in the description. Fractals are treated differently from other objects, and
introduce a number of unique problems. We have waited until this chapter to
cover all of their aspects in a single place.

The M i d po i nt- Displacement Tech n ique


The method used to generate our fractal scenery is known as the midpoint­
displacement method. It was originally described by A. Fournier, D. Fussell, and
L. Carpenter in "Computer Rendering of Stochastic Models"Communications of
the ACM, in June 1 982. Essentially, the technique is as follows. We begin with a
single triangle and find the midpoint of each side of the triangle, randomly
displacing it in height. The displacement has a mean which is:

(Equation 1 5- 1 )

where Y I and Y 2 are the heights of the two ends of the side. (In other words, the
mean of the random distribution is actually the mean altitude of the side.) The
variance of the random distribution is:

v = (L/2) 2H (Equation 1 5-2)

where L is the length of the side and H is the fractal dimension. After we have
performed this operation for all three triangle sides, we connect each vertex of
the triangle with the displayed midpoints of its adjacent sides, creating a set of
four new triangles. This procedure is then repeated with each of the four new

295
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

triangles. The process is repeated as many times as desired. The result is a fairly
realistic representation of a mountain.

In July 1 983, James T. Kajiya published a paper, "New Techniques for Ray
Tracing Procedurally Defined Objects" in Computer Graphics. Kajiya pointed
out that any fractal object generated by the midpoint displacement method in ray
tracing would have so many individual facets that attempting to check the
intersection of every ray with every facet would take an impossibly large amount
of computer time. Kajiya's solution to this dilemma was to begin only with the
initiating triangle. Around this, he placed what he called a "cheesecake" extent,
which was a triangular faced solid having a height such that it would include any
displacements that might occur in succeeding triangles generated by midpoint
d isplacement. (Actually, since a random process was involved, the extent
dimensions were set up to include all cases w i th better than 99 percent
probability; it was impossible to assure that every case would be within the
extent.) Now, if a ray being traced did not intersect this extent, it also wouldn't
intersect the fractal, so the ray tracing task was done. If there was an intersection
with the extent, Kajiya generated the next four midpoint displacement triangles,
placed extents around each of them, and checked for intersections with each
extent. He continued with this process, generating only those lower levels of the
fractal that were needed to check for actual intersections with the ray being
traced. This substantially reduced the number of intersection checks that needed
to be performed, and thus reduced the computer time to a reasonable amount.
Since then, other articles have appeared, using basically thesame technique, but
suggesting more efficient extents which could reduce the computer time even
further.

Actually, thi s technique slightly misses the mark. The cause of much wasted
computer time is the attempt to intersect each facet directly with the ray. It is
solved by placing extents around l arger and l arger subsets of the fractal .
Generating pieces of the fractal on demand doesn ' t really contribute to the
situation; since many facets will have to be generated more than once, the actual
fractal generation time will be larger than if all facets were generated initially.

296
R E N D E R I N G F R A C TA L S C E N E S

With computer memory continually decreasing in cost, the storage requirements


for an entire fractal is no longer prohibitive.

Han d l i ng a Fractal with Our Ray- Tracing Prog ram


We can begin to see that these strange procedures have counterparts that are
already set up in our ray-tracing program. Let's start with a triangle and perform
the midpoint displacement procedure to create more and more triangles down to
a predetermined level. We can consider all of these primitive facets to be objects
of class Triangle and list them as we would any other objects. Suppose that at
each step in the midpoint displacement procedure, we specify a bounding box
around the four triangles at the next level down. We now have a hierarchy of
bounding boxes that are very similar to Kajiya's cheesecake extents in their
function (although our boxes are rectangles and thus not as efficient as Kajiya's
cheesecakes). We can then use the techniques that we have already set up to ray­
trace the fractal. The amount of time is not too excessive - even for a lowly PC.

Before we proceed to do this, a few things need to be said. We are treating


each fractal as an object, which means that it carries with it the whole baggage of
the basic object class, which uses up several hundred bytes of memory. This
tends to limit us to a level of four, which results in a fractal with 1 024 facets
before we run out of memory and the program bombs. We could define the
facets for the special fractal case in a more efficient manner and have ample
space. Thi s would require quite a bit of reprogramming, and would tend to
obscure the relationship between the fractal facets and ordinary objects. If
you ' re really into ray-tracing fractals, however, you may want to try this. I
would suggest that you take everything out of the base class except what i s
needed fo r a fractal facet, and then add in other things t o the derived classes as
they are required.

Implementing Fractal Processing


We ' re ready to begin developing our procedures for handling fractals in the
ray-tracing program . Let ' s start by looking at the definition of the world
structure in Figure 5 - 1 . There are three v ariables that are used in treating

297
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

fractals. They are fractal_dim. fractal_scalar, and limit. The first is actually
twice the fractal dimension as given in Equation 1 5- 1 . It has been set at 0.9.
You can adjust it to change the "ruggedness" of the terrain, but be ready for
some surprises in the scenes that you generate. The second is a scalar that is
necessary to make sure that the fractal mountain is the right size to fit into the
picture. It has been initialized to 0.002. Be careful when you change these two
parameters; it is easy to get a mountain that takes up almost the whole picture,
which may require 1 0 to 1 2 hours to ray-trace the scene, even when using a 386
machine with a math coprocessor. The final parameter level cannot be any larger
than 4 unless you rework the program to allow more facets, without using up all
of the memory.

Next tum to the input.cpp file. In the Get_Object function, you ' ll see that
there is a case for getting a fractal object, which calls the function GetFractal.
Note that this function returns newobj which is of class Triangle so that once we
leave thi s function, there will never be any difference between this and an
ordinary triangle. (However, it gets a lot more complicated than this as we shall
see.) The next part of the function is just the same as that for a triangle, getting
the s ame parameters and performing the same checking to assure that all
necessary parameters have been read in.

Now we come to the first major difference when the function Fractal_comp
is called. This is part of the file fractal.cpp, which is listed in Figure 1 5- 1 . This
function does the same calculations that were performed for the triangle at the
end of the GetTriangle function and also calculates the variance to be used for
each midpoint displacement. These three variances are stored in the three
components of the vector vect3 . Next GetFractal calls MakeJractal_triangles,
passing it the data on the three vertices of the triangle; the variances, the address
of the current object, and the level. This function begins by creating four new
triangles, the color data for them, and a bounding box. If this is the top level, the
current object address is set up as the bounding box 's next object address, and
the address of the bounding box is stored to be returned when the function
terminates. If we are at some lower level, the bounding box 's next object

298
RENDERING F R A C TA L S C E N E S

address is set to NULL. The function then sets up the location vector for each of
the first three new triangles and computes the three bisectors of the sides of the
original triangle. Next, the altitude displacement for each bisector is computed.
A seed is generated for each side for the random number generator. This makes
the random number generator a little less than random. However, it is needed
because some of the triangle sides are common to two triangles. If different
values of altitude displacement were calculated for the two uses of the same side,
there would be objectionable discontinuities in the figure. The seed is based
upon the three coordinates of the bisect point in such a way that it is unique to a
particular position but will be the same each time that position occurs, so that the
same random number is produced. After the seed is generated, gauss is called to
generate the altitude displacement, which is multiplied by the variance and added
to the bisector altitude value. To avoid underground mountains, the new altitude
of the bisector is never allowed to fall below zero. Next, each of the three new
triangles has its color data set to the default color data. The remaining vectors
for the three new triangles and the information for the fourth triangle (which is
the connection of the three bisectors) are then computed. Then the function
Fractal_comp for all four new triangles is run to do the remaining computations,
including the variances for the next level bisectors. If the level has not reached
zero , we decrease the level by one and then call Make Jractal_triangles
recursively for each of the four new triangles to make four more new triangles at
the next lower level. The four next higher-level triangles are then deleted. If we
have reached the lowest (zero) level, we don't generate any more triangles, but
place the address of the four low level ones in the list of objects, increase the
object count by four and, return. The lowest level triangles are in the list, with
bounding boxes surrounding every set of four, and a bounding box surrounding
each set of four of these bounding boxes, and so forth, so that at the top is only a
single bounding box encompassing the entire fractal. The ray-tracing program
then treats these just as it would any other objects.

299
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

Figure 1 5-1 . The fractal.cpp File

/*
f r a c t a l . cpp = F u n c t i on s to t re a t f r a c t a l s

By R o g e r T . S t e v e n s - 5 / 1 2 / 9 0

*I

#i n c l ude < c ty p e . h >


#i n c l ude <stri ng . h>
#i n c l ude <stdi o . h>
#i n c l ude <ma t h . h >
#i n c l ude <dos . h>
#i n c l ude " render . hpp"

gauss ( ) F u n c t i o n t o g e n e r a t e G a u s s i a n r a n d om v a r i a b l e

*/

f l o a t g a u s s ( u n s i g n e d i n t s e ed )
{
f l o a t x=O ;
i nt i ;

i f ( s eed ! = 0 )
s rand ( seed ) ;
f o r ( i =O ; i < l 2 : i ++ )
x += ( f l o a t ) ( r a n d ( ) ) / 3 2 7 6 8 . 0 ;
x -= 6.0;
return ( x ) ;

/*
M a k e_f r a c t a l _t r i a n g l e s ( ) C r e a t e f o u r n ew f r a c t a l
t r i a n g l e s f r om a t r i a n g l e

300
R E N D E R I N G F R A C TA L S C E N E S

O b j e c t * M a k e_f r a c t a l _t r i a n g l e s ( V e c t o r l o c , V e c t o r v e c t l , V e c t o r
vect2 , Vector vect3 , Obj ect *queue , i n t l evel )

V e c t o r b i s e c t l , b i s e c t 2 , b i sect3 , temp ;
u n s i g n e d i n t s e ed ;
f l o a t t e m p l , t e m p 2 , t e m p 3 , m u , m a x_h t ;
T r i a n g l e * n e w t r i O , * n ew t r i l , * n e w t r i 2 , * n ewt r i 3 ;

BBox * n ewobj ;
c o l _m a x Vector ( 63 , 63 , 63 ) ;
n ewt r i O new T r i a n g l e ;
newt r i l n ew T r i a n g l e ;
n ewt r i 2 new T r i a n g l e ;
n ewt r i 3 new T r i a n g l e ;
n ew t r i O - > c o l d a t a n e w c o l o r_d a t a ;
n ewt r i l - > c o l d a t a n e w c o l o r_d a t a ;
n ew t r i 2 - > c o l d a t a n e w c o l o r_d a t a ;
n ewt r i 3 - > c o l d a t a n ew c o l o r_d a t a ;
n ewobj = n ew BBox ;

n e w o b j - > ty p e = B B O X ;
i f ( l e v e l == W O R L D . l e v e l )
{
n ewobj - > nextobj = q ueue ;
q u e u e = n ewobj ;

el se
n ewobj - > n e x t o bj = N U L L ;
n ew t r i O - > l o c l oc ;
n ewt r i l - > l o c = l o c + v e c t l ;
n ew t r i 2 - > l o c = l o c + v e c t 2 ;
bi sectl l oc + vectl I 2 ;
bi sect2 = l oc + vect2 I 2 ;
b i s e c t 3 = n e wt r i l - > l o c + ( v e c t 2 - v e c t l ) I 2 ;
seed = ( ( u n s i gned i n t ) ( b i sect3 . x * 1 0000 + bi sect3 . y * 100 +
b i s e c t3 . z ) ) %32767 + 2 ;
b i s e c t 3 . y += g a u s s ( s e e d ) * v e c t 3 . z ;
b i s e c t 3 . y = MAX ( b i sect3 . y , 0 ) ;

301
F R A C T A L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

seed = ( ( un s i gned i nt ) ( b i s e c t l . x * 1 0000 + bi sectl . y * 1 00 +


b i s e c t l . z ) ) %3 2 7 6 7 + 2 ;
b i s e c t l . y += g a u s s ( s e e d ) * v e c t 3 . x ;
b i s e c t l . y = MA X ( b i s e c t l . y , 0 ) ;
s eed = ( ( u n s i g n e d i n t ) ( b i s e c t 2 . x * 1 0000 + b i s e c t 2 . y * 1 00 +
b i s e c t 2 . z ) ) %3 2 7 6 7 + 2 ;
b i s e c t 2 . y += g a u s s ( s e e d ) * v e c t 3 . y ;
b i s e c t 2 . y = MAX ( b i s e c t 2 . y , 0 ) ;
* n ew t r i O - > c o l d a t a d e f . c o l _d a t a ;
* n ew t r i l - > c o l d a t a d e f . c o l _d a t a ;
* n ew t r i 2 - > c o l d a t a d e f . c o l _d a t a ;
* n ew t r i 3 - > c o l d a t a d e f . c o l _d a t a ;
n ew t r i O - > v e c t l b i s e c t l - n ew t r i O - > l o c ;
n ew t r i O - > v e c t 2 b i s e c t 2 - n ew t r i O - > l o c ;
n ew t r i 1 - > v e c t l bi sect3 n ew t r i l - > l o c ;
n ew t r i l - > v e c t 2 bi sectl n ew t r i l - > l o c ;
n ew t r i 2 - > v e c t l bi sect2 n ew t r i 2 - > l o c ;
n ew t r i 2 - > v e c t 2 b i s e c t 3 - n ew t r i 2 - > l o c ;
n ew t r i 3 - > l o c = b i s e c t l ;
n ew t r i 3 - > v e c t l = b i s e c t 3 - n ew t r i 3 - > l o c ;
n ew t r i 3 - > v e c t 2 = b i s e c t 2 - n ew t r i 3 - > l o c ;
F r a c t a l _c om p ( n ewt r i O ) ;
F r a c t a l _c om p ( n ew t r i l ) ;
F r a c t a l _c om p ( n ew t r i 2 ) ;
F r a c t a l _c om p ( n ew t r i 3 ) ;
i f ( l evel > 0 )
{
l evel-;
n ew o b j - > c h i l d = M a k e_f r a c t a l _t r i a n g l e s ( n ew t r i 3 - > l o c ,
n ew t r i 3 - > v e c t l , n ew t r i 3 - > v e c t 2 ,
n ew t r i 3 - > v e c t 3 , q u e u e . l e v e l ) ;
n ew o b j - > c h i l d - > n e x t o b j = M a ke_f r a c t a l _t r i a n g l e s
( n ewt r i 2 - > l o c , n ew t r i 2 - > v e c t l ,
n ew t r i 2 - > v e c t 2 , n ew t r i 2 - > v e c t 3 , q u e u e . l e v e l ) ;
n ew o b j - > c h i l d - > n e x t o b j - > n e x t o b j =
M a k e_f r a c t a l _t r i a n g l e s ( n ew t r i l - > l o c ,
n ew t r i l - > v e c t l , n ew t r i l - > v e c t 2 ,
n ew t r i l - > v e c t 3 , q u e u e , l e v e l ) ;
n ew o b j - > c h i l d - > n e x t o b j - > n e x t o b j - > n e x t o b j =

302
R E N D E R I N G F R A C TA L S C E N E S

M a k e_f r a c t a l _t r i a n g l e s ( n ew t r i O - > l o c ,
n ew t r i O - > v e c t l , n ew t r i 0 - > v e c t 2 ,
n ew t r i O - > v e c t 3 , q u e u e , l e v e l ) ;
n ew o b j - > c h i l d - > n e x t o b j - > n e x t o b j - > n e x t o bj - > n e x t o b j NU L L ;
d e l e t e n ew t r i O ;
d e l e t e n ew t r i l ;
d e l e t e n ew t r i 2 ;
d e l e t e n ew t r i 3 ;

el se
{
n ew t r i O - > n e x t o b j NULL ;
n ew t r i l - > n e x t o b j newtr i O ;
newt r i 2 - > n e x t obj n ew t r i l ;
n ew t r i 3 - > n e x t o b j n ew t r i 2 ;
n ew o b j - > n e x t o b j = N U L L ;
n ew o b j - > c h i l d = n ew t r i 3 ;
W O R L D . o b j c o u n t += 4 ;

i f ( l e v e l == W O R L D . l e v e l )
return ( queue ) ;
re t u r n ( n ewobj ) ;

/*

F r a c t a l _c om p ( ) C om p u t e s f r a c t a l p a r a me t e r s

*/

v o i d F r a c t a l _c om p ( T r i a n g l e * n ew o b j )
{
V e c t o r temp ;
t e m p = n ew o b j - > v e c t 2 - n ew o b j - > v e c t l ;
n ew o b j - > v e c t 3 . z = t e m p % t e m p ;
n ew o b j - > v e c t 3 . z = p ow ( n ew o b j - > v e c t 3 . z / 4 , WO R L D . f r a c t a l _d i m ) *
W O R L D . f r a c t a l _s c a l a r ;
n ew o b j - > v e c t 3 . x = n e w o b j - > v e c t l % n ew o b j - > v e c t l ;
n ew o b j - > v e c t 3 . x = p ow ( n e w o b j - > v e c t 3 . x / 4 , W O R L D . f r a c t a l _d i m ) *
W O R L D . f r a c t a l _s c a l a r ;
n ew o b j - > v e c t 3 . y = n ew o b j - > v e c t 2 % n ew o b j - > v e c t 2 ;

303
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

n ew o b j - > v e c t 3 . y = p ow ( n ew o b j - > v e c t 3 . y / 4 , WO R L D . f r a c t a l _d i m ) *
W O R L D . f r a c t a l _s c a l a r ;
n ew o b j - > n o rm = n ew o b j - > v e c t l A n ew o b j - > v e c t 2 ;
n ew o b j - > n o rm = - n ew o b j - > n o rm ;
n ew o b j - > n l = n e w o b j - > n o rm % n ew o b j - > l o c ;
newobj - > l e n l n ew o b j - > v e c t l % n ew o b j - > v e c t l ;
newobj - > l en2 = n ew o b j - > v e c t 2 % n ew o b j - > v e c t 2 ;

304
CHAPTER 1 6

Quaternions and Their


Mathematics

History and Def i n ition of Quaternions

The discovery of quaternions by Sir William Hamilton in 1 843 marked the


revival of mathematics through Great Britain which provided the foundation for
important discoveries in both mathematics and physics throughout the next
century. Quaternions have many similarities to numbers (both real and complex)
but differ in having the surprising characteristic that their multiplication does not
follow the commutative law. By this we mean the following. We normally
accept as true for numbers that:

axb=bxa (Equation 1 6- 1 )

The order i n which the numbers are multiplied doesn't matter; we get the
same result no matter what order is used. For quaternions, this is not true. In
fact, we find that if a and b are quaternions then:

a x b = - (b x a) (Equation 1 6-2)

So just what is a quaternion, anyway? We may define a quaternion as


consisting of a scalar qo . and a three-dimensional vector having components ql •

qi , and qJ . directed along the mutually orthogonal axes identified by the unit
vectors i, }, and k. These vectors follow the rules for vector cross products in a
right-hand coordinate system, namely:

ij = k j i = -k

305
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

jk = i kj = -i

ki = j ik = -j (Equation 1 6-3)

and

ijk = i 2 = p = k2 = -1 (Equation 1 6-4)

We can write the quaternion as:

(Equation 1 6-5)

or alternately as:

(Equation 1 6-6)

where the underlining means that the variable is a three-dimensional vector, or:

(Equation 1 6-7)

Probably you ' re wondering just what quaternions are for, besides being an
interesting mathematical exercise. One important use is in the dynamics of
flight. Suppose we represent the position of an aircraft by an ordinary three­
dimensional coordinate system. In following the aircraft through complex
maneuvers, we often want to keep track of some quantities in a coordinate
system centered at and oriented to the aircraft and of other quantities in a
g ro u n d - b a s e d c o o r d i nate s y s t e m . T h i s i n v o l v e s a l o t o f c o o r d i nate
transformations and for certain rotations, singularities occur. These don't bother
an observer; when the aircraft angle is such that one coordinate system needs to
be rotated 90 degrees to get to another, we observe that particular angular
relationship without comment. But computers get confused when they try to
handle division by zero or find tangents that go to infinity. Thus with the usual
matrix transformations of one three-dimensional coordinate system to another,

306
Q U AT E R N I O N S A N D T H E I R M AT H E M AT I C S

computer programs have to be written with code devoted to handling singular


points. Unfortunately, if you miss only one singular point, your program may
work just fine, for a long time before the aircraft gets to the proper angle to
expose the problem.

Happily there is a technique for using quaternions to perform the rotations


required to transform from one coordinate system to another. Using quaternions,
singularities never occur, and there is no problem dealing with exceptional
points. The transformations involved when an aircraft is in all sorts of strange
positions and performing all kinds of strange maneuvers can be handled simply,
without exceptions, making the program robust.

In this book, we aren 't concerned with aircraft flight, although if you have
occasion to get into that field, you ' ll be glad to get a grounding in quaternion
mathematics. What we are going to do is apply quaternions to Julia and dragon
sets. It turns out that the same kinds of iterated equations that make use of
complex numbers to generate two-dimensional Julia and dragon sets, can be used
with quaternions to create four-dimensional Julia and dragon sets. We 'll get into
the deta i l s of t h i s later; first we have to become fam i l i ar w ith how the
mathematics of quaternions works.

Quatern ion Mathematics


Quaternion addition and subtraction can be done on a component-by­
c omponent basis j u st l ike vectors are added and subtracted. Quaternion
multiplication gets a little more complicated. Suppose we have two quaternions,
P and Q. The product is:

= Poqo + pog + qon - ill- ill + 12..XJl (Equation 1 6-8)

307
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

where J!.g_and p_x_q are the vector dot product and vector cross product
respectively as defined in any text on vector analysis. This expression has two
scalar terms (which added give one scalar) and three three-dimensional vector
terms (which added give one three-dimensional vector). The result consists of a
scalar and a three-dimensional vector (which is a quaternion) so that the product
of two quaternions is a quaternion. Note that since one of these terms is not
commutative (J! x g_ = - g_ x J!) , the quaternion multiplication is also not
commutative. Next, we define the conjugate of a quaternion, Q* . The conjugate
of the quaternion Q =qo + q is defined as Q* = qo - q. Applying the rule for
quaternion multiplication, we find that:

(Equation 1 6-9)

(Observe that g x g = 0.) The product Q*Q is a degenerate form of the


general multiplication case, in which the vector portion disappears and the result
is a scalar only. This product is called the norm of the quaternion. The norm can
take on any positive real value and, in many cases, it is useful to have it equal to
one. This is accomplished by imposing the condition on every quaternion that:

(Equation 1 6- 1 0)

When thi s condition i s imposed, the four component e lements of the


quaternion are no longer independent, since the specification of any three
components determines the value of the fourth.

308
Q U AT E R N I O N S A N D T H E I R M AT H E M AT I C S

Next, we want to consider the product of a quaternion and a vector. Given a


quaternion Q and a vector r., we impose the multiplication rule and obtain:

= q()! - (Q . r) + (g x r) (Equation 1 6- 1 1 )

Similarly,

J:Q = q()! - (r . g) + (r x g) (Equation 1 6- 1 2)

Now that we understand how to multiply a vector and a quaternion, consider


the geometric effects of such multiplications. Begin with the operation rQ. As a
matter of convenience, we are going to consider r. to be composed of two
vectors, .s_ and t The portion .s_ is perpendicular to the vector portion (g) of the
quaternion Q, and the portion l is aligned with g (parallel to g and either in the
same or the exactly opposite direction). Perform the multiplication of the .s_

portion. The result is:

liQ = q ()li._+ (£ x g) (Equation 1 6- 1 3)

Note that the dot product ordinarily produced by the multiplication drops
out, since our definition states that is perpendicular to g , making the dot
.s_

product of the pair zero. Since the result of our multiplication therefore does not
have a constant term, it is a vector, rather than a quaternion. The magnitude of
liQ is:

(Equation 1 6- 1 4)

However, we have already specified that the norm of Q is 1 , which means


that:

(Equation 1 6- 1 5)

309
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

Thus the portion of Equation 1 6- 1 4 that is under the square root sign drops
out, which means that the magnitude of ii. is unchanged. Let 's look at Figure 1 6-
1 to see what the multiplication means geometrically. Suppose that ii. is in the
plane of the paper and that g is directed inward, perpendicular to the plane of the
paper. Since the cross product is perpendicular to both vectors, ii. x g is also in
the plane of the paper. The resultant, ii.Q is thus a rotation of s about the axis that
is defined by g. S ince the magnitude of ii. remains the same; it is a rotation only,
with no scaling. The amount of this rotation is tan - 1 l gl/q0. The direction of
rotation is that of a left-handed screw in the direction g. (Incidentally, if we
perform the multiplication Qii. instead of ii.Q, the only difference is that the
rotation is in the opposite direction.)

We still have to consider the effect of multiplication of the other vector


component, l, and the quaternion. Performing the multiplication, we have:

1Q = Q1 = q ol - (g . 1) (Equation 1 6- 1 6)

The order is unimportant in the dot product, since it is commutative, the


trouble is that the result is a quaternion, which doesn't help us too much if we
are looking for a method whereby quaternions may be used to transform (rotate)
c o ordinate s y stem s . S up p o s e , however, that we take the re s u l t of thi s
multiplication and multiply i t by Q* . We obtain the following equation:

Q* 1Q = q o21 + g(g 1)
· (Equation 1 6- 1 7)

However, since g and 1 are aligned,

g(g . 1) = l gl 1 (Equation 1 6- 1 8)

which reduces Equation 1 6- 1 7 to:

Q* !Q = ! (Equation 1 6- 1 9)

31 0
Q U AT E R N I O N S A N D T H E I R M AT H E M AT I C S

Thus, this operation leaves l unchanged, resolving our worries about that
component of vector. Now we have to make sure that this operation does
nothing drastic to the s_ component. It turns out that pre-multiplication by Q* is
exactly the same as post-multiplication by Q, which means that the total effect is
to rotate s_ around g by twice the angle tan - 1 l gl /q0. So the operation Q*rQ can
be used to perform the rotation from one coordinate system to another without
any singularities occurring. An advantage is that the components of g are the
same in either coordinate system, so that the expression of the components of g
is independent of the coordinate system selected.

.s_ x g resultant .s.Q

qo.s.

into paper

Figure 1 6-1 . Geometry of Quaternion-Vector Multiplication

T h i s i s a b r i e f i n trod u c t i o n to some of the m athe m a t i c a l u s e s and


manipulations of quaternions. In the next chapter, we shall develop the C++
class Quaternion and set up its mathematical operations.

31 1
C H A PT E R 1 7

Quaternion Mathematics
with C++

In this chapter, we ' ll look in some detail a t using C++ t o define the class
Q u a te r n i o n of q u atern i o n s-tho s e m athe m a t i c al c u ri o s i t i e s d e s c ri b e d
theoretically in the previous chapter. A l l o f the information that is needed to
define quaternions for use in the ray-tracing of Julia sets and dragons is included
in two files. The first of these, qmath .hpp is a header file which contains the
definition of the class. It is listed in Figure 1 7- 1 . The second file, qmath .cpp,
contains the detailed definitions of all of the functions that are contained within
the class. It is listed in Figure 1 7-2. For the quaternion programs, the vector
mathematics has also been included in the two quaternion mathematics files, so
as to make it simpler to compile, link and execute these files. Since vector
mathematics has already been described in Chapter 4, it will not be described
here.

First, look at Figure 1 7- 1 . The class of quaternions contains four floating­


point variables, one for the real term and one for each of three coordinates of a
Cartesian coordinate system. The keyword public appears at the beginning of the
class definition, so all members of the class are available to external functions.
There are three constructors: one for use when no parameters are passed at
initialization, another for use when four floating-point variables are passed, and a
third for use when another quaternion i s passed. Thu s we c an have the
statement:

q = Quaternion(6,7 ,8,9)

31 3
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

where q is a quaternion which takes on the real value of 6 and the i, j, and k
values of 7, 8, and 9, respectively, and we can also have:

q = Quaternion()

where q is a quaternion that takes on the real i, j, and k values of 0, 0, and 0.

Figure 1 7-1 . Quaternion Mathematics Header File

I* r.======-i

qma t h . h pp H e a d e r F i l e f o r Q u a t e r n i o n M a t h em a t i c s

*I l!=======!I

#i n c l ude < s t ream . hpp>


#i n c l ude <ma t h . h >
cl ass Vector {
publ i c :
fl oat x , y , z :

Vector ( ) ;
Vector ( fl oat xl . fl oat y l , fl oat z l ) ;
Vecto r ( Vector & ) ;
V e c t o r o p e r a t o r+ ( V e c t o r & ) ;
Vector ope r a t o r - ( Vector & ) ;
Vector operato r - ( ) ;
V e c t o r o p e r a t o r= ( V e c t o r & ) ;
Vector ope rator* ( V ector & ) ;
Vector ope r a t o r* ( fl oat ) ;
Vector operator l ( fl oat ) ;
fl oat ope r a t o r% ( Vector & ) ; I I Dot product
Vector operatorA ( Vector & ) ; I I C ross product
V e c t o r o p e r a t o r- ( ) ; I I N o rm a l i z e v e c t o r
Vector mi n ( Vector & l ;
Vector ma x ( Vector & ) ;
V e c t o r Ro t a t e ( f l o a t c o s l , f l o a t s i n l , f l o a t co s 2 , f l o a t s i n 2 ) ;
V e c t o r Rev_Ro t a te ( f l o a t c o s l , f l o a t s i n l , f l o a t c o s 2 , f l o a t
s i n2 ) ;
f r i e n d o s t r e a m & o p e r a t o r < < ( o s t r e a m& , V e c t o r & ) ;

314
Q U AT E R N I O N M AT H E M AT I C S W I T H C + +

I ;

c l a s s Q u a t e r n i on
{
publ i c :
fl oat rea l , i , j , k ;
Q u a t e r n i on ( ) ;
Quatern i on ( fl oat rea l l , fl oat i l , fl oat j l , fl oat k l ) ;
Q u a t e r n i on ( Qu a t e rn i on & l ;
Q u a t e r n i o n o p e r a t o r+ ( Q u a t e r n i o n & l ;
Q u a t e r n i on ope r a t o r - ( Qu a t e r n i on & l ;
Q u a t e r n i on ope r a t o r - ( ) ;
Q u a t e r n i on ope r a t o r= ( Qua t e r n i on & l ;
Q u a t e r n i on ope r a tor* ( Qu a t e rn i on & l ;
Quatern i on ope r a t o r* ( fl oa t ) ;
Quatern i on operator/ ( fl oat ) ;
Q u a t e r n i on ope r a to r / ( Qu a t e rn i on & l ;
Q u a t e r n i o n o p e r a t o r- ( ) ; / / N o rm a l i z e q u a t e r n i o n
Quatern i on s q r ( ) ;
f r i e n d o s t r e a m & o p e r a t o r < < C o s t r e a m& , Q u a t e r n i o n & l ;
f r i end fl o a t ma g ( Quaterni on& l ;
f r i e n d f l o a t m a g_s q ( Q u a t e r n i o n & ) ;
I ;

Overload i n g of Quaternion Operators


First, we are going to look at the details of the operator overloading for the
Quaternion class (refer to Figure 1 7-2 for the listings) wherein the first two
operations, addition ( + ) and subtraction (-) of two quaternions, are very simple.
For the first, the values of each pair of like coordinates are added together; for
the second, the value of each coordinate for the second quaternion is subtracted
from the value of the like coordinate for the first quaternion. Now look at the
next function, which is overloading of - for a single quaternion only. This occurs
in expressions like:

c = -a;

where both c and a are quaternions. This will only work because the - operator

31 5
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +

is already defined in C++ as being applicable to a single variable as well as the


difference between two variables. Note that if we decided to use the operator I
as the operator for subtraction, we could only use it to define subtraction
between two quaternions, since there is no single variable variation of /.

Now, let's look at multiplication (* ) . You can trace through the code in the
previous chapter and see how the components of each variable in the quaternion
are calculated. Remember that quaternion multiplication is not commutative,
which you can check for yourself by tracing through the code.

The code for overloading of the division operator (/) is a little misleading if
you don 't examine it carefully. There are two temporary quaternions, temp] and
temp2 . Consider the denominator to be of the form a + b, where a is the real part
of the quaternion and b is the imaginary part. We begin by setting temp] to
equal a - b, then we set temp2 to be the product of the numerator and temp] . We
then recompute temp] so that it is the product (a + b)(a - b) or a2 - b2. Because
of the non-commutative nature of quaternion multiplication, it turns out that all
of the i, j, and k terms drop out of this result, so that, although it is a quaternion,
it has only a real part. This is the denominator of a fraction which is identical to
the old one, since we have multiplied numerator and denominator by the same
thing. We now get the final form of the numerator by dividing each term of
temp2 by the real part of temp] (which is the only part there is). This is a typical
technique for performing a division in complex numbers and then transforming
so that there is no complex part in the denominator. The thing that makes this
unusual is that one would think that when the non-real part of the denominator
had several orthogonal terms, the technique would fail. Fortunately, everything
that is not real cancels out in the denominator.

Next, look at the operator used to normalize a quaternion. In this case, we


want an operator that accepts only one input parameter. The - normally gives
the user the complement of an integer. Normalization simply divides all
components of the vector by its magnitude so that the resulting vector has a
magnitude of one.

31 6
Q U AT E R N I O N M AT H E M AT I C S W I T H C + +

Other Quaternion Fu nctions


There are functions that don 't make use of overloading of the quaternion
class operators. The print function is an overload of the << operator of the
ostream class to make it possible to use cout (for example) with quaternions as
well as other types of data. The form in which the quaternion is output is a
starting parenthesis, followed by the four floating-point coordinates (separated
by commas), followed by a close parenthesis (refer to Chapter 3).

We now come to a sqr function. This function simply squares a quaternion.


There appear to be several missing terms. If you work out the multiplication for
yourself, you will see that a number of pairs of terms cancel out, so that what is
given in the function is correct.

The fun c t i o n mag_sq i s a s p e c i a l i ze d m a gni tude fun c t i o n u s e d i n


determining threshold values fo r Julia sets and dragon curves. I t i s actually the
square of the magnitude of the first two terms of the quaternion, with the
remaining two terms ignored. The function getQuaternion is used to read a
quaternion from the input data file.

Figure 1 7-2. Quaternion Mathematics Function File

qma t h . cpp F u n c t i o n s for Q u a t e r n i on M a t hema t i c s

*/

#i n c l ude < s t ream . h pp>


#i n c l ude "q render . hpp"

/*
Qua te rn i on on s t ru cto r s

l �������
l� �C ��������==i
========= ==========

*/

31 7
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +

Q u a t e r n i on : : Q u a t e r n i on ( )
{
rea l = 0 ;
O;
j 0;
k 0;

Q u a t e r n i on : : Q u a t e r n i on ( f l o a t rea l l , f l o a t i l , fl o a t j l , f l o a t k l )
{
rea l = rea 1 1 ;
i1;
j jl;
k kl ;

Q u a t e r n i on : : Qu a t e r n i on ( Q u a t e r n i on & a r g )
{
rea l = a rg . real ;
a rg . i ;
j a rg . j ;
k a rg . k ;

I* r.=======;i

Quatern i on O v e r l oad of + Ope r a t o r

*/

Q u a t e r n i o n Q u a t e r n i o n : : o p e r a t o r+ ( Q u a t e r n i o n & a r g )
{
Quatern i on res ul t ;
res u l t . rea l = real + a r g . rea l ;
res ul t . i i + a rg . i ;
res u l t . j = j + a rg . j ;
res ul t . k = k + a rg . k ;
return res ul t ;

/*
Quatern i on O v e r l oad of - Ope r a t o r ( a - bl

*/

31 8
Q U AT E R N I O N M AT H E M AT I C S W I T H C + +

Q u a t e r n i on Q u a t e rn i on : : ope rator - ( Quatern i on & a rg )


{
Quatern i on res u l t ;
res u l t . rea l = rea l - a rg . rea l ; resul t . i - a rg . i ;
res u l t . j = j - a rg . j ;
res u l t . k = k - a rg . k ;
return res ul t ;

I*
Quatern i on Overl oad of - Operator ( - a )

Q u a t e r n i on Qua t e r n i on : : ope r a t o r - ( )
{
Q u a t e r n i on res u l t ;
res ul t . rea l = - rea l ;
resul t . i - i;
resul t . j = - j ;
res ul t . k = - k ;
return res ul t ;

I*
Q u a t e r n i on O v e r l o a d of * O pe r a t o r
( Qu a t e r n i on X a Q u a t e rn i on )
I 'f
Q u a t e r n i on Q u a t e r n i on : : o pe r a t o r* ( Q u a t e rn i on & a rg )
{
Quatern i on res u l t ;
res u l t . rea l = rea l * a rg . rea l - i * a rg . i - j * a rg . j - k *
a rg . k ;
resul t . i r e a l * a rg . i + i * a rg . r e a l + j * a rg . k k * a rg . j ;
res u l t . j = rea l * a rg . j + j * a rg . rea l + k * a rg . i - i * a rg . k ;
res u l t . k = real * a rg . k + k * a rg . rea l + i * a rg . j - j * a rg . i ;
return res ul t ;

I*
Q u a t e r n i on O v e r l oad of * Ope rator ( Quatern i on X a fl oat )

I 'f
31 9
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

Q u a te r n i on Q u a t e r n i on : : ope ra to r* ( f l oa t a rg )
{
Quatern i on res u l t ;
res ul t . rea l = real * a rg ;
res ul t . i i * a rg ;
res u l t . j = j * a rg ;
res ul t . k = k * a rg ;
return res ul t ;

/*
Q u a t e r n i on O v e r l o a d of I Ope r a t o r
( Qu a t e r n i on D i v i ded b y a Q u a t e rn i on )

*I

Q u a t e r n i on Q u a t e r n i on : : ope r a t o r / ( Q u a t e rn i on &a rg )
{
Q u a t e r n i o n t e mp l , t em p 2 , r e s u l t ;
temp l = Qua t e r n i on ( a r g . r ea l , - a r g . i , - a r g . j , - a rg . k ) ;
c o u t < < " N u me r a t o r : " < < * t h i s < < " \ n " ;
c o u t < < " D e n om i n a t o r : " < < a r g < < " \ n " ;
c o u t < < " M u l t i p l i e r : " < < t em p l < < " \ n " ;
temp2 = * t h i s * temp l ;
c o u t < < " N u me r a t o r p r o d u c t : " < < t em p 2 < < " \ n " ;
t em p l = a r g * t e m p l ;
c o u t < < " D e n om i n a t o r p r o d u c t : " < < t em p l < < " \ n " ;
res u l t . r e a l = temp2 . rea l I temp l . rea l ;
res ul t . i t e m p 2 . i I t em p l . r e a l ;
res u l t . j = temp2 . j I temp l . re a l ;
res u l t . k = temp2 . k I templ . re a l ;
return res ul t ;

/*
Quatern i on O v e r l oad of Ope rator

*/

Q u a t e r n i o n Q u a t e r n i o n : : o p e r a t o r= ( Q u a t e r n i o n & r v a l u e )
{
rea l = r v a l ue . real ;

320
Q U AT E R N I O N M AT H E M AT I C S W I T H C + +

rva l ue . i ;
j rval ue . j ;
k r v a l ue . k ;
return *thi s ;

/*
Q u a t e r n i on O v e r l o a d of - O pe r a t o r ( N o rma l i ze a Q u a t e rn i on )

*/

Q u a t e r n i o n Q u a t e r n i o n : : o p e r a t o r- ( )
{
Quatern i on res u l t ;
fl oat l ength ;
l en g t h = re a l *rea l + i * i + j *j + j *j ;
l ength = sqrt ( l ength ) ;
res ul t . rea l = rea l / l ength ;
resul t . i i / l ength ;
res ul t . j = j / l ength ;
res ul t . k = k/l ength ;
return res ul t ;

I*

I
P r i n t O u t Qua t e rn i on Contents

*/ l!========================================================!I

o s t r e a m & o p e r a t o r < < ( o s t r e a m& s , Q u a t e r n i o n & a r g )


{
s << · ( · << a rg . rea l << << a rg . i <<" , " << a rg . j << «
a rg . k « · ) " ;
ret urn s ;

321
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +

/*
Functi on to squa re a Quatern i on

*I

Quatern i on Quatern i on : : s q r ( )
{
Quatern i on res u l t ;
f l o a t t em p ;
temp = 2 * rea l ;
res u l t . rea l = real * real - * i - j * j - k * k;
res ul t . i temp * i ;
res ul t . j t em p * j ;
res ul t . k temp * k ;
return ( re s u l t ) ;

/*
F u n ct i on to fi n d t h e s q u a re of t h e
ma g n i tude of a Q u a te r n i on

*/

f l o a t m a g_s q ( Q u a t e r n i o n & a r g )
{
fl oat res ul t ;
res u l t = a rg . rea l *arg . rea l + a rg . i *a rg . i ;
return res ul t ;

F u n ct i on to fi n d t h e ma g n i t ude of a Q u a t e r n i on

fl o a t ma g ( Q u a t e r n i on& a rg )
{
fl oat res ul t ;
res u l t = a rg . rea l *a rg . rea l + a rg . i *a rg . i + a rg . j * a rg . j +
a rg . k*a rg . k ;
return sqrt ( res ul t ) ;

322
Q U AT E R N I O N M AT H E M AT I C S W I T H C + +

/*
Vector Con s t ructors

*/

Vector : : Vecto r ( )
I
x =
0;
y 0;
z =
0;

Vector : : Vector ( fl oat x l , fl oat y l , fl oat z l )


{
x xl ;
=

y yl ;
z zl ;
=

Vector : : Vector ( Vector & otherVector )


{
x otherVector . x ;
y otherVector . y ;
z otherVector . z ;

/*
Vector O v e r l oad of + Ope r a t o r

*/

V e c t o r V e c t o r : : o p e r a t o r+ ( V e c t o r & a r g )
{
Vector resul t ;
res ul t . x x + a rg . x ;
res ul t . y =
y + a rg . y ;
res ul t . z =
z + a rg . z ;
return res ul t ;

323
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +

I * r.=======�
Vector O v e r l oad of - Operator ( a - b )

*/

Vector Vecto r : : ope r a t o r - ( Vector & a rg )


{
Vector res ul t ;
res ul t . x x - a rg . x ;
res ul t . y y - a rg . y ;
=

res ul t . z z - a rg . z ;
=

return res u l t ;

/*
Vector O v e r l oad of - Ope r a t o r ( - a )

*/

Vector Vecto r : : ope r a to r - ( )


{
Vector res ul t ;
res ul t . x - x;
res ul t . y - y;
=

res ul t . z - z;
=

return res ul t ;

/*
V e c t o r O v e r l o a d o f * O p e r a t o r ( V e c t o r T i me s a V e c t o r )

*I

Vector Vector : : ope r a t o r* ( Vector & a rg )


{
Vector res u l t ;
res ul t . x x * a rg . x ;
res ul t . y y * a rg . y ;
=

324
Q U AT E R N I O N M AT H E M AT I C S W I T H C + +

res ul t . z z * a rg . z ;
=

return res ul t ;

V e c t o r O v e r l o a d of * Ope r a to r ( Vector Ti mes a Fl oat )

*/

V e c t o r Vect o r : : ope r a t o r* ( fl o a t a rg )
{
Vector res u l t ;
res ul t . x x * a rg ;
res ul t . y = y * a rg ;
resul t . z = z * a rg ;
return res ul t ;

V e c t o r O v e r l o a d o f I O p e r a t o r ( V e c t o r D i v i d e d by a F l o a t )

*/

V e c t o r V e c t o r : : ope r a t o r / ( f l oa t a rg )
{
Vector res ul t ;
res ul t . x x I a rg ;
res ul t . y = y I a rg ;
res u l t . z = z I a rg ;
return res ul t ;

/*
Vector O v e r l oad of Ope rator

*/

325
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

V e c t o r V e c t o r : : o p e r a t o r= ( V e c t o r & r v a l u e )
{
x r v a l ue . x ;
y rva l ue . y ;
z rva l ue . z ;
return *thi s ;

/*
V e c t o r O v e r l o a d o f % O p e r a t o r ( D o t P r o d u c t o f Two V e c t o r s )

*I

f l o a t Vecto r : : ope r a t o r% ( Vector & a rg )


{
fl o a t re s u l t ;
resul t = x*a rg . x + y*a rg . y + z*a rg . z ;
ret u rn res u l t ;

I*
Vector Ove r l oad of A Ope rator ( C ro s s P roduct
of Two Vectors )

*/

V e c t o r V e c t o r : : o pe r a t o r A ( V e c t o r & a r g )
{
V e c t o r re s u l t ;
re s u l t . x y*a rg . z - z*a rg . y ;
res u l t . y = z*a rg . x - x*a rg . z ;
re s u l t . z = x*a rg . y y*a rg . x ;
ret u r n re s u l t ;

/*
V e c t o r O v e r l o a d of - Ope r a t o r ( N o rma l i z e a V e c t o r )

*/

326
Q U AT E R N I O N M AT H E M AT I C S W I T H C + +

V e c t o r V e c t o r : : o p e r a t o r- ( )
{
Vector resul t ;
fl oat l ;
l = *t h i s % *thi s ;
l = sqrt ( l ) ;
resul t . x x/l ;
res ul t . y = y / l ;
resul t . z = z/l ;
return resul t ;

/*
max Re t u r n t h e ma x i mum of t w o v e c t o r s

*I

Vector Vecto r : : ma x ( Vector & a rg )


{
Vector res ul t ;
res ul t . x MAX ( x . a rg . x ) ;
r e s u l t . y = MA X ( y , a r g . y ) ;
r e s u l t . z = MAX ( z , a r g . z ) ;
ret u r n re s u l t ;

/*
mi n Ret u r n t h e m i n i mum o f two v e c t o r s

*I

Vector Vector : : mi n ( Vector & a rg )


{
V e c t o r re s u l t ;
resul t . x M I N ( x , a rg . x ) ;
re s u l t . y = M I N ( y , a rg . y ) ;
resul t . z = M I N ( z , a rg . z ) ;
return re s u l t ;

327
/
*

I�
I ========!I
Pri nt Out Vector Contents

*
/
o s t ream &ope r a t o r < < ( o s t re am& s . V e c t o r& a r g )
I
s << " ( " << a rg . x << << a rg . y <<" . " << a rg . z << " ) " ;
return s ;

328
CHAPTER 1 8

Julia Sets and Dragons in


Quaternions
Julia sets are derived from the iterated equation:

(Equation 1 8- 1 )

and dragon curves are derived from the iterated equation:

(Equation 1 8-2)

where both z and c are complex numbers in both equations. The results can be
plotted in the complex plane to give two-dimensional displays of unusual beauty
and i ntere s t . S i m i l ar equations c an be used to produce curves in four­
dimensions, using quaternions . The corresponding equation for a quaternion
Julia set is:

(Equation 1 8-3)

and dragon curves are derived from the iterated equation:

(Equation 1 8-4)

where c and z are quaternions. The best we can do in plotting these curves is to
take a three-dimensional slice and project it onto our two-dimensional display.
We now have many more possibilities, since rotating the basic curve in four
dimensional space gives innumerable possible displays on the computer screen.

In the last chapter, we developed the mathematics for quaternion operations


using C++ and a Quaternion class. That makes the computations easy, although

329
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

lengthy. We are going to make use of a simplified ray-tracing method using a z­


buffer. The z-buffer is a matrix of x and y points, with each pair of points having
a z height assigned to it. Later we 'll explain how all this works. Three separate
programs will be used. The first program is quater.cpp. This program performs
the quaternion calculations and stores them in the z-buffer on a disk file. The
second program, qrender. cpp , does the simplified ray tracing and stores the
results in a file similar to that used by the ray-tracing program described in
earlier chapters. The third program, quatproc.cpp, processes the color data from
the previous file and generates the color display. Now for the details.

The Header File


The fi l e qrender. hpp is the header fi l e for both the quater. cpp and
qrender. cpp files. It is listed in Figure 1 8- 1 . This file contains the #define
statements, which are used to make switch statements throughout the programs
easier to understand, along with prototypes for various functions, and a couple of
miscellaneous math functions.

Input for the Quaternion Prog ram


The first two programs require different inputs to describe the curve to be
generated. The quater. cpp program requires l imits of the display in three
dimension s , the parameters of the quaternion, the maximum number of
iterations , and the divergence boundary value. The qrender. cpp program
requires color data, position of the light source, and position of the v iewer.
Rather than having to have two separate data files to describe each curve to be
generated, all data for a curve is kept in a single file. The technique to read this
file is very similar to that used in the ray tracing program described previously.
The same input program is used for either generating quaternions, or ray tracing
them. It is stored in the file qin.cpp and can be linked to the desired file at the
appropriate time. This file is listed in Figure 1 8-2. In looking at the programs
that follow, you need to remember that the quater.cpp and qrender.cpp programs
each use only part of the data included in the qin.cpp file, but each must have
dummy variables to store all of the data, even data which it doesn 't use.

330
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S

The same parser, get_string , that was used for the ray tracing program is
u sed here . Refer to Chapter 8 for a description of how the parser works.
Although the parser is the same, the list of allowable inputs is quite different.
The function qin() processes the inputs from the data file, looping until the end
of the file is encountered. You will observe from the listing that the processing
for each input is rather simple. At the beginning of each loop through the
function, the function gets a string from the data file which identifies the type of
input. The function then enters a long switch routine and immediately goes to
the section for the particular input being processed. The actual processing is
very simple, usually involving getting one or more numbers in string form,
converting them to integer or floating point format, as needed, and storing the
result in the appropriate variable. The permissible input variable names and their
functions are described in the following sections.

Header Fi l e for Quatern i on Ray Tra c i ng Program


B y Rog e r T . Stevens 7 1 10190
-

*/

#i n c l ude <dos . h>


#i n c l ude <st ream . h pp>
#i n c l ude <stdi o . h>
#i n c l ude <ma t h . h >
#i n c l ude <stri ng . h>
#i n c l ude <con i o . h>
#i n c l ude <stdl i b . h>
#i n c l ude < c ty p e . h >
#i n c l ude "qma t h . h pp"

#d e f i n e B A C K G RO U N D 0
#d e f i n e AMB 1
#d e f i n e DI FF 2
#d e f i n e S R E F L E CT 3
#d e f i n e R E F L ECT 4
#d e f i n e F I L E_ N A M E 5
#d e f i n e FLIP 6

331
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

#de f i n e L I G H T_P H I 7
#d e f i n e L I G H T_T H E T A 8
#d e f i n e V I EW_P H I 9
#de f i n e XRES 10
#d e f i n e Y RES 11
#de f i n e XMAX 12
#d e f i n e XMI N 13
#d e f i n e Y MA X 14
#d e f i n e YMI N 15
#d e f i n e ZMAX 16
#d e f i n e ZM I N 17
#d e f i n e Q U AT E R N I O N 18
#de f i n e M A X_S I Z E 19
#d e f i n e M A X _ I T E RAT I O N S 20
#d e f i n e JULIA 21
#d e f i n e D RA G O N 22
#d e f i n e Nul l 23
#d e f i n e l a s t_n o 24

v o i d c om p u t e_c o l o r ( c h a r F i l e N a me [ 3 2 J ) ;
V e c t o r I n t e n s i ty ( i n t i . i n t j ) ;
i n t g e t_s t r i n g ( c h a r s t r i n g_b u f [ J ) ;
i nt q i n ( voi d ) ;

/*

Ma t h Defi n i t i on s

*I

#de f i n e MIN(x,y) ( (x)<(y) ? (x) (y ) )


#de f i n e MAX ( x , y ) ( ( x ) > ( y ) ? (x) (y ) )
#d e f i n e M a x ( x , y , z ) ( x >y & & x>z ? x ( y>z ? y Z))
#d e f i n e M i n ( x , y , z ) ( x <y && x<z ? x : ( y<z ? y Z))

Figure 1 8·1 Header File for Quaternion Ray Tracing Program

Backg round
This denotes a vector that represents the red, green, and blue components of
the background color of the picture. The program is set up so that when the
height of any pixel is equal to zero, that pixel is painted in the background color.

332
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S

It must be followed by one or more non-string type characters, which must be


fol l o w e d b y three numbers ( s eparated by one or more non-string type
characters), that are between zero and one.

/*

qi n( ) Func ti on to proce s s i n put data


Rog e r T . Stev e n s 7 - 1 6 - 90

*/

#i n c l ude "q rende r . hpp"

V e c t o r g e t_v e c t o r ( v o i d )
Q u a t e r n i o n g e t_q u a t e r n i o n ( v o i d )

exte rn Vector ba c kg round , ambi ent , d i ffu se , specul a r ;


e x t e r n i n t b , F l i p , d i v e r g e n c e_bo u n d a ry , m a x_i t e r a t i o n s , X r e s ,
Y res , fl a g ;
e x t e r n f l o a t L i g h t P h i , L i g h t T h e t a . V i ew P h i , X m a x , X m i n , Y ma x .
Y m i n . Zma x . Z m i n ;
exte rn Quatern i on c ;
exte rn c h a r Obj ect Fi l e [32 J ;
e x t e r n c h a r f i l e_ i n [ 3 2 J ;
c h a r s t r i n g_b u f [ 3 2 J ;
c h a r s t r i n g_ty p e s [ 1 2 8 ] [ 3 2 ] = { " B A C K G RO U N D " , " AM B " , " D I F F " ,
" S R E F L E C T " , " R E F L E C T " , " F I L E_NAM E " , " F L I P " , " L I G H T_PH I " ,
" L I G H T_T H E T A " , " V I E W_ P H I " , " X R E S " , " Y R E S " , " X M A X " ,
" X M I N " , " Y MA X " , " Y M I N " , " Z M A X " , " Z M I N " , " Q U AT E R N I O N " .
" M A X_S I Z E " , " M A X_ I T E RAT I O N S " , " J U L I A " , " D RAGO N " , N U L L I ;
F I LE *fget ;

i nt qi n ( voi d )
{
i n t Ty p e ;

fget =f o p e n ( f i l e_ i n , " r b " ) ;


wh i l e ( ! feof ( fget ) )
{

333
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

Ty p e g e t_s t r i n g ( s t r i n g_b u f ) ;
s w i t c h ( Ty p e )
{
c a s e BACKGROUND :
backg round vector ( ) ;
brea k ;
c a s e AMB :
amb i e n t g e t_v e c t o r ( ) ;
b rea k ;

case D I F F :
di ffu s e g e t_v e c t o r ( ) ;
brea k ;
case SREF LECT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
b = a t o i ( s t r i n g_b u f ) ;
brea k ;
c a s e REFLECT :
s pecul a r g e t_v e c t o r ( ) ;
brea k ;
c a s e F I L E_ N AM E :
g e t_s t r i n g ( s t r i n g_b u f ) ;
s t r c py ( O b j e c t F i l e , s t r i n g_b u f ) ;
brea k ;
case FLI P :
g e t_s t r i n g ( s t r i n g_b u f ) ;
F l i p = a t o i ( s t r i n g_b u f ) ;
brea k ;
c a s e L I G H T_ P H I :
g e t_s t r i n g ( s t r i n g_b u f ) ;
L i g h t P h i = a t o f ( s t r i n g_b u f ) ;
Li g h t P h i *= 0 . 0 1 7453925 ;
brea k ;
c a s e L I G H T_T H E T A :
g e t_s t r i n g ( s t r i n g_b u f ) ;
L i g h t T h e t a = a t o f ( s t r i n g_b u f ) ;
Li g h tTheta *= 0 . 0 1 7453925 ;
brea k ;
c a s e V I E W_ P H I :
g e t_ s t r i n g ( s t r i n g_b u f ) ;
V i e w P h i = a t o f ( s t r i n g_b u f ) ;
V i ewP h i *= 0 . 0 1 74539 2 5 ;

334
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S

b rea k ;
case XRES :
g e t_s t r i n g ( s t r i n g_b u f ) ;
X res a t o i ( s t r i n g_b u f ) ;
=

brea k ;
case Y RES :
g e t_s t r i n g ( s t r i n g_b u f ) ;
Y res a t o i ( s t r i n g_b u f ) ;
=

brea k ;

c a s e XMAX :
g e t_s t r i n g ( s t r i n g_b u f ) ;
Xmax = a t o f ( s t r i n g_b u f ) ;
brea k :
case XMI N :
g e t_s t r i n g ( s t r i n g_b u f ) ;
Xmi n = a t o f ( s t r i n g_b u f ) ;
brea k ;
case YMAX :
g e t_s t r i n g ( s t r i n g_b u f ) ;
Ymax = a t o f ( s t r i n g_b u f ) :
brea k ;
case YMI N :
g e t_s t r i n g ( s t r i n g_b u f ) ;
Ymi n = a t o f ( s t r i n g_b u f ) ;
brea k ;
c a s e ZMAX :
g e t_s t r i n g ( s t r i n g_b u f ) ;
Zma x = a t o f ( s t r i n g_b u f ) ;
brea k :
case ZMI N :
g e t_s t r i n g ( s t r i n g_b u f l :
Zmi n = a t o f ( s t r i n g_b u f ) ;
b rea k :
c a s e Q U AT E R N I O N :
c = g e t_q u a t e r n i o n ( ) ;
b rea k :
c a s e M A X_S I Z E :
g e t_s t r i n g ( s t r i n g_b u f ) :
d i v e r g e n c e_bo u n d a ry = a t o f ( s t r i n g_b u f ) ;
brea k :
c a s e M A X_ I T E RAT I O N S :

335
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

g e t_s t r i n g ( s t r i n g_b u f ) ;
m a x_i t e r a t i o n s = a t o i ( s t r i n g_b u f ) ;
brea k ;
case JULIA:
fl ag = O ;
brea k ;
c a s e D RA G O N :
fl ag = l ;
brea k ;
case Nul l :
brea k ;
defa ul t :
c o u t < < " I l l e g a l i n p u t p a r a m e t e r ty p e "
« Type « " buffe r : · "
« s t r i n g_b u f « " · . \ n " ;
ex i t ( O ) ;

fcl o s e ( fget ) ;

I*

g e t_s t r i n g ( ) Re a d s a s t r i n g o f d a t a f r om f i l e

*I

i n t g e t_s t r i n g ( c h a r s t r i n g_b u f [ J )
I
char ch ;
i nt fl a g = O , i , resul t , test ;
s t r i n g_b u f [ O J =NULL ;
r e s u l t = l a s t_n o ;
w h i l e ( ! feof ( fget ) )
{
c h = touppe r ( fgetc ( fget ) ) ;
i f ( fl ag 0)==

I
i f ( ( i s a l n um ( c h ) ) 1 1 ( c h . . l I I (ch .-. )
.
I I ( ch == . l. ll

336
J U L I A S E T S A N D D R A G O N S IN Q U AT E R N I O N S

s t r i n g_b u f [ O J ch :
brea k :

el se
{
i f ( ch -- .{.)
fl ag = 1 ;

el se
.
i f ( c h == . } )
fl ag = 0 :

f o r ( i = l : i < 3 2 : i ++ )
{
.
i f ( c h == ) ) .

{
s t r i n g_b u f [ l ] NULL :
brea k ;

c h = touppe r ( fget c ( fget ) ) ;


i f ( ( i s a l n u m ( c h ) ) I I ( c h == · ' ) I I ( ch '. ))
'

s t r i n g_b u f [ i ] = c h ;
el se
!
s t r i n g_b u f [ i ] NULL ;
brea k ;

f o r ( i =O ; i < l a s t_n o : i ++ )
!
i f ( s t r c m p ( s t r i n g_b u f , s t r i n g_ty p e s [ i ] ) 0)
!
res ul t = i :
brea k :

c o u t < < " S t r i n g b u f f e r c o n t a i n s : " < < s t r i n g_b u f < <


" w h i c h i s ty p e " < < r e s u l t < < " \ n " ;
return ( resul t ) ;

I*

337
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

g e t_v e c t o r ( ) G e t v e c t o r f r om t h e f i l e

*I

V e c t o r g e t_v e c t o r ( v o i d )
{
Vector res ul t ;
g e t_s t r i n g ( s t r i n g_b u f ) ;
res ul t . x = a t o f ( s t r i n g_b u f ) ; g e t_s t r i n g ( s t r i n g_b u f ) :
resul t . y = a t o f ( s t r i n g_b u f ) ;
g e t_s t r i n g ( s t r i n g_b u f ) ;
res ul t . z = a t o f ( s t r i n g_b u f ) :
return ( resul t ) ;

I*
g e t_q u a t e r n i o n ( ) G e t Q u a t e r n i o n f r om t h e f i l e

*I

Q u a t e r n i o n g e t_q u a t e r n i o n ( v o i d )
I
Quatern i on resul t :
g e t_s t r i n g C s t r i n g_b u f ) :
resul t . real = a t o f ( s t r i n g_b u f ) ;
g e t_s t r i n g ( s t r i n g_b u f ) ;
res ul t . i = a t o f ( s t r i n g_b u f ) :
g e t_s t r i n g ( s t r i n g_b u f ) ;
resul t . j = a t o f ( s t r i n g_b u f ) :
g e t_s t r i n g ( s t r i n g_b u f ) ;
res ul t . k = a t o f ( s t r i n g_b u f ) :
ret u r n ( resul t ) :

Figure 1 8·2. Program for Inputting Quaternion Data

338
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S

AMB
This denotes a vector that represents the color of ambient light which strikes
the quaternion object. This is the color that will appear on parts of the object
that are entirely shielded from the light source. It must be followed by one or
more non-string type characters, and be followed by three numbers (separated by
one or more non-string type characters) which are between zero and one.

DIFF
This denotes a vector that is the diffuse color of the object. This is the
inherent color of the object, which is sent to the observer when a light source
strikes the object. It must be followed by one or more non-string type characters
followed by three numbers (separated by one or more non-string type characters)
which are between zero and one.

SREFLECT
This denotes an integer that is the power used in computing Phong shading
of a curved object. It must be followed by one or more non-string type
characters, followed by an integer.

REFL ECT
This denotes a vector that represents the color of reflected light from the
quaternion object when the Phong shading is computed. It must be followed by
one or more non-string type characters followed by three numbers (separated by
one or more non-string type characters) which are between zero and one.

FI L E NAM E
This denotes a string that is the name of the file (without extension) which is
used for storage of intermediate results. The quater.cpp program generates a z­
buffer file which it stores in filename.zbf, where filename is the name you
assigned using this command. The qrender.cpp file stores the color data in a file
named filenam e . raw. It must be followed by one or more non-string type
characters, followed by a string of no more than eight characters selected from
those characters which are acceptable as part of a DOS file name.

339
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +

FLI P
This denotes an integer that determines if the display will be flipped over in
the vertical direction. It must be followed by one or more non-string type
characters, followed by either a zero if the display is not to be flipped, or a one if
the display is to be flipped.

z p li ght


y

V i ew i n g P l a n e

Figure 1 8-3. Ray Tracing Geometry for Z-Buffer System

LIG HT_PHI
This denotes an integer that represents the angle in degrees of the light
source around the z (height) axis. The geometry of the situation is shown in
Figure 1 8-3. It must be followed by one or more non-string type characters,
followed by an integer.

340
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S

LIG HT_THETA
This denotes an integer that represents the angle in degrees of the light
source off the z (height) axis. The geometry of the situation is shown in Figure
1 8-3. It must be followed by one or more non-string type characters, followed
by an integer.

V I EW PHI
This denotes an integer which represents the angle in degrees of the x-y
plane with respect to the viewing plane. It must be followed by one or more
non-string type characters, followed by an integer.

XRES
This denotes an integer which represents the resolution of the display in
pixels in the horizontal direction. In the quaternion programs, this should be the
number of the maximum column in the x direction. As there is also a zero pixel,
the number is one less than the number of screen columns. It must be followed
by one or more non-string type characters, followed by an integer.

Y RES
This denotes an integer which represents the resolution of the display in
rows in the vertical direction. In the quaternion programs, it represents the
number of the last row. Since there is also a zero row, the number is one less
than the actual row resolution of the screen. It must be followed by one or more
non-string type characters, followed by an integer.

XMAX
This denotes a floating point number which represents the maximum value
of the real part of the quaternion for which computations are to be made. It must
be followed by one or more non-string type characters, followed by a floating­
point number.

XMIN
This denotes a floating-point number which represents the minimum value

341
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

of the real part of the quaternion for which computations are to be made. It must
be followed by one or more non-string type characters, which must be followed
by a floating-point number.

Y MAX
This denotes a floating-point number which represents the maximum value
of the i part of the quaternion for which computations are to be made. It must be
followed by one or more non-string type characters, followed by a floating point
number.

Y MIN
This denotes a floating-point number which represents the minimum value
of the i part of the quaternion for which computations are to be made. It must be
followed by one or more non-string type characters, followed by a floating-point
number.

ZMAX
This denotes a floating-point number which represents the maximum value
of the j part of the quaternion for which computations are to be made. It must be
followed by one or more non-string type characters, followed by a floating point
number.

ZMIN
This denotes a floating-point number which represents the minimum value
of the j part of the quaternion for which computations are to be made. It must be
followed by one or more non-string type characters, followed by a floating-point
number.

QUATERNION
T h i s denotes the c o n stant quatern i o n w h i c h is u s e d in the iterated
calculations. It must be followed by one or more non-string type characters,
followed by four numbers (separated by one or more non-string type characters).

342
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S

MAX_SIZE
This denotes the floating-point number which is the size of the specialized
square of the iterated quaternion which is considered to be the divergence
boundary. When the quaternion reaches this value, it is considered to have
diverged and no further iterations are performed. It must be followed by one or
more non-string type characters, followed by a floating-point number.

MAX_ITERATIONS

This denotes an integer which represents the maximum number of iterations


of the iterated equation which are to take place. If the quaternion has not
exceeded the divergence boundary after this many iterations, the process
terminates and the quaternion is considered not to have diverged. It must be
followed by one or more non-string type characters, which must be followed by
an integer.

J ULIA
This indicates that a quaternion Julia Set is to be computed.

DRAGON
This indicates that a quaternion dragon curve is to be computed.

I*
C++ Q u a t e r n i o n F r a c t a l G e n e r a t o r
Jul i a Sets = f( q ) = q * q + c
Dra gon Cu rves f(q) = c * q * (q - 1)
By R o g e r T . S t e v e n s 7 - 1 1 - 9 0

*I

#i n c l ude <dos . h>


#i ncl ude <st ream . hpp>
#i n c l ude <stdi o . h>
#i n c l ude <ma t h . h >
#i n c l ude <stdl i b . h>

343
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

#i n c l ude "q rende r . hpp"

voi d j ul i a ( voi d ) ;
voi d d ragon ( voi d ) ;

V e c t o r b a c k g r o u n d , a mb i e n t , d i f f u s e , s p e c u l a r ;
i nt X res , Y res , Zres ;
i nt Hei ght [800 J ;
i n t s c a l e_fa c t o r , d i v e r g e n c e_b o u n d a ry , m a x_i t e r a t i o n s , i , k , r ow
col .
n o_o f_i t e r a t i o n s . b , F l i p , f l a g , T y p e ;
f l o a t X m a x , X m i n , Y m i n , Y m a x , Z m i n , Z m a x , d x , dy , d z , x , y , z ,
del taZ .
z v a l . Z F a c t o r . L i g h t P h i , L i g h t T h e t a . V i ew P h i ;
F I LE *fs ave ;
cha r Obj ectFi l e [ 3 2 J ;
Q u a t e r n i o n q , c , q_s q ;
c h a r f i l e_ i n [ 3 2 J ;

/*

L
I
Ma i n P rogram

- ========!I

*/
ma i n ( i n t a r g c , c h a r * a rg v [ J )
{
s t r c py ( f i l e_i n , a r g v [ l ] ) ;
qi n ( ) ;
p r i n t f ( " X re s : %d Y res : %d\ n " , X res , Y res ) ;
pri ntf( "XMax : %f XMi n : %f\ n " , Xmax , Xmi n l ;
pri ntf ( "YMax : %f YMi n : %f\ n " , Ymax , Ymi n ) ;
p r i n t f ( "ZMa x : %f Z M i n : % f \ n " , Zm a x , Z m i n ) ;
strca t ( Obj ectFi l e , " . zbf" ) ;
Zres = 256 ;
q = Quater n i on ( 0 , 0 , 0 , 0 ) ;
s c a l e_fa c t o r = 32767 I Zres ;
Z Fa c t o r = ( f l o a t ) s c a l e_fa c t o r I ( 2 * ( Z m a x - Zm i n ) ) ;
fsave = f o p e n ( O b j e c t F i l e , " wb " ) ;
fw r i t e ( & X r e s , 1 , 2 , f s a v e ) ;
fw r i t e ( & Y r e s , 1 , 2 , f s a v e ) ;
fw r i t e ( & s c a l e_fa c t o r , 1 , 2 , f s a v e ) ;

344
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S

dx C f l o a t l C Xm i n - Xma x ) I X re s ;
dy C f l oa t ) ( Ym i n - Yma x ) I Y re s ;
dz ( f l o a t ) ( Zm a x - Z m i n ) I Z r e s ;
f o r C c o l =O ; c o l <=X r e s ; c o l ++ )
{
x = Xmax + col * dx ;
f o r C r ow=O ; r ow<=Y r e s ; r o w++ )
{
y = Y m a x + r o w * dy ;
d e l t a Z = 0 . 5 * C Zm a x - Z m i n ) ;
z = Zmi n ;
i f C f l a g == 0 )
j ul i a ( ) ;
el se
dragon ( ) ;
i f C n o_o f_i t e r a t i o n s < m a x_i t e r a t i o n s )
H e i g h t [ rowJ = Zmi n * Z Fa c to r ;
el se
{
z =Zma x ;
i f C f l a g == 0 )
j ul i a ( ) ;
el se
d ragon ( ) ;
i f C n o of i t e r a t i on s
m a x_i t e r a t i o n s )
H e i g h t [ r o w ] = Zma x * Z F a c t o r ;
el se
{
z -= del taZ ;
f o r ( k=O ; k < 7 ; k++ )
{
d e l t a Z *= 0 . 5 ;
i f ( f l a g == 0 )
j ul i a ( ) ;
el se
dragon ( ) ;
i f ( n o_o f_i t e r a t i o n s <
m a x_i t e r a t i o n s )

zval = z ;
z - = del taZ ;

345
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

el se
z += d e l t a Z ;

Hei g h t [ row] = zva l * ZFactor ;

fw r i t e ( & H e i g h t , 2 , Y r e s + l , f s a v e l ;
c o u t < < " \ n P r oce s s i n g c o l umn # " < < c o l ;

cout « \n
\n"
« \n"
< " P r o c e s s i n g C om p l e t e . \n" ;
pri ntf ( " Data i n Fi l e : %12s \ n " , Obj ectFi l e l ;
cout « " \n"
..
<< " \n ;
fcl ose ( fsave ) ;

/*
j ul i a ( ) Funct i on to gen e r a te J u l i a Set

*/

voi d j ul i a ( voi d )
{
no of i terati ons = O ;
q = Ouatern i on ( x , y , z . 0 ) ;
w h i l e ( ( n o o f i te r a t i o n s < max i te r a t i o n s ) &&
( m a g_s q ( q ) < d i v e r g e n c e_bo u n d a ry ) )

q = q . sq r ( ) ;
q = q + c;
n o_o f_i t e r a t i o n s ++ ;

/*

346
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S

dra gon ( ) Funct i on to gene rate d ragon curves

*/
voi d d ra gon ( voi d )
{
no of i terati ons 0;
=

q = Quatern i on ( x , y , z , 0 ) ;
w h i l e ( ( n o_of_i t e r a t i o n s < m a x_i t e r a t i o n s ) &&
( m a g_s q ( q ) < d i v e r g e n c e_b o u n d a ry ) )

q_s q = q . sq r ( ) ;
q = q q_s q ;
-

q = c * q;
n o_o f_i t e r a t i o n s ++ ;

Figure 1 8-4. Listing of Quaternion Fractal Generator

Computi ng the Quaternions


Figure 1 8-4 lists the quaternion fractal generator. The main program is
called with a command line argument which is the name (including extension)
asthe file containing data on the curve to be generated. The program begins by
transferring this file name to file_in. It then calls qin to read the data from the
file. Next it displays various parameters, which the user can check to assure that
the correct data file is being processed. Next, the program appends the extension
.zbf to the output file name that was read from the data file. It then assigns a
value of 256 for the resolution in the z direction. (The x and y resolutions are
read from the data file.) The initial value of the quaternion q is set to zero to
begin the iteration process. The program then computes the scale factor. The
scale factor is a height multiplier used to multiply heights that are a fraction of
one, by as large a number as possible without the maximum height exceeding the
largest possible signed integer. The output file is then opened and the x and y
resolutions and the scale factor are written out to it. Next, the incremental change
(dx, dy, and dz) in x, y, and z for one pixel movement in the x or y direction or

347
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

one resolution element in the z direction are computed. The program enters a
pair of nested for loops to enable it to determine a height value for each pixel in
the xy plane. If we were going to take the simple approach, we 'd just make
another loop, this time through z, starting with the lowest value. At the first
increment where the iterated equation blew up, we 'd stop and record this value
of z in our height matrix. Unfortunately, this takes too long, so we 're going to
make use of a binary searching technique. We first perform the iterations for the
minimum value of z. If this doesn 't blow up, we try again for the maximum
value. If this doesn't blow up either, our search is over and we set the height to
the maximum value. If the maximum value causes blow up, we try again for a
value half way between the two extremes. If this blows up, we work our way
down in an increment half the size of the previous one; if it doesn't blow up, we
move upward by the same increment. In this way, we can move through 256
levels of height with only eight steps. There is one thing we need to be careful
about. After we have performed the eight sets of iterations, the last attempt either
does or does not cause blow up. If it doesn't, then it is the proper value for the
height matrix, but if it does, then the previous value of z is the one that should be
used. Therefore, we always save the previous value, so that it will be available if
we need to load it into the matrix.

The functions julia and dragon perform the quaternion iterations. A flag is
set by the input from the data program to determine which function is used. You
can easily determine that these functions iterate the equations shown above.
After a full line of the matrix has been filled with height values, this line is
written to the output file. When the program ends, it displays a message which
includes the name of the output file. The output file is then closed and the
program terminates.

Ray Traci ng the Object


We now have a file full of height data, so we need to process it to obtain
color v alues for a display. The program qrender.cpp , listed in Figure 1 8-5,
performs this function. As with the quaternion program, this program passes an
argument on the command line which is the name of the data file. The program

348
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S

begins by transferring this file name to the variable file_in. Next it displays a title
and then zeroes the height buffer. Then qin is called to read the input data. The
program opens a file having the file name and the extension .zbf as the file from
which to read the height data, and another file having the file name and the
extension .raw as the output file for the color data. The names of these files are
displayed. Next, the values for SinViewPhi and CosViewPhi are computed for
the angle which came from the input data file. These are then used to define the
view vector. The value of the light vector is also determined. The program then
reads the values of Xres and Yres from the height file and displays them on the
screen. It then displays, "Hit any key to continue . . . " and waits for a keystroke.

The purpose of this program is to generate a file of pixel color data which
can be processed to render a 256 color-shaded display. However, for quick
observation of what is going on, the functions setMode and plot have been
included and the program thereby plots a pixel each time that it is saving the
pixel color data to a file. The data is plotted in EGA 1 6 color mode, which
makes i n tere sting, if not real i st i c , displays, and also permits you to see
something if you don't have a VGA display. The next thing that the program
does is to set the display to a graphics mode using setMode. It then continues by
reading the Scaling factor from the height file and writing it and the resolution
parameters to the color output file. Next, the program reads the first row of
height data from the height file. (The height buffer contains room for two rows
of data, which are needed in determining the normal surface vector. Modulus
arithmetic is used to define the height array addresses from here on, so that as
each row i s c ompleted , a new row of height data is read into the buffer,
overwriting the one that is no longer needed.) The program now enters a pair of
nested for loops, which, for each column, scan an entire row, performing the
necessary processing. At the beginning of each pass through the column loop,
the program reads another row of height data.

The next thing that the program does is to compute the first point. It does
this by taking the first height value together with its x and y coordinates and,
making use of the viewing angle, projecting it onto the viewing plane. The

349
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

resulting y v alue i s also set as the horizon. Before proceeding further, the
program sets all of the values of the red, green, and blue column arrays to the
background color. Next, the program loops through the column, from bottom to
top; at each pass through the loop, the appropriate height value is projected onto
the viewing plane. If it is above the horizon, the intensity of the color at that
point is obtained and, if the height is greater than zero, the color is stored in the
color arrays for the projected row value. At the same time, the function Pixel
plots two adjacent columns with the color which is the green color value divided
by three. If you aren 't interested in the instantaneous EGA plot, you can remove
this and the next call to Pixel, and the program will then only generate the color
data file. The program then finds the intensity of the color of the next value in
the column that is to be plotted. Since this is projected onto the viewing plane,
the next value may not be the adjacent pixel of the screen display. If this is the
case, the program interpolates between the colors of the two pixels to fill in the
pixels that were skipped due to projection. Each new pixel value is saved to the
output file and displayed on the instantaneous display. When the end of the row
loop is reached, the column number is written out to the color data file, followed
by the whole column of red data, the column of green data, and the column of
blue data. The program then loops through the next column. After all columns
have been processed, an output message is displayed which includes the name of
the color output data file. Both input and output files are then closed and the
program terminates.

/*
Z - Bu ffe r Rende r i ng P ro g r a m

Rog e r T . S t e v e n s 7 - 24 - 9 0

*/

#i n c l ude "q rende r . hpp"

voi d cl s ( i nt col o r ) ;
voi d pl ot ( i nt x , i nt y , i nt col o r ) ;
v o i d s e tMode ( i n t mod e ) ;

350
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S

voi d Pi xel ( i nt x . i nt y , i nt col or ) ;

c h a r Obj ect Fi l e [ 3 2 J ;
c h a r f i l e_i n [ 3 2 J ;
i n t X r e s , Y r e s , Z r e s =2 5 5 ;
i nt Hei ght [ 2 ] [800 J ;
i n t S c a l i n g , m a x_c o l o r= 6 3 , m a x_i t e r a t i o n s , f l a g ;
V e c t o r v i ew ; I I g l o b a l v i ew v e c t o r
Vector l i ght ; I I g l oba l l i g ht vector
f l o a t V i ew P h i , V i ewT h e t a , S i n V i ew P h i , C o s V i ewP h i , L i g h t P h i ,
Li ghtTheta ,
X m a x , X m i n , Y m a x , Y m i n , Z m a x , Z m i n , d i v e r g e n c e_b o u n d a ry ;
F I LE *fget , *fsave ;
i n t m , i , j , k , p , pO , p l , h o r i z o n ;
V e c t o r P i x , n ew P i x , o l d P i x ;
f l o a t h , t e mp ;
c h a r F i l eNameOut [ 3 2 J ;
i nt Ti l t . Fl i p ;
V e c t o r ambi e n t ; I I p e r c en t a g e o f amb i e n t l i g ht
V e c t o r d i f f u s e ; I I p e r c e n t a g e o f d i f f u s e l i g h t f r om r e f l e c t i o n
gra i nul a r
V e c t o r s p e c u l a r ; I I p e r c e n t a g e o f s p e c u l a r l i g h t f r om r e f l e c t i o n -
Eucl i di an }
Vector bac kg round ;
i nt b = 2 ; I I shi ni ness
i n t Ty p e , t y p e , i n t e g e r :
c h a r red [ 80 0 ] , g r een [ 800 J , b l ue [ 800 J ;
Quatern i on c ;

I*
Ma i n Program

*I
ma i n ( i n t a r g c , c h a r * a rg v [ J )
{
s t r c py ( f i l e_i n , a r g v [ l ] ) ;
p r i n tf ( " Z - Buffer Rende ri ng P rogram\n \ n " ) ;
f o r ( i =O ; i < 2 ; i ++ )
f o r ( j =O ; j <=Y r e s ; j ++ )
Hei ght[ i ] [j ] O;

351
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

qi n ( ) ;
s t r c py ( F i l e N a m e O u t , O b j e c t F i l e ) ;
strcat ( Obj ectFi l e , " . zbf" ) ;
s t r c a t ( F i l e N a meO u t , " . raw " ) ;
cout << "\nSa v i ng " << Fi l eNameOut << " \ n " ;
f s a v e = f o p e n ( F i l e N a me O u t , " w b " ) ;
cout << " \ n load i ng " << Obj ectFi l e << " \ n " ;
fget = fopen ( O bj e c t F i l e , " rb " ) ;
S i n V i ew P h i= s i n ( V i ew P h i ) ;
C o s V i ew P h i = c o s ( V i ew P h i ) ;
v i ew = V e c t o r ( O , - C o s V i e w P h i , S i n V i ew P h i ) ;
l i g ht = Vector ( s i n ( Li g h tTheta ) * cos ( L i g h t P h i ) ,
s i n ( Li ghtTheta ) *
s i n ( L i g h t P h i ) , c o s ( L i g h t T i� e t a ) ) ;
fget = fopen ( Obj ect F i l e , " r b " ) ;
frea d ( &Xres , 2 , 1 , fget ) ;
frea d ( &Y res , 2 , 1 , fget ) ;
c o u t < < " Re s o l u t i o n i s " < < X r e s < < " p i x e l s by " < < Y r e s < < "
r ow s . \ n " ;
c o u t « " H i t a ny k e y t o c o n t i n u e . . . \ n " ;
s etMode ( OxO E ) ;
f r e a d ( &Sc a l i n g , 2 , 1 , fge t ) ;
fw r i t e ( & X r e s , 2 , 1 , f s a v e ) ;
fw r i t e ( & Y r e s , 2 , 1 , f s a v e ) ;
fw r i t e ( & S c a l i n g , 2 , 1 , f s a v e ) ;
fre a d ( &Hei g h t [ O J [ O J , 2 , Y res+l , fget ) ;
f o r ( i =O ; i < ( X r e s - 1 ) ; i ++ )
{
f r e a d ( &H e i g h t [ ( i +l ) % 2 J [ O J , 2 , Y r e s+l , fget ) ;
pO = ( f l o a t ) Z r e s * ( ( H e i g h t [ i % 2 J [ O J I ( f l o a t ) Sc a l i n g ) *
C o s V i ew P h i ) ;
h o r i z o n = pO ;
f o r ( j =O ; j < Y r e s ; j ++ )
I
r e d [ j ] = b a c k g r o u n d . x * m a x_c o l o r ;
g reen [ j ] = b a c k g r o u n d . y * m a x_c o l o r ;
b l u e [ j ] = b a c k g r o u n d . z * m a x_c o l o r ;

f o r ( j = l ; j < Y r e s ; j ++ )
{
p l = ( f l o a t ) Z r e s * ( ( j I ( ( f l o a t ) Z r e s ) ) * S i n V i ew P h i +
( He i g ht [ i % 2 J [j ] I ( fl oat ) Sca l i ng ) *

352
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S

C o s V i ew P h i ) ;
i f ( p l > hori zon )
{
o l d P i x = I n t e n s i ty ( i , j ) ;
Pi xel ( i , pl , ol dPi x . y /3 ) ;
i f ( H e i g h t [ i % 2 ] [ j ] ! =0 )
{
red [ p l J = ol d P i x . x ;
g reen [ p l J = ol d P i x . y ;
bl ue[pl J = ol dPi x . z ;

el se
{
r e d [ p l J = b a c k g r o u n d . x *m a x_c o l o r ;
g r e e n [ p l J = b a c k g r o u n d . y * m a x_c o l o r ;
b l u e [ p l ] = b a c k g r o u n d . z * m a x_c o l o r ;

p pl - l ;
n ew P i x = I n t e n s i ty ( i , j - 1 ) ;
whi l e ( p > hori zon )
{
h = ( f l o a t ) ( p - p O ) I ( f l o a t ) ( p l - pO ) ;
P i x = ( ( o l d P i x * h ) + ( n ew P i x * ( 1 -
h ) ) ) / m a x_c o l o r ;
Pi xel ( i , p , Pi x . y/3 ) ;
i f ( H e i g h t [ i % 2 ] [ j ] ! =0 )
{
red [ p ] = Pi x . x ;
g reen [ p ] = Pi x . y ;
bl ue [ p ] = P i x . z ;

el se
{
r e d [ p J = b a c k g r o u n d . x*ma x_c o l o r ;
g r e e n [ p ] = b a c k g r o u n d . y *ma x_c o l o r ;
b l u e [ p ] = b a c k g r o u n d . z * m a x_c o l o r ;

p- ;

hori zon pl ;

pO pl ;

353
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

fw r i t e ( & i , 2 , 1 , f s a v e ) ;
fw r i t e ( & r e d [ O J , 1 , Y r e s + l , f s a v e ) ;
fw r i t e ( & g r e e n [ O J , l , Y r e s + l , f s a v e ) ;
fw r i t e ( & b l u e [ O J , l , Y r e s + l , f s a v e ) ;

getch ( ) ;
cout « \n \n"
« .. \n"
« .. P r o c e s s i n g C om p l e t e . \n" ;
pri ntf ( " Data i n Fi l e : %12s \ n " , F i l e NameO ut ) ;
cout « " \n"
« .. \n" ;
fc l o s e ( fget ) ;
fcl ose ( fsave ) ;

/ * r.===
====a
pl ot ( ) =Pl ots a poi n t a t ( x , y ) i n col or
f o r E n h a n c e d G r a p h i c s Ad a p t e r . u s i n g T u r b o C p o r t
output funct i on s

*/

voi d pl ot ( i n t x . i n t y , i nt col o r )
{
#d e f i n e d a t a O u t ( r e g , v a l u e ) { outp( Ox3C E . reg ) ; \
outp ( Ox3C F . va l ue ) ; I
#d e f i n e E G A a d d r e s s O x A O O O O O O O L

u n s i g n e d c h a r m a s k , d ummy ;
c h a r f a r * c o l o r_a d d r e s s ;
c o l o r_a d d r e s s = ( c h a r f a r * ) ( E GA a d d r e s s +
( ( l o n g l y * 80 L + ( ( l on g ) x I B L ) ) ) ;
ma s k = Ox80 > > ( x % 8 ) ;
d u mmy = * c o l o r_a d d r e s s ;
dataOut ( O , col o r ) ;
d a t a O ut ( l , OxO F l ;
data0ut ( 3 , 0 ) ;
d a t a 0 u t ( 8 , ma s k ) ;
* c o l o r_a d d r e s s &= O x F F ;
dataOut ( O , O l ;

354
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S

dataOut ( l , 0 ) ;
data0ut ( 3 , 0 ) ;
data0ut ( 8 , 0xFF ) ;

/*
setMode ( ) Sets V i deo Mode

*/

u n i on REGS reg ;

v o i d s etMode ( i n t mode )
{
reg . h . a h = O ;
re g . h . a l = mode ;
i nt86 ( Ox l O , & reg , & reg ) ;

/*
Pi xel ( ) p l o t s two a d j a c ent p i x e l s on s c reen

*/

voi d Pi xel ( i nt x . i nt y , i nt col o r)


{
p l o t ( 2*x , Y r e s - y , c o l o r ) ;
p l o t ( 2 * x+l , Y r e s - y , c o l o r ) ;

/*
I n t e n s i ty ( ) F i n d s l i g h t i n t e n s i ty a t a p o i n t

*/
V e c t o r I n t e n s i ty ( i n t i . i n t j )
{
V e c t o r n l . n 2 , d i f f e r e n c e , n o r m a l . r e f l e c t e d . t emp ;
fl oat CosTheta . CosAl pha ;

355
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

nl V e c t o r ( ( Xma x - Xmi n ) / ( X r es+l ) , 0 , ( f l o a t ) (


H e i g h t [ ( i +l ) %2 ] [ j ] -
Hei g ht [ i %2 ] [ j ] ) ) ;
n2 V e c t o r ( O , ( Y ma x - Ymi n ) / ( Y r es+ l ) ,
( f l oa t ) ( He i g ht [ i %2 J [ j +l ]
Hei ght [ i %2 ] [ j ] ) ) ;
n o rma l = n l " n 2 ;
n o rma l = -n o r m a l ;
C o s T h e t a = n o rma l % l i g h t ;
i f ( CosTheta < 0 )
r e t u r n ( a m b i e n t * m a x_c o l o r ) ;
el se
(
r e f l e c t ed = ( n o rma l - l i g h t ) * ( 2 . 0 * C o s T h e t a ) ;
C o s A l p h a = v i ew % r e f l e c t e d ;
t em p = s p e c u l a r * p ow ( C o s A l p h a , b ) + a m b i e n t +
( d i ffu se *
CosTheta ) ;
t em p = t em p * m a x_c o l o r ;
retu rn ( temp ) ; )

Figure 1 8-5. Program to Ray Trace a Quaternion

Determ i n i ng the Color of a Pixel


The intensity of a color is determined by the part of the above program that
makes up a function called Intensity. It begins by finding a vector normal to the
quaternion surface at a designated point in the height matrix. First, a vector is
defined which begins at the designated point and height and proceeds to the
point represented by the next x, the same y, and the next height. Next, another
vector is defined which goes from the designated point and height to the same x,
the next y, and the next height. We end up then with two orthogonal vectors on
the surface. We then take the cross product of these, which is a vector normal to
the surface. This is then normalized to be a unit vector. We next find the cosine
of an angle theta , which is the angle between the light source vector and the
normal vector. This is found by taking the dot product between the two vectors.

356
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S

If this angle is less than zero, we return the ambient light value. This is the light
from the object surface when it is not directly illuminated by the light source. If
the angle is greater than zero, the color of the pixel is made up of the sum of
three components. The first is the ambient color, the second is the diffused
color multiplied by the cosine of the angle theta, and the third is the specular
reflection. To find this, first find the reflected vector, which is the vector which
is the difference between the light vector and the normal vector multiplied by
twice the cosine of theta. Then take the cosine of the angle between the reflected
vector and the viewing vector and raise it to a power that is specified in the input
data fi l e . This i s the Phong shading mode l . You may select the power
(SREFLECT in the input data file) to give the kind of highlights that you desire.
The result of this operation multiplied by the specified reflected color gives you
the third component of pixel color.

Producing the Color Pictu re


We now have a color data file and a color picture whose colors are more
abstract than actual. To produce the shaded picture, use the program quatproc.c.
This program is listed in Figure 1 8-6. It is like the colproc program that was
described in Chapter 1 4, except that it scans columns rather than rows. (The
column scanning is necessary with the Z- buffer, since some of the projected
values may overlap, and if they do, we want the highest altitude to override the
others.)

/*
quadproc P r o g r a m t o P r o c e s s V GA C o l o r D a t a f o r
Quaterni ons

*/
#i n c l ude <dos . h>
#i n c l ude < s t d i o . h >

voi d g o t o xy ( i n t x , i n t y ) ;
voi d pl ot ( i n t x , i n t y , i nt col or ) :
voi d s etMode ( i n t mode ) ;
voi d s e t V GA p a l e t t e ( u n s i g n e d c h a r * b u f f e r ) :

357
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

voi d sort ( un s i gned i nt sta rt , unsi gned i n t end ) ;

typed ef s t r u c t
{
c h a r Red ;
cha r G reen ;
cha r Bl ue ;

RGB ;

e n um { r e d =O , g r n = l , b l u=2 ) ;

u n i on REGS reg ;
st ruct SREGS i n reg ;

#d e f i n e MA X X R E S 800 /* set max hori z coord expected


*/
u n s i g n e d i n t C o l _A r r a y [ 2 5 6 ] [ 2 J ;
u n s i g n e d c h a r P a l _A r r a y [ 2 5 6 ] [ 3 J ;
RGB Col o r , C ol o r 2 :

i n t i , k , x r e s , y r e s . l a s t_c o l o r . s c a n l i n e , r l , r 2 , g l , g 2 , b l , b 2 ;
u n s i g n e d c h a r r [ M A X X R E S J , g [ MA X X R E S J , b [ MA X X R E S J ;
F I L E * f i l e_l ;
u n s i g n e d c h a r f a r * c o l o r_h i s t ;
l o n g i n t c o l o r_n o ;
u n s i g n ed i n t j ;
u n s i g n e d c h a r f r e q u e n cy [ 8 1 9 2 J ;
u n s i g n ed i n t h u e s [ 8 1 9 2 J ;

v o i d ma i n ( a r g c , a rg v )

i nt a rgc ;
c h a r *a rg v [ J ;

i nt i ndex ;
i nt rgbi ndex ;
i nt xl ;
u n s i g n e d i n t d l , t e m p_d ;
unsi gned cha r d2 ;

358
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S

s etMode ( 3 ) ;
i f ( a rgc ! = 2 )
{
p r i n t f ( " V GA C o l o r P r o c e s s o r f o r Q u a t e r n i o n s by "
" Roge r Steven s \ n " ) ;
p r i n t f ( " U s a g e : % s f i l e n a me . RAW \ n " , a r g v [ O J ) ;
ex i t ( l ) ;

i f ( ( f i l e_ l = f o p e n ( a r g v [ l J , " r b " ) ) == N U L L )
{
p r i n t f ( "Cou l dn ' t open fi l e %s \ n " , a rg v [ l ] ) ;
exi t ( l ) ;

c o l o r_h i s t = f a r m a l l o c ( 3 2 7 6 8 ) ;
f o r ( i =O ; i < 2 5 6 ; i ++ )
{
P a l _A r r a y [ i J [ r e d J O;
P a l _A r r a y [ i J [ g r n J 0;
P a l _A r r a y [ i J [ b l u J 0;

f o r ( j =O ; j < 3 2 7 6 8 ; j ++ )
c o l o r_h i s t [ j ] = 0 ;
xres = y res = O ;
f r e a d ( & x r e s . s i z e o f ( i n t ) , l , f i l e_l ) ;
f r e a d ( &y r e s , s i z e o f ( i n t ) , l , f i l e_l ) ;
p r i n t f ( " V GA c o l o r p o s t - p r o c e s s o r f o r Q u a t e r n i o n s by "
" Rog e r Steven s \ n " ) ;
p r i n t f ( " I m a g e f i l e r e s o l u t i o n i s : % d by % d \ n " , x r e s , y r e s ) ;
f o r ( i =O ; i < 2 5 6 ; i ++ )
{
P a l _A r r a y [ i J [ r e d J O;
P a l _A r r a y [ i J [ g r n J O;
P a l _A r r a y [ i J [ b l u J O;

xl = O ;
pri ntf( "Col l ecti ng col or data [ ]") ;
w h i l e ( ! f e o f ( f i l e_l ) )
{
f r e a d ( & s c a n l i n e , s i z e o f ( i n t ) , l , f i l e_l ) ;
i f ( s c a n l i n e >= x r e s )
{
p r i n t f ( " F a u l ty d a t a f i l e . \ n " ) ;

359
F R A CTA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

exi t ( l l :

g o t oxy ( 2 4 , 3 l ;
pri ntf( "%d" , scanl i ne l :
f r e a d ( & r [ O J , s i z e o f ( c h a r ) , y r e s + l , f i l e_l l :
f r e a d ( & g [ O J , s i z e o f ( c h a r l , y r e s + l , f i l e_l l :
f r e a d ( & b [ O J , s i z e o f ( c h a r ) , y r e s + l , f i l e_l ) ;
f o r ( i n d e x=O ; i n d e x < =y r e s ; i n d e x++ )
{
C o l o r . Re d ( r [ i ndexJ & Ox3e l ;
Col or . Green ( g [ i ndex ] & Ox3e l :
Col o r . B l ue ( b [ i ndex ] & Ox3e ) ;
c o l o r_n o = ( C o l o r . Re d » 1 ) I ( C o l o r . G r e e n «
4) I
( C ol or . B l ue << 9 ) ;
i f ( c o l o r_h i s t [ c o l o r_n o J < 2 5 5 )
c o l o r_h i s t [ c o l o r_n o ] ++ ;

x l += 1 ;

l a st col or = - 1 ;
f o r ( j =O : j < 3 2 7 6 8 ; j ++ l
{
i f ( c o l o r_h i s t [ j ] > 0 )
{
l a s t_c o l o r++ ;
h u e s [ l a s t_c o l o r J j:
f r e q u e n cy [ l a s t_c o l o r J c o l o r_h i s t [ j J ;

p r i n t f ( " \ n T h e r e a r e % d c o l o r s . " , l a s t_c o l o r l :


pri ntf( " \nSta rti ng sort . " ) ;
s o r t ( O , l a s t_c o l o r l :
p r i n t f ( " \ n S o r t c ompl eted . " ) ;
p r i n t f ( " \ n M o d i fy i n g e x t r a c o l o r s ]") ;
f o r ( i =O : i < 2 5 6 ; i ++ )
f r e q u e n cy [ i ] = i :
f o r ( i =2 5 6 ; i <= l a s t_c o l o r : i ++ )
{
g o t o xy ( 2 5 , 7 l ;
pri ntf( "%5d" , i l :
dl = 32768 ;

360
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S

f o r ( j =O ; j < 2 5 6 ; j ++ )
{
C o l o r . Re d = ( h u e s [ i ] < < l l & O x 3 E ;
Col o r . G reen = ( h ues [ i ] >> 4 ) & Ox3 E ;
C o l o r . B l ue = ( h ue s [ i ] > > 9 ) & Ox3 E ;
C o l o r 2 . Red = ( h u e s [ j ] < < l l & O x 3 E ;
Col o r 2 . Green = ( h ues [ j ] >> 4 ) & Ox3E ;
Col o r2 . B l ue = ( h ues [ j ] >> 9 ) & Ox3 E ;
t e m p_d = ( C o l o r . Red - C o l o r 2 . Re d ) * ( C o l o r . Red -
C o l o r 2 . Red ) + ( C o l o r . Green -
Col o r 2 . G reen l * ( C ol o r . Green - Col or2 . G reen l +
( Col o r . B l ue - Col o r2 . B l ue ) * ( Col or . B l ue -
Col o r2 . B l ue l ;
i f ( t em p_d < d l l
{
dl t e m p_d ;
d2 j;

f r e q u e n cy [ i ] d2 ;

f o r ( j =O ; j < 2 5 6 ; j ++ )
{
C o l o r . Re d = ( h u e s [ j J < < l l & O x 3 E ;
Col o r G reen = ( h ues [ j ] >> 4 ) & Ox3 E ;
Col o r . B l ue = ( h ues [ j ] >> 9 ) & Ox3 E ;
P a l _A r r a y [ j J [ O J C o l o r . Re d ;
P a l _A r r a y [ j J [ l J Col o r . Green ;
P a l _A r r a y [ j J [ 2 J Col o r . Bl ue ;

s e tMode ( Ox l 3 ) ;
s e t V GA p a l e t t e ( & P a l _A r r a y [ O J [ O J ) ;
f o r ( j =O ; j < 3 2 7 6 8 ; j ++ )
c o l o r_h i s t [ j ] = O ;
f o r ( j =O ; j <= l a s t_c o l o r ; j ++ )
c o l o r_h i s t [ h u e s [ j ] J f r e q u e n cy [ j J ;
r e w i n d ( f i l e_l ) ;
xl = O ;
f r e a d ( & x r e s , s i z e o f ( i n t l , l , f i l e_l l ;
f r e a d ( &y r e s , s i z e o f ( i n t ) , l , f i l e_l ) ;
w h i l e ( ! f e o f ( f i l e_l l l
{

361
F R A C TA L P R O G R A M M I N G A N D R A Y T R A C I N G W I T H C + +

f r e a d ( & s c a n l i n e , s i z e o f ( i n t ) , l , f i l e_l ) ;
i f ( s c a n l i n e >= x r e s )
l
p r i n t f ( " Fa u l ty d a t a f i l e . \ n " ) ;
ex i t ( l ) ;

f r e a d ( & r [ O J , s i z e o f ( c h a r ) , y r e s + l , f i l e_l ) ;
f r e a d ( & g [ O J , s i z e o f ( c h a r ) , y r e s + l , f i l e_l ) ;
f r e a d ( & b [ O J , s i z e o f ( c h a r ) , y r e s + l , f i l e_l ) ;
f o r ( i n d e x=O ; i n d e x <=y r e s ; i n d e x++ )
l
C o l o r . Red ( r[ i ndex] & Ox3e ) ;
Col o r . Green ( g [ i ndexJ & Ox3e ) ;
Col or . Bl ue ( b [ i ndex ] & Ox3e ) ;
c o l o r_n o = ( C o l o r . Re d » 1 ) I ( Col or . Green «
4) I
( Col or . Bl ue « 9 ) ;
p l o t ( x l , y r e s - i n d e x , c o l o r_h i s t [ c o l o r_n o ] ) ;

x l += 1 ;

getch ( ) ;
setMode ( 3 ) ;
f c l o s e ( f i l e_l ) ;

/*
setMode ( ) Sets V i deo Mode

*/
v o i d setMode ( i n t mode )
l
reg . h . a h = O ;
reg . h . a l = mode ;
i n t86 ( Ox l O , &reg , &reg ) ;

/*
pl ot ( ) F u n c t i on to p l ot poi n t to VGA 2 5 6 Col o r Sc reen

*/
362
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S

voi d pl ot ( i nt x , i nt y , i nt col o r )
l
un s i gned i n t offset :
c h a r fa r * a d d r e s s :
offset = 320 * y + x :
a d d r e s s = ( c h a r fa r * ) ( OxAOOOOOO O L + o ffset ) :
*address = col or :

s e t V GA p a l e t t e ( ) Funct i on to set a l l 256 col o r reg i sters

*/
v o i d s e t V GA p a l e t t e ( u n s i g n e d c h a r * b u f f e r )
l
reg . x . a x = Oxl 0 1 2 :
segread ( &i n reg ) ;
i n reg . es i n reg . d s :
reg . x . bx 0:
reg . x . cx 256 :
reg . x . dx ( i n t ) &b u f fe r [ O J :
i n t86x ( Ox l 0 , & reg , & reg , &i n reg ) ;

sort ( ) O u i c k s o r t t o s o r t c o l o r s by f r e q u e n cy

*/
v o i d s o r t ( un s i g n e d i n t s t a r t . u n s i g n ed i n t end )
l
un s i g n ed i n t pi vot . temp2 ;
u n s i g n ed c h a r temp :

i f ( s t a r t < ( end - 1 ) )
l
i = sta rt :
j = end :
p i v o t = ( f r e q u e n cy [ i ] + f r e q u e n cy [ j ] +
f r e q u e n cy [ ( i +j ) / 2 ] ) / 3 :

363
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

do
{
w h i l e ( f r e q u e n cy [ i ] > p i v o t )
i ++ ;
w h i l e ( f r e q u e n cy [ j J < p i v o t )
j-;
if (i < j)
{
t e m p = f r e q u e n cy [ i ] ;
f r e q u e n cy [ i ] = f r e q u e n cy [ j ] ;
f r e q u e n cy [ j ] = t em p ;
temp2 = hues [ i ] ;
h u e s [ i ++ J = hues [j ] ;
h u e s [ j -J = temp2 ;

whi l e ( i < j ) ;
i f ( j < end )
{
sort ( sta rt , j ) ;
s o r t ( j+l , end ) ;

i f ( f r e q u e n cy [ e n d J > f r e q u e n cy [ s t a r t ] )
{
t em p = f r e q u e n cy [ s t a r t ] ;
f r e q u e n cy [ s t a r t ] = f r e q u e n cy [ e n d ] ;
f r e q u e n cy [ e n d ] = temp ;
temp2 = hues [start J ;
hues [ s t a r t ] = hues [ end ] ;
hues [ end J = t em p 2 ;

v o i d g o t o xy ( i n t x , i n t y )
{
reg . h . a h 2·
reg . h . bh O;
reg . h . d h y-1 ;
reg . h . d l x-1 ;
i nt86 ( 0x l 0 , &reg , &reg ) ;

Figu re 1 8-6. Program to Display Quaternion Data

364
Appendix A:
Data Files for Ray
Tracing

Plates 4 through 1 2 were generated with the ray-tracing program. The data
fi les for these pl ates have the extension .ray. Plate s 1 3 through 1 6 were
generated with the quaternion program. The data files for these plates have the
extension .qat. The data files are listed below so that you can duplicate the color
plates. After that, you're on your own. It sometimes takes a number of tries to
determine exactly where to position each element of a picture and how large to
make it.

P l a t e 04 . r a y

P i c t u r e o f s p h e re s a n d a b r i c k wa l l

By R o g e r T . S t e v e n s 1 2 / 3 1 /89

F I L E_N A M E = W S p h e r e . RAW

PATT E R N S U S E D I

PATT E R N ( x si ze 60 , ! C H E C K E R E D G RO U N D I
y_s i z e 60 ,
n a me CHECK ,

365
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

RECTA N G L E
s t a r t_x 0.
s t a r t_y 0.
e n d_x 40 ,
e n d_y 40 ,
d i ff ( .1 ,1.0, .4) ,
di ther 0,

RECTA N G L E
s t a r t_x = 40 ,
s t a r t_y = 40 ,
e n d_x = 80 ,
e n d_y = 80 ,
d i ff ( .1,1.0, .1) ,
di ther = 0,

PATT E R N x s i z e = 80 , { PATT E R N F O R B R I C K S l
y_s i z e = 5 0 ,
n a me = BRICK,
RECTANG L E (
s t a r t_x = 0 , s t a r t_y = 2 ,
e n d_x 1 8 , e n d_y 23 ,
d i ff ( 1 . 00 , . 20 , . 20 ) ;
di ther 0,

RECTANGLE
sta rt x 6 2 , s t a r t_y = 2 ,
e n d_x 8 0 , e n d_y = 23 ,
d i ff ( 1 . 00 , . 24 , . 20 ) ;
di ther 2.

RECTA N G L E
sta rt x 2 2 , s t a r t_y = 2 ,
e n d_x 5 8 , e n d_y = 23 ,
d i ff ( . 80 , . 2 0 , . 2 0 ) ;
di ther 0,

R E C TA N G L E
sta rt x 2 , s t a r t_y = 2 7 .
e n d_x 3 8 , e n d_y = 48 ,
d i ff ( . 85 , . 35 , . 10 ) ;

366
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G

di ther 0,

RECTANGLE ( { bri ck 4 }
s t a r t_x = 4 2 , s t a r t_y = 2 7 ,
e n d_x 7 8 , e n d_y = 48 ,
d i ff ( . 70 , . 25 , . 20 ) ;
di ther 0'

P A RA L L E L O G RA M l ac - 1 0000 , 0 , - 1 0000 ) ,
vl ( 20000 , 0 , 0) ,
v2 0 , 0 , 20000 ) ,
d i ff .8, .8, 0) ,
di ther 0,
pattern = CHECK
xm u l t 2
ymul t = 2

B E G I N_B B O X
B E G I N_B B O X
SPHERE l ac = ( 2 1 0 , 55 , - 80 ) ,
ra d i u s = 40 ,
d i ff = ( . 5 , . 3 , . 5 ) ,
xm u l t = 1.5,
ymul t = 1.5
mi rror ( .9, .9, .9)

Q U A D RAT I C ( l o c ( 2 1 0 ' 0 ' - 80 ) ,


a 1,
b 0'
c 1,
d 1 50 ,
xmi n - 13 ,
xma x 13 '
ymi n 0'
yma x 50 ,
zmi n - 13 '
zma x 13 '
d i ff (.1. .1, .1)'
mi rror = ( . 8 ' . 8 , . 8 )

367
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

E N D_B B O X
B E G I N_B B O X
SPHERE l oc ( 2 00 , 90 , 7 0 ) ,
radi us 35 ,
d i ff ( .3 •5 . 9) .
• .

amb ( . 32 , . 32 , . 32 ) ,
refl ect . 60
s refl ect = 20
xm u l t 1.0,
ymu l t = 1.0

Q U A D RAT I C ( l o c = ( 2 0 0 , o . 7 0 ) ,
a = 1.
b = o.
c 1.
d 1 50 ,
xmi n - 13 .
xma x 13 .
ymi n 0.
ymax 90 ,
zmi n - 13 .
zma x = 1 3 ,
d i ff = ( . 1 . . 1 , . 1 ) .
mi rror = ( . 8 , . 8 , . 8 )

E N D_B B O X
END BBOX

B E G I N_B B O X
P A RA L L E L O G RA M l oc ( 1 50 , 00 , - 1 5 ) ,
vl ( 0 , 0 , 30 ) ,
v2 ( 0 , 60 , 0 )
d i ff = ( 1 , 1 . 1 ) .
pattern = B R I C K
xm u l t .5.
ymu l t = . 5

P A RA L L E L O G RA M l oc ( 1 50 , 00 , 1 5 ) - ,

vl ( 1 50 , 0 , 0 ) ,
v2 ( 0 , 60 , 0 )
d i ff = ( 1 , 1 , 1 ) ,
pattern = BRICK

368
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G

xm u l t .5,
ym u l t .5

P A RA L L E L O G RA M l oc ( 1 50 , 00 , 1 5 ) ,
vl ( 1 50 , 0 , 0 ) ,
v2 ( 0 , 60 , 0 )
d i ff (1, 1, 1),
=

pattern BRICK=

xm u l t .5, =

ymu l t .5 =

)
P A RA L L E L O G RA M ( l o c ( 1 50 , 60 , - 1 5 ) ,
=

v1 ( 0 . 0 . 30 ) .
=

v2 ( 1 50 , 0 , 0 )
=

d i ff (1, 1, 1),
=

pattern BRICK =

xm u l t .5,
ymu l t .5 =

E N D_B B O X

B E G I N_B B O X

P A RA L L E L O G RA M l oc ( 2 00 , 60 , - 1 5 ) ,
vl ( 0 , 0 , 30 ) ,
v2 ( 0 , 60 , 0 )
d i ff (1, 1. 1),
=

pattern BRICK=

xm u l t .5, =

ymu l t .5 =

P A RA L L E L O G RA M l oc ( 200 , 60 , - 1 5 ) ,
vl ( 50 , 0 , 0 ) ,
v2 ( 0 , 60 , 0 )
d i ff (1, 1. 1),
=

p a t t e rn BRICK
=

xm u l t . 5 ,
ymu l t .5=

P A RA L L E L O G RA M l oc ( 200 , 60 , 1 5 ) ,
vl ( 50 . 0 . 0 ) .
v2 ( 0 . 60 . 0 )

369
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

di ff = ( 1 , l , 1 ) ,
pattern = BRICK
xmul t .5,
ymul t = . 5

E N D_B B O X
O B S E RV E R l oc ( - 20 ' 70 , - 40 ) ,
l ookat ( 200 ' 50 ' 0 )

L A M P ( l o c = ( 1 2 0 ., 1 2 0 , - 5 0 ) '
rad i us = 5 ,
d i s t = 80

LAMP l oc = ( 1 20 ' 1 5 0 , 80 ) ,
radi us = 5 ,
di st = 70

S KY hori z (0' .4' .6) .


zen i th (0' .4' .6) '
di ther 1

X RES 320
Y RES 200

FOC L ENGTH 80

Pl ate 05 . ray

Pi cture of t h ree cones and spheres

B y Rog e r T . S t e v e n s - 1 2 / 3 1 /89

F I L E_ N A M E C O N E 5 . RAW
=

{ PATT E R N S U S E D )

PATT E R N ( x s i z e 80 , { C H E C K E R E D G RO U N D )
y_s i z e 80 ,

370
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G

n a me = CHEC K ,
RECTANG L E (
s t a r t_x = 0,
s t a r t_y = 0,
e n d_x = 40 ,
e n d_y = 40 ,
d i ff = ( . 75 , . 25 , . 75 ) ,
di ther = O,

RECTANG L E
s t a r t_x = 40 ,
s t a r t_y = 40 ,
e n d_x = 80 ,
e n d_y = 80 ,
d i ff ( . 75 ' . 25 , . 75 ) ,
di ther = 0,

P A RA L L E L O G RA M l oc - 1 0000 , 0 , - 1 0000 ) ,
vl ( 20000 , 0 , 0) ,
v2 0 , 0 , 20000 ) ,
d i ff ( l , l , . 75 ) ,
=

di ther 0, =

pattern CHECK =

xmul t 2
ymul t 2 =

B E G I N_B B O X
SPHERE ( l oc ( 2 30 , 90 , - 7 0 ) ,
=

rad i us 30 , =

d i ff ( .7, .7, .7),


=

xm u l t 1 =

ymul t 1 =

mi r ro r ( .9, .9, .9)

CONE ( l oc ( 230 , 60 , - 7 0 ) ,
radi us 35 =

hei ght 60 =

d i ff (1, 0, 0) ,
=

)
E N D_B B O X

371
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

B E G I N_B B O X
SPHERE l oc = ( 2 20 , 90 , 50 ) ,
radi us = 30 ,
di ff ( .7' .7' .7) '
mi r ro r ( .9' .9' .9)
xm u l t 1.0'
ymu l t 1.0

CONE ( l oc = ( 2 20 , 60 , 50 ) ,
rad i us = 30
hei ght = 60
d i ff = ( 0 , 1 , 0 . 6 ) ,
)
E N D_B B O X

B E G I N_B B O X
SPHERE l oc = ( 350 , 90 , 0 ) ,
r a d i u s = 30 ,
d i ff = ( . 7 , . 7 , . 7 ) ,
xm u l t = 1
ymul t = 1
mi rror = ( . 9 , . 9 , . 9 )

CONE ( l oc = ( 3 50 , 60 , 0 ) '
rad i us = 35
hei ght = 60
d i ff = (0, 0' 1) '
)
E N D_B B O X
O B S E RV E R l oc ( - 20 ' 70 , - 40 ) ,
l oo k a t ( 2 00 , 50 , - 1 5 )

LAM P l oc = ( 1 20 , 400 , - 50 ) '


rad i u s = 5 ,
di st 250
)
LAM P ( l o c ( - 200 , 450 , 140 )
rad i us = 5 ,
d i st = 220

S KY hori z (0, .4, .8) ,


zen i th (0, .4, .9) ,

372
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G

di ther 1

X RES =320
Y RES =200
FOC L ENGTH 65
{

Pl ate 06 . ray

N e w Y o r k W o r l d ' s F a i r 1 9 3 9 - T ry l o n a n d P e r i s p h e r e

By R o g e r T . S t e v e n s - 2 / 1 8 - 9 0

F I L E N A M E = N Y W F 3 9 . RAW

PATT E R N S U S E D )

PATT E R N ( x s i z e 60 , { C H EC K E RE D GROUND )
y_s i z e 60 ,
n a me CHECK ,
RECTANGLE (
s t a r t_x 0'
s t a r t_y 0'
e n d_x 30 ,
e n d_y 30 ,
d i ff ( . 1 ,1 .0, .4) ,
di ther 0,

RECTANG L E
s t a r t_x 30 ,
s t a r t_y 30 ,
e n d_x 60 ,
e n d_y 60 ,
d i ff ( . 1,1.0, .1),
di ther 0'

373
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

P A RA L L E L O G RAM ( l o c - 1 0000 , 0 , - 1 0000 ) ,


vl ( 20000 , 0 , 0) ,
v2 0 , 0 , 20000 ) .
d i ff = ( . 8 , . 8 , 0 ) ,
di ther = 0 ,
pattern = CHECK
xm u l t = 1
ymul t = 1
)
S P H E R E ( l oc = ( 3 50 , 30 , - 40 ) ,
ra d i u s = 30 ,
d i ff
= (1.0,1.0,1.0) ,

B EG I N BBOX
TRI ANGLE
l oc = ( 380 , 0 , 20 ) ,
v l = ( 60 , 0 , 0 ) ,
v2 = ( 30 , 1 50 , 1 7 ) ,
d i ff = ( 1 . 0 , 1 . 0 , 1 . 0 ) ,
xm u l t 1.5,
ymul t = 1 . 5 ,
)
TRI ANGLE (
l oc = ( 380 , 0 , 20 ) ,
v l = ( 30 , 0 , 52 ) ,
v2 = ( 30 , 1 50 , 1 7 ) ,
di ff = ( 1 . 0 , 1 . 0 , 1 . 0 ) ,
xm u l t 1.5,
ym u l t = 1 . 5 ,
)
E N D_B B O X
OBSERVER l oc ( - 80 , 7 0 , - 40 ) ,
l ookat ( 2 00 , 7 0 , 0 )

! ** A l amp ** )
LAMP ( l oc = ( 0 , 1 50 , 1 20 ) ,
radi us = 5 ,
d i s t = 200

SKY hori z (0, .2, .9) .


zen i th (0, .2, .9) ,
di ther 1

374
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G

X RES = 320

Y RES = 200

F O C L E N GT H 120
I

Pl a te 07 . ray

P i c t u r e o f Py r a m i d s i n t h e D e s e r t

By Rog e r T . Steven s - 4 / 2 2 - 90

F I L E_N A M E = Py r a m i d . RAW

B E G I N_ I N S T A N C E S
name = P Y RAM I D

BEGI N BBOX
T R I ANGLE ( l oc 0 , 0 , 0 )
vl ( 52 , 0 , 30 )
=

v2 ( 34 . 3 , 30 , 0 )
=

di ff ( . 72 , . 41 . . 14 )
=

TRIANGLE ( l QC 0 , 0 . 0 )
vl = ( 52 . 0 . - 30 )
v2 = ( 34 . 3 . 3 0 , 0 )
diff = ( . 72 . . 4 1 . . 14 )
)
T R I ANGLE ( l oc 52 , 0 . - 30 )
vl = ( 0 , 0 , 60 )
v2 = ( - 1 7 . 7 . 30 , 30 )
d i ff = ( . 72 . . 41 . . 14 )

E N D_B B O X
E N D_ I N S T A N C E S

375
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

P A RA L L E L O G RAM ( l a c - 1 0000 , 0 , - 1 0000 ) ,


vl ( 20000 , 0 , 0) ,
v2 0 , 0 , 20000 ) ,
amb = ( . 48 , . 3 2 , . 40 )
di ff = ( 1 . 0 , . 8 , . 4 ) ,
di ther = 0 ,

I N S T A N C E_O F n a m e = P Y RAM I D
l ac = ( 200 , 0 , - 40 )
sca l e = ( 1 . 3 , 1 . 3 , 1 . 3 )
)
I N S T A N C E O F n a m e = P Y RAM I D
l ac = ( 1 7 0 , 0 , 80 )
sca l e = ( 1 . 2 , 1 . 2 , 1 . 2 )
)
I N ST A N C E O F n a m e = P Y RAM I D
l ac = ( 225 , 0 . 20 )
)
I N S T A N C E O F n a m e = P Y RAM I D
l ac = ( 350 , 0 . - 70 )
)
I N S T A N C E O F n a m e = P Y RAM I D
1 a c = ( 400 , 0 . 1 20 )
sca l e ( 1 . 25 , 1 . 25 . 1 . 25 )
)
I N S T A N C E O F n a m e = P Y RAM I D
l ac = ( 500 , 0 . - 60 )
)
I N S TA N C E O F n a m e = P Y RAM I D
l ac = ( 7 00 . 0 . - 1 00 )
scal e ( 1 . 25 , 1 . 25 . 1 . 25 )

I N S T A N C E O F n a m e = P Y RAM I D
l ac = ( 7 50 , 0 . 140 )
)
I N S T A N C E O F n a m e = P Y RAM I D
1 a c = ( 900 , 0 . - 80 )
scal e ( 1 . 25 , 1 . 25 . 1 . 25 )
)
I N S T A N C E O F n a m e = P Y RAM I D
-

l ac = ( 950 , 0 . 300 )

376
A P P E N D I X A : D AT A F I L E S F O R R AY T R A C I N G

I N S T A N C E_O F n a m e = P Y RAM I D
l oc = ( 1050 , 0 , 0 )

OBSERVER l oc ( - 20 , 70 , - 40 ) ,
l ookat ( 200 , 50 , 0 )

LAM P ( l oc = ( 1 2 0 , 1 8 0 , 80 ) ,
rad i us = 5 ,
di st = 70

LAM P l oc = ( - 20 , 350 , -400 ) ,


radi us = 5 ,
d i s t = 1 500

S KY hori z = ( 0 , . 4 , . 7 ) ,
zeni th = ( 0 , . 4 , . 7 ) ,
di ther 1

X RES = 320
Y RES = 200
F O C L E N GT H 75

P l a t e 08 . ray

I n d i a n S t o ry T e l l e r

By R o g e r T . S t e v e n s - 4 / 2 2 - 9 0

F I L E N A M E = M S P H E R E 4 . RAW

OBSERVER
( l oc ( 2 . 1 00000 , 1 . 000000 , 1 . 700000 ) ,
=

l oo k a t = ( 0 . 000000 , 0 . 8000000 , 0 . 000000 )


)

377
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

XRES = 320
Y RES = 200

S KY
( ha r i z = ( 0 . 078000 , 0 . 3 6 1 000 , 0 . 7 53000 )
z en i t h = ( 0 . 078000 , 0 . 361 000 , 0 . 7 53000 )
di ther = 0
)
LAM P
( l ac = ( 4 . 000000 , 3 . 000000 , 2 . 000000 )
radi us = 5
di st = 5
)
LAM P
( l ac = ( 1 . 000000 , - 4 . 000000 , 4 . 000000 )
radi us = 5
di st = 5
)
LAM P
( l ac = ( - 3 . 000000 , 1 . 000000 , 5 . 000000 )
radi us = 5
di st = 0
)
P A RA L L E L O G RAM
( l ac ( - 1 000 , 0 , - 1 000 )
v l = ( 0 , 0 , 20000 )
v 2 = ( 20000 , 0 , 0 )
d i ff = ( 1 . 000000 , 0 . 7 50000 , 0 . 330000 ) ,
refl ect = 0 . 000000 ,
s refl ect = 0 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
B E G I N_B B O X
SPHERE
( l ac = ( 0 . 000000 , 0 . 500000 , 0 . 000000 ) ,
radi us = 0 . 500000 ,
d i ff = ( 0 . 00000 , 0 . 0000 , 0 . 850000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,

378
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G

SPHERE
( l o c = ( 0 . 2 7 2 1 6 6 , 0 . 7 7 2 1 6 6 , 0 . 544 3 3 1 ) ,
rad i us = 0 . 1 66667 ,
d i ff = ( 1 . 00000 , 0 . 0000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 4 2 0 3 1 4 , 0 . 9 2 0 3 1 4 , 0 . 6 1 84 0 5 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t ra n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 4 6 1 844 , 0 . 8 0 4 7 0 9 , 0 . 4 3 3 2 2 0 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 3 0 4 7 0 9 , 0 . 9 6 1 844 , 0 . 4 3 3 2 2 0 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 2 3 0 6 3 5 , 0 . 88 7 7 7 0 , 0 . 7 2 9 5 1 6 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,

379
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

s refl ect = 3 . 000000 ,


t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l a c = ( 0 . 1 1 5 0 3 1 , 0 . 9 2 9 3 0 0 , 0 . 544 3 3 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l a c = ( 0 . 082487 , 0 . 7 3 9 6 2 2 , 0 . 6 5 5442 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,

SPHERE
( l ac = ( 0 . 387 7 7 0 , 0 . 7 3 0 6 3 5 , 0 . 7 2 9 5 1 6 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( 0 . 239622 . 0 . 582487 , 0 . 6 5 5442 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t ra n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac ( 0 . 4 29300 , 0 . 6 1 503 1 , 0 . 54433 1 ) ,

380
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G

radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPH E RE
( l oc = ( 0 . 6439 5 1 , 0 . 67 2546 , 0 . 000000 ) ,
radi us = 0 . 1 66667 ,
d i ff = ( 0 . 50000 , 0 . 0000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 8 0 2 6 0 8 , 0 . 88 1 4 7 1 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPH E RE
( l oc = ( Q . 6439 5 1 . 0 . 6 7 2 546 , - 0 . 2 2 2 2 2 2 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 59 4 1 4 1 , 0 . 858439 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,

381
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

SPHERE
( l ac = ( 0 . 802608 , 0 . 7 8 1 4 7 1 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 350000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( 0 . 59414 1 , 0 . 858439 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 350000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( 0 . 6439 5 1 , 0 . 6 7 2 546 , 0 . 2 2 2 2 2 2 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 350000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t ra n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( 0 . 8524 1 8 , 0 . 595579 , 0 . 000000 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 350000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t ra n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( 0 . 693760 , 0 . 486654 , 0 . 1 1 1 1 1 1 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 350000 ) ,
refl ect = 0 . 500000 ,

382
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G

s refl ect = 3 . 000000 ,


t rans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( 0 . 6 9 3 7 6 0 , 0 . 486654 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( 0 . 1 7 2546 , 1 . 14395 1 , 0 . 000000 ) ,
radi us = 0 . 166667 ,
d i ff = ( 0 . 800000 , 0 . 0000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t ra n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( 0 . 28 1 47 1 , 1 . 302608 , - 0 . 1 1 1 1 1 1 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l a c = ( 0 . 3 5 84 3 9 , 1 . 0 9 4 1 4 1 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t ra n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac ( 0 . 1 7 2 546 , 1 . 14395 1 , - 0 . 222222 ) ,

383
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l a c = ( 0 . 09 5 5 7 9 , 1 . 3 5 24 1 8 , - 0 . 000000 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( - 0 . 01 3346 , 1 . 1 93760 , - 0 . 1 1 1 1 1 1 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( - 0 . 01 3346 , 1 . 1 93760 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( 0 . 28147 1 , 1 . 302608 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 509000 ,
s r e f l e c t = 3 . 0 00 0 0 0 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,

384
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G

SPHERE
( l ac = ( 0 . 1 72546 , 1 . 14395 1 , 0 . 222222 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t rans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( 0 . 3 58439 , 1 . 19414 1 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t ra n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l a c = ( - 0 . 3 7 1 7 8 5 , 0 . 5 9 9 6 1 9 , 0 . 544 3 3 1 ) ,
radi us = 0 . 166667 ,
d i ff = ( 0 . 800000 , 0 . 0000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( - 0 . 39362 1 , 0 . 7 20501 , 0 . 729516 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( - 0 . 1 9 1 24 7 , 0 . 6 6 6 2 7 5 , 0 . 6 5 544 2 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,

385
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

s refl ect = 3 . 000000 ,


t ra n s = ( 0 . 000000 . 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 3 1 4 2 7 0 , 0 . 8 1 4 2 7 0 , 0 . 544 3 3 1 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 5 7 4 1 5 9 , 0 . 6 5 3 8 4 5 , 0 . 6 1 84 0 5 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 494808 , 0 . 7 4 7 6 1 4 , 0 . 43 3 2 20 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 552323 , 0 . 532964 , 0 . 433220 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc ( - 0 . 45 1 1 36 , 0 . 50585 1 , 0 . 7 29 5 1 6 ) ,

386
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G

radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( - 0 . 4 2 9 3 0 0 , 0 . 3 8 4 9 6 9 , 0 . 5 44 3 3 1 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( - 0 . 2 4 8 7 6 2 , 0 . 4 5 1 6 2 5 , 0 . 6 5 5 44 2 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 4 7 1 4 0 5 , 0 . 9 7 1 4 0 5 , 0 . 000000 ) ,
radi u s = 0 . 1 66667 ,
d i ff = ( 0 . 800000 , 0 . 0000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 508983 , 1 . 1 90426 , - 0 . 000000 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,

387
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

SPHERE
( l oc = ( - 0 . 335322 , 1 . 1 07487 , 0 . 1 1 1 1 1 1 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 335322 , 1 . 1 07487 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 645066 , 1 . 0 54344 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 47 1405 , 0 . 9 7 1 405 , - 0 . 222222 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 6 0 7 4 8 7 , 0 . 83 5 3 2 2 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,

388
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G

s refl ect = 3 . 000000 ,


trans = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 645066 , 1 . 1 54344 , 0 . 1 1 1 1 1 1 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 60 7 487 , 0 . 83 5 3 2 2 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 47 1405 , 0 . 97 1405 , 0 . 222222 ) ,
radi us = 0 . 055556 ,
d i f f = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 6439 5 1 , 0 . 327454 , 0 . 000000 ) ,
radi us = 0 . 1 66667 ,
d i ff = ( 0 . 500000 , 0 . 0000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc ( - 0 . 83 5 8 1 5 , 0 . 34 2 3 5 7 , 0 . 1 1 1 1 1 1 ) ,

389
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i nd ex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 6439 5 1 , 0 . 327454 , 0 . 2 2 2 2 2 2 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 693760 , 0 . 5 1 3346 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 83 5 8 1 5 , 0 . 3424 5 7 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 693760 , 0 . 5 1 3346 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i f f = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,

390
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G

SPHERE
( l o c = ( - 0 . 6 4 3 9 5 1 , 0 . 3 2 7 4 54 , - 0 . 2 2 2 2 2 2 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 78600 5 , 0 . 1 56 5 6 5 , - 0 . 000000 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) .
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 594141 , 0 . 141561 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) .
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 59 4 1 4 1 , 0 . 1 5 1 5 6 1 . 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 . 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 0 9 9 6 1 9 , 0 . 1 2 8 2 1 5 , 0 . 5 44 3 3 1 ) ,
radi us = 0 . 1 66667 ,
d i ff = ( 0 . 800000 , 0 . 0000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,

391
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

s refl ect = 3 . 000000 ,


t r a n s = ( 0 . 00000 0 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 22050 1 , 0 . 1 06479 , 0 . 7 2 9 5 1 6 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 3 1 4 2 7 0 , 0 . 1 8 5 7 3 0 , 0 . 5 44 3 3 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 1 6 6 2 7 5 , 0 . 3087 5 3 , 0 . 65 5442 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 00000 0 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 0 0 5 8 5 1 , 0 . 04 8 8 6 1 , 0 . 7 2 9 5 1 6 ) ,
radi us = 0 . 055556 ,
d i f f = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc ( - 0 . 04 8 3 7 5 , 0 . 2 5 1 2 3 8 , 0 . 6 5 5 4 4 2 ) ,

392
A P P E N D I X A : D AT A F I L E S F O R R AY T R A C I N G

rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 00000 0 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 1 1 503 1 , 0 . 0 7 0 7 0 0 , 0 . 54433 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 1 5 3845 , - 0 . 0 7 4 1 5 9 , 0 . 6 1 8405 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 032964 , - 0 . 052323 , 0 . 433220 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 24 7 6 1 4 , 0 . 00 5 1 9 2 , 0 . 43 3 2 20 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,

393
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

)
SPHERE
( l oc = ( - 0 . 1 7 2546 , - 0 . 14395 1 . 0 . 000000 ) ,
rad i us = 0 . 1 66667 ,
d i ff = ( 0 . 800000 , 0 . 0000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t rans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 1 5 7 543 , - 0 . 33581 5 . 0 . 1 1 1 1 1 1 ) .
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) .
refl ect = 0 . 500000 .
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i n d ex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 0 1 3346 , - 0 . 1 93760 , 0 . 1 1 1 1 1 1 ) .
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 1 7 2546 , - 0 . 14395 1 , 0 . 222222 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 . 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 34343 5 , - 0 . 286005 , - 0 . 000000 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,

394
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G

s refl ect = 3 . 000000 ,


trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 3 58439 , - 0 . 09 4 1 4 1 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( - 0 . 3 5 84 3 9 , - 0 . 0 9 4 1 4 1 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 1 5 7 543 , - 0 . 3358 1 5 , - 0 . 1 1 1 1 1 1 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 1 7 2 546 , - 0 . 1439 5 1 , - 0 . 2 2 2 2 2 2 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc ( 0 . 0 1 3346 , - 0 . 193760 , - 0 . 1 1 1 1 1 1 ) ,

395
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 47 1 405 , 0 . 0285 1 5 , 0 . 000000 ) ,
rad i us = 0 . 166667 ,
d i ff = ( 0 . 800000 , 0 . 0000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 69042 6 , - 0 . 008983 , 0 . 000000 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 . 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 607487 , 0 . 1 64678 , - 0 . 1 1 1 1 1 1 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 607487 , 0 . 1 64678 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,

396
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G

SPHERE
( l oc = ( 0 . 5 54344 , - 0 . 145066 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 47 1405 , 0 . 028595 , 0 . 222222 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t ra n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
S P H E RE
( l oc = ( 0 . 335322 , - 0 . 1 07487 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 5 54344 , - 0 . 1 45066 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 33 5 3 2 2 , - 0 . 1 0 7 487 , - 0 . 1 1 1 1 1 1 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,

397
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

s refl ect = 3 . 000000 ,


t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 47 1405 , 0 . 028595 , - 0 . 222222 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
E N D_B B O X
F I L E_N A M E = M S P H E R E 4 . RAW
O B S E RV E R
( l oc = ( 2 . 1 00000 , 1 . 000000 , 1 . 7 00000 ) ,
l oo k a t = ( 0 . 000000 , 0 . 8000000 , 0 . 000000 )
)
X RES = 320
Y RES = 200

SKY
( ho r i z = ( 0 . 078000 , 0 . 361 000 , 0 . 753000 )
zen i th = ( 0 . 078000 , 0 . 3 6 1 000 , 0 . 7 53000 )
di ther = 0
)
LAM P
( l oc = ( 4 . 000000 , 3 . 000000 , 2 . 000000 )
radi us = 5
di st = 5
)
LAM P
( l oc = ( 1 . 000000 , - 4 . 000000 , 4 . 000000 )
radi us = 5
di st = 5
)
LAM P
( l oc = ( - 3 . 000000 , 1 . 000000 , 5 . 000000 )
radi us = 5
di st = O
)

398
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G

P A RA L L E L O G RA M
( l oc = ( - 1 000 , 0 , - 1 000 )
v l = ( 0 , 0 , 20000 )
v 2 = ( 20000 , 0 , 0 )
d i ff = ( 1 . 000000 , 0 . 7 5 0000 , 0 . 330000 ) ,
refl ect = 0 . 000000 ,
s refl ect = 0 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
B E G I N_B B O X
SPHERE
( l oc = ( 0 . 000000 , 0 . 500000 , 0 . 000000 ) ,
rad i us = 0 . 500000 ,
d i ff = ( 0 . 00000 , 0 . 0000 , 0 . 850000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 2 7 2 1 6 6 , 0 . 7 7 2 1 66 , 0 . 54433 1 ) ,
radi us = 0 . 1 66667 ,
d i ff = ( 1 . 00000 , 0 . 0000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 42 0 3 1 4 , 0 . 9203 1 4 , 0 . 6 1 8405 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 4 6 1 84 4 , 0 . 8 04 7 0 9 , 0 . 4 3 3 2 2 0 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,

399
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

refl ect = 0 . 500000 ,


s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 3 0 4 7 0 9 , 0 . 9 6 1 84 4 , 0 . 4 3 3 2 2 0 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 23063 5 , 0 . 88 7 7 7 0 , 0 . 7 2 9 5 1 6 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect � 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 1 1 5 0 3 1 , 0 . 929300 , 0 . 54433 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 082487 , 0 . 739622 , 0 . 655442 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE

400
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G

( l oc = ( 0 . 38 7 7 7 0 , 0 . 7 3 0 63 5 , 0 . 7 2 9 5 1 6 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) .
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 2 3 9 6 2 2 , 0 . 582487 , 0 . 6 5 5442 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 4 2 9 3 0 0 , 0 . 6 1 5 0 3 1 , 0 . 544 3 3 1 ) .
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 64395 1 , 0 . 672546 , 0 . 000000 ) ,
radi us = 0 . 1 66667 ,
d i ff = ( 0 . 50000 . 0 . 0000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 . 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 8 0 2 6 0 8 , 0 . 88 1 4 7 1 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,

401
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 6439 5 1 , 0 . 6 7 2 546 , - 0 . 2 2 2 2 2 2 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 . 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 594141 , 0 . 858439 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 802608 . 0 . 78147 1 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 350000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 5 94 1 4 1 , 0 . 8 58439 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 350000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 6439 5 1 , 0 . 6 7 2 546 , 0 . 2 2 2 2 2 2 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 350000 ) ,

402
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G

refl ect = 0 . 500000 ,


s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( 0 . 85241 8 , 0 . 59557 9 , 0 . 000000 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 350000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l a c = ( 0 . 6 9 3 7 6 0 , 0 . 486654 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 350000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l a c = ( 0 . 6 9 3 7 60 . 0 . 486654 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( 0 . 1 7 2546 , 1 . 14395 1 , 0 . 000000 ) ,
rad i us = 0 . 166667 ,
d i ff = ( 0 . 800000 , 0 . 0000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t ra n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE

403
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

( l ac = ( 0 . 2814 7 1 , 1 . 302608 , - 0 . 1 1 1 1 1 1 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t ra n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l a c = ( 0 . 3 5 84 3 9 , 1 . 0 9 4 1 4 1 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( 0 . 1 7 2546 , 1 . 14395 1 , - 0 . 222222 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( 0 . 09 5 5 7 9 , 1 . 352418 , - 0 . 000000 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( - 0 . 0 1 3346 , 1 . 1 93760 , - 0 . 1 � 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,

404
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G

i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 0 1 3346 , 1 . 1 93760 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) .
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 28147 1 , 1 . 302608 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 . 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect - 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
S P H E RE
( l oc = ( 0 . 1 7 2 546 , 1 . 1 4395 1 , 0 . 222222 ) .
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t ra n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 3 58439 , 1 . 1 94 1 4 1 . 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 3 7 1 7 85 , 0 . 5996 1 9 , 0 . 54433 1 ) ,
rad i us = 0 . 166667 ,
d i ff = ( 0 . 800000 , 0 . 0000 , 0 . 00000 ) ,

405
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

refl ect = 0 . 500000 ,


s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = C - 0 . 393621 . 0 . 7 20501 , 0 . 729516 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = C - 0 . 1 9 1 24 7 , 0 . 6 6 6 2 7 5 , 0 . 6 5 5442 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l o e = C - 0 . 3 1 4 2 7 0 , 0 . 8 1 4 2 7 0 , 0 . 5 44 3 3 1 ) ,
rad i us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l o e = C - 0 . 5 7 4 1 5 9 , 0 . 6 5 3 84 5 , 0 . 6 1 84 0 5 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE

406
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G

( l oc = ( - 0 . 494808 , 0 . 747 6 1 4 , 0 . 433220 ) ,


radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( - 0 . 5 5 2 3 2 3 , 0 . 5 3 2 9 64 , 0 . 433220 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 45 1 1 36 , 0 . 50585 1 , 0 . 7 2 9 5 1 6 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( - 0 . 4 2 9 3 0 0 , 0 . 3 84 9 6 9 , 0 . 5 44 3 3 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl e c t = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 2487 6 2 , 0 . 45 1 6 2 5 , 0 . 6 5 5442 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,

407
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

i ndex = 0 . 000000 ,
)
SPHERE
C l oe = C - 0 . 47 1 405 , 0 . 97 1405 , 0 . 000000 ) ,
rad i us = 0 . 1 66667 ,
d i ff = C 0 . 800000 , 0 . 0000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = C - 0 . 508983 , 1 . 1 90426 , - 0 . 000000 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = C - 0 . 335322 , 1 . 1 07487 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = C - 0 . 335322 , 1 . 1 07487 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
S P H E RE
C l oe = C - 0 . 64 5 0 6 6 , 1 . 054344 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,

408
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G

refl ect = 0 . 500000 ,


s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
S P H E RE
C l oe = C - 0 . 47 1 405 , 0 . 97 1405 , - 0 . 222222 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l o e = C - 0 . 6 07487 , 0 . 83 5 3 2 2 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
S PH E RE
C l o e = C - 0 . 645066 , 1 . 1 54344 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = C - 0 . 607487 , 0 . 835322 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE

409
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

( l oc = ( - 0 . 47 1405 , 0 . 97 1405 , 0 . 222222 ) ,


radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
S P H E RE
( l oc = ( - 0 . 6439 5 1 , 0 . 327454 , 0 . 000000 ) ,
radi us = 0 . 1 66667 ,
d i ff = ( 0 . 500000 , 0 . 0000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 83 5 8 1 5 , 0 . 34 2 3 5 7 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 6439 5 1 , 0 . 3 2 7 4 54 , 0 . 2 2 2 2 2 2 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 693760 , 0 . 5 1 3346 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,

41 0
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G

i ndex 0 . 000000 ,
)
SPHERE
( l o c = ( - 0 . 8 3 5 8 1 5 , 0 . 34 2 4 5 7 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
S P H E RE
( l oc = ( - 0 . 693760 , 0 . 5 1 3346 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 6439 5 1 , 0 . 327454 , - 0 . 222222 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 78600 5 , 0 . 1 56565 , - 0 . 000000 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t rans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc= ( - 0 . 594141 , 0 . 141561 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,

41 1
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

refl ect = 0 . 500000 ,


s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = C - 0 . 594141 , 0 . 1 5 1 561 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l o e = C 0 . 09 9 6 1 9 , 0 . 1 282 1 5 , 0 . 54433 1 ) ,
radi us = 0 . 166667 ,
d i ff = C 0 . 800000 , 0 . 0000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = C 0 . 2 2 0 50 1 , 0 . 1 0647 9 , 0 . 7 2 9 5 1 6 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = C 0 . 3 1 4 2 7 0 , 0 . 1 8 5 7 3 0 , 0 . 54433 1 ) ,
rad i us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE

41 2
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G

( l oc = ( 0 . 1 6 6 2 7 5 , 0 . 3087 5 3 , 0 . 6 5 5442 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 0 0 5 8 5 1 , 0 . 04 8 8 6 1 , 0 . 7 2 9 5 1 6 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( - 0 . 04837 5 , 0 . 2 5 1 238 , 0 . 6 5 5442 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
S P H E RE
( l o c = ( - 0 . 1 1 5 0 3 1 , 0 . 0 7 0 7 0 0 , 0 . 5 44 3 3 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPH E RE
( l oc = ( 0 . 1 53845 , - 0 . 07 4 1 5 9 , 0 . 6 1 8405 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,

41 3
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

i ndex = 0 . 000000 ,
)
S P H E RE
C l oe = ( 0 . 032964 , - 0 . 052323 . 0 . 433220 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = ( 0 . 24 7 6 1 4 , 0 . 00 5 1 9 2 . 0 . 433220 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = ( - 0 . 1 7 2546 , - 0 . 14395 1 , 0 . 000000 ) ,
radi us = 0 . 1 66667 ,
d i ff = ( 0 . 800000 , 0 . 0000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i n dex = 0 . 000000 ,
)
SPHERE
C l oe = ( - 0 . 1 5 7 543 , - 0 . 33581 5 . 0 . 1 1 1 1 1 1 ) ,
radi u s = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 . 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = ( 0 . 0 1 3346 , - 0 . 1 93760 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,

414
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G

refl ect = 0 . 500000 ,


s refl e c t = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = C - 0 . 1 7 2546 , - 0 . 14395 1 , 0 . 222222 ) ,
rad i us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
c l oc = ( - 0. 343435 . - 0. 286005 . - 0. 000000 ) .
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = C - 0 . 3 58439 , - 0 . 094141 , 0 . 1 1 1 1 1 1 ) ,
rad i us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
S P H E RE
C l oe = C - 0 . 358439 , - 0 . 094141 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE

41 5
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

C l oe = C - 0 . 1 5 7 543 , - 0 . 33581 5 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = C - 0 . 1 7 2 546 , - 0 . 1439 5 1 . - 0 . 22222 2 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = C 0 . 0 1 3346 , - 0 . 1 93760 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = C 0 . 47 1405 , 0 . 0285 1 5 , 0 . 000000 ) ,
radi us = 0 . 1 66667 ,
d i ff = C 0 . 800000 , 0 . 0000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = C 0 . 690426 , - 0 . 008983 , 0 . 000000 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,

41 6
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G

i ndex 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 607487 , 0 . 1 64678 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s re f l ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
S P H E RE
( l oc = ( 0 . 607487 , 0 . 1 64678 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s re f l ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 554344 , - 0 . 145066 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 47 1405 , 0 . 028595 , 0 . 222222 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s re f l ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 335322 , - 0 . 1 07487 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,

41 7
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

refl ect = 0 . 500000 ,


s refl ect = 3 . 000000 ,
t rans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 , )
SPHERE
( l oc = ( 0 . 5 54344 , - 0 . 145066 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 335322 , - 0 . 1 0 7487 , - 0 . 1 1 1 1 1 1 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 47 1405 , 0 . 028595 , - 0 . 222222 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t ra n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
E N D_B B O X

Pl ate 09 . ray

P i c t u r e s of q u a d r i c s h a pes

By Roge r T . Stevens - 6 / 1 7 1 90

41 8
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G

F I L E_ N A M E = S H A P E S 2 . RAW

PATT E R N S U S E D }
P A T T E R N ( x_s i z e = 8 0 , { C H E C K E R E D G RO U N D }
y_s i z e = 8 0 .
n a me = CHECK .
R E CTAN G L E (
s t a r t_x = 0 ,
s t a r t_y = O .
e n d_x = 40 ,
e n d_y = 40 .
d i ff ( . 75 , . 25 , . 75 ) ,
di ther O.
)
RECTANG L E (
s t a r t_x = 4 0 .
s t a r t_y = 4 0 ,
e n d_x = 80 ,
e n d_y = 80 .
d i ff ( . 75 . 25 . . 75) .

di ther = o .

P A RA L L E L O G RA M l oc ( - 1 0000 , 0 , - 10000 ) .
vl ( 20000 . O . 0) .
v2 ( 0 , 0 , 20000 ) ,
d i ff = ( 1 . 1 . . 7 5 ) .
di ther = 0 .
pattern = CHECK
xmu l t 2
ymu l t = 2
)
B E G I N_B B O X
Q U A D RAT I C ( l oc= ( 230 , 60 . - 1 00 ) { el l i pt i c cone -
cy a n }
a = 2500 . b = - 625 , c = 2500 ,
d = 0.
xmi n - 2 5 , xma x = 2 5 ,
ymi n - 50 . yma x = 5 0 ,
zmi n - 2 5 . zma x = 2 5 ,
d i ff (0. 1 .0, 1.0) .

41 9
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

E N D_ B B O X

B E G I N_B B O X
Q U A D RAT I C ( l ac= ( 300 , 0 , - 5 5 ) { cy l i n d e r - g r e e n )
a 1, b = o. c 1, =

d = 300 ,
xmi n = - 1 8 , xma x 18 ,
ymi n = 0, yma x 60 ,
zmi n - 18 . zmax 18 ,
d i ff = (0, 1.0, 0) .
)
E N D_B B O X

B E G I N_B B O X
Q U A D RAT I C ( l ac= ( 220 , 60 , 2 5 ) { el l i pt i c
pa rabol oi d -
purpl e )
a 60 , e =- 60 , c 60 ,
d 0.
xmi n - 2 0 , xma x = 20 ,
ymi n - 40 , yma x =60 ,
zmi n - 20 , zmax = 20 ,
d i ff (1.0, 0, 1.0) ,
)
E N D_B B O X

B E G I N_B B O X
Q U A D RAT I C ( l ac= ( 1 60 , 30 , - 3 5 ) { hype rbol i c
pa r a b o l o i d -
bl ue )
a 2. e = - 1 00 . c -2.
d 0
xmi n - 1 5 , xma x = 15 ,
ymi n - 25 , ymax 40 ,
=

zmi n - 1 5 , zma x = 15 ,
d i ff (0, 0, 1.0) ,
)
E N D_B B O X

B E G I N_B B O X
Q U A D RAT I C ( l ac= ( 2 30 , 60 , 90 ) { hy p e r b o l o i d of

420
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G

o n e s h eet
- orange }
a 1. b = -1, c = 1.
d 300 ,
xmi n - 2 5 , xma x = 2 5 ,
ymi n - 60 , ymax = 60 ,
zmi n - 2 5 , zma x =25 ,
d i ff (1.0, 0.5, 0) ,
)
E N D_B B O X

B E G I N _B B O X
Q U A D RAT I C ( l oc= ( 500 . 60 , 30 ) l { h y p e r b o l o i d o f two
s heets - red }
a -5. b = -7, c = 3,
d 700 ,
xmi n - 2 2 , xma x = 2 2 ,
ymi n - 60 , yma x = 60 ,
zmi n - 2 2 , zma x = 2 2 ,
di ff (1, 0, 0) ,
)
E N D_B B O X

B E G I N_B B O X
Q U A D RAT I C ( l ac= ( 1 30 , 30 , 3 5 ) { e l l i ps o i d - wh i te }
a = 8, b = 4, c = l,
d 500 ,
xmi n - 2 5 , xma x = 2 5 ,
ymi n - 40 , ymax = 60 ,
zmi n - 2 5 , zma x = 2 5 ,
d i ff (1.0, 1.0, 1.0) ,
)
E N D_B B O X

O B S E RV E R l oc ( - 2 0 . 7 0 , - 80 )
l oo k a t ( 200 , 50 , - 1 5 )

LAM P ( l OC = ( 1 20 , 400 , - 50 ) ,
rad i us = 5 ,
di st = 250

LAM P l OC = ( - 200 , 450 , 140 )

421
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

radi us = 5 ,
di st 220
)
LAMP ( l oc ( - 200 , 200 , 140 )
rad i us = 5 ,
di st = 220

S KY hori z (0, .4, .8) ,


zeni th (0, .4, .9) ,
di ther 1

X RES = 320
Y RES = 200
FOC L ENGTH 65

Pl ate 1 0 . ray

Pi c t u r e s of T roj a n H o r s e

B y Ro g e r T . S t e v e n s - 6 1 24 1 9 0

F I L E_N A M E = H o r s e . RAW

P A RA L L E L O G RAM ( l o c ( - 1 0000 , 0 , - 1 0000 ) ,


vl ( 20000 , o . 0) ,
v2 ( 0 . 0 . 20000 ) .
amb = ( . 48 , . 3 2 , . 40 )
d i ff = ( 1 . 0 . . 8 . . 4 ) ,
di ther = 0 ,
)

B E G I N_B B O X

Q U A D RAT I C ( l oc= ( 1 30 , 60 , - 20 ) { e l l i ps o i d !
a 8, b = 4, c = 1,
d 4000 ,
xmi n - 1 0 0 , xma x 100 ,
ymi n - 80 , yma x = 80 ,

422
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G

zmi n = - 1 00 , zmax = 100 ,


d i ff (1.0, .6, .4) ,

Q U A D RAT I C ( l oc= ( 1 30 , 100 , - 60 ) ! el l i ps oi d !


a = 4, b = 8, c = 1.
d 1 000 .
xmi n - 1 00 , xma x 100 .
ymi n - 1 50 , y m a x = 1 00 ,
zmi n - 100 , zmax = 100 ,
d i ff (1.0. .6. .4) .
)
Q U A D RAT I C ( l oc= ( 140 , 0 , - 50 ) { cy l i n d e r !
a 1, b = 0, c l,
d 50 ,
xmi n - 1 8 , xma x 18 ,
ymi n 0, yma x 30 ,
zmi n - 1 8 , zma x 18 ,
d i ff (1.0, .6, .4) ,
)
Q U A D RAT I C ( l oc= ( 1 20 , 0 , - 50 ) { cyl i nder !
a 1, b = 0, c 1,
d 50 ,
xmi n - 1 8 , xma x = 1 8 ,
ymi n 0, yma x = 30 ,
zmi n - 18 , zmax = 18 ,
d i ff = (1.0, .6, .4) ,

Q U A D RAT I C ( l oc= ( 1 40 , 0 , 1 0 ) ! cy l i n d e r !
a 1, b = o. c 1,
d 50 ,
xmi n - 1 8 , xma x 18,
ymi n 0, ymax 30 ,
zmi n - 1 8 , zma x 18 ,
di ff (1.0, .6, .4) .
)
Q U A D RAT I C ( l oc= ( 1 20 , 0 , 1 0 ) ! cy l i n d e r !
a l, b = O, c 1.
d 50 ,
xmi n - 1 8 , xma x 18 ,
ymi n 0, ymax 30 ,
zmi n - 1 8 , zma x 18,
d i ff (1.0, .6, .4) ,

423
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

E N D_B B O X

O B S E RV E R l ac ( - 20 , 7 0 , - 80 )
l ookat ( 200 , 50 , - 1 5 )

LAM P l ac = ( 1 20 , 180 , 80 ) ,
radi us = 5 ,
di st = 70

LAM P l OC = ( - 20 . 350 , - 400 ) ,


rad i us = 5 ,
di s t = 1 500
)
S KY ( hori z = ( 0 . . 4 . . 7 ) .
zen i t h (0. .4. .7) .
di ther 1
)
X RES = 320
Y RES = 200

FOC L ENGTH 50

Pl a te 1 1 . ray

T h e Re f l e c t i n g B l i m p

By R o g e r T . S t e v e n s - 6 / 2 4 / 9 0

F I L E_NAM E = B L I M P . RAW
B E G I N_ I N S TA N C E S
n a me = P Y RAM I D
B E G I N_B B O X
T R I AN G L E ( l ac o . o . 0 )

424
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G

vl =( 52 , 0, 30 )
v2 =( 34 . 3 , 30 , 0 )
di ff (1, 0, 0)
=

T R I AN G L E ( l ac 0 , 0 , 0 )
vl = ( 52 , 0 , - 30 )
v2 = ( 34 . 3 , 30 , 0 )
di ff (1, 0, 0)
=

T R I AN G L E ( l ac 52 , 0 , - 30 )
vl = ( 0 , 0 , 60 )
v2 = ( - 1 7 . 7 , 30 , 30 )
d i ff (1, 0, 0)
=

E N D_B B O X
E N D_ I N S T A N C E S

PATT E RN S U S E D }

P A T T E R N ( x_s i z e = 80 , { C H E C K E R E D G RO U N D }
y_s i z e = 80 ,
n a me = C H EC K ,
R E C TA N G L E (
s t a r t_x = 0,
s t a r t_y = 0,
e n d_x = 40 ,
e n d_y = 40 ,
d i ff = ( . 25 • . 85 , . 2 5 ) ,
di ther = 0,

R E C TA N G L E
sta rt x = 40 ,
s t a r t_y = 40 ,
e n d_x = 80 ,
e n d_y = 80 ,
d i ff ( . 25 . . 85 , . 2 5 ) .
di ther = 0,

P A RA L L E L O G RA M l OC ( - 1 0000 , 0 , - 1 0000 ) .
vl ( 20000 , 0 , 0) .

425
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

v2 0 , 0 , 20000 ) ,
d i ff = 1 . 1 . . 75) ,
di ther = 0,
pattern = CHECK
xm u l t 2
ymu l t = 2

I N S TA N C E_O F n a m e = P Y RAM I D
l ac = ( 1 50 , 0 , - 60 )
sca l e = ( 2 , 2 , 2 )
)
Q U A D RAT I C ( l o c= ( 2 5 0 , 7 0 , 2 0 ) { e l l i p s o i d }
a 12 , b = 4 , c = 1 ,
d = 4000 ,
xmi n - 1 0 0 , xma x = 1 0 0 .
ymi n - 80 . ymax = 80 ,
zmi n - 1 00 . zmax = 1 00 ,
d i ff ( .5 .3. .5)
• •

mi r ro r = ( 9 . . 9
. 9) ;, .

T R I ANGLE l ac = ( 2 50 , 7 0 , 80 )
v l = ( 0 , 30 , 25 )
v2 = ( 0 , - 30 , 25 )
d i ff = ( . 5 3
• .5) • .

mi r ro r = ( . 9 . . 9 . . 9 )

O B S E RV E R l ac = ( - 20 7 0 , - 80 )

l ookat ( 200 , 50 , - 1 5 )

LAMP ( l ac = ( - 200 , 200 , 140 )


radi us = 5 ,
di st = 220

S KY hori z (0, .4. .8) ,


zen i th (0, .4. .9) ,
di ther 1

X RES 320
Y RES 200

426
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G

FOC L E NGTH 65
I
Pl a te 1 2 . ray

Pi cture of Fra cta l Mounta i n

By R o g e r T . S t e v e n s - 6 1 2 1 9 0

C O LO R
di ff ( . 75 • . 43 , . 14 )
d i ff ( . 85 . . 43 , . 14 )
di ff ( . 95 . . 65 , . 65 )
amb ( .2. .3. .3) :

BEG I N BBOX
SPHERE l ac = 230 , 50 , - 50
rad i us 8
d i ff 1 . . 35 , . 35

R I NG l oc 230 . 50 . - 50
vl = 1 . 0 , 0
v2 = 0 . 0 . 1
r a d_2 = 2 0
r a d_l = 8
d i ff = . 2 , . 8 , . 8

SPHERE l o c = 1 8 0 . 50 . 0
radi us 8
d i ff 1 , . 35 , . 35

RI NG l o c = 1 80 . 5 0 . 0
vl = l , 0 , 0
v2 = 0 , 0 ,
r a d_2 = 2 0
r a d_l = 8
di ff = . 2 8, .8
• .

SPHERE l ac 230 , 50 , 50
radi us 8
d i ff 1 , . 35 , . 35

427
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

vl = 1. 0, 0
v2 = 0 , 0 , 1
r a d_2 20
=

r a d_l 8
=

d i ff= .2. .8. .8

E N D_B B O X

P A RA L L E L O G RAM l oc - 1 0000 , 0 , - 1 0000 ) ,


vl ( 20000 , 0 , 0) ,
v2 0 , 0 , 20000 ) ,
amb = ( . 48 , . 32 , . 40 )
d i ff = ( 1 . 0 , . 8 . . 4 ) ,
di ther = O ,

F RA C T A L ( l o c = ( 3 0 0 , 0 , 1 0 0 )
scal a r = 0 . 01
d i men s i on = 0 . 8
vl ( 502 , 0 , - 650 )
v2 = ( 502 , 0 , 750 )

O B S E RV E R l oc ( - 20 . 70 . - 40 ) .
=

l ookat = ( 200 , 50 , 0 )

LAM P l oc = ( 120 . 180 , 80 ) .


radi us = 5 ,
di st = 270

LAMP l oc = ( - 20 . 350 , - 400 ) ,


radi us = 5 ,
di st - 200

S KY hori z = ( 0 . . 4 . . 7 ) .
zen i th (0. .4. .7 ) .
di ther 1

XRES 320
YRES 200

F O C_ L E N G T � - 75

428
APPENDIX A: D ATA FILES F O R R AY T R A C I N G

Pl ate 13 . qat

Quatern i on J u l i a Set

By R o g e r T . S t e v e n s - 7 / 1 /90

B A C K G RO U N D
(1. 0. 1)
AMB
(0. .4. .4)
DI FF
(0 • .8, .8)
SREFLECT
4
R E F L ECT ( 0 , . 8 , . 8 )

F I L E_NA M E
j ul i a
FLI P

L I G H T_PH I :
- 20
L I G H T_T H E T A :
50
V I E W_PH I :
45
XRES
319
Y RES
199
XMAX
1.8
XMI N

-1.8

429
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

Y MA X
1.0
YM I N
-1. 0
Z MA X
1.0
ZM I N
0.0
MA X_S I Z E
256
M A X_ I T E RAT I O N S
100
Q U AT E R N I O N
( - 1 , 0. 0. 0)
JULIA

Pl ate 14 . qat

Q u a t e rn i on J u l i a Set

By R o g e r T . S t e v e n s 7 / 1 /90

B A C K G RO U N D
( 1 , 1 . 0)
AMB
(0.3, 0.3, 0.6)

DIFF
(0.5, 0.5 1 .0)
SREF LECT
3
REF LECT ( 0 . 3 , 0 . 3 , . 9 )

F I L E_ N A M E
pl a tel4
FL!p
1
L I GHT PH I :

430
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G

-40
L I GHT TH ETA :
45
V I E W_ P H I :
75
XRES
319
YRES
199
XMAX
2.0
XM I N
-2.0
YMAX
1.3
YMI N
-1.3
ZMAX
0.6
ZM I N
0.0
M A X _S I Z E
1 28
M A X _ I T E RAT I O N S
64
Q U AT E R N I O N
( - 0 . 743036 , 0 . 1 1 3467 , 0 , 0 )
JULIA
!

Pl ate 15 . qat

Q u a t e rn i on J u l i a Set

By R o g e r T . S t e v e n s - 7 / 1 / 9 0

BAC KGRO U N D
(1, l, 0)

431
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

AMB
(0. 0. .4)
DI FF
(0. o. .8)
SREFLECT
4
REF LECT C O . o . . 8 )

F I L E_ N A M E
pl atel5
FL!p
1
L I GHT PH I :
- 32
L I G H T_ T H E T A :
70
V I E W_ P H I :
60
XRES
319
Y RES
199
XMAX
1.3
XM I N
-1.3
YMAX
1.3
YM I N
-1.3
ZMAX
2.0
ZM I N
0.0
M A X_S I Z E
1 28
M A X_ I T E RAT I O N S
64
Q U AT E R N I O N
( 0 . 2809 , 0 . 53 , 0 , 0 )
DRAGON

432
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G

Pl a te 1 6 . qa t

Quatern i on Dra gon Cu rve

By Rog e r T . Stevens - 7 / 1 / 90

B A C K G RO U N D
( 0 . 0. 0 )
AMB
( .9. 0. 0)
DI FF
( .9. .7. .4)
SREF LECT
2
REF LECT ( . 9 , . 7 . 4 )

F I L E_N A M E
g ood r a g
FL! p
0
L I GHT PH I :
- 32
L I G H T_T H E T A :
40
V I E W_ P H I :
100
X RES
319
YRES /
/
199
XMAX
1.2
XM I N
-0.2
Y MA X
0.8

YMI N

433
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

0.8
ZMAX
0.8
ZM I N
0.0
M A X _S I Z E
1 28
M A X _ I T E RA T I O N S
32
Q U AT E R N I O N
( 1 . 646009 , 0 . 9 6 7 049 , o . 0 )
D RA G O N

434
Appendix B :
Format for .PCX Files

The ZSoft .PCX file format begins with a 1 28 byte header, the contents of
which are shown below:

Header Data for . PCX Screen File

Byte Size Name Description


(Bytes)

0 1 Password OAH designates ZSoft. PCX Fi les.

1 1 Version Versions of PC Paintbrush are :


0 = vers. 2.5
2 = vers. 2.8 with palette
i nformation .
3 = vers. 2.8 without pal lete
i nformation .
5 = vers. 3.0

2 1 Encoding Encoding scheme used .


1 = . PCX ru n length encoding.
3 1 Bits per pixel No. of bits requ i red to store data
for 1 pixel from 1 plane.
1 = EGA, VGA, or Hercu les
2 = CGA

435
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

Byte Size Name Description


(Bytes)

4 8 Wi ndow 4 i ntegers (2 bytes each) giving top


Di mensions left and bottom right corners of
display in order x 1 , y 1 , x2, y2.

12 2 Horizontal Horizontal resolution of display


Resolution device (colu m ns)
640 = EGA, VGA
320 = CGA
720 = Hercules

14 2 Vertical Vertical resolution of display


Resolution Resolution divide (rows)
480 = VGA
350 = EGA
200 = CGA
348 = Hercules

16 48 Color Map I nformation on color palette


settings. See followi ng figu res for
details.

64 1 Reserved

65 1 Number N u mber of color planes i n the


of planes original i mage
1 = CGA, Hercules
4 = EGA, VGA

66 2 Bytes per line Number of bytes per scan line


i n the image

436
APPENDIX B : F O R M AT F O R . P C X F I L E S

Byte Size Name Description


(Bytes)

68 2 Palette How to i nterpret the palette


description
i nformation

70 56 Not used Fill to the end of the header block

Except for the color map, most of the header contents are self-evident. The
part of the header that is not currently being used by ZSoft may be used to
include some of your own variables to identify particular programs, but do so at
your own risk, as ZSoft may make use of these spaces in a future version.

The contents of a palette register for the EGA color system is described as
follows. Six bits are used, with two each for the primary colors red, green, and
blue. The capital letters represent colors of 75% amplitude; the small letters
colors of 2 5 % amplitude. So for each of the primary colors, four levels are
available : 0 (none of that color), 25% amplitude, 75% amplitude, and 1 00%
amplitude (both capital and small letter bits are one). The color map in the file
header contains 1 6 sets of triples, one for each EGA palette. For the first byte of
a triple, the values of the capital and small letter position for red are extracted
and combined to produce a number from one to three. This number is multiplied
by 85 and stored in the header. The same procedure takes place for the second
byte of the triple for green and the third byte for blue. The process is repeated
sixteen times, once for each palette. Note that when you set the palette registers
on the EGA you are setting a write-only register, this means that you will not be
able to recover the contents at a later date if you need to know what the setting
was. Consequently, our setEGApalette function saves the palette register
information in a global arrayPALEITE [ 1 6] . Use this data to write the color map

437
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

in the header when you are saving a screen.

The VGA is quite different in the way that it handles colors. With the VGA,
each palette register contains the number of a color register. The color register
contains six bits, permitting 64 shades of each color. With the VGA you can
read the six bit value for each of the colors red, green, and blue, as well as
information in the palette registers and in the color registers. To create the color
map, read each palette register and then go and read the color register pointed to
by that palette register. Then multiply the red, green, and blue values by four
and store the results in the triple associated with that palette. Note that when you
restore a screen, you may not assign a color value to the same color register that
it was obtained from originally, and that the palette registers may not select the
same color registers. The net result is the same, however, because each palette
register points to a color register that contains the same color information that
was contained in the original screen. The VGA also has a color mode in which
256 different colors may be displayed simultaneously. This is the mode that we
use for reproducing the ray traced pictures. The format is the same as that used to
display the 1 6 color palette, but due to the 256 colors, the palette information is
much longer. It i s appended at the end of the . PCX file. To access this
information, you must first ascertain that the version number data in the header
(byte 1 ) is 5 (version 3 .0). Then read to the end of the file and count back 769
bytes. If the value in this byte position is ' OCH ' ( 1 2 decimal), the succeeding
information is 256 color palette data.

Data is read from the screen, horizontally from left to right, starting at the
pixel position for the upper left comer. For EGA and VGA, which have multiple
memory plane s , a line is read of the color red (to the end of the window
boundary), then the green information for the same line is read, and finally the
blue.

Data is run length encoded in the following manner. If the byte is unlike the
ones on either side of it, and if its two most significant bits are not 11 , it is
written to the file. Otherwise a count is made of the number of like bytes (up to

438
APPENDIX B : F O R M AT F O R . P C X F I L E S

63) and this count is ANDed with COH and the result written to the file, followed
by the value of the byte. If there are more that 63 successive like bytes, the
count for 63 and the byte are written, and then the count begins all over again.
(Note that the case for a singular byte having the two most significant bits 1 is
handled by writing a count of one followed by the byte value.)

Contents o f E G A Palette Reg ister

Byte 7 Byte 6 Byte s Byte 4 Byte 3 Byte 2 Byte 1 Byte 0

red green blue Red Green Blue


(2S%) (2S%) (2S%) (7S%) (7S%) (7S%)

Contents of . PCX File Color Map

Byte Palette Color Description

16 0 Red For the EGA, the values of color


17 0 G reen of each byte of each triple are :
18 0 Blue OOH to S4H = 0%
SSH to A9H = 2S%
19 1 Red
20 1 Green AAH to FEH = 7S%
21 1 Blue For the VGA, the val ue of each
byte is t h e va l u e of t h e s i x - b i t
22 2 Red c o l o r v a l u e f r o m t h e co l o r
23 2 Green r e g i s t e r p o i n t e d to b y t h e
24 2 Blue
a p p r o p r i at e p a l e t t e r e g i st e r
2S 3 Red multiplied by four.
26 3 Green
27 3 Blue

28 4 Red
29 4 Green
30 4 Blue

439
Byte Palette Color
31 5 Red
32 5 Green
33 5 Blue

34 6 Red
35 6 G reen
36 6 Blue

37 7 Red
38 7 Green
39 7 Blue

40 8 Red
41 8 Green
42 8 Blue

43 9 Red
44 9 G reen
45 9 Blue

46 10 Red
47 10 Green
48 10 Blue

49 11 Red
50 11 G reen
51 11 Blue

52 12 Red
53 12 Green
54 12 Blue

55 13 Red
56 13 Green
57 13 Blue

58 14 Red
59 14 G reen
60 14 Blue

61 15 Red
62 15 Green
63 15 Blue

440
Appendix C :
Hardware Requirements

With the wide variety of PC clones that are now available, including some
that use 80286 and 80386 microprocessors at speeds far higher than anything
envisioned by IBM, there is no telling when some strange glitch is going to
wreak havoc with your program . To attempt to minimize that kind of problem, I
have attempted to run most of the programs described in this book on several
different systems. The primary system consists of the following:

Motherboard : B u l let 3 8 6 from Wave Mate , Incorporated, 234 1 205th


Street, Torrance, CA 9050 1 . The quality of this board is such that you drop it in
and it works the first time around. Highly recommended . It is a 20 MHz
machine, used with 4 megabytes of 1 M by 1 memory chips. The board will use
either an 80387, 80287, or Weitek 1 1 67 math coprocessor. I used an 80287 .

Disk Control ler: Perstor PS l 80- 1 6FN from Hard Drives International, 1 9 1 2
West Fourth Street, Tempe, Arizona 8528 1 . This controller not only controls
two floppy disk drives of any type (5 1 /4 inch or 3 1 /2 inch), but also just about
doubles the capacity of your hard drive. I have found it to be completely reliable
with no signs of drop-outs or deterioration.

F l o ppy D i s k D r i ves : I Fuj itsu 1 . 2 Megabyte disk drive, from Gems


Computer, 2 1 1 5 Old Oakland Road, San Jose, CA 95 1 3 1 .

I Mitsubishi 360Kbyte floppy disk drive.

1/0 Board : AT Multi 1/0 #AI-2 from Gems Computer.

441
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

Hard Disk Drive:Seagate ST25 1 - 1 from Hard Drives International 1 9 1 2


West Fourth Street, Tempe, AZ 8528 1 . If you 've had trouble with a recently
purchased hard drive and the people you bought it from seemed to disappear,
then you need to buy your next drive from Hard Drives International. They
stand 1 00 percent behind their products and provide quick and efficient service
when it is needed. This is a 28 msec. , 40 megabyte drive, but with the Perstor
controller, it stores 78 megabytes.

Keyboard : KeyCat Keyboard. (This is a 1 0 1 key keyboard with a built-in


trackball) from Dexxa International, 1 89 Airport Boulevard, Burlingame, CA
948 1 8.

Veg a V G A from H e ad l and Technology, 4622 1 Landing


V G A C a rd :
Parkway, Fremont, CA 94538.

V G A Monitor: Classic Professional Graphics Display, (no longer available


for purchase). This is actually one of the original IBM VGA monitors. The most
important point to remember is that whatever brand you use, it must be fully
IBM compatible.

The Second System


Motherboard : MCT-386SX from JDR Microdevices, 2233 Branham Lane,
San Jose, CA 95 1 24. This is a 1 6 MHz machine which contains 4 megabyte of
I M by 1 memory chips. It uses the Chips and Technology Neat chip set, which
gives a lot of flexibility in memory assignment, clock speeds, and shadow
memory.

Disk Controller:Perstor PS 1 80- 1 6FN from Hard Drives International, 1 9 1 2


West Fourth Street, Tempe, Arizona 8528 1 . This controller not only controls
two floppy disk drives of any type (5 1 /4 inch or 3 1 /2 inch), but also just about
doubles the capacity of your hard drive. I have found it completely reliable with
no signs of drop-outs or deterioration.

442
A P P E N D I X C : H A R D WA R E R E Q U I R E M E N TS

1 Fuj itsu 1 . 2 Megabyte disk drive, from Gems


F l o p p y D i s k D r i ves :
Computer, 2 1 1 5 Old Oakland Road., San Jose, CA 95 1 3 1 .

1 Mitsubishi 360Kbyte floppy disk drive.


1 Sony 1 .44 M 3 1 /2 inch Drive

1/0 Board : AT Multi 1/0 #AI-2 from Gems Computer.

Hard Disk Drive: Miniscribe 308 5 , from Hard Drives International, 1 9 1 2


West Fourth Street, Tempe, AZ 8528 1 . This i s a 7 2 megabyte drive that formats
to 1 1 3 megabytes with the Perstor controller.

Keyboard : CAT 1 05 Keyboard. (This is a 1 0 1 key keyboard with a built-in


trackball) from CAD and Graphics, 1 30 1 Evans Avenue, San Francisco, CA
94 1 24.

VGA Card : V i d e o S e v e n V G A 1 0 2 4 i from H e ad l an d Tec hn o l ogy,


Incorporated, 4622 1 Landing Parkway, Fremont, CA 945 38. This card contains
extensions of the standard VGA for higher resolution. However, you must buy
another manual to learn how to use them. The one that comes with the product
doesn't provide you with enough information.

VGA Monitor : NEC Multisync Plus from NEC Technologies Incorporated,


1 255 Michael Drive, Wood Dale, IL 60 1 9 1 .

I n addition, some programs were tested on a Dell 3 1 0 computer ( a 386


machine with a VGA) and on a JDR 12 MHz 286 motherboard used in the
second system described. Text was printed out on a Hewlett-Packard LaserJet IIP
Printer, and color pictures were printed out on a Hewlett-Packard PaintJet
Printer.

Programs that work satisfactorily on such a wide variety of systems as this


should have a good chance of working on your system too. If you encounter

443
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +

problems, try to identify how your system differs from the two described above.
In troubleshooting your system, try to pinpoint which card or peripheral may be
the cause of the problem and then proceed from there. Once again, the most
important thing is to make sure that your system is fully IBM compatible.

Display Considerations
In order to run the ray tracing programs described in this book, you must
have a VGA display. The Newton 's method and quaternion programs can also
be run on an EGA display. If you have a Video Seven 1 024i display, you will be
able to create scenes that have much higher resolution than the ones in this
book. If you have another enhanced VGA card, the techniques are similar, but
you ' 1 1 have to discover the right ones for your particular card.

Processor Speed
Some of the ray tracing displays can take hours or days to generate, even
using a 386 machine with a math coprocessor. As you downgrade from this,
things get slower and slower, but if you have enough patience, you can usually
complete the program. One good thing; once you have the data file generated, it
only takes a few seconds to recreate the picture on your screen, and if you have
converted it to a .PCX file, you can reproduce it even faster.

444
Index

! = operator 36 = operator, Vector, overloading 53


% operator 50 == operator 36
% operator, Vector, overloading 53
* operator 49
* operator, Vector, overloading 52 -A-

+ operator 35, 49 active_bank 268


+ operator, Vector, overloading 5 1 AMB 1 62, 339
- operator 49 AmbientColor function 233, 242, 243
- operator, Vector, overloading 5 1 , 52 Aristotle 1 9
Attach_Pattem function 1 3 1 , 1 5 3
.PCX file 1 1 , 445
attenuate 244
.PCX file format 278
attenuation 246
.PCX file, program to view 288
attribute 1 0 1 , 1 0 1
.PCX files, format of 436
attributes, processing 142
I operator, Vector, overloading 53
256 color mode .PCX file, program to
view 288 -8-
286 computer 1 3 BACKGROUND 333
386 computer 1 3 background color, determining 243
800proc.c program, listing of 268 base class 1 86
<< operator 37 BEGIN_BBOX 147, 1 56, 1 63
= operator 35 BEGIN_INSTANCES 1 46, 1 64, 2 1 4
= operator, overload for color_data bounding box 1 2
class 83 bounding box, intersection with 226
= operator, overload, for Object class bounding boxes 1 0 1
82 bounding boxes, generating 2 1 3
bounding boxes, making 1 56
= operator, overloading 79
bounding boxes, processing 1 46 Parallelogram 206
box, bounding 1 2 CollisionTest function for Quadratic
box, bounding, intersection with 226 208
boxes, bounding 1 0 1 CollisionTest function for Ring 208
boxes, bounding, generating 2 1 3 CollisionTest function for Sphere 203
boxes, bounding, making 1 56 CollisionTest function for Triangle 204
boxes, bounding, processing 1 46 COLOR 79, 1 43, 1 6 1
Byte magazine 1 5 color_data class 7 1
color data processing program 258
color data, processing 1 46
-
C - color data, program to process 258
c language 1 9, 24 color information 1 60, 1 6 1 , 1 65 , 1 67,
C++ language 20, 27, 35 1 69, 1 7 1 , 1 75 , 1 77
C++, general description of 3 color mode, 256 color 1 3
Carpenter, L. 296 color picture, producing 358
changing scale of user-generated color_hist 266
object 2 14 colors, extra, modifying 267
child 72, 74, 1 47 colproc.c program listing 258
CIRCLE 1 59, 1 60 col_data->trans 245
class, derived 75 color emitted by an object 244
classes 1 7 , 1 9 color, background, determining 243
classes for ray tracing 7 communicating with the ray tracer 1 00
classes, concept of 27 Communications of the ACM 296
els 22, 23 Complex class 28, 32, 34
Closest_Object 2 1 6, 2 1 8 Complex class, programming for 28
Close_File function 85, 87, 88 Computer Graphics 297
CNUM 1 46 Computer rendering of stochastic
CollisionTest function 2 1 6, 2 1 7 , 2 1 9, Models 296
223, 225 , 226 CONE 1 75 , 1 86, 1 87
CollisionTest function for bounding Cone class 1 88
box 2 1 0 cone, creating 1 5 2
CollisionTest function for Object 203 constructor 34, 1 89
CollisionTest function for constructor, for Vector 47
INDEX

constructor for Quaternion 3 1 8 DIR 1 74, 1 76


constructor for Vector 323 direction, cone 1 52
constructor, Parallelogram 1 92 directions, new 42
constructor, Quadratic 1 92 disk controller 442, 443
constructor, Ring 1 9 1 display considerations 445
constructor, Sphere 1 90 display, program to save in .PCX
constructor, Triangle 1 9 1 format 278
constructors, Vector, listing 50 display, program to save in .PCX
conventional programming 1 6 format, listing of 279
cos l 1 5 1 display, saving 278
cos2 1 5 1 displaying screens 256
CosViewPhi 349 displaying the created scene 1 1
cout 37, 3 1 8 DIST 1 7 8
crossing_no 225 DITHER 1 4 3 , 1 63, 1 77
Cube class 1 88 Dither function 237, 242, 243
CurrObj 2 1 6 DOS 249, 252
cylinder 2 1 9, 22 1 DRAGON 344, 349
dragon curves, equation for 330
dragon curves, in quaternions 330
- D- dragon quaternion 1 2
data file, simplified, sample 1 82 Dump_Line function 229, 239, 246
default 1 42, 148, 1 49, 1 50, 1 5 1 , 1 5 3
Dell 3 1 0 computer 444
delete 34 - E-
delta 224 effects, pattern 246
DENSITY 1 62 EGA 445
derived class 75 ellipsoid 2 1 9, 22 1
destructor 34, 1 89 elliptic cone 2 1 9, 22 1
determining background color 243 elliptic paraboloid 2 1 9, 22 1
determining position variables for an END_BBOX 1 47, 1 63
object 2 1 5 END_INSTANCES 1 46, 1 64, 2 1 4
DIFF 1 62, 340 END_X 1 54, 1 60
DiffuseColor function 234, 242 END_Y 1 54, 1 60
English language 1 9 floppy disk drives 442, 444
equation, for intersection with plane FOC_LENGTH 1 44, 1 7 8
223 found 1 0 1 , 1 42, 1 44, 1 4 5 , 1 48, 1 49,
extra colors, modifying 267 1 50, 1 5 1 , 1 5 3
Fournier, A . 296
fractal processing, implementing 298
-
F - fractal scenes, rendering 296
filename 248 fractal.cpp file 299
files, sample 1 80 fractal.cpp file, listing of 301
file_in 348 Fractal_comp function 300
FILE_NAME 1 44, 1 5 8 , 340 Fractal_comp function, listing of 304
FindBbox function 1 56 fractal_dim 299
FindBbox function for bounding box fractal_scalar 299
1 97 Fractal Programming in C 1 1 , 22
FindBbox function for Object 1 95 fractal scenes, rendering 1 1
FindBbox function for Parallelogram fractals, handling 298
1 95 friends 36, 38
FindBbox function for Quadratic 1 97 functions that match an object 9, 1 0
FindBbox function for Ring 1 97 Fussell, D . 296
FindBbox function for Sphere 1 95
FindBbox function for Triangle 1 96
finding normal to an object 2 1 2 -G-
FindNorm function for Object 1 93 gauss function, listing of 301
Findnorm function for Parallelogram generating bounding boxes 2 1 3
1 93 Get_Attrib function 1 08
FindNorm function for Quadratic 1 94 Get_Circle_Pattem function 1 32, 1 54
FindNorm function for Ring 1 94 get_color_data function 1 43
FindNorm function for Sphere 1 93 get_data function 1 0 1 , 1 04, 1 42, 1 46,
FindNorm function for Triangle 1 93 1 47
Find_ Color function 2 1 7, 239, 242, Get_Instance function 1 39
246 Get_Instance_Of function 1 55 , 1 56
FLIP 340 Get_Object function 1 30, 1 47, 299
floppy disk 256 GetFractal function 299
INDEX

GetTriangle function 299 high resolution VGA, plot function for


Get_Poly_Pattem function 1 35 , 1 55 268, 275
get_quaterion function, listing of 339 high resolution VGA, setMode
Get_Rect_Pattem function 1 33 , 1 54 function for 268, 274
get_string function I 06, 332 high resolution VGA, using 268
get_string function, listing of 337 HORIZ 143, 1 77
Get_SubPattem function 1 36, 1 53 , 1 54 hyperbolic paraboloid 2 1 9, 22 1
get_vector function 1 46 hyperboloid of one sheet 2 1 9, 22 1
GetAttrib 1 45 hyperboloid of two sheets 2 1 9, 22 1
GetAttrib function 1 42
GetCone function 1 22, 1 52 -1-
GetFractal function 1 28 IBM PC 4
getting Vector data from input file 56 1/0 board 442, 444
GetParallelogram function 1 20 IEEE Computer Graphics and
GetPattem function 1 36, 1 5 3 Applications 89
GetQuadratic function 1 25 init_color function 82
GetRing function 1 1 8 init_world 79
GetTriangle function 1 1 6 init_world function 8 1
get_ vector function, listing of 338 input.cpp file 1 00, 1 52, 299
glassdist 245 input with C++ 36
graphics functions 22 instance 1 0 l
Graphics Programming in C 22, 266 instance, transferring to object list 1 55
gu 225 INSTANCE_OF 1 55
gv 225 instances, processing 1 46
Intensity function 357
Intensity function, listing of 356
-H- interface procedures, RenderMan 92
Haines, Eric 89, 90 interface, RenderMan 90, 9 1 , 92
Hamilton, Sir William 1 2, 306 interfaces, rendering, ray tracing 89
hard disk drive 443, 444 Intersect function 2 1 6, 2 1 7, 2 1 8, 23 1 ,
hardware requirements 1 3 , 442 242, 244
HEIGHT 1 76 intersection equations for quadric
height, cone 1 52 curves 222
intersection math 2 1 8 len l 1 49, 1 5 1
intersection with bounding box 226 len2 1 49, 1 5 1
intersection with plane, equation for light 349
223 LIGHT_PHI 34 1
intersection, with parallelogram 224 light source 73
intersection, with Quadric curve 2 1 9 LIGHT_THETA 34 1
intersection, with ring 223 limit 299
intersection, with sphere 2 1 9 Line class 73
intersection, with triangle 226 line, sending to data file 246
intersections, determining ray tracing 9 line->flag 245
intersections, ray-object 2 1 6 linenumber 77
iostream.h header file 252 link 74
linked list for ray tracing program 76
linked lists, concept of 7 1
-J- loading the World 1 0 1
JULIA 344, 349 LoadWorld function 8 8 , 1 04
Julia quaternion 1 2 Joe 1 50, 1 64, 1 67, 1 68, 1 70- 1 79, 2 1 2-
Julia sets, equation for 330 217
Julia sets, in quaternions 330 location 224
LOOKAT 1 79
-K-
Kajiya, James T. 297 , 298
keyboard 443, 444 - M-
Koran, Steve 98 make 248 , 249, 250
Korzybski, Alfred 1 8 , 1 9 Make Bbox function 1 56
make capability 1 1 , 248
- L- makefile 249, 252
I amp 1 44, 1 7 8 makefile, Turbo C++, listing 253
Lamp class 73 makefile, Zortech C++, listing 250
lamp->distance 244, 245 Make_Bbox function 88, 1 38, 1 57
language, input 9 Make_fractal_triangles function 299,
language, QRT 99, 1 00, 1 5 8 300
language, ray tracing, using 1 5 8 Make_fractal_triangles, listing of 30 1
INDEX

malloc 33 Procedurally Defined Objects 297


math coprocessor 1 3, 445 newdir 1 5 1
math, intersection 2 1 8 newline.dir 222
max function for Vector class 54, 57 newline.loc 222
max function for vector 327 newobj 299
maximum of two numbers 77 newpos 2 1 3
MAX_ITERATIONS 344 Newton's method 7 , 2 1 , 24
MAX_SIZE 343 Newton's method program, another 42
memory, assigning for a class 33 Newton's method program,
MicroDoc 89 generalized 38
midpoint-displacement method 1 1 Newton's method program,
midpoint displacement technique 296 generalized, listing 40
min function for Vector class 5 5 , 57 Newton's Method program, listing of
min function for vector 327 another 43
minimum of two numbers 77 Newton's method, complications with
MIRROR 1 62, 246 38
modifying extra colors 267 Newton's method, program for solving
motherboard 442, 443 simple equation 25
Move_Instance function 1 4 1 , 1 56 nextobj 2 1 5
MS-DOS 1 5 8 next object 72
mult 1 55 next_line 73
multiplication, non-comutative 306 next_object 73
multiplier 245 , 246 normal, finding, for object 2 1 2
no_parem 1 44- 1 50, 1 5 1 - 1 55
norm 1 49, 1 5 1
- N-
n 1 1 48 , 1 49, 1 5 1 , 224
NAME 1 45 , 1 59, 1 65 , 1 67 , 1 69, 1 7 1 , -0-
1 74, 1 76, 1 80 0bject class 74, 1 86
Name_Find function 1 39, 1 56 Object Oriented Software Systems 1 5
new 34 object, attaching a pattern to 1 52
new directions 42 object, determining position variables
New Techniques for Tracing for 2 1 5
object, finding normal to 2 1 2 PATTERN 1 45- 1 49, 1 50- 1 59, 1 64-
object, functions that match 9 , 1 0 1 68, 1 70, 1 74
object, user-generated, changing scale Pattern class 7 4
of 2 1 4 pattern data, processing 1 5 3
object structures for ray tracing 59 pattern effects 246
object-ray intersections 2 1 6 pattern, attaching to an object 1 52
object.cpp file 2 1 6 pattern->link 1 55
Object.next 79 PC Paintbrush 278
object-oriented programming 6, 1 6 pcxgen.cpp program, description of
objects 1 0 1 278
objects, processing 1 47 pcxgen.cpp program, listing of 279
objects.cpp file 1 89, 2 1 6 philosophical background 1 8
objects.cpp file, listing of 1 90 Phong shading 244, 358
OBSERVER 1 79 PhotoRealistic RenderMan 98
Offset_lnstance function 1 42 picture, color, producing 358
old_position 245 pictures, ray tracing 254
Open_File function 85, 87, 88 Pixar 90
operator overloading 35, 49 pixel 228, 350, 35 1
ostream 37 Pixel function, listing of 356
output with C++ 36 pixel, determining color of 357
overloading operators for Vector 49 Plate04.ray, listing of 366
overview of rendering a scene 79 Plate05 .ray, listing of 3 7 1
Plate06.ray, listing of 374
Plate07 .ray, listing of 376
- P- Plate08.ray, listing of 378
Pal_Array 266 Plate09 .ray, listing of 4 1 9
paradigm 1 7 Plate I O.ray, listing of 423
PARALLELOGRAM 1 69, 226 Plate 1 1 .ray, listing of 425
Parallelogram class 80, 1 50, 2 1 4, 2 1 5 Plate 1 2.ray, listing of 427
parallelogram, intersection with 224 Plate 1 3 .ray, listing of 429
parameters, pattern 1 53 Plate 1 4.qat, listing of 43 1
PAREN 1 65- 1 69, 1 7 1 - 1 79 Plate l 5 .qat, listing of 432
parser 1 00 Plate 1 6.qat, listing of 434
INDEX

plot 22, 23 program to display quaternion data


plot function 263 , 350, 363 358
plot function for 256 colors 293 program to process color data 258
plot function for 256 colors, protected 32
description of 265 public 32, 34, 47, 3 1 4
plot function, for high resolution VGA
268, 275
POINT 1 55 , 1 6 1 - Q-
pointpatt->link 1 55 qin.cpp file 33 1 , 349
POLYGON 1 59, 1 6 1 qin.cpp file, listing of 334
pos l 2 1 5 qmath.cpp file 3 1 8
pos2 2 1 5 qmath.hpp header file 3 1 5
Position function 246 qrender.cpp file 349
Position function for Object 200 qrender.cpp file, listing of 344, 35 1
Position function for Parallelogram qrender.cpp program 33 1
20 1 qrender.hpp file, listing of 332
Position function for Quadratic 202 qrender.hpp header file 33 1
Position function for Ring 202 QRT data file, sample 1 8 1
Position function for Sphere 200 QRT language 99, 1 00, 1 58
Position function for Triangle 20 1 QRT program 98
position variables for object, quadproc.cpp program, listing of 358
determining 2 1 5 QUADRATIC 1 7 1
printing Vector data 56, 57 Quadratic class 1 5 1 , 1 52, 2 1 5
private 32 quadric curve, intersection with 2 1 9
processing attributes 1 42 quadric curves, intersection equations
processing bounding boxes 1 46 for 222
processing color data 1 46 QUADRILATERAL 226
processing instances 1 46 quater.cpp program 33 1
processing objects 1 4 7 QUATERNION 343
processing pattern data 1 5 3 Quaternion class 3 1 4, 330
processor speed 445 Quaternion class header file 3 1 5
product of quaternion and vector 3 1 0 quaternion data, program to display
program, ray tracing 59 358
quaternion input data file 33 1
quaternion multiplication, geometric -
R -

effect of 3 1 0, 3 1 2 rad 224


Quaternion, constructor for 3 1 8 RADIUS 1 54, 1 60, 1 64, 1 75, 1 78
quaternion, definition 307 radius, cone 1 52
quaternion, dragon 1 2 RAD_ l 1 68
quaternion, Julia 1 2 RAD_2 1 68
quaternions 1 2 ray tracer, communicating with 9, 1 00
quaternion, function to find magnitude ray tracer, main program, description
323 of 87
quaternion, mag_sq function for 3 1 8 , ray tracer, main program, listing of 86
323 ray tracing, complex geometry 6
quaternion, norm of 309 ray tracing, general description of 3
quaternion, overload of * operator 320 ray tracing, simple geometry 4
quaternion, overload of + operator 3 1 9 ray tracing program 59
quaternion, overload of - operator 3 1 9, ray tracing program, creating 249
320 ray tracing rendering interfaces 89
quaternion, overload of I operator 32 1 ray, tracing 1 1 , 24 1
quaternion, overload of = operator 32 1 ray, tracing through transparent
quaternion, overload of - operator 322 medium 245
quaternion, print function for 3 1 8, 322 ray-object intersections 2 1 6
quaternion, product of with vector 3 1 0 ray-tracing, classes used in 8
quaternion, sqr function for 3 1 8, 322 ray.cpp file 2 1 6, 228
quaternion, uses of 308 ray.cpp file, listing 229
quaternions, computing 348 RECTANGLE 1 59
quaternions, dragon curves in 330 REFLECT 1 63 , 245 , 340
quaternions, Julia sets in 330 ReflectColor function 236, 242, 246
quaternions, mathematics of 306 reflections 246
quaternions, overloading of operators reflections, specular 244
for 3 1 6 registers, VGA 268
quaternions, product of two 308 REMOVE 1 65, 1 67, 1 69, 1 7 1 , 1 74,
quick ray tracing program 98 1 76, 2 1 7
Quicksort algorithm 266 render.cpp file 79
INDEX

render.cpp file, listing of 80 1 98


render.hpp header file 59, 248 Scale_Instance function for Triangle
render.hpp header file, listing of 60 1 99
rendering fractal scenes 1 1 , 296 Scaling 350
rendering interfaces for ray tracing 8 scene, displaying the created 1 1
rendering the screen 8 scenes, fractal, rendering 1 1 , 296
rendering interfaces, ray tracing 89 screens, displaying and saving 256
rendering scene, overview 79 setMode 22, 23
RenderMan interface 90, 9 1 , 92 setMode function 262, 287, 292, 350,
RenderMan interface procedures 92 363
requirements, hardware 442 setMode function, description 265
Rev_Rotate function for Vector class setMode function, for high resolution
55 VGA 268 , 274
RING 1 67 setMode function, listing of 356
Ring class 1 49, 2 1 5 setVGApalette function 263, 276, 292,
ring, intersection with 223 363
Robeson, David 1 5 setVGApalette function, description of
Rotate function for Vector class 55 265
shadow_flag 2 1 8
Shape class 1 88
-5- Shortest_time 2 1 6, 2 1 8
sam p le files 1 80 sibling 74
saving screens 256 simplified data file, sample 1 82
scale of user-generated object, sin 1 1 5 1
changing 2 1 4 sin2 1 5 1
Scale_Instance function 1 56, 2 1 4, 2 1 5 Sin ViewPhi 349
Scale_Instance function for Object 1 98 SKY 1 77
Scale_Instance function for sky data 1 43
Parallelogram 1 98 SkyColor function 237, 242, 243
Scale_Instance function for Quadratic Smalltalk 1 5
200 software requirements 1 3
Scale_Instance function for Ring 1 99 sort function 263 , 276, 286, 364
Scale_Instance function for Sphere specular reflections 244
SPHERE 1 64 user-generated object, changing scale
Sphere class 75, 80, 1 47 , 1 86, 1 87, of 2 1 4
1 88 , 2 1 4 using high resolution VGA 268
SREFLECT 1 63 , 340
Standard Procedural Database 89
START_X 1 54, 1 59 - V-
START_Y 1 54, 1 60 v l 1 50, 1 67, 1 68 , 1 70, 2 1 3
stream.hpp header file 25 1 v2 1 50, 1 67 , 1 68 , 1 70, 2 1 3
structures 1 9 vect l 1 50, 1 5 1 , 2 1 2, 2 1 3, 2 1 4, 222
vect2 1 50, 2 1 2, 2 1 3 , 2 1 4
-T- vect3 2 1 5
theta 357 Vector class 47
touch program 248 Vector, constructor for 323
Trace_Ray function 229, 230, 24 1 -246 Vector, constructors, listing 50
Trace_Scene function 88, 228, 229, vector, cross product 50
242 vector, dot product 50
tracing a ray 228, 24 1 vector, max function for 327
TRANS 1 62 vector, min function for 327
transferring an instance to the object Vector, overload of % operator 326
list 1 55 Vector, overload of * operator 325
transparent medium, tracing ray Vector, overload of + operator 323
through 245 Vector, overload of - operator 323
TransparentColor function 235, 242, Vector, overload of I operator 325
245 Vector, overload of = operator 326
TRIANGLE 1 65 Vector, overload of " operator 326
Triangle class 1 48 , 2 1 5 , 299 Vector, overload of - operator 327
triangle, intersection with 226 vector, print function for 328
Turbo C++ 1 3 , 1 6, 28, 25 1 , 252 vector, product of with quaternion 3 1 0
Turbo Pascal 5 . 5 1 6 vectors, three-dimensional 7 , 47
Vega 1 024i VGA card 268
VGA 1 1 , 1 3, 79, 256, 350, 445
- U- VGA card 443, 444
UP 1 79 VGA card, Vega l 024i 268
INDEX

VGA display, creating 256 XMAX 1 73 , 342


VGA monitor 443 , 444 XMIN 1 73 , 342
VGA registers 268 XMULT 1 67 , 1 69, 1 7 1 , 1 74, 1 76
VGA, high resolution, plot function XRES 79, 1 79, 268, 342, 350
for 268 , 275 x_mult 246
VGA, high resolution, setMode XSIZE 79
function for 268, 274 X_SIZE 1 59
VGA, high resolution, using 268 XMULT 1 65
VIEW_PHI 342 XRES 1 45
virtual function 1 87
virtual functions, concept of 1 86 -
Y -

YMAX 1 7 3 , 342
YMIN 1 73 , 343
-W- YMULT 1 67 , 1 69, 1 7 1 , 1 74, 1 76
World 75, 1 43 , 229, 243 YRES 79
World, loading l 0 l YSIZE 79
WORLD.first_scan 228 YRES 1 80, 268, 342, 350
WORLD.flength 1 44 y_mult 246
WORLD.lamps 1 45 Y_SIZE 1 59
WORLD.last_scan 228 YMULT 1 65
WORLD.objcount 1 48 YRES 1 45
WORLD.outfile 1 44
WORLD.patlist 1 53
WORLD.sky_dither 1 43 , 243 -Z-
WORLD.stack 72 z buffer 1 2
WORLD_stack 73 ZENITH 1 43 , 1 77
WORLD.threshold 242 ZMAX 1 74, 343
World_Stats function 8 3 , 87, 8 8 ZMIN 1 73 , 343
wsphere.ray data file 25 1 Zortech C++ 1 3, 1 6, 28, 36, 80, 249,
25 1 , 252
zs256.c program, listing of 288
-
X -
ZSoft 278 , 436
Xerox Palo Alto Research Center 1 5 " operator 50
" operator, Vector, overloading 53
- operator 36
- operator, Vector, overloading 54

You might also like