POV-Ray : Newsgroups : povray.general : Strange syntax Server Time
10 Mar 2026 13:20:15 EDT (-0400)
  Strange syntax (Message 10 to 19 of 19)  
<<< Previous 9 Messages Goto Initial 10 Messages
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:

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



a float across all components, but it does not apply to boolean results of
comparisons. [github.com], [math.hws.edu]




Equality is scalar
In POV‑Ray SDL, A = B is a comparison with a scalar truth value (1 for

one. Internally the expression evaluator carries results in a small fixed array

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

colours are 5‑component vectors: rgbft), the arity is 5. The documentation


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]




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]



If you need a vector/colour mask of ones after a comparison, build it
explicitly, e.g.:

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]


handles = and point to the code paths that set only the first component on

3.8 alpha, or master). [github.com]


The relevant code in the parser



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

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
}




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


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>.




the end result depends on which one the parser chooses from context:


Float → N‑vector replication (operator promotion rule).

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

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

5‑vector is expected and it starts from a true float, not from a

had in mind. [povray.org], [math.hws.edu]

Why does a comparison yield a 1‑lane vector instead of a float?


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.

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]


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



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

<<< Previous 9 Messages Goto Initial 10 Messages

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