6.2.2  Las Directivas #declare y #local

Se pueden declarar identificadores para referenciarlos más tarde y hacer así las escenas más legibles, pero también para poder parametrizar la escena de manera que, cambiando una simple declaración, se cambien diferentes valores. Existen varios identificadores incorporados que POV-Ray declara por ti. Mira las secciones "Identificadores predefinidos de coma flotante" e "Identificadores vectoriales predefinidos" para más detalles.

6.2.2.1  Declarando Identificadores

Un identificador se declara de la siguiente forma:

DECLARACION:
    #declare IDENTIFICADOR = DVALOR |
    #localIDENTIFICADOR = DVALOR
DVALOR:
    COMA FLOTANTE; | VECTOR; | COLOR; | CADENA | OBJETO | TEXTURA | 
    PIGMENTO | NORMAL | ACABADO | INTERIOR | MEDIA | DENSIDAD |
    MAPA_DE_COLOR | MAPA_DE_PIGMENTO | MAPA_DE_INCLINACION | MAPA_DE_NORMAL | 
    MAPA_DE_DENSIDAD | CAMARA | FUENTE_DE_LUZ | NIEBLA | ARCOIRIS | 
    ESFERA_CELESTE | TRANSFORMACION

Donde IDENTIFICADOR es el nombre de un identificador de hasta 40 caracteres de longitud, y DVALOR es cualquiera de los ítems citados. Se les llama así porque son valores que pueden aparecer a la derecha del signo igual. La sintaxis para cada uno se encuentra en la correspondiente sección de esta referencia del lenguaje.

 #declare Filas = 5;
 #declare Contador = Contador+1;
 #local  Aqui = <1,2,3>;
 #declare Blanco = rgb <1,1,1>;
 #declare Cyan = color blue 1.0 green 1.0;
 #declare Fuente = "ariel.ttf"
 #declare Rodillo = cylinder {-5*x,5*x,1}
 #declare Anillo = torus {5,1}
 #local  Cuadros = pigment { checker White, Cyan }
 #declare Reduccion = 0.5;
 object{ Rodillo scale y*5 }     // no "cylinder { Rodillo }"
 object {
  Anillo
  pigment { Cuadros scale 0.5 }
  transform Reduccion
 }

Nota: Observa que debe haber un punto y coma después de la expresión siempre que se trate de valores de coma flotante, vectores o colores. Este punto y coma fue introducido en la versión 3.1 de POV-Ray. Si se omite, POV-Ray genera un mensaje de alerta y además, algunas macros pueden no funcionar correctamente.

Las declaraciones, como la mayoría de directivas del lenguaje, pueden aparecer en cualquier parte del archivo, incluso dentro de otras sentencias. Por ejemplo:

#declare Aqui=<1,2,3>;
#declare Contador=0;         // inicializa el contador
union {
 object { Rodillo translate Aqui*Contador }
 #declare Contador=Contador+1;     // lo redeclara dentro de la unión
 object { Rodillo translate Aqui*Contador }
 #declare Contador=Contador+1;     // lo redeclara dentro de la unión
 object { Rodillo translate Aqui*Contador }
}

Como muestra este ejemplo, puedes redeclarar un identificador y usar su contenido previo en la propia redeclaración.

Nota: Los identificadores de objetos usan la sentencia de envoltorio genérico object{ ... }. No necesitas saber qué tipo de objeto es cuando lo citas.

Las declaraciones se pueden anidar hasta cierto punto. En el ejemplo de la sección anterior podrías declarar la unión entera como un objeto. Sin embargo, por razones técnicas, hay ciertas situaciones en las que no puedes usar una directiva del lenguaje dentro de la declaración de expresiones de coma flotante, vectores o colores. Aunque estos límites se han reducido desde POV-Ray 3.1, todavía existen.

Los identificadores declarados dentro del bloque #macro ... #end no se crean cuando se define la macro, sino cuando se invoca. Al igual que otros ítems dentro de una definición #macro, se ignoran en la definición de la macro.

6.2.2.2  #declare frente a #local

Los identificadores se pueden declarar tanto globales, usando la directiva #declare, como locales, usando la directiva #local.

Los identificadores creados mediante la directiva #declare son de duración permanente y alcance global. Una vez creados, están disponibles para toda la escena, y no pueden ser liberados hasta el final del análisis o hasta que se destruyan específicamente usando #undef. Véase "Destruyendo Identificadores" para más detalles.

Aquellos creados con la directiva #local son de duración temporal y de alcance local. Sobreescriben temporalmente cualquier identificador con el mismo nombre. Véase "Conflictos en nombre de identificadores".

Si la directiva #local se usa dentro de una sentencia #macro, el identificador será local para esa macro. El identificador se crea cuando se invoca la macro y se analiza la directiva #local. Persiste hasta que se alcanza la directiva #end de final de la macro, momento en el que se destruye. Las siguientes invocaciones de la macro crean identificadores totalmente nuevos.

El uso de #local dentro de un archivo de inclusión, pero no en una macro, también crea un identificador temporal local al archivo de inclusión. Cuando el archivo se incluye y se analiza la directiva #local, se crea el identificador, que permanece hasta que se alcanza el final del archivo de inclusión y se destruye. Las siguientes inclusiones del archivo dan lugar a identificadores totalmente nuevos.

Si se usa la directiva #local en el archivo principal de escena (no en un fichero de inclusión ni en una macro), se comporta igual que la directiva #declare. Por claridad, no deberías usar #local en el archivo principal, excepto dentro de macros.

No hay actualmente una manera de crear identificadores locales permanentes en POV-Ray.

Los identificadores locales pueden liberarse específicamente usando #undef, pero en general, no existe la necesidad de hacerlo. Mira la sección "Destruyendo Identificadores" para más detalles.

6.2.2.3  Conflictos con Nombres de Identificadores

Los identificadores locales pueden usar nombres de identificadores ya declarados. La precedencia corresponde al identificador más reciente y más local. Cuando se incluye un archivo o se invoca una macro, se crea una nueva tabla de símbolos. Cuando referenciamos identificadores, se buscan primero en la tabla de símbolos más reciente, después en la siguiente más reciente y así sucesivamente hasta llegar a la tabla global del archivo de escena principal. Cada vez que se sale de una macro o archivo de inclusión, se destruyen su tabla y sus identificadores. Los parámetros pasados por valor residen en la misma tabla de símbolos usada para los identificadores locales de la macro.

Las reglas para duplicar nombres de identificador pueden parecer complicadas cuando se usan múltiples macros o archivos de inclusión anidados, pero, en la práctica real, suelen dar los resultados esperados.

Considera el siguiente ejemplo: tienes un archivo principal de escena llamado myscene.pov que contiene:

 #declare A = 123;
 #declare B = rgb<1,2,3>;
 #declare C = 0;
 #include "myinc.inc"

Dentro del archivo de inclusión, invocas a una macro llamada MiMacro(J,K,L). Observa que no es importante dónde esté definida MiMacro, siempre que sea antes de ser invocada. En este ejemplo, lo importante es que la macro se invoca desde dentro de mi_inc.inc.

Los identificadores A, B, y C están generalmente disponibles en todos los niveles. Si mi_inc.inc o MiMacro contienen, por ejemplo, la sentencia #declare C=C+1;, entonces el valor de C cambia en cualquier parte, tal y como esperabas.

Ahora supón que dentro de mi_inc.inc haces lo siguiente...

 #local A = 546;

La versión global de A se oculta y se crea una nueva A que está también disponible dentro de MiMacro, ya que ésta se invoca desde mi_inc.inc. Una vez que sales de mi_inc.inc, la variable local A se destruye y se restaura la variable original A con su valor de 123. Como habías creado la variable local A dentro de mi_inc.inc, no hay ninguna manera de referenciar la variable global original A hasta que uses #undef A, o finalice el archivo de inclusión. La directiva #undef siempre destruye la versión más local de un identificador.

De manera similar, si MiMacro contuviera...

 #local B = box{0,1}

se crearía un nuevo identificador B local a la macro. El valor original de B permanece oculto y se restaura cuando finaliza la macro. Observa que la local B no tiene por qué ser del mismo tipo que la original.

La cosa se complica cuando intentamos asignar un nuevo valor a un identificador que fue declarado local en un nivel anterior. Supón que dentro de mi_inc.inc haces lo siguiente...

 #local D = 789;

Si desde dentro de mi_inc.inc quieres incrementar D en uno, deberías hacer lo siguiente:

 #local D = D + 1;

pero si intentas hacer esto dentro de MiMacro crearás una nueva variable D que será local a MiMacro y no incrementarás la variable D original, que es externa a MiMacro pero local a mi_inc.inc. Lo que has ordenado es "crear una nueva variable D local a MiMacro cogiendo el valor de la variable D local a mi_inc.inc más uno". Seguramente, no es lo que querías. En vez de ello, deberías de hacer lo siguiente:

 #declare D = D + 1;

Puedes pensar que esto crearía una nueva D global, pero realmente incrementa el valor de la variable D declarada en mi_inc.inc. ¿Confundido? Aquí están las reglas:

  1. Al referenciar un identificador, siempre obtienes la versión más reciente, más local. Por "referenciar" entendemos usar el valor del identificados en una sentencia de POV-Ray o a la derecha del signo igual tanto en #declare como en #local.
  2. Al declarar un identificador usando la directiva #local, el identificador que se está creando o al que se está asignando un nuevo valor, SIEMPRE se crea en el nivel actual de anidamiento de la macro o del archivo de inclusión.
  3. Al declarar un NUEVO identificador no existente hasta el momento, usando #declare, se crea con alcance global y se almacena en la tabla de símbolos del archivo de escena principal.
  4. Al ASIGNAR UN VALOR a un identificador EXISTENTE usando #declare, éste se asigna a la versión más local y reciente en ese momento.

En resumen, #local siempre significa "el nivel actual", mientras que #declare significa "global" para identificadores nuevos y "el más reciente" para identificadores existentes.

6.2.2.4  Destruyendo Identificadores con #undef

Los identificadores creados con #declare persisten, generalmente, hasta que el análisis de la escena ha finalizado. Los identificadores creados con #local duran sólo hasta el fin de la macro o el archivo de inclusión en que se crearon. Sin embargo, puedes destruir un identificador usando la directiva #undef. Por ejemplo:

#undef MiValor

Si existieran múltiples versiones locales anidadas del identificador, sólo la más reciente y más local será destruida, existiendo todavía los identificadores con idéntico nombre que fueron creados en niveles superiores.

Véase también "las Directivas #ifdef e #ifndef".