|
Identifiers may be declared and later referenced to make scene files more readable and to parameterize scenes so that changing a single declaration changes many values. There are several built-in identifiers which POV-Ray declares for you. See section "Built-in Float Identifiers" and "Built-in Vector Identifiers" for details.
An identifier is declared as follows.
DECLARATION: #declare IDENTIFIER = RVALUE | #local IDENTIFIER = RVALUE RVALUE: FLOAT; | VECTOR; | COLOR; | STRING | OBJECT | TEXTURE | PIGMENT | NORMAL | FINISH | INTERIOR | MEDIA | DENSITY | COLOR_MAP | PIGMENT_MAP | SLOPE_MAP | NORMAL_MAP | DENSITY_MAP | CAMERA | LIGHT_SOURCE | FOG | RAINBOW | SKY_SPHERE | TRANSFORM
Where IDENTIFIER is the name of the identifier up to 40 characters long and RVALUE is any of the listed items. They are called that because they are values that can appear to the right of the equals sign. The syntax for each is in the corresponding section of this language reference. Here are some examples.
#declare Rows = 5; #declare Count = Count+1; #local Here = <1,2,3>; #declare White = rgb <1,1,1>; #declare Cyan = color blue 1.0 green 1.0; #declare Font_Name = "ariel.ttf" #declare Rod = cylinder {-5*x,5*x,1} #declare Ring = torus {5,1} #local Checks = pigment { checker White, Cyan } object{ Rod scale y*5 } // not "cylinder { Rod }" object { Ring pigment { Checks scale 0.5 } transform Skew }
Note: that there should be a semi-colon after the expression in all float, vector and color identifier declarations. This semi-colon is introduced in POV-Ray version 3.1. If omitted, it generates a warning and some macros may not work properly. Semicolons after other declarations are optional.
Declarations, like most language directives, can appear almost anywhere in the file - even within other statements. For example:
#declare Here=<1,2,3>; #declare Count=0; // initialize Count union { object { Rod translate Here*Count } #declare Count=Count+1; // re-declare inside union object { Rod translate Here*Count } #declare Count=Count+1; // re-declare inside union object { Rod translate Here*Count } }
As this example shows, you can re-declare an identifier and may use previously declared values in that re-declaration.
Note: object identifiers use the generic wrapper statement
object{
... }
. You do not need to know what kind of
object it is.
Declarations may be nested inside each other within limits. In the example in the previous section you could declare the entire union as a object. However for technical reasons there are instances where you may not use any language directive inside the declaration of floats, vectors or color expressions. Although these limits have been loosened somewhat since POV-Ray 3.1, they still exist.
Identifiers declared within #macro
...
#end
blocks are not created at the
time the macro is defined. They are only created at the time the macro is
actually invoked. Like all other items inside such a #macro definition,
they are ignored when the macro is defined.
Identifiers may be declared either global using #declare
or
local using the #local
directive.
Those created by the #declare
directive are permanent in
duration and global in scope. Once created, they are available throughout the
scene and they are not released until all parsing is complete or until they
are specifically released using #undef
. See
"Destroying Identifiers".
Those created by the #local
directive are temporary in duration
and local in scope. They temporarily override any identifiers with the same
name. See "Identifier Name Collisions".
If #local
is used inside a #macro
then the
identifier is local to that macro. When the macro is invoked and the
#local
directive is parsed, the identifier is created. It persists
until the #end
directive of the macro is reached. At the #end
directive, the identifier is destroyed. Subsequent invocations of the macro
create totally new identifiers.
Use of #local
within an include file but not in a macro, also
creates a temporary identifier that is local to that include file. When the
include file is included and the #local
directive is parsed, the
identifier is created. It persists until the end of the include file is
reached. At the end of file the identifier is destroyed. Subsequent inclusions
of the file create totally new identifiers.
Use of #local
in the main scene file (not in an include file
and not in a macro) is identical to #declare
. For clarity sake
you should not use #local
in a main file except in a macro.
There is currently no way to create permanent, yet local identifiers in POV-Ray.
Local identifiers may be specifically released early using #undef
but in general there is no need to do so. See "Destroying Identifiers".
Local identifiers may have the same names as previously declared identifiers. In this instance, the most recent, most local identifier takes precedence. Upon entering an include file or invoking a macro, a new symbol table is created. When referencing identifiers, the most recently created symbol table is searched first, then the next most recent and so on back to the global table of the main scene file. As each macro or include file is exited, its table and identifiers are destroyed. Parameters passed by value reside in the same symbol table as the one used for identifiers local to the macro.
The rules for duplicate identifiers may seem complicated when multiple-nested includes and macros are involved, but in actual practice the results are generally what you intended.
Consider this example: You have a main scene file called myscene.pov
and it contains
#declare A = 123; #declare B = rgb<1,2,3>; #declare C = 0; #include "myinc.inc"
Inside the include file you invoke a macro called MyMacro(J,K,L)
.
It isn't important where MyMacro
is defined as long
as it is defined before it is invoked. In this example, it is important
that the macro is invoked from within myinc.inc
.
The identifiers A
, B
, and C
are
generally available at all levels. If either myinc.inc
or
MyMacro
contain a line such as #declare C=C+1;
then the value C
is changed everywhere as you might expect.
Now suppose inside myinc.inc
you do...
#local A = 546;
The main version of A
is hidden and a new A
is
created. This new A
is also available inside
MyMacro
because MyMacro
is nested inside
myinc.inc
. Once you exit myinc.inc
, the local
A
is destroyed and the original A
with its value of
123
is now in effect. Once you have created the local
A
inside myinc.inc
, there is no way to reference the
original global A
unless you #undef A
or exit the
include file. Using #undef
always undefines the most local
version of an identifier.
Similarly if MyMacro
contained...
#local B = box{0,1}
then a new identifier B
is created local to the macro only.
The original value of B
remains hidden but is restored when the
macro is finished. The local B
need not have the same
type as the original.
The complication comes when trying to assign a new value to an identifier at
one level that was declared local at an earlier level. Suppose inside
myinc.inc
you do...
#local D = 789;
If you are inside myinc.inc
and you want to increment
D
by one, you might try to do...
#local D = D + 1;
but if you try to do that inside MyMacro
you'll create a
new D
which is local to MyMacro
and not the
D
which is external to MyMacro
but local to
myinc.inc
. Therefore you've said "create a MyMacro
D
from the value of myinc.inc
's D
plus
one". That's probably not what you wanted. Instead you should
do...
#declare D = D + 1;
You might think this creates a new D
that is global but it
actually increments the myinc.inc version of D
. Confusing
isn't it? Here are the rules:
#declare
or #local
.#local
keyword,
the identifier which is created or has a new value assigned, is ALWAYS
created at the current nesting level of macros or include files.#declare
,
it is created as fully global. It is put in the symbol table of the main
scene file.#declare
,
it assigns it to the most recent, most local version at the time.In summary, #local
always means "the current
level", and #declare
means "global" for new
identifiers and "most recent" for existing identifiers.
Identifiers created with #declare
will generally persist
until parsing is complete. Identifiers created with #local
will
persist until the end of the macro or include file in which they were
created. You may however un-define an identifier using the
#undef
directive. For example:
#undef MyValue
If multiple local nested versions of the identifier exist, the most local most recent version is deleted and any identically named identifiers which were created at higher levels will still exist.
See also "The #ifdef and #ifndef Directives".
|