[Bf-taskforce25] Blender API
vekoon
vekoon at gmail.com
Fri Feb 27 17:32:26 CET 2009
Hey guys,
lately I've seen discussions especially on channel about what should be
made into operators and what should not and how to eventually solve or
provide access to the functionality not covered by operators.
Is obvious that operatorifying everything is a mistake or even
impossible in some circumstances (like direct UI) but personally I'd
also prefer to make into operators only what is strictly a tool of some
kind. I'm not sure "everything user-accessible" is a good measure in
that the user is in the end able to access almost everything. There are
various gray areas on top of this argument. For instance moving a
space's splitter, is that a "tool"? No, but it's definitively
user-accessible in the sense that the user can actually interact with it
and change every aspect of it (not that it has many aspects though). Now
this is the case of a grey area. If you resize the splitter while
registering a macro and the action is registered and then you run the
macro with a different screen layout, what happens? Of course someone
could argue that you can make the operator non-registrable but of course
you don't want to have a moved splitter as undoable (you move an object,
resize window, now you have to undo twice to reset the object to the old
location?), so what's the point of having it as an operator at all if
you're not using operators' features?
So probably operators should be either tools or actions directly linked
to tool customization/interactivity, which in the end means nothing,
other than there's the need for an API parallel to operators.
For this reason in the last few days I tried to implement an API system.
The main point of such a system was to achieve some kind of abstraction
over *functionality* and to provide a common interface to make it
accessible. This description looks pretty much the same as RNA's if you
replace "functionality" with "data" and indeed they're very connected
components. So in the end my idea was to create a wrapper exactly like
RNA but which would wrap functionality instead of data. This system
integrates perfectly with RNA by using RNA structs as basic type
definition and associating functionality to these structs by defining
generic "types" that use RNA structs as their data structurization. The
implementation is much simpler than it may sound especially because I'm
tired and probably I'm explaining it badly.
patch: http://vekoon.googlecode.com/files/blender_api_0.1.patch
Tried on scons/mingw and cmake/msvc8
How the definition looks like (very similar to RNA):
void API_def_object(struct BlenderAPI *bapi)
{
TypeAPI *tapi;
FunctionAPI *func;
ParameterAPI *parm;
tapi= API_def_type(bapi, "Object", "ID");
API_def_type_struct(tapi, "Object");
API_def_type_ui_description(tapi, "Object type");
func= API_def_function(tapi, "move");
API_def_function_call(func, "api_Object_move_call");
API_def_function_description(func, "Move the object by an offset
relative to its current position.");
parm= API_def_parameter(func, "x");
API_def_parameter_type(parm, "Float");
API_def_parameter_ui_description(parm, "Offset on the X axis");
parm= API_def_parameter(func, "y");
API_def_parameter_type(parm, "Float");
API_def_parameter_ui_description(parm, "Offset on the Y axis");
parm= API_def_parameter(func, "z");
API_def_parameter_type(parm, "Float");
API_def_parameter_ui_description(parm, "Offset on the Z axis");
func= API_def_function(tapi, "swap");
API_def_function_call(func, "api_Object_swap_call");
API_def_function_description(func, "Swap this object's location with
another object.");
parm= API_def_parameter(func, "ob");
API_def_parameter_type(parm, "Object");
API_def_parameter_flag(parm, PARAM_POINTER);
API_def_parameter_ui_description(parm, "The target object this
object's location must swap with.");
}
How it looks in usage:
camera = bpy.objects['Camera']
cube = bpy.objects['Cube']
camera.move(0.8,0.7,0.4)
camera.swap(cube)
cube.rename('Camera');
camera.rename('Cube');
cube.rename('Camera');
# update changes
for scene in bpy.scenes:
scene.refresh()
Note: the script above already works if you apply the patch although as
a script it doesn't make a lot of sense but it's just to show something.
The definition may look a bit verbose I know, but in the end there's a
lot of copy/paste involved. I also initially thought of using RNA or
other form of structurization for parameter lists but then decided to
instead redefine parameters for every function as it introduced too many
difficulties not to do so. At most one can define a function
API_def_something_params(...) which defines a common list of parameters
and reuse it for similar function and the result will more or less be
the same.
Note also that this is just a demo implementation far from being perfect
or even complete. Various things are missing or yet to be decided or
changed etc. It's just to show how it could work and that it works but
it's just an idea, I just thought some functional code was better than
written theories. There are some low level things like parameter
allocation/handling which may look bad but they work and they're
probably faster than doing it in other ways. I also initially thought of
using ID properties groups as operators do but then dropped as it was
not performance friendly. In the end operators need this because they
have to be savable while instead API parameters don't and that's the
point of having a parallel API for things that don't need operator
features so they can be faster.
To conclude this message I'd also like to point out some of the nice
advantages/features of this system. First that comes to mind is that
this system is generalized exactly like RNA so in theory can be ported
automatically to any other scripting language and probably the most
interesting part is the reverse where you can automatically import into
the system stuff defined into the scripts and thereby for instance use a
class defined in python from withing a Lua script. This although
possible is not implemented yet as I'm not a python expert and I don't
know how much time that would have required. Connected to this is that
API defined through this system would of course be accessible
automatically from the GE so you could theoretically create a plugin in
C (or even in python if we export the API access calls themselves!) that
allows Lua access and then code your game entirely in Lua.
Another advantage is automatic extension. For instance you could just
create a class in py that inherits from GraphSpace thus creating a new
space type and extend it by overriding its methods and there you have a
custom editor. This again is not implemented and will require some
thinking but I'm pretty sure is feasible.
Thanks for reading and any comment/critique is well accepted.
More information about the Bf-taskforce25
mailing list