3 #ifndef WORLD_LOGIC_BRICKS_H
4 #define WORLD_LOGIC_BRICKS_H
8 typedef struct logic_packet logic_packet
;
11 u32 location
, function
;
12 union mdl_128bit_union data
;
13 enum mdl_128bit_datatype type
;
16 VG_STATIC
void logic_bricks_debug_connection( world_instance
*world
,
17 mdl_node
*from
, u32 next
,
23 mdl_node
*to
= mdl_node_from_id( world
->meta
, next
);
26 float brightness
= 0.8f
+ world
->logic_bricks
[ from
->sub_uid
].usage
* 4.0f
;
27 v3_muls( colour
, brightness
, c
);
29 u32 clamped
= 0xff000000;
31 for( int i
=0; i
<3; i
++ )
33 u8 byte
= vg_minf( 1.0f
, c
[i
] ) * 255.0f
;
34 clamped
|= byte
<< (i
*8);
37 vg_line( from
->co
, to
->co
, clamped
);
40 VG_STATIC
void logic_bricks_debug( world_instance
*world
, v3f pos
)
42 v3f white
= {1.0f
,1.0f
,1.0f
},
43 red
= {1.0f
,0.2f
,0.1f
},
44 black
= {0.2f
,0.2f
,0.2f
};
48 for( int i
=0; i
<world
->logic_brick_count
; i
++ )
50 struct logic_brick_ref
*ref
= &world
->logic_bricks
[i
];
51 mdl_node
*node
= ref
->node
;
53 if( v3_dist2( node
->co
, pos
) > 50.0f
*50.0f
)
56 void *entdata
= mdl_get_entdata( world
->meta
, node
);
58 if( ref
->node
->classtype
== k_classtype_logic_wire
)
60 struct classtype_logic_wire
*wire
= entdata
;
62 logic_bricks_debug_connection( world
, node
, wire
->next
, white
);
64 else if( ref
->node
->classtype
== k_classtype_logic_chances
)
66 struct classtype_logic_chances
*chances
= entdata
;
68 logic_bricks_debug_connection(world
, node
, chances
->targets
[0], red
);
69 logic_bricks_debug_connection(world
, node
, chances
->targets
[1], black
);
71 else if( ref
->node
->classtype
== k_classtype_signal_splitter
)
73 struct classtype_signal_splitter
*splitter
= entdata
;
74 logic_bricks_debug_connection( world
, node
, splitter
->next
[0], white
);
75 logic_bricks_debug_connection( world
, node
, splitter
->next
[1], white
);
76 logic_bricks_debug_connection( world
, node
, splitter
->next
[2], white
);
77 logic_bricks_debug_connection( world
, node
, splitter
->next
[3], white
);
79 else if( ref
->node
->classtype
== k_classtype_soundscape
)
81 struct classtype_soundscape
*inf
= entdata
;
82 struct soundscape
*s
= &world
->soundscapes
[ ref
->internal_id
];
85 v3_copy( ref
->node
->co
, co
);
88 box
[0][0] = co
[0]-0.12f
;
89 box
[0][1] = co
[1]-0.12f
;
90 box
[0][2] = co
[2]-0.12f
;
91 box
[1][0] = co
[0]+0.12f
;
92 box
[1][1] = co
[1]+0.12f
+ 0.1f
*(float)inf
->max_instances
;
93 box
[1][2] = co
[2]+0.12f
;
95 vg_line_boxf( box
, VG__WHITE
);
97 for( int i
=0; i
<s
->usage_count
; i
++ )
99 vg_line_pt3( co
, 0.09f
, VG__GREEN
);
103 else if( ref
->node
->classtype
== k_classtype_trigger
)
105 struct classtype_trigger
*trigger
= entdata
;
106 logic_bricks_debug_connection( world
, node
, trigger
->target
, white
);
108 else if( ref
->node
->classtype
== k_classtype_particle_box
)
110 struct classtype_particle_box
*pb
= entdata
;
111 logic_bricks_debug_connection( world
, node
, pb
->target
, white
);
114 ref
->usage
*= vg_maxf( 0.0f
, 1.0f
-vg
.time_delta
*5.0f
);
118 VG_STATIC
void logic_packet_terminate( logic_packet
*packet
)
120 packet
->location
= 0xffffffff;
123 VG_STATIC
void logic_wire_call( world_instance
*world
,
124 struct logic_brick_ref
*ref
,
125 logic_packet
*packet
)
127 struct classtype_logic_wire
*inf
= mdl_get_entdata( world
->meta
, ref
->node
);
129 if( packet
->function
== 0 ) /* pass onwards */
133 if( inf
->data_type
!= k_mdl_128bit_datatype_nothing
)
135 packet
->data
= inf
->data
;
136 packet
->type
= inf
->data_type
;
139 mdl_node
*next
= mdl_node_from_id( world
->meta
, inf
->next
);
140 packet
->location
= next
->sub_uid
;
141 packet
->function
= inf
->function
;
144 logic_packet_terminate( packet
);
146 else if( packet
->function
== 1 ) /* TODO enable */
148 logic_packet_terminate( packet
);
150 else if( packet
->function
== 2 ) /* TODO disable */
152 logic_packet_terminate( packet
);
156 vg_error( "[INVALID FUNCTION] logic_wire:[%u]\n", packet
->function
);
157 logic_packet_terminate( packet
);
161 VG_STATIC
void logic_chances_call( world_instance
*world
,
162 struct logic_brick_ref
*ref
,
163 logic_packet
*packet
)
165 struct classtype_logic_chances
*inf
=
166 mdl_get_entdata( world
->meta
, ref
->node
);
168 if( packet
->function
== 0 ) /* pass along */
172 if( vg_randf() > inf
->p
)
175 if( inf
->targets
[red
] )
177 mdl_node
*pnext
= mdl_node_from_id( world
->meta
, inf
->targets
[red
] );
179 if( (pnext
->classtype
== k_classtype_logic_wire
) ||
180 (pnext
->classtype
== k_classtype_logic_chances
) ||
181 (pnext
->classtype
== k_classtype_signal_splitter
) )
183 packet
->location
= pnext
->sub_uid
;
187 vg_error( "[INVALID TARGET] logic_chances:pass( ... )\n" );
188 vg_warn( " target[%d] must be classtype logic_wire\n", red
);
189 logic_packet_terminate( packet
);
194 logic_packet_terminate( packet
);
197 else if( packet
->function
== 1 ) /* set ratio */
199 if( packet
->type
== k_mdl_128bit_datatype_number
)
201 inf
->p
= packet
->data
._f32
;
205 vg_error( "[INVALID ARGUMENT] logic_chances:set_ratio( f32 p )\n" );
208 logic_packet_terminate( packet
);
212 vg_error( "[INVALID FUNCTION] logic_chances:[%u]\n", packet
->function
);
213 logic_packet_terminate( packet
);
217 VG_STATIC
void logic_soundscape_call( world_instance
*world
,
218 struct logic_brick_ref
*ref
,
219 logic_packet
*packet
)
221 struct classtype_soundscape
*inf
= mdl_get_entdata( world
->meta
, ref
->node
);
222 struct soundscape
*soundscape
= &world
->soundscapes
[ ref
->internal_id
];
224 if( packet
->function
== 0 ) /* play */
226 /* TODO: Only spawn within certain range of player */
228 if( packet
->type
!= k_mdl_128bit_datatype_target
)
230 vg_error( "[INVALID ARGUMENT] logic_soundscape:play( ref sound )\n" );
231 vg_warn( " got datatype: %u\n", packet
->type
);
232 logic_packet_terminate( packet
);
236 mdl_node
*data
= mdl_node_from_id( world
->meta
, packet
->data
._u32
);
238 if( data
->classtype
!= k_classtype_audio
)
240 vg_error( "[INVALID TARGET] logic_soundscape:play( ref sound )\n" );
241 logic_packet_terminate( packet
);
245 if( soundscape
->usage_count
< soundscape
->max_instances
)
247 struct world_audio_thing
*audio
= &world
->audio_things
[data
->sub_uid
];
250 for( int i
=0; i
<soundscape
->max_instances
; i
++ )
252 if( !soundscape
->channels
[i
] )
255 soundscape
->channels
[i
] = audio_request_channel(
256 &audio
->temp_embedded_clip
,
259 if( soundscape
->channels
[i
] )
261 if( audio
->flags
& AUDIO_FLAG_SPACIAL_3D
)
263 audio_channel_set_spacial( soundscape
->channels
[i
],
264 soundscape
->spawn_position
,
268 audio_channel_edit_volume( soundscape
->channels
[i
],
275 soundscape
->usage_count
++;
282 logic_packet_terminate( packet
);
284 else if( packet
->function
== 1 ) /* set position */
286 if( packet
->type
!= k_mdl_128bit_datatype_vec3
)
288 vg_error( "[INVALID ARGUMENT] logic_soundscape:position( v3f co )\n" );
289 logic_packet_terminate( packet
);
293 v3_copy( packet
->data
._v4f
, soundscape
->spawn_position
);
294 logic_packet_terminate( packet
);
298 vg_error( "[INVALID FUNCTION] logic_wire:[%u]\n", packet
->function
);
299 logic_packet_terminate( packet
);
303 VG_STATIC
void _logic_trigger_base_call( world_instance
*world
, u32 target
,
304 logic_packet
*packet
)
306 if( packet
->function
== 0 ) /* pass onwards */
310 mdl_node
*next
= mdl_node_from_id( world
->meta
, target
);
311 packet
->location
= next
->sub_uid
;
312 packet
->function
= 0; /* always call the default function */
315 logic_packet_terminate( packet
);
319 vg_error( "[INVALID FUNCTION] logic_trigger:[%u]\n", packet
->function
);
320 logic_packet_terminate( packet
);
324 VG_STATIC
void logic_trigger_call( world_instance
*world
,
325 struct logic_brick_ref
*ref
,
326 logic_packet
*packet
)
328 struct classtype_trigger
*inf
= mdl_get_entdata( world
->meta
, ref
->node
);
329 _logic_trigger_base_call( world
, inf
->target
, packet
);
332 VG_STATIC
void logic_particle_call( world_instance
*world
,
333 struct logic_brick_ref
*ref
,
334 logic_packet
*packet
)
336 struct classtype_particle_box
*inf
=
337 mdl_get_entdata( world
->meta
, ref
->node
);
339 /* rate of 1.0 means we get one a second or 0.1 per tick */
341 if( vg_randf() < inf
->rate
* 0.1f
)
344 _logic_trigger_base_call( world
, inf
->target
, packet
);
348 logic_packet_terminate( packet
);
352 VG_STATIC
void logic_bricks_send_packet( world_instance
*world
,
353 logic_packet
*packet
);
355 VG_STATIC
void logic_splitter( world_instance
*world
,
356 struct logic_brick_ref
*ref
,
357 logic_packet
*packet
)
359 struct classtype_signal_splitter
*inf
360 = mdl_get_entdata( world
->meta
, ref
->node
);
362 if( packet
->function
== 0 ) /* pass onwards */
364 for( int i
=0; i
<4; i
++ )
368 logic_packet copy
= *packet
;
370 mdl_node
*next
= mdl_node_from_id( world
->meta
, inf
->next
[i
] );
371 copy
.location
= next
->sub_uid
;
372 copy
.function
= 0; /* always call the default function */
374 logic_bricks_send_packet( world
, ©
);
378 logic_packet_terminate( packet
);
382 vg_error( "[INVALID FUNCTION] logic_splitter:[%u]\n", packet
->function
);
383 logic_packet_terminate( packet
);
387 VG_STATIC
void logic_bricks_send_packet( world_instance
*world
,
388 logic_packet
*packet
)
390 while( packet
->location
!= 0xffffffff )
392 struct logic_brick_ref
*ref
= &world
->logic_bricks
[ packet
->location
];
393 enum classtype type
= ref
->node
->classtype
;
395 if( type
== k_classtype_logic_wire
)
397 logic_wire_call( world
, ref
, packet
);
399 else if( type
== k_classtype_logic_chances
)
401 logic_chances_call( world
, ref
, packet
);
403 else if( type
== k_classtype_soundscape
)
405 logic_soundscape_call( world
, ref
, packet
);
407 else if( type
== k_classtype_trigger
)
409 logic_trigger_call( world
, ref
, packet
);
411 else if( type
== k_classtype_particle_box
)
413 logic_particle_call( world
, ref
, packet
);
416 else if( type
== k_classtype_signal_splitter
)
418 logic_splitter( world
, ref
, packet
);
422 vg_error( "Undefined logic brick (entity type %d)\n", type
);
423 logic_packet_terminate( packet
);
430 VG_STATIC
void logic_bricks_world_gen_allocate( world_instance
*world
)
432 /* REVISION: unify allocations, loaders and extensions for entities.
433 * we currently seem to do every which entity a different way */
435 world
->logic_brick_count
= 0;
436 world
->logic_bricks
= NULL
;
437 world
->soundscape_count
= 0;
438 world
->trigger_count
= 0;
440 for( int i
=0; i
<world
->meta
->info
.node_count
; i
++ )
442 mdl_node
*pnode
= mdl_node_from_id( world
->meta
, i
);
444 if( pnode
->classtype
== k_classtype_logic_wire
||
445 pnode
->classtype
== k_classtype_logic_chances
||
446 pnode
->classtype
== k_classtype_soundscape
||
447 pnode
->classtype
== k_classtype_trigger
||
448 pnode
->classtype
== k_classtype_particle_box
||
449 pnode
->classtype
== k_classtype_signal_splitter
)
451 world
->logic_bricks
=
452 vg_linear_extend( world_global
.generic_heap
,
454 sizeof( struct logic_brick_ref
) );
456 pnode
->sub_uid
= world
->logic_brick_count
;
458 struct logic_brick_ref
*ref
=
459 &world
->logic_bricks
[ world
->logic_brick_count
];
461 ref
->internal_id
= 0;
463 if( pnode
->classtype
== k_classtype_soundscape
)
465 u32 id
= world
->soundscape_count
;
467 struct soundscape
*soundscape
= &world
->soundscapes
[ id
];
469 struct classtype_soundscape
*inf
=
470 mdl_get_entdata( world
->meta
, pnode
);
472 soundscape
->label
= mdl_pstr( world
->meta
, inf
->label
);
473 soundscape
->max_instances
= inf
->max_instances
;
474 soundscape
->allow_transitions
= inf
->allow_transitions
;
475 soundscape
->transition_duration
= inf
->transition_duration
;
476 v3_copy( pnode
->co
, soundscape
->spawn_position
);
478 ref
->internal_id
= id
;
479 world
->soundscape_count
++;
481 else if( pnode
->classtype
== k_classtype_trigger
||
482 pnode
->classtype
== k_classtype_particle_box
)
484 u32 id
= world
->trigger_count
;
485 struct trigger_zone
*trigger
= &world
->triggers
[ id
];
487 mdl_node_transform( pnode
, trigger
->transform
);
488 m4x3_invert_full( trigger
->transform
, trigger
->inv_transform
);
489 trigger
->target_logic_brick
= world
->logic_brick_count
;
490 trigger
->classtype
= pnode
->classtype
;
492 world
->trigger_count
++;
495 world
->logic_brick_count
++;
506 * ----------------------------------------------------------------------------
509 VG_STATIC
void trigger_bh_expand_bound( void *user
, boxf bound
, u32 item_index
)
511 world_instance
*world
= user
;
512 struct trigger_zone
*trigger
= &world
->triggers
[ item_index
];
514 m4x3_expand_aabb_point( trigger
->transform
, bound
, (v3f
){ 1.0f
, 1.0f
, 1.0f
} );
515 m4x3_expand_aabb_point( trigger
->transform
, bound
, (v3f
){ 1.0f
, 1.0f
,-1.0f
} );
516 m4x3_expand_aabb_point( trigger
->transform
, bound
, (v3f
){ 1.0f
,-1.0f
, 1.0f
} );
517 m4x3_expand_aabb_point( trigger
->transform
, bound
, (v3f
){ 1.0f
,-1.0f
,-1.0f
} );
518 m4x3_expand_aabb_point( trigger
->transform
, bound
, (v3f
){-1.0f
, 1.0f
, 1.0f
} );
519 m4x3_expand_aabb_point( trigger
->transform
, bound
, (v3f
){-1.0f
, 1.0f
,-1.0f
} );
520 m4x3_expand_aabb_point( trigger
->transform
, bound
, (v3f
){-1.0f
,-1.0f
, 1.0f
} );
521 m4x3_expand_aabb_point( trigger
->transform
, bound
, (v3f
){-1.0f
,-1.0f
,-1.0f
} );
524 VG_STATIC
float trigger_bh_centroid( void *user
, u32 item_index
, int axis
)
526 world_instance
*world
= user
;
527 struct trigger_zone
*trigger
= &world
->triggers
[ item_index
];
529 return trigger
->transform
[3][axis
];
532 VG_STATIC
void trigger_bh_swap( void *user
, u32 ia
, u32 ib
)
534 world_instance
*world
= user
;
535 struct trigger_zone
*a
= &world
->triggers
[ ia
],
536 *b
= &world
->triggers
[ ib
],
544 VG_STATIC
void trigger_bh_debug( void *user
, u32 item_index
)
546 world_instance
*world
= user
;
547 struct trigger_zone
*zone
= &world
->triggers
[ item_index
];
549 vg_line_boxf_transformed( zone
->transform
, (boxf
){{-1.0f
,-1.0f
,-1.0f
},
550 { 1.0f
, 1.0f
, 1.0f
}},
554 VG_STATIC bh_system bh_system_triggers
=
556 .expand_bound
= trigger_bh_expand_bound
,
557 .item_centroid
= trigger_bh_centroid
,
558 .item_closest
= NULL
,
559 .item_swap
= trigger_bh_swap
,
560 .item_debug
= trigger_bh_debug
,
564 #endif /* WORLD_LOGIC_BRICKS_H */