POV-Ray : Newsgroups : povray.general : #ifdef using a string expression? Server Time
1 May 2024 19:45:32 EDT (-0400)
  #ifdef using a string expression? (Message 14 to 23 of 38)  
<<< Previous 10 Messages Goto Latest 10 Messages Next 10 Messages >>>
From: Bald Eagle
Subject: Re: #ifdef using a string expression?
Date: 19 Mar 2023 10:45:00
Message: <web.64171f2898df09c91f9dae3025979125@news.povray.org>
"Kenneth" <kdw### [at] gmailcom> wrote:

> Given the current mix of flaws, the use of a string literal still has me
> scratching my head...
>         #ifdef("...string...")
>
> Alain's and JR's explanation of the expected behavior seems valid; but with a
> properly-working #ifdef, should the comparison fail outright (fatal error)? Or
> should it still be seen as defined? I'm mostly just curious ;-)

One might suggest:
"Expected variable name, literal value found instead."

-or- "It is what is is." ;)




The correct answer for me has always been OPTIONS.

When everything gets locked into a one-right-answer only format, it usually just
creates new problems in the process of "solving" the old.

I was just reading some old threads concerning this type of thing, and the
degenerate triangle warning vs 0-length fatal error for cylinders was brought
up.

For some scenes it could be a critical thing to stop the render.   For others,
you might want to just ignore them all.  Usually these things are addressed by
the users with workarounds, but why not have a configuration file that states
how to handle these cases, an additional argument for the object instantiation
that provides for individual control, or an error-trapping mechanism (with error
code) that allows the user to write their own programmatic/logical solution
based on further testing and flow control, and allows the user to issue better
warnings that the cryptic ones currently hard-coded in source?


Post a reply to this message

From: William F Pokorny
Subject: Re: #ifdef using a string expression?
Date: 19 Mar 2023 16:30:35
Message: <641770eb$1@news.povray.org>
On 3/19/23 10:14, Kenneth wrote:
> William F Pokorny <ano### [at] anonymousorg> wrote:
>>
>> Alright.
>>
>> A long time ago I created a bunch of statically linked(a) versions of
>> POV-Ray going back through time. Anyhow. Used these to trace the
>> introduction of the str/num OK in #ifdef test bug.
>> [clip]
>> My BIG bet is on the following commit being the problem,
>> but I don't have a static compile of it or the one prior to it to
>> be sure.
>>
> 
> Given the current mix of flaws, the use of a string literal still has me
> scratching my head...
>          #ifdef("...string...")
> 
> Alain's and JR's explanation of the expected behavior seems valid; but with a
> properly-working #ifdef, should the comparison fail outright (fatal error)? Or
> should it still be seen as defined? I'm mostly just curious ;-)
> 

I'm a little further along in looking at this. It's looking messy.

I think we need to start with the fact #ifdef, #ifndef and #undef have 
ALWAYS been #ifIdDefined, #ifIdNotDefined and #undefineId. Going back to 
the v3.6 documentation we have:

---------------
2.2.2.6.2 The #ifdef and #ifndef Directives

The #ifdef and #ifndef directive are similar to the #if directive 
however they are used to determine if an identifier has been previously 
declared.

IFDEF_DIRECTIVE:
     #ifdef ( IDENTIFIER ) TOKENS... [#else TOKENS...] #end
IFNDEF_DIRECTIVE:
     #ifndef ( IDENTIFIER ) TOKENS... [#else TOKENS...] #end

If the IDENTIFIER exists then the first group of tokens is parsed 
normally and the second set is skipped. If false, the first set is 
skipped and the second set is parsed. ...
----------------

So... The up front, not so good, news is the behavior of at least the 
#ifdef and #ifndef keywords was partly changed back in March of 2015. 
Intentional or accidental? It's not mentioned as an intended change 
anywhere I have seen - and I still don't understand how it happened even 
with some time reviewing the changes when it happened.

Christoph went on to add a bunch of inbuilt keywords to be considered 
'defined' sometime after late November 2018 - which makes me begin to 
think he too might have been considering these *def keywords in the 
c/c++ coding, macro test sense.

The few 'keywords' I've tested these generate a warning in at least some 
versions of POV-Ray. But it's weird, keywords NOT returning immediate 
numbers or strings are also considered 'defined' in these versions 
though they are in fact arbitrary SDL keywords.

Even this worked in the pre-backed off v3.8 release parser:

#ifdef(#declare V=99;#undef V)
...

Though without some other mistake it would usually die with a later 
unmatched something parsing fail. That said it's not hard to get it to 
parse clean - say with an added #if(). I will always die if somebody 
tries use the undef'd V.

So, much more was being supported as testing true in povr/v4.0, but 
still not some things like raw vectors. Though things like x,y,z are OK.

Christoph backed up the v3.8 parser and again lost the inbuilt keywords 
as "defined". I do not know the reasons for the parser backup, but 
perhaps this issue it - or big part of it. I don't know.

I do know, I've got a mess with these in the povr parser given my branch 
point... :-(


When I test v3.7, v3.8b2 and my povr(v4.0?) code I get:

v3.7
----------------------
GOOD_ID  --> This is a valid ID. (ifdef returning true)
GOOD_ID  --> This is a valid ID. (ifndef returning false)
BAD_ID   --> This is NOT a valid ID. (ifdef returning false)
BAD_ID   --> This is NOT a valid ID. (ifndef returning true)
"STRING" --> Other than an ID. (ifdef returning false)
"STRING" --> Other than an ID. (ifndef returning true)
""       --> Other than an ID. (ifdef returning false)
""       --> Other than an ID. (ifndef returning true)
1.23456  --> Other than an ID. (ifdef returning false)
1.23456  --> Other than an ID. (ifndef returning true)
0        --> Other than an ID. (ifdef returning false)
0        --> Other than an ID. (ifndef returning true)
pi       --> Other than an ID. (ifdef returning false)
pi       --> Other than an ID. (ifndef returning true)
          --> Other than an ID. (ifdef returning true)
          --> Other than an ID. (ifndef returning true)

v3.8b2
-----------------------
GOOD_ID  --> This is a valid ID. (ifdef returning true)
GOOD_ID  --> This is a valid ID. (ifndef returning false)
BAD_ID   --> This is NOT a valid ID. (ifdef returning false)
BAD_ID   --> This is NOT a valid ID. (ifndef returning true)
"STRING" --> Other than an ID. (ifdef returning true)        ***
"STRING" --> Other than an ID. (ifndef returning false)      ***
""       --> Other than an ID. (ifdef returning true)        ***
""       --> Other than an ID. (ifndef returning false)      ***
1.23456  --> Other than an ID. (ifdef returning true)        ***
1.23456  --> Other than an ID. (ifndef returning false)      ***
0        --> Other than an ID. (ifdef returning true)        ***
0        --> Other than an ID. (ifndef returning false)      ***
pi       --> Other than an ID. (ifdef returning false)
pi       --> Other than an ID. (ifndef returning true)
          --> Other than an ID. (ifdef returning true)
          --> Other than an ID. (ifndef returning true)

povr & likely v4.0 and other misc releases before parser backup
-------------------------
GOOD_ID  --> This is a valid ID. (ifdef returning true)
GOOD_ID  --> This is a valid ID. (ifndef returning false)
BAD_ID   --> This is NOT a valid ID. (ifdef returning false)
BAD_ID   --> This is NOT a valid ID. (ifndef returning true)
"STRING" --> Other than an ID. (ifdef returning true)        ***
"STRING" --> Other than an ID. (ifndef returning false)      ***
""       --> Other than an ID. (ifdef returning true)        ***
""       --> Other than an ID. (ifndef returning false)      ***
1.23456  --> Other than an ID. (ifdef returning true)        ***
1.23456  --> Other than an ID. (ifndef returning false)      ***
0        --> Other than an ID. (ifdef returning true)        ***
0        --> Other than an ID. (ifndef returning false)      ***
pi       --> Other than an ID. (ifdef returning true)        ###
pi       --> Other than an ID. (ifndef returning false)      ###
          --> Other than an ID. (ifdef returning true)
          --> Other than an ID. (ifndef returning true)

The last case with empty parens is an exposure back to v3.7. In a lot of 
code the effective fall through at the #if____ will cause later parsing 
problems, but the error are of the more unhelpful sort. It would be best
if the empty parens were themselves a parse error. I 'think' it's 
probably also possible to fix the following parsing issues with another, 
cleaning syntax (actual bad-syntax) sort of mistake.

My feeling is the right thing to do would be to take the behavior back 
to what it has always been with the nearer term v3.8 release. If we want 
the most backward compatibility this it. Further, the extra now being 
changed currently in the v3.8 code is not consistent with respect to 
things like pi - which to the parser is an immediate value of pi. And 
datetime would be an example of an immediate string which would test 
true, you'd think, if "string" does.

What to do... I could spend a lot of time trying to figure out the 
history here, but I think the current state not completely tenable since 
2015...

We need functionality which deals only with IDs.

We, perhaps, need some sort of what is in the parenthesis is 'defined' 
functionality too, but the generic sort being allowed or not seems 
questionable to me. Are people already using this functionality?

With povr I might do something drastic like create 'id' versions and and 
'defined' versions - with all new keyword names so users would be forced 
to look at potential problems with interpretation and behavior given the 
old keywords wouldn't work!

Hmm... We do have new to v3.8 the local and global dictionaries. Could I 
just dump the #ifdef and #ifndef keyword for something based on those. I 
can't remember at the moment how they work.

Don't know... Whatever it is in povr, afraid at the moment it'll be a 
lot of work - because I'll need to digest a lot of the parser code.

Guess it's time to do my taxes... :-)

Bill P.


Post a reply to this message

From: Bald Eagle
Subject: Re: #ifdef using a string expression?
Date: 19 Mar 2023 17:55:00
Message: <web.6417846d98df09c91f9dae3025979125@news.povray.org>
William F Pokorny <ano### [at] anonymousorg> wrote:

> The few 'keywords' I've tested these generate a warning in at least some
> versions of POV-Ray. But it's weird, keywords NOT returning immediate
> numbers or strings are also considered 'defined' in these versions
> though they are in fact arbitrary SDL keywords.

I think you're going to run into the same hamstringing that an over-concern
about backwards compatibility inevitably results in.  If any of this stuff is
going to be fixed, there needs to be a clean break, and a sane, logical,
rational, basis for moving forward.

> Even this worked in the pre-backed off v3.8 release parser:
> #ifdef(#declare V=99;#undef V)
> Though without some other mistake it would usually die with a later
> unmatched something parsing fail.

That looks fine - given someone may have some reason to do that.  Some sort of
quick bypass workaround.


> I will always die if somebody tries use the undef'd V.

Yes.  Because V is for Victory, and undefining it results in Failure.  :P

> So, much more was being supported as testing true in povr/v4.0, but
> still not some things like raw vectors. Though things like x,y,z are OK.

.....

> Further, the extra now being
> changed currently in the v3.8 code is not consistent with respect to
> things like pi - which to the parser is an immediate value of pi. And
> datetime would be an example of an immediate string which would test
> true, you'd think, if "string" does.
>
> What to do... I could spend a lot of time trying to figure out the
> history here, but I think the current state not completely tenable since
> 2015...
>
> We need functionality which deals only with IDs.
>
> We, perhaps, need some sort of what is in the parenthesis is 'defined'
> functionality too, but the generic sort being allowed or not seems
> questionable to me. Are people already using this functionality?

I use and abuse whatever I can find as a workaround for lack of functionality.
I absolutely don't mind rewriting code to perform with a new and better version.

Currently trying to implement some geometric testing code, it's becoming
increasingly clear that we have plenty of raytracing capability, and missing
programming code to make coding the scenes easier and more capable.

Example:
I'm testing for an intersection.  What do I do in SDL if there's a) none, or b)
more than 1?   Or if I'm looking at parallel or skew lines.  Or the user or the
circumstances require the endpoints of a line to be the same (a point)?

I'm dreaming up workarounds like mixed arrays with succeed/fail flags followed
by the variable number of results (line/line | line/circle | circle/circle).
For data type cast, I'm thinking I need a 2D mixed array with the [0] holding
the data type as a string, and the actual data in the 1[].

It would be so much easier to code these things (and faster) if we had some
tools to deal with variable results.

null, NaN, variable type detection, error trapping, etc.
It would make testing with #ifdef a little more sane if #ifdef (keyword)
returned a versatile value that I could make use of in a broad number of
circumstances.

First - I think POV-Ray needs to sort out keywords vs values, scalars vs
vectors, vs parse/render/function space variable names.  It's confusing, and is
contributing directly to the mess you're trying to sort out. You can't.  It's
all inextricably mixed.  clipka correctly pointed out that all of this stuff
needs to get disentangled in the parser.

So, I would say that "if" should return a value that denotes keyword,
whereas "pi" should return a value that denotes a reserved value.  "CONST", or
whatever that compiler one is.  "PRAGMA"

It's "nice" that I can swizzle things all over the place between vectors and
colors, etc.  But it makes for lazy / bad programming practices.  Better the
ability to recast a value from a scalar to a vector to a color, etc.

It would probably take me a month, tops, to adapt to the new requirements, and
I'd be able to write better, shorter, more easily understood and maintained
code.  Further, if there were sufficient programmatic capability, "fixes" for
old scenes could be coded, much like TOK and I code custom functions and macros
to handle pow (0, 0), factorial, N choose M, mod () crossing the origin, etc.
Just change the keyword in the old scene to a capitalized version ("We love you,
jr!") and boom - you have a macro that could possibly handle a lot of the
backward compatibility with a simple find/replace on the old scene file.

The first rule of holes is: when you find yourself in one, stop digging.
The second is: climb out.

I'd rather suffer now, and profit later.


Post a reply to this message

From: Kenneth
Subject: Re: #ifdef using a string expression?
Date: 19 Mar 2023 23:45:00
Message: <web.6417d58798df09c99b4924336e066e29@news.povray.org>
William F Pokorny <ano### [at] anonymousorg> wrote:
>

Thanks for doing such a detailed series of tests and an examination of the
various code versions! I can imagine that it was a lot of drudgery.

> I think we need to start with the fact #ifdef, #ifndef and #undef have
> ALWAYS been #ifIdDefined, #ifIdNotDefined and #undefineId. Going back to
> the v3.6 documentation we have:
> [clip]
>
> We need functionality which deals only with IDs.
>
> ...but the generic sort being allowed or not seems
> questionable to me.

I agree; IMO, #ifdef etc. should adhere to the much more strict behavior
described in the docs. Admittedly, I am not as sophisticated a user of these
functions as some others are, but the current behavior seems quite lax and could
lead to unintended scene errors or coding 'mysteries'.

And I would be happier if my silly string-literal example produced a fatal
error! Otherwise, I can't imagine a scenario where a 'naked' string would even
be used there.

I also think that using an *actual* zero or a float (while having some meaning
as boolean values) does not really represent a 'valid ID' as per docs, and so
should fail outright as well. My opinion ;-) HOWEVER... I can see a scenario
where 0 or 1 could be used simply to test whether a scene's specific #ifdef
construct is working properly or not-- in other words, without relying on an
actually-defined identifier for the test. On the other hand...it would be a
simple matter to pre-define a temp dummy identifier for the same use.

> Christoph went on to add a bunch of inbuilt keywords to be considered
> 'defined' sometime after late November 2018 - which makes me begin to
> think he too might have been considering these *def keywords in the
> c/c++ coding, macro test sense.

Actually, it's not clear to me why any keywords at all would or should be valid
'parameters' for an #ifdef comparison-- but I'm rather naive at present about
what might be such a useful coding scenario. For example, my own rather
meaningless(?) test of
               #ifdef(true)
appears to be a flat-out mistaken use of the function, since the comparison will
(or rather, *should*) always invoke the first clause, never the #else. In other
words, this construct should use #if or #while or #switch or etc, not #ifdef.

I am obviously not seeing why a keyword could be meaningfully used there.


----------
In general, I think that most of not all of the non-fatal error messages re:
#ifdef should be changed to fatal-- if only as a guard against using entities
that don't belong there and need changing. Personally, I'm lazy about taking
note of non-fatal messages.


Post a reply to this message

From: jr
Subject: Re: #ifdef using a string expression?
Date: 20 Mar 2023 03:20:00
Message: <web.641808dd98df09c94301edef6cde94f1@news.povray.org>
hi,

"Kenneth" <kdw### [at] gmailcom> wrote:
> William F Pokorny <ano### [at] anonymousorg> wrote:
> ...
> Actually, it's not clear to me why any keywords at all would or should be valid
> 'parameters' for an #ifdef comparison ...

one use I see, though I have never tried/used it, is determining whether a given
keyword (already) exists in the POV-Ray version doing the parsing; if it worked
for, eg, 'tau'.  also, fwiw, agree that parsing (generally) should be "strict".


regards, jr.


Post a reply to this message

From: Alain Martel
Subject: Re: #ifdef using a string expression?
Date: 20 Mar 2023 11:11:17
Message: <64187795$1@news.povray.org>
Le 2023-03-19 à 10:41, Bald Eagle a écrit :
> "Kenneth" <kdw### [at] gmailcom> wrote:
> 
>> Given the current mix of flaws, the use of a string literal still has me
>> scratching my head...
>>          #ifdef("...string...")
>>
>> Alain's and JR's explanation of the expected behavior seems valid; but with a
>> properly-working #ifdef, should the comparison fail outright (fatal error)? Or
>> should it still be seen as defined? I'm mostly just curious ;-)
> 
> One might suggest:
> "Expected variable name, literal value found instead."
> 
> -or- "It is what is is." ;)
> 
> 
> 
> 
> The correct answer for me has always been OPTIONS.
> 
> When everything gets locked into a one-right-answer only format, it usually just
> creates new problems in the process of "solving" the old.
> 
> I was just reading some old threads concerning this type of thing, and the
> degenerate triangle warning vs 0-length fatal error for cylinders was brought
> up.
> 
> For some scenes it could be a critical thing to stop the render.   For others,
> you might want to just ignore them all.  Usually these things are addressed by
> the users with workarounds, but why not have a configuration file that states
> how to handle these cases, an additional argument for the object instantiation
> that provides for individual control, or an error-trapping mechanism (with error
> code) that allows the user to write their own programmatic/logical solution
> based on further testing and flow control, and allows the user to issue better
> warnings that the cryptic ones currently hard-coded in source?
> 
> 
> 

Or even a global_settings entry, such as :
Ignore_degenerate true|false //default to false


Post a reply to this message

From: Kenneth
Subject: Re: #ifdef using a string expression?
Date: 20 Mar 2023 21:20:00
Message: <web.6419062498df09c99b4924336e066e29@news.povray.org>
"jr" <cre### [at] gmailcom> wrote:
>
> "Kenneth" <kdw### [at] gmailcom> wrote:
> >
> > Actually, it's not clear to me why any keywords at all would or should
> > be valid 'parameters' for an #ifdef comparison ...
>
> one use I see, though I have never tried/used it, is determining whether a given
> keyword (already) exists in the POV-Ray version doing the parsing; if it worked
> for, eg, 'tau'.
>

Ah! Yes, I see the usefulness of that. Thanks. That totally escaped me. My
#ifdef(true) example was a bad choice to illustrate the situation.

> > And I would be happier if my silly string-literal example produced a fatal
> > error! Otherwise, I can't imagine a scenario where a 'naked' string would
> > even be used there.


Post a reply to this message

From: Kenneth
Subject: Re: #ifdef using a string expression?
Date: 20 Mar 2023 23:35:00
Message: <web.6419252d98df09c99b4924336e066e29@news.povray.org>
I hit the 'post' button too soon :-/

> And I would be happier if my silly string-literal example produced a fatal
> error! Otherwise, I can't imagine a scenario where a 'naked' string would even
> be used there.
>

Well, on 2nd thought, I do see at least one special-case string use: To try to
easily determine if a particular #include file is actually present in a scene.
Like:
              #ifdef("my sphere file.inc")
or maybe a no-string version:  #ifdef(my sphere file.inc)
                           or  #ifdef(my sphere file)

Nothing like this works in v3.8xx. Of course, #ifdef may not be the correct
thing to use, but it's the first idea that comes to mind. (I have a vague
memory-- possibly mistaken-- that I did use the string- construct version in the
*distant* past, and that it worked. Or maybe not.) But with the current behavior
of #ifdef("...string..."), it's of no use. And   (my sphere file.inc)   fails
outright because of the 'dot'; likewise   (my sphere file)  because of the
spaces.

There IS an obscure built-in identifier (or variable?) called
View_Include_Stack, that can be used to determine if any of POV-ray's *own*
specific include files are present-- ALL that are being used-- by putting the
following at the top of a scene, running it, then looking afterward in
'Messages' (in Windows GUI versions, that is):
                     #declare View_POV_Include_Stack = true;

I can't find it in the documentation; but take a look here...
https://news.povray.org/povray.general/thread/%3C5c0827cd%241%40news.povray.org%3E/

Unfortunately, it will not list any user-made #includes-- even if they are
placed in POV-ray's 'includes' folder; I just tested it. That seems strange.

(The link above actually discusses the topic of how to determine the presence of
such user-made files, but the various methods seem to require that code snippets
be added to each and every file first. A simpler #ifdef scheme would be much
easier!)


Post a reply to this message

From: William F Pokorny
Subject: Re: #ifdef using a string expression?
Date: 21 Mar 2023 03:26:38
Message: <64195c2e$1@news.povray.org>
On 3/20/23 23:31, Kenneth wrote:
> Well, on 2nd thought, I do see at least one special-case string use: To try to
> easily determine if a particular #include file is actually present in a scene.

I'm having a hard time seeing a good reason for the capability. If you 
are trying to do something like swap in simple stand in for a complex 
model while developing a scene, it seems like you should just set that 
up on a declared true false variable ahead of time.

Maybe you'd want to automatically use a simple stand end until the 
include of the complex model is created. Well then you could use 
file_exists() and the complex model will be included as soon as it exist 
somewhere POV-Ray can find it.

A failing include stops parsing.

Folks often include far more than they need (stnd.inc ?) for any given 
scene. While that slows down parsing, it usually isn't a fatal mistake.

Unfortunate undefs or re-declares to the same IDs do happen, and that is 
the one place where a user might want to throw an error if, say, he 
knows POV-Ray's color.inc has the potential to undo his flavor or Red. 
But, then maybe, MyBetterThanPOVRayRed is a better name... :-)

Not arguing you couldn't use the functionality, it's just hard for me to 
see the return on investment.

Aside: Even checking the name there is a search order for the file too 
and, if there are multiple files called color.inc available, the next 
feature request will be something about knowing which actual color.inc 
POV-Ray included.

---

I'm thinking, jr, about a keyword_exists() kind of feature.

---

Aside: I'm digging around more on the - since 2015 - ifdef(), ifndef() 
v3.71/v3.8/v4.0 behavior; I noticed when keywords are passed, Christoph 
made updates to some releases to kick out a warning:

Parse Warning:
Trying to test whether a reserved keyword is defined.
Test result may not be what you expect.

(or a similar message depending on releases)

I take it as evidence he was playing with looking at more than IDs - or 
perhaps he realized there was an unintended an unintended behavior he 
needed to back out (a part of it he did for v3.8). For povr I'll likely 
leave the message in place on restoring v3.7 and prior behavior; Users 
can get different results depending on what release code they run on 
testing keywords.

Yep, I need to look at how he made the inbuilt keyword determination for 
the message - there are hidden reserved words too which are not visible 
SDL 'keywords' / reserved words. Msg method might offer a way to an 
iskeyword().

Bill P.


Post a reply to this message

From: Kenneth
Subject: Re: #ifdef using a string expression?
Date: 21 Mar 2023 07:45:00
Message: <web.6419986c98df09c99b4924336e066e29@news.povray.org>
"Kenneth" <kdw### [at] gmailcom> wrote:
>
> There IS an obscure built-in identifier (or variable?) called
> View_Include_Stack...

Well... In the light of a new day, I remembered that I had seen that
*somewhere*; it's not an "obscure built-in identifier" :-[  It's just 'a name'
or variable-- part of an #ifdef block at the top of every 'official' POV-ray
include file, with a simple #debug statement:

             #ifdef(View_POV_Include_Stack)
             #debug "including arrays.inc\n"
             #end

It's just a useful/descriptive phrase that someone came up with in the past.
Which explains why adding    #declare View_POV_Include_Stack = true;   at the
top of your main scene file results in a list of those #included files in
'messages'.  Duh. No special magic.

>
> I can't find it in the documentation...
>
...because it's, uh, not part of POV-ray.
>
> Unfortunately, it will not list any user-made #includes-- even if they are
> placed in POV-ray's 'includes' folder; I just tested it. That seems strange.

That's because my personal #include files don't have the added #ifdef block.
Until now, I never gave much thought as to why I should add that. NOW I see why.
It's a good way to see which files might be buried in a large scene with lots of
nested #includes.

I haven't yet tested it to see if it will flag *multiple* instances of the same
#include. That would be useful too.


Post a reply to this message

<<< Previous 10 Messages Goto Latest 10 Messages Next 10 Messages >>>

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