Blender Development: adding an actuator part 1

In this guide I’m going to cover how to add a new blank actuator to the Blender Game Engine (BGE). The actuator will not actually do anything, the focus is just on getting a new actuator into the BGE. By the end you should be able to attach it to a game object. Eventually, over the course of these tutorials I hope to cover getting the actuator to do something, maybe even something useful and communicating with it through Python. I wont give line numbers as they will change over time and could be different on your version, but I’ll try to include bits of code around the pieces we’re adding to give you some kind of landmark.

First off, a disclaimer: I’m still very new to Blender’s source code and do not fully understand what I’m doing. The steps to adding an actuator were figured out with the help of my friend Marcus. All I can do is present the steps, I can’t really explain much. As I learn more about how Blender works I’ll update this post. If anyone has extra details they want to add leave a comment and I’ll include it. I’m posting this because there is a lack of tutorials in getting into Blender development and nothing on creating a new actuator (Snailrose did a tutorial, but all links lead to 404 land).

Setup
I’ll try and keep this guide as free from system specifics as possible. But for those who are interested: I’m using QT Creator as my IDE, CMake for the build system and minGW as the compiler. I’m running Windows 7 64bit on a laptop. I’d also recommend that you watch this video and this one too as a good primer for navigating Blender’s source code.

Getting Started
The first step is to find where an actuator is defined. A quick glance at the BGE source and you’ll notice a lot of header and source files for each actuator. These contain the instructions for what the actuator does, creating a header and source for your new actuator will not do anything. We need to define the actuator as part of Blender. Finding the relevant parts of the code can be tricky. By looking through the various source files I came across a file called DNA_actuator_types.h, which judging by its name indicates that it declares the various actuators. From there I started searching for lines of code relating to any actuator. It’s best to pick one and stick with it. I used the steering actuator and just searched for every place where something to do with defining the steering actuator occurred. Then just copied the bare bones used in it’s construction. Much of the time it was simple trail and error to get it all working.

DNA_actuator_types.h
The DNA datatypes are the foundations of more or less everything in blender. On top of these is the RNA stuff, which is a layer of abstraction to provide an interface for using the DNA structs. It provides things like reflection, documentation generation, python interface, access and min-max values and so forth. (Did I explain the DNA/RNA correctly? Still trying to understand it). So the first we need to do is define a struct for the new actuator in DNA_actuator_types.h. In this tutorial we’ll call it test. So scroll down and add this after the last actuator struct:

...
typedef struct bTestActuator {
  ;
}bTestActuator;
...

Each struct in DNA_actuator_types contains the variables for that actuator – the actuators properties. If you look up at some of the other structs you’ll see variables that sound a lot like the options that exist for that actuator. You’ll also notice the a variable called pad or padding crop up a lot. This is to do with data alignment. Rather than attempt to poorly explain the concept of padding (and it’s beyond the scope of this article) take a look at this page or this one. If you want more information google ‘data alignment’ or ‘struct padding’.

Blender pads structs based using 8 byte alignment for 64 bit systems, which will automatically become 4 byet on 32 bit systems. Here’s the padding rules taken from the Blender Notes on SDNA page:

  • Structures are always multiples of 8 bytes in size
  • Pretend pointers are 8 bytes long, even for 32 bits systems
  • Structs within structs start at an 8-dividable location
  • Pointers start at an 8-dividable location, unless the previous variable is a pointer!
  • ints/floats start at a 4-dividable location
  • shorts start at a 2-dividable location

For now our struct contains no variables, so we don’t need to do anything, later it will. This is important, so make sure you understand this. Without proper data alignment your structs will not compile.

Further down in DNA_actuator_types.h you’ll come across a number of #defines that define constants used in various switch statements when dealing with actuators. We’ll need to define one for the new actuator, increasing the number by 1:

...
#define ACT_ARMATURE	23
#define ACT_STEERING    24
#define ACT_TEST	25

/* actuator flag */
#define ACT_SHOW		1
...

rna_actuator.c
Once the data for the test actuator is sorted we can move on to describing it’s interface – the RNA side. Open up the file rna_actuator.c, which contains the interface for accessing and using the actuator we described in DNA_actuator_types.h. The first change we need to make is in the actuator_type_items array:

...
	{ACT_STEERING, "STEERING", 0, "Steering", ""},
	{ACT_TEST, "TEST", 0, "Test", ""},
	{0, NULL, 0, NULL, NULL}};
...

My understanding is that this controls what you’ll see when you click on the add actuator button. Changing the second string in the sequence will change the name that appears in that list. Scrolling a little further down to the rna_actuator_refine function, enter:

...
		case ACT_ARMATURE:
			return &RNA_ArmatureActuator;
		case ACT_STEERING:
			return &RNA_SteeringActuator;
		case ACT_TEST:
			return &RNA_TestActuator;
		default:
			return &RNA_Actuator;
...

Don’t worry if you can’t find RNA_TestActuator declared anywhere in the source tree. It’s generated as part of the RNA code generation process I believe. Continue scrolling  and you should come across a function called rna_Actuator_type_itemf, lets add:

...
	RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_SCENE);
	RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_STEERING);
	RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_TEST);
...

Next we add a function that defines the interface for the test actuator:

static void rna_def_test_actuator(BlenderRNA *brna)
{
	StructRNA *srna;
	srna = RNA_def_struct(brna, "Test Actuator", "Actuator");
	RNA_def_struct_ui_text(srna, "Test Actuator", "Actuator to do nothing");
	RNA_def_struct_sdna_from(srna, "bTestActuator", "data");
}

You’ll notice that all the functions for the other actuators contain large amounts of code, this is for interfacing with the DNA structs properties. Since we don’t have any properties attached to our test actuator we don’t need to do much here. All that needs to be included is the code needed for the actuator’s RNA generation. Finally, at the bottom of the file we add the following to the RNA_def_actuator function:

...
	rna_def_armature_actuator(brna);
	rna_def_steering_actuator(brna);
	rna_def_test_actuator(brna);
}

sca.c
If you compile Blender now and run it you’ll find your new actuator available in the logic panel. However, there are still a few last little bits to take care of. In sca.c we need to add some code to the init_actuator function so that Blender knows how much memory to allocate for the new actuator:

...
	case ACT_STEERING:
		act->data = MEM_callocN(sizeof( bSteeringActuator), "steering act");
		sta = act->data;
		sta->acceleration = 3.f;
		sta->turnspeed = 120.f;
		sta->dist = 1.f;
		sta->velocity= 3.f;
		sta->flag = ACT_STEERING_AUTOMATICFACING;
		sta->facingaxis = 1;
		break;
	case ACT_TEST:
		act->data = MEM_callocN(sizeof( bTestActuator ), "test act");
		break;
	default:
		; /* this is very severe... I cannot make any memory for this        */
		/* logic brick...                                                    */
	}
...

writefile.c
And now we just have to edit writefile.c in the write_actuators function:

...
		case ACT_STEERING:
			writestruct(wd, DATA, "bSteeringActuator", 1, ->data);
			break;
		case ACT_TEST:
			writestruct(wd, DATA, "bTestActuator", 1, ->data);
			break;
		default:
			; /* error: don't know how to write this file */
		}
...

I believe that this file is used for saving data in a .blend file.

And that’s it! Time to compile and enjoy your new actuator that does, erm, nothing. In the next tutorial I’ll cover getting it to do something useful. If there’s anything missing, or that I’ve gotten something wrong, please let me know.

Updates
09/04/12 – details on padding

PS: This is day 9 of my 30 Days of Writing, I just left it out of the title for clarities sake.

Advertisements

~ by Jay on March 29, 2012.

One Response to “Blender Development: adding an actuator part 1”

  1. […] First of all, make sure you’ve read part 1 and got your new test actuator setup as explained. I’m still using Qt Creator, CMake and […]

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

 
%d bloggers like this: