+struct vg_controller *vg_active_controller(void){
+ if( vg_input.active_controller_index >= 0 )
+ return &vg_input.controllers[vg_input.active_controller_index];
+ else
+ return NULL;
+}
+
+static u8 vg_controller_button( SDL_GameControllerButton button ){
+ struct vg_controller *c = vg_active_controller();
+ if( c ) return c->buttons[ button ];
+ else return 0;
+}
+
+static f32 vg_controller_axis( SDL_GameControllerAxis axis ){
+ struct vg_controller *c = vg_active_controller();
+ if( c ) return c->axises[ axis ];
+ else return 0;
+}
+
+static void vg_input_apply_to_u8( vg_input_op mode, u8 data, u8 *inout_result ){
+ if ( mode == vg_mode_absmax ) *inout_result |= data;
+ else if( mode == vg_mode_mul ) *inout_result &= data;
+ else vg_fatal_error( "mode not supported for destination type (%d)", mode );
+}
+
+static void vg_input_apply_to_f32( vg_input_op mode, f32 data,
+ f32 *inout_result ){
+ if ( mode == vg_mode_absmax ){
+ if( fabsf(data) > fabsf(*inout_result) )
+ *inout_result = data;
+ }
+ else if( mode == vg_mode_max ) *inout_result = vg_maxf(*inout_result,data);
+ else if( mode == vg_mode_mul ) *inout_result *= (f32)data;
+ else if( mode == vg_mode_sub ) *inout_result -= (f32)data;
+ else if( mode == vg_mode_add ) *inout_result += (f32)data;
+ else vg_fatal_error( "mode not supported for destination type (%d)", mode );
+}
+
+static void vg_exec_input_program( enum vg_input_type type, vg_input_op *ops,
+ void *out_result ){
+ u8 *out_button = NULL;
+ f32 *out_joy = NULL;
+
+ if( type == k_vg_input_type_button_u8 ){
+ out_button = out_result;
+ *out_button = 0;
+ }
+ else if( type == k_vg_input_type_axis_f32 ){
+ out_joy = out_result;
+ out_joy[0] = 0.0f;
+ }
+ else if( type == k_vg_input_type_joy_v2f ){
+ out_joy = out_result;
+ out_joy[0] = 0.0f;
+ out_joy[1] = 0.0f;
+ }
+
+ /* computer state */
+ vg_input_op mode = vg_mode_absmax;
+ u32 pc = 0, index = 0;
+
+next_code:;
+ vg_input_op op = ops[ pc ++ ];
+
+ if( (op >= vg_mode_mul) && (op <= vg_mode_max) ){
+ mode = op;
+ }
+ else if( (op == vg_keyboard) || (op == vg_mouse) || (op == vg_joy_button) ){
+ u8 state = 0;
+
+ if( op == vg_keyboard )
+ state = vg_getkey(ops[pc ++]);
+ else if( op == vg_mouse )
+ state = (vg_input.sdl_mouse & SDL_BUTTON(ops[pc ++]))?1:0;
+ else
+ state = vg_controller_button(ops[pc ++]);
+
+ if( type == k_vg_input_type_button_u8 )
+ vg_input_apply_to_u8( mode, state, out_button );
+ else
+ vg_input_apply_to_f32( mode, (f32)state, &out_joy[index] );
+ }
+ else if( op == vg_joy_axis ){
+ f32 state = vg_controller_axis( ops[pc ++] );
+ if( type == k_vg_input_type_button_u8 )
+ vg_input_apply_to_u8( mode, state>0.5f?1:0, out_button );
+ else
+ vg_input_apply_to_f32( mode, state, &out_joy[index] );
+ }
+ else if( (op >= vg_0_0f) && (op <= vg_2_0f) ){
+ f32 value = (f32)(op - vg_0_5f) * 0.5f;
+ vg_input_apply_to_f32( mode, value, &out_joy[index] );
+ }
+ else if( op == vg_index ){
+ index = ops[pc ++];
+ }
+ else if( op == vg_end ){
+ return;
+ }
+ else if( op == vg_normalize ){
+ v2_normalize( out_joy );
+ }
+ else {
+ vg_fatal_error( "unknown op\n" );
+ }
+
+ goto next_code;
+}
+