POV-Ray : Newsgroups : povray.general : Strange syntax Server Time
9 Oct 2026 03:31:13 EDT (-0400)
  Strange syntax (Message 1 to 19 of 19)  
From: kurtz le pirate
Subject: Strange syntax
Date: 24 Feb 2026 11:36:24
Message: <699dd388$1@news.povray.org>
Hello,


I found this in some very old code (2016) :

light_source {
   <0, 100, 0>
   color White=1
   }


and with thise, the light in the scene is red.
of course, back to "normal" color White give white light.



How this <color White=1> is interpreted and why does it turn red?




-- 
kurtz le pirate
compagnie de la banquise


Post a reply to this message

From: Bald Eagle
Subject: Re: Strange syntax
Date: 24 Feb 2026 12:25:00
Message: <web.699dddebf71f0dcaa433a43625979125@news.povray.org>
kurtz le pirate <kur### [at] freefr> wrote:
> Hello,
>
>
> I found this in some very old code (2016) :
>
> light_source {
>    <0, 100, 0>
>    color White=1
>    }

> How this <color White=1> is interpreted and why does it turn red?

Yeah, that's weird.
The parser is a strange and wondrous thing.

Presumably you are including colors.inc.
Can you output the color value of White as a 5D vector to the debug stream
before instantiating the light source, and then show what happens to it after?

- BE


Post a reply to this message

From: Cousin Ricky
Subject: Re: Strange syntax
Date: 24 Feb 2026 22:21:40
Message: <699e6ac4$1@news.povray.org>
On 2026-02-24 12:36 (-4), kurtz le pirate wrote:
>
> How this <color White=1> is interpreted and why does it turn red?

Where does the identifier `White` come from?  Like BE, I would like to
know its value.

My understanding of that syntax is that it compares each component of
`White` with 1.  But if `White` comes from colors.inc, the
component-wise comparison would still end up as white.  The only way I
can see this evaluating as red is if `White.red` is exactly 1, and
`White.green`, `White.blue`, `White.filter`, and `White.transmit` are
all something other than 1.


Post a reply to this message

From: kurtz le pirate
Subject: Re: Strange syntax
Date: 25 Feb 2026 03:56:54
Message: <699eb956@news.povray.org>
On 25/02/2026 04:21, Cousin Ricky wrote:
> On 2026-02-24 12:36 (-4), kurtz le pirate wrote:
>>
>> How this <color White=1> is interpreted and why does it turn red?
> 
> Where does the identifier `White` come from?  Like BE, I would like to
> know its value.

White come from "colors.inc"



> My understanding of that syntax is that it compares each component of
> `White` with 1.  But if `White` comes from colors.inc, the
> component-wise comparison would still end up as white.  The only way I
> can see this evaluating as red is if `White.red` is exactly 1, and
> `White.green`, `White.blue`, `White.filter`, and `White.transmit` are
> all something other than 1.
> 

I also thought that "=" was interpreted as a comparison operator.

But since “White” is defined by rgb 1, that doesn't explain anything.







-- 
kurtz le pirate
compagnie de la banquise


Post a reply to this message

From: Bald Eagle
Subject: Re: Strange syntax
Date: 25 Feb 2026 06:50:00
Message: <web.699ee0d4f71f0dca1f9dae3025979125@news.povray.org>
[before light_source]
White = <1.000, 1.000, 1.000, 0.000, 0.000>

[after light_source]
White = <1.000, 1.000, 1.000, 0.000, 0.000>
"C:\Users\Mini\Documents\POV-Ray\v3.8-beta\scenes\_CodeScratchPad.pov" line 13:
Parse Warning: Expected pure RGB color expression,
unexpected filter and transmit components will have no effect.
-
"C:\Users\Mini\Documents\POV-Ray\v3.8-beta\scenes\_CodeScratchPad.pov" line 16:
Parse Error: Parse halted by #error directive: No
objects in scene

I'm thinking that the red must be coming from something else.
Post the whole scene, a link, or at least more to work from?

- BE


Post a reply to this message

From: Alain Martel
Subject: Re: Strange syntax
Date: 25 Feb 2026 13:45:13
Message: <699f4339$1@news.povray.org>
Le 2026-02-25 à 06:45, Bald Eagle a écrit :
> [before light_source]
> White = <1.000, 1.000, 1.000, 0.000, 0.000>
> 
> [after light_source]
> White = <1.000, 1.000, 1.000, 0.000, 0.000>
> "C:\Users\Mini\Documents\POV-Ray\v3.8-beta\scenes\_CodeScratchPad.pov" line 13:
> Parse Warning: Expected pure RGB color expression,
> unexpected filter and transmit components will have no effect.
> -
> "C:\Users\Mini\Documents\POV-Ray\v3.8-beta\scenes\_CodeScratchPad.pov" line 16:
> Parse Error: Parse halted by #error directive: No
> objects in scene
> 
> I'm thinking that the red must be coming from something else.
> Post the whole scene, a link, or at least more to work from?
> 
> - BE
> 

Just tested, using this : #declare W = (White=1);
And got this :

W = <1.000, 0.000, 0.000, 1.000, 1.000>
NOT what I would expect.


Post a reply to this message

From: Bald Eagle
Subject: Re: Strange syntax
Date: 25 Feb 2026 14:25:00
Message: <web.699f4b6cf71f0dcaa433a43625979125@news.povray.org>
Alain Martel <kua### [at] videotronca> wrote:

> Just tested, using this : #declare W = (White=1);
> And got this :
>
> W = <1.000, 0.000, 0.000, 1.000, 1.000>
> NOT what I would expect.

Yes indeed, VERY strange.
I was going to do something like that, but I needed to head out.

what if plug (White=1) directly into a debug vstr statement?

- BE


Post a reply to this message

From: Cousin Ricky
Subject: Re: Strange syntax
Date: 25 Feb 2026 15:01:50
Message: <699f552e$1@news.povray.org>
On 226-02-24 12:36 (-4), kurtz le pirate wrote:
> 
> How this <color White=1> is interpreted and why does it turn red?

I just tried it with different versions of POV-Ray.  It is red only with
POV-Ray 3.8 and the discontinued POV-Ray 3.7.1.  It is white for all
versions 3.5 to 3.7.0.10.

This appears to be a bug that was introduced in POV-Ray 3.7.1.


Post a reply to this message

From: Bald Eagle
Subject: Re: Strange syntax
Date: 25 Feb 2026 15:15:00
Message: <web.699f575ff71f0dcaa433a43625979125@news.povray.org>
Cousin Ricky <ric### [at] yahoocom> wrote:
> On 226-02-24 12:36 (-4), kurtz le pirate wrote:
> >
> > How this <color White=1> is interpreted and why does it turn red?
>
> I just tried it with different versions of POV-Ray.  It is red only with
> POV-Ray 3.8 and the discontinued POV-Ray 3.7.1.  It is white for all
> versions 3.5 to 3.7.0.10.
>
> This appears to be a bug that was introduced in POV-Ray 3.7.1.

Nice work, Richard.
So what are you doing that I didn't?
Because as you can see above/below, I'm using 3.8

[after light_source]
White = <1.000, 1.000, 1.000, 0.000, 0.000>
"C:\Users\Mini\Documents\POV-Ray\v3.8-beta\scenes\_CodeScratchPad.pov" line 13:
Parse Warning: Expected pure RGB color expression,
unexpected filter and transmit components will have no effect.

Are you outputting the color value with vstr(), or performing a render using
that light source?

I'm just trying to understand where this all goes off the rails, and where to
look under the hood.

- BE


Post a reply to this message

From: Cousin Ricky
Subject: Re: Strange syntax
Date: 25 Feb 2026 15:50:28
Message: <699f6094$1@news.povray.org>
On 2026-02-25 16:11 (-4), Bald Eagle wrote:
> Cousin Ricky <ric### [at] yahoocom> wrote:
>> On 226-02-24 12:36 (-4), kurtz le pirate wrote:
>>>
>>> How this <color White=1> is interpreted and why does it turn red?
>>
>> I just tried it with different versions of POV-Ray.  It is red only with
>> POV-Ray 3.8 and the discontinued POV-Ray 3.7.1.  It is white for all
>> versions 3.5 to 3.7.0.10.
>>
>> This appears to be a bug that was introduced in POV-Ray 3.7.1.
> 
> Nice work, Richard.
> So what are you doing that I didn't?
> Because as you can see above/below, I'm using 3.8

I just opened a bug report on GitHub, issue #486.
https://github.com/POV-Ray/povray/issues/486

> [after light_source]
> White = <1.000, 1.000, 1.000, 0.000, 0.000>
> "C:\Users\Mini\Documents\POV-Ray\v3.8-beta\scenes\_CodeScratchPad.pov" line 13:
> Parse Warning: Expected pure RGB color expression,
> unexpected filter and transmit components will have no effect.

The warning about unexpected filter and transmit components indicates
that the bug did manifest, but without altering `White`.  Did you create
an image output?  Did you vstr() the expression `(White=1)`?

> Are you outputting the color value with vstr(), or performing a render using
> that light source?

Both.  My source code is in the GitHub report.


Post a reply to this message

From: Bald Eagle
Subject: Re: Strange syntax
Date: 25 Feb 2026 16:10:00
Message: <web.699f6513f71f0dcaa433a43625979125@news.povray.org>
Cousin Ricky <ric### [at] yahoocom> wrote:

> The warning about unexpected filter and transmit components indicates
> that the bug did manifest, but without altering `White`.  Did you create
> an image output?  Did you vstr() the expression `(White=1)`?

As far as I can remember (it was early and I was on my way out the door to
work):

I vstr()'d the expression White,

then instantiated the light source (copy/pasted kurtz le pirate's exact code) ,

then vstr()'d the expression White again.

Which is now even weirder, because if White got changed to include filter and
transmit, then why didn't it show up with vstr?  And why did it still have g&b
values of 1?

I'll check/post my actual code when I get home - but that won't be for another
5h.

- BE


Post a reply to this message

From: Cousin Ricky
Subject: Re: Strange syntax
Date: 25 Feb 2026 17:03:18
Message: <699f71a6$1@news.povray.org>
On 2026-02-25 17:09 (-4), Bald Eagle wrote:
> 
> I vstr()'d the expression White,
> 
> then instantiated the light source (copy/pasted kurtz le pirate's exact code) ,
> 
> then vstr()'d the expression White again.
> 
> Which is now even weirder, because if White got changed to include filter and
> transmit, then why didn't it show up with vstr?  And why did it still have g&b
> values of 1?
> 
> I'll check/post my actual code when I get home - but that won't be for another
> 5h.

The value of `White` never changes.  It is the expression `(White=1)`
(which is a conditional in this context, not an assignment) that you
should vstr().


Post a reply to this message

From: Bald Eagle
Subject: Re: Strange syntax
Date: 26 Feb 2026 08:20:00
Message: <web.69a04805f71f0dca68a6daf225979125@news.povray.org>
Cousin Ricky <ric### [at] yahoocom> wrote:

> The value of `White` never changes.  It is the expression `(White=1)`
> (which is a conditional in this context, not an assignment) that you
> should vstr().

Ah, yes.  Very interesting.

So <1, 1, 1> gets promoted to rgbft <1, 1, 1, 0, 0>,
and 1 gets promoted to <1, 0, 0, 0, 0>

and then comparing element by element ones gets

<1, 1, 1, 0, 0>
<1, 0, 0, 0, 0>
---------------
<1, 0, 0, 1, 1>


Totally logical, yet totally unexpected!

- BE


Post a reply to this message

From: kurtz le pirate
Subject: Re: Strange syntax
Date: 26 Feb 2026 12:33:25
Message: <69a083e5$1@news.povray.org>
On 25/02/2026 12:45, Bald Eagle wrote:
> I'm thinking that the red must be coming from something else.
> Post the whole scene, a link, or at least more to work from?

the scene :

#version 3.8;

#include "colors"

global_settings {
   assumed_gamma 1.0
   max_trace_level 5
   }
#default {
   finish {
     ambient 0.00
     emission 0.40
     diffuse 0.60
     }
   }

camera {
   location <40,20,22>
   up y
   right x*image_width/image_height
   look_at <0, a*0.60, 0>
   angle 36
   }

light_source {
   <290, 384, 1350>
   color White=1
   }

plane {
   y,0
   pigment { White }
   }

#declare a = 4;
box {
   <-a, 0, -a>, <+a, 2*a, +a>
   pigment { White }
   }


With the warning :
Parse Warning: Expected pure RGB color expression, unexpected filter and 
transmit components will have no effect.






-- 
kurtz le pirate
compagnie de la banquise


Post a reply to this message

From: Cousin Ricky
Subject: Re: Strange syntax
Date: 26 Feb 2026 20:02:10
Message: <69a0ed12@news.povray.org>
On 2026-02-26 09:17 (-4), Bald Eagle wrote:
> 
> So <1, 1, 1> gets promoted to rgbft <1, 1, 1, 0, 0>,
> and 1 gets promoted to <1, 0, 0, 0, 0>
> 
> and then comparing element by element ones gets
> 
> <1, 1, 1, 0, 0>
> <1, 0, 0, 0, 0>
> ---------------
> <1, 0, 0, 1, 1>

Good work!

The 1 should have been promoted to <1, 1, 1, 1, 1>.  This would be
consistent with previous behavior and with other contexts where a scalar
appears in the same expression as a color or vector.

> Totally logical, yet totally unexpected!

Logic can give you wrong answers if a premise (in this case, the
promotion of the scalar) is wrong.

P.S. Not that it makes a difference here, but colors.inc defines `White`
as `rgb 1`, which means it does not need promotion.  It already has the
value <1, 1, 1, 0, 0>.


Post a reply to this message

From: Bald Eagle
Subject: Re: Strange syntax
Date: 27 Feb 2026 06:50:00
Message: <web.69a18400f71f0dca1f9dae3025979125@news.povray.org>
Cousin Ricky <ric### [at] yahoocom> wrote:

> The 1 should have been promoted to <1, 1, 1, 1, 1>.

Well, this is the danger with code, stems in general, and expectations.

"We would have _expected_ the 1 to be promoted to <1, 1, 1, 0, 0>."
But it did not.

> This would be
> consistent with previous behavior and with other contexts where a scalar
> appears in the same expression as a color or vector.

Right, which is what I was expecting, and what was throwing me off.

> > Totally logical, yet totally unexpected!
>
> Logic can give you wrong answers if a premise (in this case, the
> promotion of the scalar) is wrong.
>
> P.S. Not that it makes a difference here, but colors.inc defines `White`
> as `rgb 1`, which means it does not need promotion.  It already has the
> value <1, 1, 1, 0, 0>.

But it DOES make a difference.
White is _rgb_ 1.  NOT rgbft1.
That only happens on the fly when it needs to be compared to 1, which gets
promoted on the fly to rgbft.

That warning about f&t in the light source being ignored tells you it got
promoted, whereas a "normal" scene with rgb 1 would not issue such a warning.

This will take a lot of looking into to find out WHY it does what it does.
I'm just very thankful that no such thing took place when I was working out the
vector / scalar typing/differentiation!

- BE


Post a reply to this message

From: Bald Eagle
Subject: Re: Strange syntax
Date: 27 Feb 2026 10:10:00
Message: <web.69a1b372f71f0dca68a6daf225979125@news.povray.org>
I wanted to dig in a bit deeper to discover why scalar 1 gets promoted to <1, 0,
0, 0, 0, 0> instead of <1, 1, 1, 1, 1>.

Something clever that I noticed in the response was using vdot (V, V) as a way
to "count" the number of components in the vector (assuming they are all 1).
I will have to play with this idea.
Is there a way to normalize all the components of a vector without knowing how
many components there are?


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

AI response:
Because of how POV‑Ray’s parser “types” expressions and encodes boolean
results: the equality operator = produces a scalar (0/1). If that scalar is then
required to participate in a 5‑component colour/vector context higher up
the expression tree, the parser embeds the scalar into a 5‑component
register by placing it in the first component only and zeroing the rest—yielding
<1,0,0,0,0> rather than <1,1,1,1,1>. This is distinct from the general “operator
promotion” rule you’re thinking of (float → vector), which does replicate
a float across all components, but it does not apply to boolean results of
comparisons. [github.com], [math.hws.edu]

What’s going on in detail


Equality is scalar
In POV‑Ray SDL, A = B is a comparison with a scalar truth value (1 for
true, 0 for false). It’s not a vectorized comparison unless you explicitly build
one. Internally the expression evaluator carries results in a small fixed array
(“EXPRESS”) and tracks how many components are “live”. For comparisons, the live
count is 1. [github.com]


Type/arity is decided by surrounding context
When that scalar result is used where a vector/colour is expected, the parser
promotes it to the needed arity. There are two different promotion paths in the
language implementation:




General operator promotion (float → N‑vector), described in the
reference manual: a lone float can be promoted to a vector of 2/3/4/5 components
by replicating the same value into all components (e.g., 5 → <5,5,5> when
a 3‑vector is needed). This rule applies when a float literal/expression
itself is being used as a vector. [math.hws.edu]


Embedding of boolean/scalar results into multi‑component registers that
occurs inside the expression parser for comparison/logical operations. For
these, the parser stores the truth value in component 0 and clears the
remainder, producing <1,0,0,0,0> if the surrounding context expects a
5‑component value (as happens in colour/5‑term vector contexts).
This is why you observe <1,0,0,0,0> instead of <1,1,1,1,1>. You can see the
relevant behavior in the expression parser implementation (comparison handling
and result packing) in parser_expressions.cpp. [github.com]



Colour (5‑term) contexts are common
Any time an expression is in a colour context (e.g., inside pigment { … } where
colours are 5‑component vectors: rgbft), the arity is 5. The documentation
explains that colour expressions have 5 components—<red, green, blue, filter,
transmit>—and that unspecified filter and transmit default to 0. That’s why a
non‑colour scalar promoted into a colour context naturally becomes
something shaped like <value, 0, 0, 0, 0> when it comes from a boolean
comparison result. [povray.org], [museum.state.il.us]


Why this differs from “the usual” float→vector promotion
The “replicate to all components” rule is the Operator Promotion rule that
applies when a numeric float is directly promoted to an N‑vector (e.g.,
scale 5 → scale <5,5,5>). That rule does not override how
boolean/comparison results are packaged internally by the parser. So:

1 used as a colour literal where replication is needed: <1,1,1,1,1> (general
promotion). [math.hws.edu]
( <1,1,1> = 1 ) used where a colour is required: comparison yields scalar 1
first → then embedded as <1,0,0,0,0> (boolean embedding). [github.com]


How to get “uniform ones” if that’s what you want
If you need a vector/colour mask of ones after a comparison, build it
explicitly, e.g.:
Plain Textpov isn’t fully supported. Syntax highlighting is based on Plain
Text.#declare V = <1,1,1>;#declare M = (vdot(V, V) = 3 ? <1,1,1,1,1> :
<0,0,0,0,0>); // example of explicit replicationShow more lines
or use arithmetic to replicate the scalar result across components before the
colour context forces 5D:
Chart.js#declare B = (<1,1,1> = 1);     // scalar 0/1#declare M = B *
<1,1,1,1,1>;   // replicate into all 5 lanesShow more lines
(Here the multiplication forces general operator promotion on the float B to a
5‑vector, giving <B,B,B,B,B>.) [math.hws.edu]

If you’d like, I can step into the exact branch of parser_expressions.cpp that
handles = and point to the code paths that set only the first component on
boolean results—just say which POV‑Ray branch/commit you’re building (3.7,
3.8 alpha, or master). [github.com]


The relevant code in the parser
1) The expression result container and the “truth” macro
POV‑Ray’s expression parser carries intermediate values in a small fixed
array (EXPRESS) plus an integer “arity” (number of live components). It also
defines an epsilon‑based predicate to turn floats into boolean truth
values. You can see both patterns in the current file and its 3.7 predecessor:


// parser_expressions.cpp
#define FTRUE (f) ( (int) (fabs (f)>EPSILON))



This is used throughout the numeric/logic code paths whenever a boolean is
needed. [github.com]
Internally, results are stored as an EXPRESS (a fixed array of DBL) with a
“Terms” count. A number of functions show this pattern; for example, the
float-parameter helper rejects multi‑term results by checking Terms>1:


DBL Parser::Parse_Float_Param ()
{
    DBL Local;
    EXPRESS Express;
    int Terms;
    bool old_allow_id = Allow_Identifier_In_Call;
    Allow_Identifier_In_Call = false;

    Parse_Paren_Begin ();
    Parse_Express (Express,&Terms);
    if (Terms>1)
    {
        Error ("Float expected but vector or color expression found.");
    }
    Local = Express [0];
    Parse_Paren_End ();
    Allow_Identifier_In_Call = old_allow_id;
    return (Local);
}



This shows the (values, arity) representation: Express[0..Terms-1] is the
payload; the scalar case is Terms == 1. [github.com]
You can see the same scheme in the 3.7 code (express.cpp) as well.
[bugs.povray.org]
2) Places that set the arity
Whenever a vector-returning construct is parsed (e.g., a vector function call),
the parser explicitly writes multiple lanes into Express[...] and sets the
arity:


void Parser::Parse_Vector_Function_Call(EXPRESS Express, int *Terms)
{
    // ... call into VM ...
    for (param = 0; param < f->return_size; param++)
        Express[param] = fnVMContext->GetLocal(param);
    *Terms = f->return_size;  // <-- explicit arity for vector returns
}



That “Terms is the number of live components” convention is consistent across
the expression parser. [bugs.povray.org]
3) Where comparisons land
The actual comparison operators (e.g., =, !=, <, <=, >=, >) are handled in the
numeric/relational part of the expression parser; the code keeps temporary
scalars like greater_val, less_val, equal_val for those results, which are then
written back to the expression register as a single component (arity 1). You can
see these locals declared in the numeric parser routine:


// inside Parser::Parse_Num_Factor(...) in 3.7
DBL greater_val, less_val, equal_val;   // temps for relational/equality tests


Those comparisons convert to 0/1 using epsilon semantics (FTRUE), and then store
the result as a scalar in Express[0] with *Terms = 1. That is the key to the
behavior you’re seeing. [bugs.povray.org]

Why we care: Once a comparison has yielded a scalar Express[0] ∈ {0,1}
with Terms=1, any later need for a vector/colour will trigger a promotion. Which
promotion path it takes determines whether you get <1,0,0,0,0> or <1,1,1,1,1>.


Boolean embedding and promotion—what exactly happens?
POV‑Ray has two distinct (but similarly named) “promotion” behaviors, and
the end result depends on which one the parser chooses from context:


Float → N‑vector replication (operator promotion rule).
The documentation’s Operator Promotion section says that if POV‑Ray
expects an N‑component vector and you give it a float, it replicates the
float into all components:
9 → <9,9,9,9> (for 4‑vectors), 5 → <5,5,5> (for
3‑vectors), etc. [math.hws.edu]


Lower‑arity vector → higher‑arity vector zero‑fill.
The same section also says that when promoting a vector of lower dimension to a
higher one, the remaining components are set to zero:
<7,6> → <7,6,0,0> if a 4‑vector is required. [math.hws.edu]


The comparison result takes path (2), not (1).
The equality (<1,1,1> = 1) is parsed/evaluated in the numeric/relational
pipeline. The boolean truth value is put into the expression register as a
single‑lane result—conceptually a 1‑component vector, i.e., Terms =
1 and Express[0] = 1.0. When that value is later needed in a 5‑component
colour context (e.g., inside pigment { ... } where colours are rgbft
5‑vectors), POV‑Ray promotes a 1‑component vector to a
5‑component vector, which fills lanes 2..5 with zeros, giving <1,0,0,0,0>.
This matches exactly what you observed. [povray.org], [math.hws.edu]
By contrast, a literal 1 (a float) appearing directly in a colour context
follows path (1): it’s replicated to <1,1,1,1,1> because the parser knows a
5‑vector is expected and it starts from a true float, not from a
“1‑lane vector” that already has an arity. That’s the “usual” behavior you
had in mind. [povray.org], [math.hws.edu]

Why does a comparison yield a 1‑lane vector instead of a float?
Because of the parser’s internal representation:

All numeric/logic sub‑expressions are computed into the EXPRESS register
(DBL Express[5]) plus an integer Terms.
Pure scalars and booleans both occupy Terms = 1 lane at that point.
But here’s the catch: after certain operations (notably vector/colour handling),
the parser treats a Terms = 1 result as a vector of arity 1 if vector/colour
typing already dominates the surrounding context. From there, the
vector→vector arity promotion (zero‑fill) applies, not the
float→vector replication. [github.com], [bugs.povray.org]

So for (<1,1,1> = 1) you end up with:

Relational evaluation → Express[0] = 1.0, Terms = 1 (boolean true).
[bugs.povray.org]
Used in a colour (5‑vector) position → 1‑lane vector upcast to
5‑lane → <1,0,0,0,0>. [povray.org], [math.hws.edu]


How to get <1,1,1,1,1> from a boolean on purpose
If your intent is a mask of ones across all five colour lanes, force the
float→vector promotion (replication) explicitly by multiplying with a full
vector constant:


#declare B = (<1,1,1> = 1);        // scalar 0/1 in Express[0]
#declare M = B * <1,1,1,1,1>;      // forces float→vector replication
→ <B,B,B,B,B>


This uses general operator promotion (a float on the left in a vector arithmetic
expression) so POV‑Ray replicates B to each lane. [math.hws.edu]
If you’d rather avoid arithmetic, you can also pick the result yourself:

#declare M = select(B, <0,0,0,0,0>, <1,1,1,1,1>);

(That’s often the clearest way to signal intent in SDL.)


Post a reply to this message

From: Bald Eagle
Subject: Re: Strange syntax
Date: 4 Mar 2026 13:05:00
Message: <web.69a87436f71f0dcaf625f77c25979125@news.povray.org>
A few more breadcrumbs from the source code.
- BE

https://github.com/POV-Ray/povray/blob/master/source/parser/parser_expressions.cpp

Starting at Line 1340:

/* Promote_Express promotes Express to the requested number of terms.  If
   *Old_Terms==1, then it sets all terms to Express[0].  Otherwise, it pads
   extra terms with 0.0.

   To maximize the consistency of results, DO NOT promote until it is actually
   required.  This is to ensure, as much as possible, that the same expression
   will produce the same results regardless of the context.
*/

void Parser::Promote_Express(EXPRESS& Express,int *Old_Terms,int New_Terms)
{
    int i;

    if (*Old_Terms >= New_Terms)
        return;

    if (*Old_Terms==1)
    {
        for(i=1;i<New_Terms;i++)
        {
            Express[i]=Express[0];
        }
    }
    else
    {
        for(i=(*Old_Terms);i<New_Terms;i++)
        {
            Express[i]=0.0;
        }
    }

    *Old_Terms=New_Terms;
}

Then, if I'm correctly inferring the meaning at Line 1581:

void Parser::Parse_Rel_Term (EXPRESS& Express,int *Terms)

this must involve the "relational operator" which I'm assuming is whatever is in
between the parentheses of a comparison)

and further down starting at line 1623:

        CASE (EQUALS_TOKEN)
            Parse_Rel_Factor(Local_Express,&Local_Terms);
            Promote_Express(Express,Terms,Local_Terms);

            for(i=0;i<*Terms;i++)
                Express[i] = (DBL)(!FTRUE(Express[i]-Local_Express[i]));
        END_CASE





Further down in the file there is the code with the light source warning
(It's actually a large block of vector code starting at line 2028)

        CASE_VECTOR_UNGET
            if (startedParsing)
            {
                EXIT
            }
            else
            {
                // Note: Setting up for potential warning on single value float
promote to
                // five value color vector. Any single float will be promoted to
the full
                // 'tgtTerms' value. This usually results in filter and transmit
values >0,
                // which caused shadow artifacts back to at least version
v3.6.1.
                if ((CurrentCategorizedTokenId() == FLOAT_TOKEN_CATEGORY) ||
(CurrentTrueTokenId() == FUNCT_ID_TOKEN))
                    sawFloatOrFloatFnct = true;
                else
                    sawFloatOrFloatFnct = false;
                if (expectFT)
                    tgtTerms = 5;
                else
                    tgtTerms = 3;
                Parse_Express(Express,&Terms);
                Promote_Express(Express,&Terms,tgtTerms);
                if (expectFT && (Terms != 5))
                    Error("Color expression expected but float or vector
expression found.");
                else if (!expectFT && ((Terms < 3) || Terms > 5))
                    Error("RGB color expression expected but float or vector
expression found.");
                colour.Set(Express, Terms);
                if (((sawFloatOrFloatFnct) && (Terms==5)) && ((colour.filter()
!= 0) && (colour.transm() != 0)))
                    Warning("Float value promoted to full color vector where
both filter and transmit >0.0.");
                if (!expectFT && ((colour.filter() != 0) || (colour.transm() !=
0)))
                    Warning("Expected pure RGB color expression, unexpected
filter and transmit components will have no effect.");
                startedParsing = true;
            }
        END_CASE


Post a reply to this message

From: Bald Eagle
Subject: Re: Strange syntax
Date: 4 Mar 2026 16:25:00
Message: <web.69a8a208f71f0dcaffa3b0a825979125@news.povray.org>
From:
https://math.hws.edu/eck/cs324/s01/pov-doc/pov171.htm

Operator Promotion
You may use a lone float expression to define a vector whose components are all
the same. POV-Ray knows when it needs a vector of a particular type and will
promote a float into a vector if need be. For example the POV-Ray scale
statement requires a three component vector. If you specify scale 5 then POV-Ray
interprets this as scale <5,5,5> which means you want to scale by 5 in every
direction.

Versions of POV-Ray prior to 3.0 only allowed such use of a float as a vector in
various limited places such as scale and turbulence. However you may now use
this trick anywhere. For example...

 box{0,1}  // Same as box{<0,0,0>,<1,1,1>}

 sphere{0,1} // Same as sphere{<0,0,0>,1}
When promoting a float into a vector of 2, 3, 4 or 5 components, all components
are set to the float value, however when promoting a vector of a lower number of
components into a higher order vector, all remaining components are set to zero.
For example if POV-Ray expects a 4D vector and you specify 9 the result is
<9,9,9,9> but if you specify <7,6> the result is <7,6,0,0>.


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.