Writing a moduleThe aim of this document is to show you how quickly you as a programmer
can realize your own module and then make use of it together with all the
other modules of VSXu, saving lots of development time. main.cppFirst, some includes. 001 #include <vsxfst.h> // file system and string functions 002 #include <vsx_param.h> // parameter definitions 003 #include <vsx_module.h> // module base class + definition 004 #include <vsx_math_3d.h> // vsx_vector and matrix maths 005 We call our class vsx_module_template 006 class vsx_module_template : public vsx_module { We define some pointers to parameter holders for inputs. Various types - float/float3/float4. The memory pointed to by these is never owned by us, it's taken care of by the engine. A consequence of this is that to set values, we have to call methods to this object. But the advantage of this is that it saves the module developer from a lot of issues, especially when the engine wants to (sometimes) override the values. 007 // in
008 vsx_module_param_float3* position;
009 vsx_module_param_float3* size;
010 vsx_module_param_float* angle;
011 vsx_module_param_float3* rotation_axis;
012 vsx_module_param_float4* color_rgb;
013 vsx_module_param_int* border;
The same is done for our only output parameter - of type render. 014 // out
015 vsx_module_param_render* render_result;
This is just a placeholder for variables internal to the class. 016 // internal
017
Now time for our first public method. This one is mandatory and it basically tells artiste stuff about us.
Where in the module hierarchy to put us, what our name is, what parameters we have, what constraints and controllers
those should have and some other flags to both the engine and artiste. 018 public: 019 020 void module_info(vsx_module_info* info) 021 { First comes the path to the module in the hierarchy. Using ; as separator. Another valid path would be for instance - render;basic;simple_module 022 info->identifier = "templates;simple";
Next comes the textual description displayed by Luna, and in the module chooser. These lines shoudn't be too wide - try out for yourself how much you can cram in. 023 info->description = 024 "Template module showing all\n" 025 "possible data types and tricks\n" 026 "you can do in modules.\n" 027 ; Now for the parameter specification. The syntax is pretty much covered in this following big code comment: 028 /* 029 * Parameter specifications 030 * Used to tell artiste what parameters we want in the GUI and how 031 * those should behave. 032 * 033 * Syntax: 034 * 035 * [name]:[type][?[flag][=value]] 036 * 037 * - Name and type are required. 038 * - Flag can be many things, controllers or options on how the GUI should 039 * treat it. 040 * 041 * To prevent connections to a parameter, add the non-connection flag: 042 * nc=1 043 * 044 * This will make it impossible to connect the parameter to any other 045 * module. That is, only the human operating VSXu can set it. 046 * Use this when you do operations that involve large chunks of memory 047 * or heavy one-time precalculations. 048 * 049 * Setting "Default Controller" (which controller is displayed when double- 050 * clicking the param): 051 * default_controller=[value] 052 * 053 * Different values (controllers) for different parameters are available: 054 * 055 * controller_knob float 056 * controller_slider float, float3, float4 057 * controller_edit string/resource 058 * controller_resource resource (to use it with strings, make it 059 * default) 060 * 061 * Example: 062 * To make a knob default (when double-clicking) go like this: 063 * angle:float?default_controller=controller_knob 064 * 065 */ 066 info->in_param_spec = 067 "spatial:complex{" 068 "position:float3," 069 "angle:float," 070 "rotation_axis:float3," 071 "size:float3," 072 "border:enum?no|yes 073 "}," 074 "color:float4" 075 ; The out-param specification shares the same syntax language as the input specification, but this module has only one output parameter. 077 info->out_param_spec = "render_out:render";
Here we tell artiste what graphic icon to display for the module. These are pre-defined so you have a bunch to choose from. Here are the possible choices: bitmap, mesh, output, parameters, particlesystem, render, system, texture, texture_surface. This module however, is a plain and simple renderer. 078 info->component_class = "render";
079 }
083 void declare_params(
084 vsx_module_param_list& in_parameters,
085 vsx_module_param_list& out_parameters
086 )
087 {
First we set loading done is a flag telling the engine that we're done loading. Since this module is not dependant on external file system or anything else that is time consuming and might not be completed in one frame, we can set it in the declare_params method. If you need to use this flag, be aware that the engine will consider the whole state runnable if loading_done is true - so if you're not really done, you'll end up displaying garbage or even crash the engine if you don't set this at the right time. 088 loading_done = true;
Now it's time to ask the engine to create our first parameter. The variable is declared at the top of the class - line 8 - and the string we pass in here - "position" is referred to in the module_info method's in_param_spec. As we just get a vsx_param_abs back, we have to typecast it to vsx_module_param_float3: 089 position = (vsx_module_param_float3*)in_parameters.create(
090 VSX_MODULE_PARAM_ID_FLOAT3,
091 "position"
092 );
Now we can set default values. As this is written, it's actually not needed as the engine will initialize float tuples to 0.0f. But it's still good practice during development to list all the starting values as it'll make it easier for you to know what's going on. 093 position->set(0.0f, 0); 094 position->set(0.0f, 1); 095 position->set(0.0f, 2); Another float3 parameter - size: 097 size = (vsx_module_param_float3*)in_parameters.create(
098 VSX_MODULE_PARAM_ID_FLOAT3,
099 "size"
100 );
This will only be 2-dimensional size, so we ignore the 3rd parameter. 101 size->set(1.0f,0); 102 size->set(0.3f,1); Now a single float parameter - angle 103 angle = (vsx_module_param_float*)in_parameters.create(
104 VSX_MODULE_PARAM_ID_FLOAT,
105 "angle"
106 );
...and its initialization. 107 angle->set(0.0f);
Now for a different type of parameter - an integer parameter. If you remember
this was declared as an enum in the in_param_spec: 109 border = (vsx_module_param_int*)in_parameters.create(
110 VSX_MODULE_PARAM_ID_INT,
111 "border"
112 );
We don't care to initialize this... The engine will set it to 0 for us.
You probably know enough now to understand what's going on in this following code block: 114 rotation_axis = (vsx_module_param_float3*)in_parameters.create( 115 VSX_MODULE_PARAM_ID_FLOAT3, 116 "rotation_axis" 117 ); 118 rotation_axis->set(1.0f, 0); 119 rotation_axis->set(1.0f, 1); 120 rotation_axis->set(0.0f, 2); 121 color_rgb = (vsx_module_param_float4*)in_parameters.create( 122 VSX_MODULE_PARAM_ID_FLOAT4, 123 "color" 124 ); 125 color_rgb->set(1.0,0); 126 color_rgb->set(1.0,1); 127 color_rgb->set(1.0,2); 128 color_rgb->set(1.0,3); The final parameter we need initialized is the render_result - our only out parameter.
Note that unlike the previous declarations, this is called from the out_parameters
parameter list. 129 130 render_result = (vsx_module_param_render*)out_parameters.create( 131 VSX_MODULE_PARAM_ID_RENDER, 132 "render_out" 133 ); 134 render_result->set(0); 135 } In this module - which is focused solely on output - we don't have a run()
method. It's however important to understand the difference between run()
and output(). 136 137 // this is run once per frame/iteration of the whole engine 138 void run() 139 { 140 // procrastinate 141 } This is now the output function. We'll not dive too much into it,
it's basically doing general OpenGL stuff to draw a rect, using the parameters
we've declared before. 143 // this is run for each connection to this in-param. 144 void output(vsx_module_param_abs* param) 145 { 146 glMatrixMode(GL_MODELVIEW); 147 glPushMatrix(); 148 // translation 149 glTranslatef(position->get(0),position->get(1),position->get(2)); 150 // rotation 151 glRotatef( 152 (float)angle->get()*360, 153 rotation_axis->get(0), 154 rotation_axis->get(1), 155 rotation_axis->get(2) 156 ); 157 // scaling 158 glScalef(size->get(0), size->get(1), size->get(2)); 159 // color 160 glColor4f( 161 color_rgb->get(0), 162 color_rgb->get(1), 163 color_rgb->get(2), 164 color_rgb->get(3) 165 ); 166 167 glBegin(GL_QUADS); 168 glTexCoord2f(0.0f,0.0f); 169 glVertex3f(-1.0f, -1.0f, 0.0f); 170 glTexCoord2f(0.0f,1.0f); 171 glVertex3f(-1.0f, 1.0f, 0.0f); 172 glTexCoord2f(1.0f,1.0f); 173 glVertex3f( 1.0f, 1.0f, 0.0f); 174 glTexCoord2f(1.0f,0.0f); 175 glVertex3f( 1.0f, -1.0f, 0.0f); 176 glEnd(); 177 178 if (border->get()) 179 { 180 glEnable(GL_LINE_SMOOTH); 181 glLineWidth(1.5); 182 glEnable(GL_BLEND); 183 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 184 185 glBegin(GL_LINE_STRIP); 186 glColor3f(0, 0, 0); 187 glVertex3f(-2, -0.4f, 0); 188 glVertex3f(-2, -0.2f, 0); 189 glVertex3f( 2, -0.2f, 0); 190 glVertex3f( 2, -0.4f, 0); 191 glVertex3f(-2, -0.4f, 0); 192 glEnd(); 193 } 194 195 glPopMatrix(); 196 render_result->set(1); 197 loading_done = true; 198 } 199 }; Finally we have our interface with the engine. It's our responsibility
to provide typecasted objects of all our module classes, so there is
support for that. Also since the engine don't know how to delete these,
we have to take care of this too. If you're familiar with design patterns,
this is the "factory" pattern. 200 201 202 203 //****************************************************************************** 204 //*** F A C T O R Y ************************************************************ 205 //****************************************************************************** 206 207 #ifndef _WIN32 208 #define __declspec(a) 209 #endif 210 211 extern "C" { 212 __declspec(dllexport) vsx_module* create_new_module(unsigned long module); 213 __declspec(dllexport) void destroy_module(vsx_module* m,unsigned long module); 214 __declspec(dllexport) unsigned long get_num_modules(); 215 } 216 217 218 vsx_module* MOD_CM(unsigned long module) { 219 switch (module) { 220 case 0: return (vsx_module*)new vsx_module_template; 221 } // switch 222 return 0; 223 } 224 225 226 void MOD_DM(vsx_module* m,unsigned long module) { 227 switch(module) { 228 case 0: delete (vsx_module_template*)m; break; 229 } 230 } 231 232 233 unsigned long MOD_NM() { 234 return 1; 235 } 236 |
