From BlenderWiki
Writing a Texture Plugin
In this Section we will write a basic texture plugin and then go through the steps to use a texture plugin.
The basics behind a texture plugin is that you are given some inputs; position, and normal values as well as some other info. Then you return intensity, colour and/or normal information depending on the type of texture plugin.
All the files necessary to develop plugins as well as a few sample plugins can be found in the blender/plugins directory. You can alternately get a bunch of plugins from this plugins repository. Plugins are supported (loaded/called) in Blender using the dlopen() family of calls. For those unfamiliar with this system, it allows a program (Blender) to use a compiled object as if it were part of the program itself, similar to dynamically linked libraries, except the objects to load are determined at runtime.
The advantage of using the dlopen system for plugins is that it is very fast to access a function, and there is no overhead in interfacing to the plugin, which is critical when as (in the case of texture plugins) the plugin can be called several million times in a single render. The disadvantage of the system is that the plugin code works just like it is part of Blender itself, if the plugin crashes, Blender crashes.
The include files found in the plugin/include/ subdirectory of the Blender installation document the Blender functionality provided to the plugins. This includes the Imbuf library functions for loading and working with images and image buffers, and noise and turbulence functions for consistent texturing.
Specification
#include <plugin.h>- Every Blender plugin should include this header file, which contains all of the structures and defines needed to properly work with Blender.
char name[]="Tiles";
- A character string containing the plugin name, this value will be displayed for the texture’s title in the Buttons window, Texture sub-context.
#define NR_TYPES 2; char stnames[NR_TYPES][16]= {"Square", "Deformed"};- Plugins are allowed to have separate subtypes for minor variations on algorithms - for example the default clouds texture in Blender has the “Default” and “Color” subtypes.
NR_TYPESshould be defined to the number of subtypes required by your plugin, and a name for each subtype should be given (stnames[NR_TYPES]). Every plugin should have at least 1 subtype and a subtype name.
VarStruct varstr[]= {...};
- The
varstrcontains all of the information Blender needs to display buttons for a plugin. Buttons for plugins can be numerical for input data, or text for comments and other information. Plugins are limited to a maximum of 32 variables. EachVarStructentry consists of a type, name, range information, and a tool tip.- The type defines the data type for each button entry, and the way to display the button. For number buttons this value should be a combination (binary OR, “
|”) of “INT” or “FLO” for the number format (integer or float), and “NUM”, “NUMSLI”, or “TOG”, for the button type (numeric, numeric with slider, or toggle). Text buttons should have a type of “LABEL”. - The name is what will be displayed on (or beside) the button. This is limited to 15 characters.
- The range information consists of three floats that define the default, minimum, and maximum values for the button. For
TOGgle buttons the minimum is set in the pressed state, and the maximum is set in the depressed state. - The tool tip is a string that will be displayed when the mouse is over this button (if the user has Tool Tips on). This has a limit of 80 characters, and should be set to the NULL string (
"") if unused.
- The type defines the data type for each button entry, and the way to display the button. For number buttons this value should be a combination (binary OR, “
typedef struct Cast {...};
- The
Caststructure is used in calling thedoitfunction, and serves as a way to simply access to each plugin’s data values. The cast should contain, in order, an integer or float for every button defined in thevarstr, including text buttons. Typically these should have the same name as the button for simple reference.
float result[8];
- The result array is used to pass information to and receive information from the plugin. The result values are mapped as follows:
resultIndexSignificance Range result[0]Intensity value 0.0 to 1.0 result[1]Red color value 0.0 to 1.0 result[2]Green color value 0.0 to 1.0 result[3]Blue color value 0.0 to 1.0 result[4]Alpha color value 0.0 to 1.0 result[5]X normal displacement -1.0 to 1.0 result[6]Y normal displacement -1.0 to 1.0 result[7]Z normal displacement -1.0 to 1.0
- The plugin should always return an intensity value. Returning RGB or a normal are optional, and should be indicated by the doit() return flag “1” (RGB) or “2” (Normal).
- Before the plugin is called, Blender includes the current rendering-normal in
result[5],result[6]andresult[7].
float cfra- The
cfravalue is set by Blender to the current frame before every render pass. This value is the frame number (± 0.5 depending on the field settings).
plugin_tex_doitprototype- The
plugin_tex_doitfunction should be prototyped for use by thegetinfofunction. You do not need to change this line.
plugin_tex_getversion- This function must be in each plugin for it to be loaded correctly. You should not change this function.
plugin_but_changed- This function is used to pass information about what buttons the user changes in the interface. Most plugins should not need to use this function, only when the interface allows the user to alter some variable that forces the plugin to do recalculation (a random hash table for example).
plugin_init- If needed plugins may use this function to initialize internal data.
- Note: This init function can be called multiple times if the same plugin texture is copied. Do not init global data specific to a single instance of a plugin in this function.
plugin_getinfo- This function is used to communicate information to Blender. You should never need to change it.
plugin_tex_doit- The doit function is responsible for returning information about the requested pixel to Blender.
- The Arguments
int stype- This is the number of the selected subtype, see the
NR_TYPESandchar stnames[NR_TYPES][16]entries above. Cast *cast- The
Caststructure which contains the plugin data, see thetypedef struct Castentry above. float *texvec- This is a pointer to three floats, which are the texture coordinates for which a texture value is to be returned.
float *dxt, float *dyt- If these pointers are non-NULL they point to two vectors (two arrays of three floats) that define the size of the requested texture value in pixel space. They are only non-NULL when OSA is on, and are used to calculate proper anti aliasing.
- The
doitfunction should fill in the result array (it should always fill in an intensity value), and return 0, 1, 2 or 3 depending on what values have been filled in:- 0 for intensity only,
- 1 for intensity + RGBA colour,
- 2 for intensity + normal, and
- 3 for intensity + RGBA colour + normal.
Texture/Material Interaction
Blender is somewhat different from most 3D packages in the logical separation between textures and materials. In Blender textures are objects that return certain values, signal generators in fact (like wave generators in synthesizer, for example). Materials control the mapping of textures onto objects, what is affected, how much, in what way, etc.
Properly designed plugins should only include variables to affect the signal returned, not the mapping of it. Buttons to control scale, range, axis, etc. are best only included when they make the texture easier to use (in the case of the Size button in the Tiles plugin), or when they speed up the calculation (the Intensity/Color/Bump subtypes in the Clouds2 plugin). Otherwise the Material sub-context make these buttons redundant, and the interface becomes needlessly complex.
Generic Texture Plugin
#include "plugin.h" /* Texture name */ char name[24]= ""; #define NR_TYPES 3 char stnames[NR_TYPES][16]= {"Intens", "Color", "Bump"}; /* Structure for buttons, * {butcode, name, default, min, max, tooltip} */ VarStruct varstr[]= { {NUM|FLO, "Const 1", 1.7, -1.0, 1.0, ""}, }; typedef struct Cast { float a; } Cast; float result[8]; float cfra; int plugin_tex_doit(int, Cast*, float*, float*, float*); /* Fixed Functions */ int plugin_tex_getversion(void) { return B_PLUGIN_VERSION; } void plugin_but_changed(int but) { } void plugin_init(void) { } void plugin_getinfo(PluginInfo *info) { info->name= name; info->stypes= NR_TYPES; info->nvars= sizeof(varstr)/sizeof(VarStruct); info->snames= stnames[0]; info->result= result; info->cfra= &cfra; info->varstr= varstr; info->init= plugin_init; info->tex_doit= (TexDoit) plugin_tex_doit; info->callback= plugin_but_changed; } int plugin_tex_doit(int stype, Cast *cast, float *texvec, float *dxt, float *dyt) { if (stype == 1) { return 1; } if (stype == 2) { return 2; } return 0; }
Our Modifications
The first step is to come up with a game plan. What is this plugin going to do, how are the users going to interact with it. For this example we will create a simple texture that creates a simple brick/block pattern.
Now we’ll copy our generic plugin to cube.c and will fill in the gaps. Its always a (very) good idea to add some comments. First off tell users what the plugin does, where they can get a copy, who they should contact for bugs/improvements, and any licensing restrictions on the code.
When using comments make sure you use “/* */” comments (C style). The plugins are in C and some C compilers do not accept “//” comments (C++ style).
/*
Description: This plugin is a sample texture plugin that creates a simple
brick/block pattern with it.
It takes two values a brick size, and a mortar size.
The brick size is the size of each brick.
The mortar size is the mortar size in between bricks.
Author: Kent Mein (mein@cs.umn.edu)
Website: http://www.cs.umn.edu/~mein/blender/plugins
Licensing: Public Domain
Last Modified: Tue Oct 21 05:57:13 CDT 2003
*/Next we need to fill in the name, you should really keep this the same as your .c file, preferably descriptive, less than 23 chars, no spaces, and all lowercase.
char name[24]= "cube.c";
We are going to keep this plugin simple, and only have one type that deals with intensity. So we need the following:
#define NR_TYPES 1 char stnames[NR_TYPES][16]= {"Default"};
For our user interface, we are going to allow people to change the size of the brick and mortar, as well as the intensity values returned for the brick and mortar. For that we need to edit varstr and Cast. Cast should have a variable for each entry in varstr.
/* Structure for buttons, * {butcode, name, default, min, max, tooltip] */ VarStruct varstr[]= { {NUM|FLO, "Brick", 0.8, 0.1, 1.0, "Size of Cell"}, {NUM|FLO, "Mortar", 0.1, 0.0, 0.4, "Size of boarder in cell"}, {NUM|FLO, "Brick Int", 1.0, 0.0, 1.0, "Color of Brick"}, {NUM|FLO, "Mortar Int", 0.0, 0.0, 1.0, "Color of Mortar"}, }; typedef struct Cast { float brick, mortar, bricki, mortari; } Cast;
Now we need to fill in plugin_tex_doit, we basically want to break down our texture into “cells” which will consist of a brick and the mortar along the bottom edges of that brick. Then determine if we are in the brick or the mortar. The following code should do that:
int plugin_tex_doit(int stype, Cast *cast, float *texvec, float *dxt, float *dyt) { int c[3]; float pos[3], cube; /* setup the size of our cell */ cube = cast->brick + cast->mortar; /* we need to do is determine where we are inside of the current brick. */ c[0] = (int)(texvec[0] / cube); c[1] = (int)(texvec[1] / cube); c[2] = (int)(texvec[2] / cube); pos[0] = ABS(texvec[0] - (c[0] * cube)); pos[1] = ABS(texvec[1] - (c[1] * cube)); pos[2] = ABS(texvec[2] - (c[2] * cube)); /* Figure out if we are in a mortar position within the brick or not. */ if ((pos[0] <= cast->mortar) || (pos[1] <= cast->mortar) || (pos[2] <= cast->mortar)) { result[0] = cast->mortari; } else { result[0] = cast->bricki; } return 0; }
One thing to note, the ABS function (absolute value) is defined in a header in plugins/include. There are some other common functions there as well, be sure to take a look at what’s there.
Compiling
“bmake” is a simple utility (shell script) to aid in the compilation and development of plugins. It can be found in the plugins/ sub-directory of the Blender installation directory. It is invoked by: bmake (plugin_name.c), and will attempt to link the proper libraries and compile the specified C file properly for your system.
If you are trying to develop plugins on a windows machine, bmake may not work for you. In that case you should look into using “lcc”. You can use the following to compile a plugin with lcc:
Assuming you have your plugins in c:\blender\plugins, here is an example of how you would compile the texture plugin sinus.c. Open a DOS prompt and do the following (note: You’ll want to make sure the lcc\bin directory is in your path):
cd c:\blender\plugins\texture\sinus
lcc -Ic:\blender\plugins\include sinus.c
lcclnk -DLL sinus.obj c:\blender\plugins\include\tex.def
implib sinus.dllThe latest version of lcc does not have “implib”. Instead, do the following:
cd c:\blender\plugins\texture\sinus
lcc -Ic:\blender\plugins\include sinus.c
lcclnk -dll -nounderscores sinus.obj c:\blender\plugins\include\tex.defNote that tex.def is not distributed with the Blender source but is available from the Blender plug-in repository. Alternatively, create a tex.def file and copy and paste it the following :
EXPORTS LibMain@12 plugin_but_changed plugin_getinfo plugin_init plugin_tex_doit plugin_tex_getversion