PDA

View Full Version : Plugins - How to write?


cgneuling
03-28-2012, 10:43 PM
Hi!
I want to write my first plugin. I have knowledge in C++ and Maxscript but not in the 3ds Max SDK. I want to read in all selected objects and their animationpath and also their vertices. In the program I want to calculate new animation path and want to write them back, if they are changed. Further there should be a User Interface. So I want to read in parameters from the User Interface, which I want to use in my program.
I have currently no idea how to start. I looked in the SDK, but it's dificult to get an overview of the things I need. The first question is, which type of plugin project I should create? Utility? Animation? or something else? And how should I start? Are there any very good examples anywhere?
Thanks a lot,
cgneuling

bnvm
03-28-2012, 11:35 PM
I've done a little with the sdk and the best place to start is with the how to's and tutorials in the sdk docs.

What I did and what would be by far the easiest would be to write an maxscript extension plugin that adds the functions required to do what you want, then build the ui in maxscript as a scripted plugin or just plain old dialog and pass the objects / inputs to the function and let it do the rest.

It is far easier to build a ui in maxscript and maxscript extensions are the simplest type of plugin to write.

You can even write the whole thing in maxscript first, which may be fast enough for what you want to do, then just replace the maxscript functions with c++ versions as you finish them. Basically make I work then make it faster.

cgneuling
03-29-2012, 01:23 AM
Ok thank you :)
I have already written the program in maxscript, but it is too slow. So I want to make it as Plugin. Is it also possible to read the animation path, vertices, objects,...with maxscript and to pass them as arrays to the c++ program and than pass the calculated animation path back to maxscript and to set the new animation paths in maxscript?

stigatle
03-29-2012, 06:00 AM
Yes, you can send data from maxscript into your plugin.
I do this for an exporter I'm making.
the function itself is in c++, I then run the function like this in maxscript:

ExportMyObject objectname "C:\\filepath.ext"

then the c++ code takes over and exports the object.

It's a very good way of doing it, because in c++ you create the functions, and you just use the functions in your maxscript GUI - then you do not have to worry about complex gui coding.


and yes, you can read \ modify all the data you ask for.

bnvm
03-29-2012, 06:01 AM
I believe you can pass whatever data you want into the function, keep in mind it will probably be easier if you try to follow c++ rules, like not mixing data types in arrays passed to the fn etc...

I would probably pass the object, data, and animation path then do all the work including assigning the new motion in the function.

denisT
03-29-2012, 06:22 AM
I have already written the program in maxscript, but it is too slow.
first of all you have to get why it's slow.
you can find some samples on this forum where an initial mxs code was improved to work 50 times faster.

cgneuling
03-29-2012, 01:21 PM
The problem is that I want to look if 1000 objects have a collison during 1000 frames, and the script only is fast for about 100 objects for 100 frames.
I don't know how to start writing the plugin.
I only would need that the Plugin gets from the Script a two-dimensional array with animation paths, and 3 further arrays which have only float values. Then I want to calculate something and then the script should receive the new two-dimensional arrray with animation paths from the plugin. The script will further write it to the objects like it does it right know. So it should be a collision detection, which calculates the new animation paths, the objects should take.
Can someone tell me what I should have to make? Thanks a lot :)

bnvm
03-29-2012, 03:02 PM
a c++ function will be able to take multiple arrays even nested arrays as inputs so that is not a problem. If you can use visual studio max has a plugin wizard that can get you started.

The only way for you to do this is to just get starting coding, the sdk is complex and difficult for anyone here to tell you exactly what you need to do. I can tell you that I successfully wrote a maxscript extension in c++ with no experience with the sdk or c++ at the time. It took a lot of trial and error but I got there eventually.

cgneuling
03-29-2012, 03:48 PM
ok. I started with it to write an extended function as plugin. My problem now is. I wanted to create an integer array by int name[i][j], but it doesn't work. Does anybody now why? i and j are the length of the field which the script will give to the plugin. It should be a two dimensional field, but it also doesn't work with a one dimensional field, but when I type in int name[5] then it works.

bnvm
03-29-2012, 07:21 PM
I believe you cannot do that with an int array, I'm still new to c++ as well so I may be wrong. I would recommend using something like std::vector instead, they can be nested.
The code below is completely untested.

std::vector<std::vector<int>> nestedvect; // would create a multi dimensional int array, basically its an array of int arrays.

for(int i = 0 ; i < 10; ++i){
std::vector<int> intvect; //makes a array of ints that is resizeable, random access etc..
for(int j = 0; j < 10; ++j){//fill intvect array
intvect.push_back(i);//add i to 1D array
}

nestedvect.push_back(intvect);//add int array to multi-dimensional array
}



if you want to use this i believe you have to #include <vector>, you may want to look into something like boost, which has other array options.

cgneuling
03-30-2012, 04:12 PM
Hi! Thanks a lot. This works.
I have written know my function which calculates the collisons of the program. And now I have two problems. I have made a function which should call my function. This function gets the parameter of maxscript. It's the following:

def_visible_primitive(Collision, "Collision");
Value* Collision_cf(Value** arg_list, int count)
{
type_check(arg_list[0], Array,"[animation_paths]);
type_check(arg_list[1], Array, "[radius]);

Array* animation_paths = static_cast<Array*>(arg_list[0]);
Array* radius = static_cast<Array*>(arg_list[1]);

This is the begin of my function. My problem now is that the animation_paths array is a two dimensional array and I want that this will be from type Point3. Is this possible? In maxscript I get the animation_paths and save them into a two dimensional array. Is this array from type point3?
The radius arry should be a two dimensional array of type float.
How can I code this? That I have the right types instead of the type Array*.

My second problem is that I want to give back 2 two-dimensional arrays to maxscript. How can that be done. Now it gives back a value from type Value*. Or does maxscript gives only pointer instead of the arrays so that the arrays are automatically changed?

Thanks a lot :)
cgneuling

bnvm
04-10-2012, 04:06 PM
I believe you can get an element from the array and type cast it to type point3 but not sure how. As for the function returning type Value*, just about all of max's data type are derived from the Value class and arrays are one of them so returning an array should be fairly straight forward. You will need to store the data you want to return in the sdk's Value / Array data type so you can return it easily.

cgneuling
04-11-2012, 11:41 AM
Hi!
Thanks. I have made it to get the values. Now all I need to finish my program is to give back a two dimensional array. I tried the following code:

Array* arg_list3;

for(int i = 0; i < object_array_size; i++)
{
Array* lol;
for(int j = 0; j < animation_paths_size; j++)
{
lol->data[j] = (Value*)visibility_vec[i][j];
}
arg_list3->data[i] = lol;
}
return arg_list3;

the visibililty_vec is an two dimensional array of type float. The problem is that it is not allowed to convert float to type Value*. Or is there an other option to convert ? I tried also static_cast but this was also not allowed.

spider853
04-11-2012, 10:26 PM
Take a look at MaxSDK Help, on MaxScript section and Casting/... subsection:

Here is a casting example:
Quote:


one_typed_value_local(Array* rArray);
vl.rArray = new Array (steps);
float data = begin;
float increment = ((end-begin)/steps);
for (int i = 0 ; i <= steps ; i++)
{
Value* aTempNumber = Float::heap_intern(data);
vl.rArray->append(aTempNumber);
data += increment;
}

return_value(vl.rArray);

Pjanssen
04-11-2012, 11:08 PM
I think it might be easier to use the function publishing macros and interfaces. That takes care of most casting issues for you. And I've found it to be less prone to import and define statement order errors.

cgneuling
04-11-2012, 11:14 PM
Ok. Thanks for your help :) is this now for a one dimensional float array? Can I give also back a two dimensional float array AND a two dimensional point3 array? If so how can I do this? If I have an array with the name "position" and its a two dimensional array. Can I give it back with the following code? If so how can I give two two dimensional arrays? Thanks a lot :) What does float::heap_intern ?

one_typed_value_local(Array* rArray); vl.rArray = new Array (steps);
vl.rArray2 = newArray(steps2); float data = begin; float increment = ((end-begin)/steps); for (int i = 0 ; i <= steps ; i++) {
for(intj = 0; j <= steps2; j++)
{
Value* aTempNumber = Float::heap_intern(position[i][j]); vl.rArray->append(aTempNumber); data += increment;
}
vl.rArray2->append(vl.Array);


} return_value(vl.rArray2);

spider853
04-12-2012, 12:12 AM
All non-static instances of the Value class family should be heap-allocated with the 'new' operator or one of the following intern() functions so that garbage collection will work.

Why you don't take a look at documentation...

About the bidimensional array I think its posibile, but didn't try it.
It should be something like, but not sure of correctness.



one_typed_value_local(Array* rArray);
vl.rArray = new Array (nrRows);
for (int i = 0 ; i < nrRows; i++)
{
vl.rArray->append(new Array(nrCols));
for (int j = 0; j < nrCols; j++) {
Value* aTempNumber = Float::intern(position[i][j]);
vl.rArray[i]->append(aTempNumber);
}
}
return_value(vl.rArray);

cgneuling
04-12-2012, 01:03 AM
does this mean that i can write for a two dimensional array of type float the following if "position" is the name of the array? if so how can I give back two two dimenaional arrays? What does heap_intern do? Thanks a lot :)
one_typed_value_local(Array* rArray);
one_typed_value_local(Array* rArray2);
vl.rArray = new Array (steps);
vl.rArray2 = new Array(steps2);
float data = begin; float increment = ((end-begin)/steps); for (int i = 0 ; i <= steps ; i++) {
for(int j = 0; j <= steps2; j++)
{
Value* aTempNumber = Float::heap_intern(position[i][j]); vl.rArray->append(aTempNumber);
}
vl.rArray2.append(vl.rArray);
}
return_value(vl.rArray2);

cgneuling
04-12-2012, 01:06 AM
sorry. i pushed the enter button.
@spider853 (http://forums.cgsociety.org/member.php?u=353931): thanks for the answer. I will try that. Do you know if it is also possible to give two arrays back?

spider853
04-12-2012, 09:45 AM
sorry. i pushed the enter button.
@spider853 (http://forums.cgsociety.org/member.php?u=353931): thanks for the answer. I will try that. Do you know if it is also possible to give two arrays back?

what do you mean? 2D array of 2xn elements? if not I don't think so, because max returns only one value from function, maybe getting variables by reference, but I'm not sure how to work with references.


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

one_typed_value_local(Array* rArray);
one_typed_value_local(Array* rArray2);

According to documentation its enough to protect one value from garbage collector, and other values connected to this value will be protected too. (if I'm not wrong)


QUOTES FROM DOC:

There can be only one value_local declaration macro per C++ block.
-----

there is no multiple-value return mechanism in MAXScript.
--------------

As with all Value creation inside C++ code, a freshly created array must be protected from garbage collection, either by placing it immediately inside some other protected value, or by using the protection macros described in the Protecting Newly Created Values from the Collector topic.

P.S. Why don't you read this section of documentation? Its only a few pages but has the answers to the most your questions.
Use the 3ds max 2009 SDK chm, or the last CHM documentation

cgneuling
04-12-2012, 10:14 AM
If I write FLOAT:: intern(positon[i][j]) I get the message: FLOAT must be a class or namespace when following by :: and intern is not a member of global namespace. Do I nead specific header files?

spider853
04-12-2012, 10:17 AM
If I write FLOAT:: intern(positon[i][j]) I get the message: FLOAT must be a class or namespace when following by :: and intern is not a member of global namespace. Do I nead specific header files?

#include "MAXScrpt.h"


#include "Numbers.h"// for handling of MAXScript Integers and Floats


#include "Arrays.h"

cgneuling
04-12-2012, 10:19 AM
I have already included this header files. Can there be another reason that it doesn't work?
ps: I cant find that chapter in the SDK.

spider853
04-12-2012, 10:30 AM
I have already included this header files. Can there be another reason that it doesn't work?
ps: I cant find that chapter in the SDK.

Float:: not FLOAT::

USE THE 2009 SDK CHM

cgneuling
04-12-2012, 10:48 AM
Ok now it works but when I call the function in maxscript I get the error: Memory allocation error (re)sizing array. This happens in the code line vl.Array[i].append(aTempNumber) if the inner loop runs a second time.

spider853
04-12-2012, 10:56 AM
Ok now it works but when I call the function in maxscript I get the error: Memory allocation error (re)sizing array. This happens in the code line vl.Array[i].append(aTempNumber) if the inner loop runs a second time.

I'm not sure why, maybe bad implementation I can't test it right now, but there is another solution to use 1D array is 2D...

basically you write the array as this:

for (int i = ...)
for (int j = ..._
Array->Append(pos[i][j]);

then access it as
for (int i = ...)
for (int j = ..._
pos[i][j] = i * nrCols + j

you can get the chm doc here http://usa.autodesk.com/adsk/servlet/item?siteID=123112&id=7481368

cgneuling
04-12-2012, 11:05 AM
I have tried now this code for a one dimensional array. But it doesn't work either. 3ds Max closes when i call Test(5);:
def_visible_primitive(Test,"Test");
Value* Test_cf(Value** arg_list, int count)
{
check_arg_count(Test,1,count);
type_check(arg_list[0],Integer,"Error");
float testarray[2];
testarray[0] = 1;
testarray[1] = 4;
one_typed_value_local(Array* rArray); vl.rArray = new Array (2); for (int i = 0 ; i <= 2 ; i++) { Value* aTempNumber = Float::heap_intern(testarray[i]); vl.rArray->append(aTempNumber); } return_value(vl.rArray);

spider853
04-12-2012, 11:08 AM
I have tried now this code for a one dimensional array. But it doesn't work either. 3ds Max closes when i call Test(5);:
def_visible_primitive(Test,"Test");
Value* Test_cf(Value** arg_list, int count)
{
check_arg_count(Test,1,count);
type_check(arg_list[0],Integer,"Error");
float testarray[2];
testarray[0] = 1;
testarray[1] = 4;
one_typed_value_local(Array* rArray); vl.rArray = new Array (2); for (int i = 0 ; i <= 2 ; i++) { Value* aTempNumber = Float::heap_intern(testarray[i]); vl.rArray->append(aTempNumber); } return_value(vl.rArray);

float testarray[2];

vl.rArray = new Array (2); for (int i = 0 ; i <= 2 ; i++)

out of bounds

spider853
04-12-2012, 11:17 AM
Here is a peace of code from my SPH simulation for scripting plugin


Value* SetupParticles_cf(Value **arg_list, int count)
{
check_arg_count(UpdateParticles, 6, count);
for (int i = 0; i < count; i++) {
if (!is_float(arg_list[i])) {
throw RuntimeError("Need 6 floats!!");
break;
}
}
h = arg_list[0]->to_float(); //dist
Rho0 = arg_list[1]->to_float(); //Rho0
k = arg_list[2]->to_float(); //spring constant
kNear = arg_list[3]->to_float();
sigma = arg_list[4]->to_float();
beta = arg_list[5]->to_float();


/*
float sigma = 0.02;
float beta = 0.01;
float kSpring = 0.5;
float yConst = 0.2;
float Lconst = 5;
float alpha = 0.3;
*/
return &ok;
}
Value* GetUniqueIDs_cf(Value **arg_list, int count)
{
check_arg_count(UpdateParticles, 0, count);
one_typed_value_local(Array* rArray);
vl.rArray = new Array (Particles.size());

map<int, Particle>::iterator pIt;
for (pIt = Particles.begin(); pIt != Particles.end(); pIt++) {
Value* tmpID = Integer::heap_intern(pIt->first);
vl.rArray->append(tmpID);
}
return_value(vl.rArray);
}
Value* GetVelocities_cf(Value **arg_list, int count)
{
check_arg_count(UpdateParticles, 0, count);
one_typed_value_local(Array* rArray);
vl.rArray = new Array (Particles.size());

map<int, Particle>::iterator pIt;
for (pIt = Particles.begin(); pIt != Particles.end(); pIt++) {
Value* tmpVel = new Point3Value(pIt->second.vel);
vl.rArray->append(tmpVel);
}
return_value(vl.rArray);
}


but I'm looking now at this line
Value* tmpVel = new Point3Value(pIt->second.vel);
and not sure if its good...
if Value gets GC then good, else its needs to register it for GC, or I need to free it after append

a better aproach could be instead of one_typed_Value_local to use
two_typed_value_locals and register some var for Point3Value so it will be visible to GC

cgneuling
04-12-2012, 11:39 AM
Thanks a lot. a float array works now, but I have the problem that Value* temp = new Point3Value(a) does not work. a is a value of type Point3. Is there a special header file for Point3Value? The error message is: error: syntax error: identifier: Point3Value

spider853
04-12-2012, 11:40 AM
Thanks a lot. a float array works now, but I have the problem that Value* temp = new Point3Value(a) does not work. a is a value of type Point3. Is there a special header file for Point3Value? The error message is: error: syntax error: identifier: Point3Value

Do you need that Point3?
Its an example from my plugin.

#include "maxscrpt/3DMath.h"

cgneuling
04-20-2012, 12:01 PM
Yes I need that. Thanks a lot :)

CGTalk Moderation
04-20-2012, 12:01 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.