Author Topic: How to compile your plugin  (Read 12018 times)

0 Members and 1 Guest are viewing this topic.

VorpalBlade

  • World Machine Guru
  • ****
  • Posts: 55
    • View Profile
How to compile your plugin
« on: October 23, 2006, 10:28:19 PM »
Would anyone be willing to write up a brief tutorial on how to comple a plugin?

I really suck at using the Visual C++ platform and don't even know where to begin.

Thanks

Remnant

  • Author
  • World Machine Guru
  • *****
  • Posts: 2311
    • View Profile
    • http://www.world-machine.com/
Re: How to compile your plugin
« Reply #1 on: October 23, 2006, 11:13:02 PM »
If you have MSVC and the WM PDK, it's simple:

simply load the Example solution (workspace) file, and Build the solution. Everything is setup to work as is; it will produce a DLLExample.dll file that you can put in your WM/plugins folder. This plugin has 4 different example devices showing how some different effects.
-- Stephen Schmitt
- Creator of World Machine

VorpalBlade

  • World Machine Guru
  • ****
  • Posts: 55
    • View Profile
Re: How to compile your plugin
« Reply #2 on: October 24, 2006, 12:32:38 AM »
What is the name of the Example solution (workspace) file. I've tried the Example.sln file and built it. It seems to work but not seeing where it is building the DLLExample.dll file to.

Thanks

VorpalBlade

  • World Machine Guru
  • ****
  • Posts: 55
    • View Profile
Re: How to compile your plugin
« Reply #3 on: October 24, 2006, 12:53:26 AM »
I noticed that it was building a file "Inverter Example.dll" I move that file to the plugin/devices directory and it looks like it has set up some generic numbered buttons. Is this correct?

Next question is, how can I give these generic buttons icons?

Also, how do I remove existing devices and add new ones?



Again thank you :)
« Last Edit: October 24, 2006, 02:34:24 AM by VorpalBlade »

Fil

  • Testing Team
  • World Machine Guru
  • *****
  • Posts: 550
    • View Profile
Re: How to compile your plugin
« Reply #4 on: October 24, 2006, 09:07:01 AM »
Some time ago, I had spare time to dedicate to the coding of a few plugins 8).. Unfortunately, spare time has not been abundant for some time :( So I'm a bit rusty on this..

*To add, delete, change devices on the same plugin (speciificly on the PDK example) go to the main DLL class (DLLExample.cpp) and you'll find a switch(i) there, on the class method that will give WM the device! That is where you decide what the i-th device on your DLL is.

*To add change remove images, on the Resource Files folder of your Solution Explorer, you'll find a "bitmap1.bmp" file That has all the icons that appear for all devices in that plugin. Note that you have all 32x32 icons stitched together in a single "strip" of icons. Make sure the bmp file is wide enough to fit icons for all your devices. Left most 32x32 space will be the first device's icon :) that means device i=0, on the previous switch

I hope I haven't said anything wrong here..

Happy fooling-around with that ;)
« Last Edit: October 24, 2006, 09:11:48 AM by Fil »
Fil.

VorpalBlade

  • World Machine Guru
  • ****
  • Posts: 55
    • View Profile
Re: How to compile your plugin
« Reply #5 on: October 24, 2006, 02:21:50 PM »
Thanks for that, but what I'm looking for is how to add and remove them from the MSVC project.

I've created a new class and replaced all references to Inverter to this class, however, when I complie I get the following error...

Example Devices error LNK2019: unresolved external symbol "public: __thiscall MyClass::MyClass(void)" ([email protected]@[email protected]) referenced in function _GetDevPlugin

Is this because there is no MyClass included in the MSVC project? If so, how do I add it and remove the Inverter class?
« Last Edit: October 24, 2006, 02:47:21 PM by VorpalBlade »

Fil

  • Testing Team
  • World Machine Guru
  • *****
  • Posts: 550
    • View Profile
Re: How to compile your plugin
« Reply #6 on: October 24, 2006, 03:46:03 PM »
oh.. Well, I have set up a new project, to leave the example as backup.. This is also a good think for training and finding out where the settings need to be changed :)
But for your case, basicly it should envolve you to comment code, change a few values on the number of devices, remove files from the project, and delete them afterwards, so they don't end up confusing you later. Anyhow, here is a big tuto on it..

So hey, imagine you wanted to plage my LEGO Filter, and wanted to make a DLL with a single device in it. Here is what you'd have to do:
in DLLExample.cpp, you'd have to make sure only your filter would be called, this means commenting all code inside the switch(i){   } and only leave the part:
Code: [Select]
case 0:
{
Device *dev =  new LegoFilter; // Instantiate the device temporarily to get at its name and life funcs
dat.lifedata = dev->GetLifeVars();
strcpy(dat.name, dev->GetTypeName());
dat.type = TYPE_FILTER; // Hey, I'm coding a filter!
delete dev;
*result = dat;
}
break;
Notice this:
Code: [Select]
default: // Out of devices; return false.
return false;
This is what tells WM that you only have 1 device in it. WM checks for device 0, then for device 1, once it reaches a "false" WM found the number of devices inside this plugin DLL!

Right! Now obviously you need to implement a class called LegoFilter :P So let's take a look at how to do that!

If I remember well, I canibalized the Inverter Filter. So basicly I made a copy of the Inverter.cpp file (because it was also a filter) and started changing every contructor name, and deleteing stuff I didn't need.
Read carefully through the coments as these will tell you what is being done.

Still the most important things I did were:
First off, dont forget to add the #include "LegoFilter.h" at the top of DLLExample.cpp, right after the include of the "DLLExample.h" file..
In LegoFilter.cpp
Code: [Select]
// What you MUST DO in the constructor of your device:
// 1) Set the Nametag, Maker and Killer in the lifeptrs struct.
// What you SHOULD do in the constructor:
// 2) Call SetLinks() with the # of inputs and outputs your device is going to use
//      ...if you dont do #2, you will use the default # of inputs your parent class assigns
LegoFilter::LegoFilter(void)
{
lifeptrs.maker = LegoFilterMaker;          // this is the method for being born! :-)
lifeptrs.killer = LegoFilterKiller;              // this is the method for suiciding :-P
strncpy(lifeptrs.nametag, "LEGO", 4);   // 4-character ID for my Lego device!
SetLinks(2, 1);                                  // I'm a filter, I have 2 input ports and 1 output!
in(1)->SetFlag(1);                             // oh, and my second (=1) input port is an optional one ;)  (flag = 1)

Now, I made sure the version was one I could read! Imagine this code is changed in two years, with version 3.. If this DLL (version 1) is loaded then, I must not load this device, because version 3 is bound to be somthing really complicated :D
Code: [Select]
// You are REQUIRED to write out and read in your 4-byte Device ID tag, as shown below. It is also recommended that your device
// have an internal version number that you keep track of to allow backwards-compatibility if you ever change your Device save layout...
// Also, make sure you call your super class's Load and Save functions as shown here. Failure to do so will cause major problems.
bool LegoFilter::Load(std::istream &in) {
char tag[5];
in.read( tag, 4);
if (strncmp(tag, lifeptrs.nametag, 4) == 0) {
int ver = 0;
in.read((char*) &ver, 1);
if(ver > 1)// the version that is being loaded is newer than this code can handle, say goodbye!
return false;
// if it is older, that we probably know how to deal with it..
return Filter::Load(in);
}
else
return false;
};

bool LegoFilter::Save(std::ostream &out) {
out.write( lifeptrs.nametag, 4);
int ver = 1; // This is the current version!
out.write((char*) &ver, 1);
return Filter::Save(out);
};

Then you need to code your device's content:
Code: [Select]
// The Activate function is where you work your magic. You should do four things in the Activate function:
// 1) Retrieve your inputs by calling RetrieveData(input#)
// 2) Do whatever you will do on it...
// 3) Store the data to make it available to your outputs
// 4) Return true to indicate successful activation, or false if there was an error.
bool LegoFilter::Activate(int pstate) {
HField *hf = HF(RetrieveData(0) ); // Get main input HF!
HField *shf = HF(RetrieveData(1) ); // get the Stud shape HF!
Oh and don't forget to do the house cleaning work, of deleting the temporary/auxiliary HFs that were not outputted! This is how my Activate code ends:
Code: [Select]
clone->Release();
shf->Release(); // you're now worthless, too!
}
// Handoff to output(s)
StoreData(hf,0); // pass the heightfield to our output stage.

return true; // Success! woo-hoo!

Right, so now, what am I missing? ...

Oh, ofcourse! in LegoFilter.h there are a few obvious things to change:
Code: [Select]
virtual char *GetDescription() { return "Converts a terrain into something apparently made by LEGO";};
virtual char *GetTypeName() { return "LEGO Filter"; };

I think this is it..
Remember that I don't code plugins in a while, so there might be something missing..

There are other things to say about user interface, but hey, try this out first with the inverter, before that :) You already have that hint on how to flag an input as optional ;)


PS - ofcourse, I forgot about the image.. I made a neat image, and placed on the first 32x32 position of the bitmap1.bmp file, corresponding to device i=0 :)
« Last Edit: October 24, 2006, 03:50:56 PM by Fil »
Fil.

VorpalBlade

  • World Machine Guru
  • ****
  • Posts: 55
    • View Profile
Re: How to compile your plugin
« Reply #7 on: October 24, 2006, 04:48:43 PM »
Thanks Fil,

I basically did what you suggested. Copied Inverter.h and Inverter.cpp to a new file MyClass.h and MyClass.cpp switched all references (Find/Replace) from Inverter to MyClass in the new files and in DLLExample.cpp and DLLExample.h. I removed the other switches so that there was only one device (option 0) and a default break. And I still get that error. And It will also error like crazy if I rename or delete the old Inverter.h and Inverter.cpp even though there is no link in my code to it.

So I looks like even though I change all the includes in my files to the new files, in order to build it, you have to include it in the project in MSVC and remove (through MSVC) the old file.

I really hate MSVC. Makes everything so damn complicated.

I can get it to work if I just edit Inverter.cpp but that is pretty lame because every device code i write will have to be named Inverter.cpp.


Remnant

  • Author
  • World Machine Guru
  • *****
  • Posts: 2311
    • View Profile
    • http://www.world-machine.com/
Re: How to compile your plugin
« Reply #8 on: October 24, 2006, 06:48:12 PM »
Having the cpp file in the project is what tells MSVC to link the object code into the DLL file; it's understandably necessary :) Just add your class .h and .cpp files to the project and rebuild, and it should work fine.

-- Stephen Schmitt
- Creator of World Machine

VorpalBlade

  • World Machine Guru
  • ****
  • Posts: 55
    • View Profile
Re: How to compile your plugin
« Reply #9 on: October 24, 2006, 11:33:28 PM »
Thats the problem. I'm not sure if I am adding my class correctly. When I right click on "Example Devices" in the Class view and select add, it creates two classes from the same files named the same. One lists all the methods for the class the second one only shows the constructor and destructor. And when I try to compile it gives the following errors...

c:\Documents and Settings\Choda Boy\Desktop\World Machine PDK\examples\MyClass.h(26): error C2011: 'MyClass' : 'class' type redefinition

c:\Documents and Settings\Choda Boy\Desktop\World Machine PDK\examples\MyClass.cpp(93): error C2084: function 'MyClass::MyClass(void)' already has a body

c:\Documents and Settings\Choda Boy\Desktop\World Machine PDK\examples\MyClass.cpp(97): error C2084: function 'MyClass::~MyClass(void)' already has a body

c:\Documents and Settings\Choda Boy\Desktop\World Machine PDK\examples\FillBasins.h(26): error C2011: 'MyClass' : 'class' type redefinition

So, for some reason when I "Add" it links to the files twice. How do I add a class without it doing this sillyness? Also how do I remove a class from my project?


Sorry for my ignorance. I leared on a line command compiler :(

EDIT: I've also tried "Project->Add existing item" and it does the same thing.

« Last Edit: October 24, 2006, 11:45:23 PM by VorpalBlade »

Remnant

  • Author
  • World Machine Guru
  • *****
  • Posts: 2311
    • View Profile
    • http://www.world-machine.com/
Re: How to compile your plugin
« Reply #10 on: October 25, 2006, 12:41:48 AM »
aha.

When you select "add class", MSVC will automatically create the necessary source files and add them to your project. If you've already created them, this is not what you want.

Remove (and delete) any of the source files that it has created. Now you have your class in a cpp and h file that you've created seperately (that's just a copy of the Inverter class, but with everything renamed); to add it to the project, just go to "Add Existing Item" in the Project menu and select those two files. You should then be good to go.
-- Stephen Schmitt
- Creator of World Machine

VorpalBlade

  • World Machine Guru
  • ****
  • Posts: 55
    • View Profile
Re: How to compile your plugin
« Reply #11 on: October 25, 2006, 01:32:01 AM »
Thanks guys,

I'll give it another try with your suggestions later on. For now I just wanna press on :)

You would think that MSVC would be smart enough to check if you already have your constructor and destructor when adding an existing class.