C++ Question AddParticleStream, how to ? [solved]

N_Molson

Addon Developer
Addon Developer
Donator
Joined
Mar 5, 2010
Messages
10,002
Reaction score
4,418
Points
203
Location
Toulouse
Hello, :tiphat:

I'm trying to use "AddParticleStream" but I fail to input the 4th parameter, which is supposed to be a double *

PSTREAM_HANDLE VESSEL::AddParticleStream ( PARTICLESTREAMSPEC * pss,

const VECTOR3 & pos,

const VECTOR3 & dir,

double * lvl
)

const
Adds a custom particle stream to a vessel.

Parameters:
pss pointer to particle stream definition structure
pos particle source position in vessel coordinates [m]
dir particle emission direction in vessel coordinates
lvl pointer to scaling factor

I've tried this, but I can't find out how to get it to work. What I (think to) know is that I need to convert a double (lvl) to a pointer (lvl*).

Code:
double lvl = 1;
*lvl = static_cast<double*>(lvl);
AddParticleStream(&contrail_main, _V(0,1.25,-18.65), _V(0,0,-1), *lvl);

Thanks for your help.
 
Last edited:
Try the "&" operator. Like double *plvl = &lvl

The & operator gives you a pointer at a variable, pointers are denoted by the "*". The more *, the more pointers in a chain Like "A points on a pointer that points on a pointer that points to b"
 
you don't want to convert the double to a pointer (that's a shortcut to a CTD), but you want to point to it (&lvl).

:ninja:
 
Thanks. It seems I'm still missing something, because the effect doesn't work, but now it compiles. I use :

double lvl = 1;
AddParticleStream(&test_main, _V(0,1.25,-18.65), _V(0,0,-1), &lvl);

And thanks for the link Hielor, though I have it in my favorites already. I'm a very amateur coder that never followed a single course of programming, with a mere IQ of 113. I discovered C++ with Orbiter SDK. So I'm trying to get it, but that pointer/values thing is very complex to me, and I still don't get the logic behind it. :tiphat:

I also tried Urumpwe "chaining" suggestion :

double lvl = 1;
double *plvl = &lvl;
AddParticleStream(&test_main, _V(0,1.25,-18.65), _V(0,0,-1), *plvl);

But still no luck (*plvl isn't accepted).
 
Last edited:
I vote for something like:

class PARTICLE {
public:
int Particle();
SURFHANDLE tex_firetrail;
PARTICLESTREAMSPEC test_main;
};

int PARTICLE::Particle() {
SURFHANDLE tex_firetrail= oapiRegisterExhaustTexture ("name_of_texture");
};

PARTICLESTREAMSPEC test_main= {
0, 2.2, 30, 150.0, 0.1, 0.3, 8, 0.1, PARTICLESTREAMSPEC::EMISSIVE,
PARTICLESTREAMSPEC::LVL_PSQRT, 0, 0.05,
PARTICLESTREAMSPEC::ATM_PLOG, 1e-6, 1,
tex_firetrail
};

double lvl = 1;
AddParticleStream(&test_main, _V(0,1.25,-18.65), _V(0,0,-1), &lvl);
 
Last edited:
For some reason, it doesn't work.

Well I think I'll go for the "fake thruster" alternative with "AddExhaustStream", which I know how to use.

Still, I'd like to know, one day... :hmm:
 
I also tried Urumpwe "chaining" suggestion :



But still no luck (*plvl isn't accepted).
You don't need the extra * in that case--it's already include in the type of plvl.

Simple example:
Let's say you've declared an integer:
Code:
int foo = 15;

When this runs, memory will be allocated for this variable and it will be stored somewhere in RAM, let's say at address 100. The address will always be an integer type, even if the value is not.

Address|Value
...
100|15
...

If you get the value of foo:
Code:
int val = foo;
This will be, as expected, 15.

You can also get the address of foo:
Code:
 int *addr;
addr = &foo;

I've split this up into two lines to make it easier to read. In the first, we are declaring a variable named "addr", and we tell the computer that its type is a pointer to an int (an "int *")--that is, this variable will hold the address of an int.

In the second line, we assign the address of "foo" to "addr" by using the "&" operator, which can be read as the "address of" operator. Per the table above, "addr" is actually 100, but the computer knows that this has meaning--specifically, it is an address of some other variable. It is "pointing" to that variable.

To access the value of foo given addr, we use the * (dereference) operator:
Code:
int val = *addr; // 15

The * operator, used in this way, tells the computer to treat its operand as an address, and to actually fetch what is at that address. "val" will once again end up as 15 in this case.

You can also set the value of foo via addr, now:
Code:
*addr = 20;
This tells the computer to place the value of 20 into whatever is being pointed to by "addr". Looking at the value of "foo" after this will show that it is now 20.

So, when you need to pass a "double *" to a function, you can either pass the address directly to the function via the & operator:

Code:
double dub = 15.2;
func(&dub);

or you can make an intermediary pointer variable:
Code:
double dub = 15.2;
double *pdub = &dub; // pdub "points to" dub--it holds the address of dub
func(pdub); // since pdub is already a double*, we don't need to do anything other than directly pass it here

I really suggest that you find a tutorial on the subject that you can understand--pointers are one of the most powerful concepts in computer science, and if you fully understand them, a whole lot will click into place :)

---------- Post added at 14:40 ---------- Previous post was at 14:37 ----------

Another reason that your code isn't working--the double that you pass to the AddParticleStream code must stick around after the function completes. In the example you provide, "lvl" will no longer be a valid variable after the function exits, so the particle stream won't have a value.

You need to use a pointer to a global or class member variable. When you AddParticleStream, the particle stream will "remember" where to look for that value, and look there in the future, so any changes to that variable will be reflected in the particle stream.
 
Got it !! This piece of code worked (in ClbkPostStep, MET is just a timer) :

if (MET >= -12 && MET < -6)
{

PARTICLESTREAMSPEC test = {
0, 2.0, 30, 1, 0.05, 5, 4, 1.0, PARTICLESTREAMSPEC::EMISSIVE,
PARTICLESTREAMSPEC::LVL_LIN, 1, 1,
PARTICLESTREAMSPEC::ATM_FLAT, 1, 1
};

double *plvl = &lvl;
AddParticleStream(&test, _V(0,0,-18.5), _V(0,0,1), plvl);

}

... with in the class declaration (private subsection) :

double lvl;

and in ClbkSetClassCaps :


This was the key to me :

Another reason that your code isn't working--the double that you pass to the AddParticleStream code must stick around after the function completes.

That AddParticleStream function needs to be updated constantly (every frame).

I don't know how to explain it, but I feel two "categories" of functions :

1- Those that take care of themselves (like AddExhaustStream, you mention it one time and then it auto-updates - I guess because it's directly related to the thrusters thing, which is in the very Orbiter core and always updates -)

2- Those that need to be "reminded" each frame, like AddParticleStream.

The tricky thing is that if you update every frame a "category 1" function, it's CTD-ish. Like, if you use "CreateThruster", updating it every frame proves to be at best useless, at worse a source of unstability.

Well, that's the way I see it. :lol:

---------- Post added at 10:30 PM ---------- Previous post was at 10:12 PM ----------

A little correction, I had to add a "do once" bool variable to make it work. Which ruins my above theory of "categories", I guess : :P

if (MET >= -12 && MET < -6)
{

PARTICLESTREAMSPEC test = {
0, 0.5, 1, 1, 0.05, 5, 2, 1.0, PARTICLESTREAMSPEC::EMISSIVE,
PARTICLESTREAMSPEC::LVL_LIN, 1, 1,
PARTICLESTREAMSPEC::ATM_FLAT, 1, 1
};

double *plvl = &lvl;

if (done06 == false)
{
AddParticleStream(&test, _V(0,1.25,-18.5), _V(0,0,-1), plvl);
done06 = true;
}
}
 
Last edited:
From your description above I am not sure if you have understood the idea behind the pointer to your lvl parameter:

  • You definitely don't want to call AddParticleStream at each frame. You call it only once (e.g. in the classcaps function, or as a response to some event)
  • What you can change at each frame is the value of your lvl parameter (between 0 and 1). This variable is what governs the output intensity of the particle stream. So modifying this variable is a lightweight method of manipulating the stream without having to call a function like "SetParticleLevel()" at each frame. By using the pointer you provided in AddParticleStream, orbiter continuously monitors the value of lvl, and adjusts the stream accordingly.
 
Back
Top