Difficulties Getting Haxe to Compile to a Blender Plugin


(Zicklag) #1

I’m trying to get Haxe to work for writing Blender plugins, specifically so that we can write the Armory Blender plugin in Haxe ( and if I ever write my own Blender plugin, I’d want to write it in Haxe, obviously :roll_eyes: ), but there are a few of difficulties I am having. If anybody could help me out that would be great.

I have what I have developed so far in a blender extern generator on GitHub. So far I nearly have the system working, but I’ve still got some things to work out.

Handling bl_info, register(), and unregister()

So my first problem is related to the fact that Haxe doesn’t let you define module level fields. For every blender plugin there has to be a global scoped bl_info dictionary containing the addon info like name, etc. You have a similar issue with the required register() and unregister() functions which need to be defined in the global scope of the module.

I managed to solve for this in a sub-optimal manner by having a two-stage compilation, where the first on compile the plugin like any Haxe program, and the second one uses a macro to add the extra content to the file generated in the first step:

The biggest problem with this setup is that it ends up compiling the program twice, which takes a little bit longer because of the large amount of extern classes from the Blender API. It is a bigger problem because of how much it slows autocompletion, I just don’t know if there is another way to do that.

Import Name is Different than Class Name

The next problem I am having has to do with imports. There is a weird thing about Blender’s bpy package, that you can’t import bpy.types. That causes an issue when I need to use the bpy.types.Operator class. At first I had the extern classes structured like this, with a :pythonImport meta.

@:pythonImport("bpy.types.Operator") extern class Operator {

The problem with this is that it causes Haxe to generate an import that looks like import bpy.types.Operator as bpy_types_operator_Operator, which break when running in Blender because bpy.types is not a module.

My current work-around is to add import bpy to the output post-processing step that I mentioned above and switched the :pythonImport meta to a :native metadata. This is bad for the same reason as the above problem, because I don’t want to have to have to compile the program two times to get the final output. Also I would need to add logic to be able to tell which extra imports I need to add, which should be possible, but isn’t optimal. I’m not sure if there is a way to get more control over how Haxe generates the Python imports.

Overriding Class Variables

On a more Blender and less Haxe note I am having trouble with not being able to tell whether or not to make a class attribute static or not. So in the plugin code you need to do something like the following, but it causes Haxe to complain that I can’t re-define bl_idname or bl_label because they are already defined in Operator.

class SimpleOperator extends Operator {
	var bl_idname = "object.simple_operator";
	var bl_label = "Tool Name";

	public override function execute(context:Dynamic) {
		trace("Hello World");
		return new Set(["FINISHED"]);

That actually makes sense, and is fixed if you make the field static, which it probably needs to be anyway. The problem is that I don’t know how to tell what class fields to make static from the XML documentation. This is the only problem I don’t have a workaround for so far.

(Allan Dowdeswell) #2

You know you’re an awesome dev when nobody knows how to help you. :smiley:

(Kevin Leung) #3

I am not python expert here are my 2cents.

  1. Perhaps @:expose could be used to expose fields to module level?
  2. I think @:pythonImport("bpy", 'types.Operator') extern class Operator {} is the answer
  3. From the blender doc and my scarse python knowledge, I believe it is a static variable. Because it is declared at class level. If it is an instance variable it would be declared in __init__ as = 'xx'.