FreeWRL / FreeX3D 4.3.0
Component_DIS.c
1
2/****************************************************************************
3 This file is part of the FreeWRL/FreeX3D Distribution.
4
5 Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
6
7 FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
8 it under the terms of the GNU Lesser Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 FreeWRL/FreeX3D is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
19****************************************************************************/
20
21
22/*******************************************************************
23
24 X3D DIS Component
25
26*********************************************************************/
27
28
29#include <config.h>
30#include <system.h>
31#include <display.h>
32#include <internal.h>
33#include <iglobal.h>
34#include <libFreeWRL.h>
35
36#include "../vrml_parser/Structs.h"
37#include "../vrml_parser/CRoutes.h"
38#include "../main/headers.h"
39
40#include "../world_script/fieldSet.h"
41#include "../x3d_parser/Bindable.h"
42#include "Collision.h"
43#include "quaternion.h"
44#include "Viewer.h"
45#include "../opengl/Frustum.h"
46#include "../opengl/Material.h"
47#include "../opengl/OpenGL_Utils.h"
48#include "../input/EAIHelpers.h" /* for newASCIIString() */
49
50#include "Polyrep.h"
51#include "LinearAlgebra.h"
52#include "Children.h"
53#include "Vector.h"
54#include "Component_Geospatial.h"
55#include "Component_DIS.h"
56#include "Component_Grouping.h"
57#include "RenderFuncs.h"
58
59//from CparseParser
60void add_node_to_broto_context(struct X3D_Proto *currentContext,struct X3D_Node *node);
61
62#ifndef WIN32
63#define SOCKET int
64#include <sys/socket.h>
65#include <netinet/in.h>
66#include <arpa/inet.h>
67#endif
68/*
69typedef struct pComponent_DIS{
70 int something;
71}* ppComponent_DIS;
72void *Component_DIS_constructor(){
73 void *v = MALLOCV(sizeof(struct pComponent_DIS));
74 memset(v,0,sizeof(struct pComponent_DIS));
75 return v;
76}
77void Component_DIS_init(struct tComponent_DIS *t){
78 //public
79 //private
80 t->prv = Component_DIS_constructor();
81 {
82 ppComponent_DIS p = (ppComponent_DIS)t->prv;
83 p->something = 0;
84 }
85}
86void Component_DIS_clear(struct tComponent_DIS *t){
87 //public
88}
89
90References:
91http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/dis.html
92https://github.com/open-dis/open-dis-cpp
93http://www.web3d.org/x3d/content/examples/Basic/DistributedInteractiveSimulation/
94http://x3dgraphics.com/slidesets/X3dForAdvancedModeling/DistributedInteractiveSimulation.pdf
95-- brutzman slideshow on DIS
96https://en.wikipedia.org/wiki/Distributed_Interactive_Simulation
97http://open-dis.sourceforge.net/Open-DIS.html
98http://movesinstitute.org/~mcgredo/MV3500/hla/1278.1-200X%20Draft%2016%20rev%2018.pdf
99- 2012 DIS draft
100- p.332 7.2.2 espdu struct/contents
101- p.665 Annex E dead reckoning formula
102
103Don's references:
104a. IITSEC 2017 slideset, DIS 101
105 https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/raw/master/presentations/IITSEC2018_DIS_Tutorial.pptx
106
107b. X3D and Distributed Interactive Simulation (DIS)
108 http://x3dgraphics.com/slidesets/X3dForAdvancedModeling/DistributedInteractiveSimulation.pdf
109 (brutzman slides)
110
111c. X3D v3.3 Distributed interactive simulation (DIS) component
112 http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/dis.html
113
114d. IEEE Standards Maintained by SISO SAC
115 https://www.sisostds.org/ProductsPublications/Standards/IEEEStandards.aspx
116
117
118Problem: our C .h and the DIS.lib (cpp) .h clash, very messy
119x didn't find a combination of headers that worked
120Options:
1211. clean up our headers
1222. convert DIS.lib objects we need to flat C structs
123 - about 30 structs
124 a) manually, from .cpp
125 b) hack xmlpg https://github.com/open-dis/xmlpg CppGenerator.java
126 into a CGenerator.java and generate flat C
1273. wrap DIS objects -just ones we need- in flat C interfaces (about 30)
1284. somehow show cpp just the C structs it needs, like X3D_EspduTransform
129 - about 5 x3d structs
130Choice: option 2.b hack xmlpg CGenerator.java DONE
131- benefits: easy to interface, could do just .h (no lib), code & license is ours/freewrl
132-disadvantages: someone has to do hacking upstream in CGenerator.java, and
133 duplicate all the CppUtils (that wrap the pdu classes) in C,
134 and mistakes can happen during transcription (risk)
135
136Problem: Transforms - unclear how goecoords are to be used.
137The DIS specs have 5 terms:
138global, world, local, body, entity
139And there are 2 major geospatial states:
140a) geoCoords not used
141- geoCoords = 0,0,0 (default)
142b) geoCoords used
143
144Proposed use of terms:
145global == world = gc ^see World Coordinates below
146local - used only for some Dead Reckoning formulas
147 == TCS (topocentric coord sys) from geospatial component, except with axes re-arranged/swizzled
148 Draft DIS specs p.675:
149 "The local coordinate system used here is defined by North, East, and Down axes
150 with their origin at the entity's center of bounding volume."
151entity == body - the coordinate system for espdu.transform.children
152 -except DIS swizzles so Z is down, X forward, see Gimbals.x3d test scene
153World2body = Location,(phi,theta,psi)
154in web3d we can split world2body in 2 parts, to make dead-reckoning in local coords easier:
155- World2Local x Local2body
156- where:
157-- World2local is the gc2tcs from geospatial
158-- local2body is the rest of world2body: local2body = world2local.inverse x world2body
159if a) no geoCoords used, then
160- World2local == 0
161and
162- world2body == local2body (we do it all with transform.translation,rotation)
163Freewrl strategy:
164- we will convert the DIS coordinate axes and naming to web3d conventions during node2pdu and pdu2node
165 - convert from geocentric GC to Topocentric TCS if geocoords != 000
166- we will be working in web3d coordinate systems elsehwere, including in dead reckoning
167 (so no need to swizzle axes if our dead reckonging formulas are all in web3d conventions)
168Q. is this compatible with Xj3d convention?
169A. don't know. But Gimbal.x3d is showing (what I interpret as)
170 the Dead Reckoning Local coord system as being
171 swizzled and aligned with what looks like our geospatial TCS
172 That could indicate where NPS thinking was on how X3D relates to DIS.
173 So its a good bet espduTransform.(translation.rotation) are tcs2body aka local2body.
174
175
176World Coordinates:
177The Entity State PDU Location field is 64bit wgs84 geocentric coordinates.
178In the draft 2012 specs document,
179p.3 1.6.3.1 World coordinate system WGS84, meters.
180p.4 Figure 1 shows world coordinates.
181- they look exactly like GC.
182- Z through Northpole
183- X through prime meridian
184- right handed (Y through bangladesh)
185p.48 e) 1) Location with respect to the world
186p.330 6.2.98 World Coordinates record
187Location of the origin of the entity's or object's coordinate system, target locations,
188 detonation locations, and other points shall be specified by a set of three coordinates: X, Y, and Z,
189 represented by 64-bit floating point numbers. The world coordinate system shall be as specified in 1.6.3.
190 The format of the World Coordinates record shall be as shown in Table134.
191p.333
192h) Entity Location. This field shall specify an entity’s physical location in the simulated world,
193 and shall be represented by a World Coordinates record (see 6.2.98).
194p.334 Entity State PDU table 135
195/World Coordinates
196
197
198*/
199//#define WITH_DIS 1
200#ifdef WITH_DIS
201#include "../DIS/DIS.h"
202
203//there's another .pdf with enums
204// SISO-REF-010-2015 Enumerations for Simulation Interoperability V21 20150413.pdf
205// we'll do just a few here as needed
206// SM > DataRecord > datumType
207enum UID66 {
208Kind = 11110,
209Domain = 11120,
210Country = 11130,
211Category = 11140,
212Subcategory = 11150,
213Specific = 11160,
214Extra = 11170,
215/*
21631000 Position
217 31010 Route (Waypoint) type
218 31100 MilGrid10
219 31200 Geocentric Coordinates
220 31210 X
221 31220 Y
222 31230 Z
223 31300 Latitude
224 31400 Longitude
225 ...
226 31600 Altitude
227 */
228};
229
230#endif //WITH_DIS
231
232
233
234
235static int allow_DIS = 0;
236void fwl_init_DIS(){
237 //from commandline --DIS or -D
238 allow_DIS = 1;
239}
240int fwl_get_allow_DIS(){
241 return allow_DIS;
242}
243void fwl_set_allow_DIS(int allow){
244 allow_DIS = allow ? 1 : 0;
245}
246
247#ifdef WITH_DIS
248
249/*
250DIS - Distributed Interactive Simulation communication
251Concepts as understood by dug9 Oct 23, 2017
252
253IMPLIED SHARED RECEIVER LOOP
254- loop 1:1 socket(IP,port)
255- 1st node to declare a port opens it and joins
256- other nodes declaring same port join
257- reading is at fine time granularity, and times are added up
258- multiple receives on one loop are all read to flush and take pdu with latest timestamp
259- if received too soon, packets dropped (and dead reconning used, or radio signal is choppy)
260- timestamp is kept as start of interval, and each loop increments it
261- on recv packet, it loops over the packet unmarshalling multiple pdus
262 - it loops over nodes registered on that port to find a matching entityID/entityId
263 - if a match, updates entity
264 - if no match, discards/skips
265
266IMPLIED SHARED SENDER LOOP
267- loop 1:1 socket(IP,port)
268- 1st node to declare a port opens it and joins
269- other nodes declaring same port join
270- nodes can have different send intervals
271- fine-granularity loop increments time and checks who is ready to send
272- bundles pdus that are ready to send at the same time
273
274Design Options
275A. per-frame - iterate over all send and receive sockets once per frame,
276 -- in the render thread
277B. per-socket-direction thread
278
279Major Issues:
2801. change detection
281- for scripts and protos we have special field structs with a change flag;
282 we do that because scripts and protos are 'opaque' to routing algorithms
283- DIS nodes when receiving are changing fields like a script node might change its fields, opaque to routing
284 and for script nodes we iterate over fields after running a script, to check fields for change flag and route
285- for sending, somewhat analogously when we change a field via routing on a DIS node,
286 we need to let the pdu sending code know which puds changed, so it can send just the changed ones
287- options:
288 a) implement nodes in terms of i) script or ii) proto fields
289 - don't have an example of script or proto used as builtin
290 - its the parser that generates them from scene file info
291 ? would that mean a lot of changes to perl code generator and parser code?
292 - might be helpful to harmonize all builtin, proto, script and shader nodes to have same field struct
293 x but will take a massive refactoring effort to do it
294 - and with DIS, you send/receive whole pdus, and maybe only one little thing changed,
295 per-node-field flags wouldn't help because those flags aren't transmitted/received with pdu
296 b) pre/post value comparison ie _oldvalue
297 - lots of examples of this, but not on such big nodes
298 choice: b) SFNode node->_oldState copies entire node
299 - generic functions compare old new fields to detect changes
300 - but keep option a) in mind for future
301
3022. nodes have a lot of similar fields, resulting in duplicate code
303x and freewrl has no structs for 'abstract interface'
304options:
305a) giant macros - used throughout freewrl for this reason
306b) careful ordering of fields so common fields are first, and nodes can be cast to a common type
307c) some kind of abstract interface added to code generation system
308 - maybe in the future
309d) change to OO language and use inheritance and polymorphism
310 - maybe in the future
311e) functions with switch-case on nodetype
312For now in DIS we're going to use b) for espduTransform and 3 radio nodes and entityManager and e)
313
314*/
315
316
317// http://movesinstitute.org/~mcgredo/MV3500/hla/enum99_2.pdf
318// p.6
319// 62 and 65 Comment-R seem duplicates, so we set it to Comment-R2
320
321enum PDUType
322{
323 PDU_OTHER = 0,
324 PDU_ENTITY_STATE = 1,
325 PDU_FIRE = 2,
326 PDU_DETONATION = 3,
327 PDU_COLLISION = 4,
328 PDU_SERVICE_REQUEST = 5,
329 PDU_RESUPPLY_OFFER = 6,
330 PDU_RESUPPLY_RECEIVED = 7,
331 PDU_RESUPPLY_CANCEL = 8,
332 PDU_REPAIR_COMPLETE = 9,
333 PDU_REPAIR_RESPONSE = 10,
334 PDU_CREATE_ENTITY = 11,
335 PDU_REMOVE_ENTITY = 12,
336 PDU_START_RESUME = 13,
337 PDU_STOP_FREEZE = 14,
338 PDU_ACKNOWLEDGE = 15,
339 PDU_ACTION_REQUEST = 16,
340 PDU_ACTION_RESPONSE = 17,
341 PDU_DATA_QUERY = 18,
342 PDU_SET_DATA = 19,
343 PDU_DATA = 20,
344 PDU_EVENT_REPORT = 21,
345 PDU_COMMENT = 22,
346 PDU_ELECTROMAGNETIC_EMISSION = 23,
347 PDU_DESIGNATOR = 24,
348 PDU_TRANSMITTER = 25,
349 PDU_SIGNAL = 26,
350 PDU_RECEIVER = 27,
351 PDU_IFF_ATC_NAVAIDS = 28,
352 PDU_UNDERWATER_ACOUSTIC = 29,
353 PDU_SUPPLEMENTAL_EMISSION_ENTITY_STATE = 30,
354 PDU_INTERCOM_SIGNAL = 31,
355 PDU_INTERCOM_CONTROL = 32,
356 PDU_AGGREGATE_STATE = 33,
357 PDU_ISGROUPOF = 34,
358 PDU_TRANSFER_CONTROL = 35,
359 PDU_ISPARTOF_= 36,
360 PDU_MINEFIELD_STATE =37,
361 PDU_MINEFIELD_QUERY = 38,
362 PDU_MINEFIELD_DATA = 39,
363 PDU_MINEFIELD_RESPONSE_NAK = 40,
364 PDU_ENVIRONMENTAL_PROCESS = 41,
365 PDU_GRIDDED_DATA = 42,
366 PDU_POINT_OBJECT_STATE = 43,
367 PDU_LINEAR_OBJECT_STATE = 44,
368 PDU_AREAL_OBJECT_STATE = 45,
369 PDU_TSPI = 46,
370 PDU_APPEARANCE = 47,
371 PDU_ARTICULATED_PARTS = 48,
372 PDU_LE_FIRE = 49,
373 PDU_LE_DETONATION = 50,
374 PDU_CREATE_ENTITY_R = 51,
375 PDU_REMOVE_ENTITY_R = 52,
376 PDU_START_RESUME_R = 53,
377 PDU_STOP_FREEZE_R = 54,
378 PDU_ACKNOWLEDGE_R = 55,
379 PDU_ACTION_REQUEST_R = 56,
380 PDU_ACTION_RESPONSE_R = 57,
381 PDU_DATA_QUERY_R = 58,
382 PDU_SET_DATA_R = 59,
383 PDU_DATA_R = 60,
384 PDU_EVENT_REPORT_R = 61,
385 PDU_COMMENT_R = 62, //62
386 PDU_RECORD_QUERY_R = 63,
387 PDU_SET_RECORD_R = 64,
388 PDU_COMMENT_R2 = 65, //DUPLICATE OF 62
389 PDU_COLLISION_ELASTIC = 66,
390 PDU_ENTITY_STATE_UPDATE = 67,
391 PDU_ANNOUNCE_OBJECT = 129,
392 PDU_DELETE_OBJECT = 130,
393 PDU_DESCRIBE_APPLICATION = 131,
394 PDU_DESCRIBE_EVENT = 132,
395 PDU_DESCRIBE_OBJECT = 133,
396 PDU_REQUEST_EVENT = 134,
397 PDU_REQUEST_OBJECT = 135,
398};
399
400void axisangle2ypr(float *xyza, float *ypr)
401{
402 //y = yaw = azimuth
403 //p = pitch = elevation
404 //r = roll
405 //assumes z is up, you re-arrange your inputs if other
406 float yaw, pitch, roll, x,y,z,a, xyz[3], flen;
407 vecnormalize3f(xyz,xyza);
408 x = xyz[0]; y = xyz[1], z=xyz[2], a=xyza[3];
409 flen = veclength2f(xyz);
410 if(flen == 0.0f){
411 yaw = 0.0f;
412 pitch = acos(-1.0) * .5; //90
413 }else{
414 yaw = atan2(y,x);
415 pitch = atan(z/flen);
416 }
417 roll = a;
418 ypr[0] = yaw;
419 ypr[1] = pitch;
420 ypr[2] = roll;
421}
422void ypr2axisangle(float *ypr, float *xyza)
423{
424 //y = yaw = azimuth
425 //p = pitch = elevation
426 //r = roll
427 //assumes z is up, you re-arrange your inputs if other
428 float yaw, pitch, roll, x,y,z,a, xyz[3];
429 yaw = ypr[0];
430 pitch = ypr[1];
431 roll = ypr[2];
432 a = roll;
433 x = cos(pitch)*cos(yaw);
434 y = cos(pitch)*sin(yaw);
435 z = sin(pitch); //or sqrt(1.0 - (x*x + y*y))
436 xyz[0] = x;
437 xyz[1] = y;
438 xyz[2] = z;
439 vecnormalize3f(xyza,xyz);
440 xyza[3] = a;
441}
442//dis stores vectors in structs .xyz, we do float[3], conversions:
443struct Vector3Float *vec3f2vector3float(struct Vector3Float *b, float *a){
444 b->x = a[0];
445 b->y = a[1];
446 b->z = a[2];
447 return b;
448}
449float *vector3float2vec3f(float *b,struct Vector3Float *a){
450 b[0] = a->x;
451 b[1] = a->y;
452 b[2] = a->z;
453 return b;
454}
455struct Vector3Double *vec3d2vector3double(struct Vector3Double *b, double *a){
456 b->x = a[0];
457 b->y = a[1];
458 b->z = a[2];
459 return b;
460}
461double *vector3double2vec3d(double *b,struct Vector3Double *a){
462 b[0] = a->x;
463 b[1] = a->y;
464 b[2] = a->z;
465 return b;
466}
467// freewrl's once-per-frame timestamp is called TickTime
468// - and TickTime is a double value representing seconds since 1970, including fractions of a second
469// DIS Clock Time record is a 64bit consisting of
470// 32bit Hours since 1970 UTC and
471// 32bit Timestamp fraction-past-the-hour scaled by 2**31
472// - the least significant bit- is reserved for flagging 1=AbsoluteTime (vs relative =0)
473// in draft specs see
474// 6.2.88 TimeStamp p.319
475// G.4 Time Terminology p.686
476//
477void TickTime2DISTime(double ticktime, int iabs, unsigned int *hours, unsigned int *hourfraction ){
478 double hours1970, fraction;
479 unsigned int bitmask;
480 hours1970 = floor(ticktime / 3600.0);
481 *hours = (unsigned int)hours1970;
482 fraction = (ticktime / 3600.0) - hours1970;
483 *hourfraction = ((unsigned int)(fraction * pow(2.0,31.0)))<<1;
484 bitmask = 0;
485 bitmask = ~bitmask;
486 if(!iabs)
487 bitmask = bitmask << 1; //clear least significant bit
488 *hourfraction = *hourfraction & bitmask;
489 if(iabs) *hourfraction |= 1;
490}
491double DISTime2TickTime(unsigned int hours, unsigned int hourfraction){
492 //pass in 0 for hours if relative timestamp (then we'll take hours from TickTime())
493 double fraction, mantissa;
494 int iabs;
495 unsigned int bitmask;
496 bitmask = 1;
497 iabs = (hourfraction & bitmask) != 0 ? TRUE : FALSE;
498 hourfraction = hourfraction >> 1; //take everything except least significant bit
499 fraction = hourfraction;
500 fraction /= pow(2.0,31.0);
501 if(iabs)
502 mantissa = hours;
503 else
504 mantissa = floor(TickTime() / 3600.0);
505 mantissa += fraction;
506 mantissa *= 3600.0;
507 return mantissa;
508
509}
510
511//A. per-frame
512
513struct dis_socket {
514 int port;
515 char *address;
516 SOCKET socket;
517 struct sockaddr_in saddr;
518 int multicastRelayPort;
519 char *multicastRelayHost;
520 int idir; //0 = receive, 1 = send
521 struct Vector *registered;
522 double lasttime;
523};
524
525
526void print_stream(unsigned char *buf, int nbytes){
527 int i,j;
528 for(i=0;i<min(210,nbytes);i+=10){
529 int j;
530 printf("%d\t",i);
531 for(j=0;j<10;j++){
532 printf("%5d",(int)buf[i+j]);
533 }
534 printf("\n");
535 }
536}
537//TCS - geospatial topocentric coordinate system
538//local - DIS equivalent
539double *tcs2localswizzled(double *local,double *tcs){
540 local[0] = -tcs[2]; //north
541 local[1] = tcs[0]; //east
542 local[2] = -tcs[1]; //vertical
543 return local;
544}
545double *local2tcsswizzled(double *tcs,double *local){
546 tcs[0] = local[1]; //east
547 tcs[1] = -local[2]; //vertical
548 tcs[2] = -local[0]; //north
549 return tcs;
550}
551void node2pdu_entityType(int *entityKind, struct EntityType *entityType){
552 //assumes node field order: kind, domain, country, category, subcategory, specific, extra
553 //p.262 draft standard http://movesinstitute.org/~mcgredo/MV3500/hla/1278.1-200X%20Draft%2016%20rev%2018.pdf
554 entityType->entityKind = (unsigned char) entityKind[0];
555 entityType->domain = (unsigned char) entityKind[1];
556 entityType->country = (unsigned short) entityKind[2];
557 entityType->category = (unsigned char) entityKind[3];
558 entityType->subcategory = (unsigned char) entityKind[4];
559 entityType->specific = (unsigned char) entityKind[5];
560 entityType->extra = (unsigned char) entityKind[6];
561}
562void pdu2node_entityType( struct EntityType *entityType, int *entityKind){
563 //assumes node field order: kind, domain, country, category, subcategory, specific, extra
564 //p.262 draft standard http://movesinstitute.org/~mcgredo/MV3500/hla/1278.1-200X%20Draft%2016%20rev%2018.pdf
565 entityKind[0] = entityType->entityKind;
566 entityKind[1] = entityType->domain;
567 entityKind[2] = entityType->country;
568 entityKind[3] = entityType->category;
569 entityKind[4] = entityType->subcategory;
570 entityKind[5] = entityType->specific;
571 entityKind[6] = entityType->extra;
572}
573static int dis_event_number = 0;
574int dis_next_event_number(){
575 dis_event_number++;
576 return dis_event_number;
577}
578static int dis_fire_mission_index = 0;
579int dis_next_fire_mission_index(){
580 dis_fire_mission_index++;
581 return dis_fire_mission_index;
582}
583struct X3D_Node * dis_find_registered_node_by_entityid(int entityid, int sendlist, int recvlist);
584struct Vector * dis_node2pdus_espdu(struct X3D_Node *node, int isHeartbeat){
585 //http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/dis.html#EspduTransform
586 //EspuTransform integrates the following pdus:
587 //EntityStatePDU, CollisionPDU, DetonationPDU, FirePDU, CreateEntity, and RemoveEntity.
588 //http://movesinstitute.org/~mcgredo/MV3500/hla/1278.1-200X%20Draft%2016%20rev%2018.pdf
589 //p.332 7.2.2 espdu struct/contents
590 //Q. how do create/remove work?
591 struct Vector *pdus;
592 struct X3D_EspduTransform * pnode = (struct X3D_EspduTransform*)node;
593 pdus = newVector(struct Pdu *, 6);
594
595 //ENTITYSTATE
596 //if(pnode->_pduchange_es_articulation || pnode->_pduchange_es_deadreckoning || pnode->_pduchange_es_info || pnode->_pduchange_es_force){
597 printf("es pduchange %d heartbeat %d\n",pnode->_pduchange_es,isHeartbeat);
598 if(pnode->_pduchange_es || isHeartbeat){
599 float xyz[3];
600 struct EntityStatePdu *espdu;
601 espdu = (struct EntityStatePdu*)dis_ctor(type_EntityStatePdu);
602 //entity
603 espdu->entityID.entity = pnode->entityID;
604 espdu->entityID.application = pnode->applicationID;
605 espdu->entityID.site = pnode->siteID;
606 //translation - assumes companion scenes will have same parent transform stack
607 //(x, -z, y).
608 if(pnode->__geoSystem){
609 //a default geo scene is in TCS at Accra (Grenwich & equator)
610 Quaternion qgc2tcs, qtcs2body, qgc2body;
611 struct SFVec3d gd, gc, translate;
612 struct SFVec4d rotate;
613 double localxyz[3], tcsxyz[3], tcs2bodyxyz[3], world2bodyxyz[3];
614 float xyza[4];
615 Geosys *gs;
616 gs = GEOSYS(pnode->__geoSystem);
617 user2gc(gs,&pnode->geoCoords,1,&gc);
618 //gc2gd(gs,&gc,1,&gd);
619 //gc2tcs_transform(gs,&gd,&translate,&rotate);
620 gc2tcsB_transform(gs,&gc,&translate,&rotate);
621 //somehow get body/entity into world/gc - rotation and translation
622 {
623 //rotation
624 float ypr[3];
625 vrmlrot4d_to_quaternion(&qgc2tcs,rotate.c);
626 vrmlrot4f_to_quaternion(&qtcs2body,pnode->rotation.c);
627 quaternion_multiply(&qgc2body,&qgc2tcs,&qtcs2body);
628 quaternion_to_vrmlrot4f(&qgc2body,xyza);
629 //vecprint4fb("send xyza",xyza,"\n");
630 xyza[3] = -xyza[3];
631 axisangle2ypr(xyza,ypr);
632
633 espdu->entityOrientation.psi = -ypr[0]; //gimbal.js shows -yaw
634 espdu->entityOrientation.theta = ypr[1];
635 espdu->entityOrientation.phi = ypr[2];
636
637 }
638 {
639 //translation
640 struct SFVec3d tcs, world;
641 float2double(tcs.c,pnode->translation.c,3);
642 //tcs2gc(gs,&gd,&tcs,1,&world);
643 tcs2gcB(gs,&gc,&tcs,1,&world);
644 vec3d2vector3double(&espdu->entityLocation,world.c);
645 }
646
647 //send > geo > dead reckoning
648 if(pnode->deadReckoning < 6){
649 //first update linear V,A, angularV
650 //for drmethod < 6
651 //all of which are in Local/TCS for freewrl/web3d, instead of world for DIS
652 pnode->_change_count++;
653 if(pnode->_change_count > 1){
654 double dtime;
655 float v1[3], tmp[3], a1[3];
656 dtime = TickTime() - pnode->_lastp0time;
657 vecscale3f(v1,vecdif3f(tmp,pnode->translation.c,pnode->_lastp0.c),1.0f/dtime);
658 //pnode->_change_count = min(pnode->_change_count,2);
659 if(pnode->_change_count > 2){
660 //a = (v1-v0)/dt
661 vecscale3f(a1,vecdif3f(tmp,v1,pnode->linearVelocity.c),1.0f/dtime);
662 veccopy3f(pnode->linearAcceleration.c,a1);
663 //v1 = v0 - 1/2at**2
664
665 }else{
666 vecset3f(pnode->linearAcceleration.c,0.0,0.0,0.0);
667 }
668 veccopy3f(pnode->linearVelocity.c,v1);
669 {
670 //update angular velocity
671 Quaternion qlast,q, qinv, qdif;
672 vrmlrot4f_to_quaternion(&qlast,pnode->_lastr0.c);
673 vrmlrot4f_to_quaternion(&q,pnode->rotation.c);
674 quaternion_inverse(&qinv,&qlast);
675 quaternion_multiply(&qdif,&q,&qinv);
676 quaternion_to_vrmlrot4f(&qdif,pnode->_angularVelocity.c);
677 pnode->_angularVelocity.c[3] *= 1.0f/dtime;
678 }
679 }
680 }
681 veccopy3f(pnode->_lastp0.c,pnode->translation.c);
682 veccopy4f(pnode->_lastr0.c,pnode->rotation.c);
683 pnode->_lastp0time = TickTime();
684
685 espdu->deadReckoningParameters.deadReckoningAlgorithm = pnode->deadReckoning;
686 {
687 float V[3], A[3];
688 // in TCS aka Local
689 veccopy3f(V,pnode->linearVelocity.c);
690 veccopy3f(A,pnode->linearAcceleration.c);
691
692 //convert Local/TCS linear/angular V,A to world or to Entity, depending on DR parameter
693 //http://movesinstitute.org/~mcgredo/MV3500/hla/1278.1-200X%20Draft%2016%20rev%2018.pdf
694 //p.333, p.329
695 if(pnode->deadReckoning < 6){
696 //convert our TCS/Local to world
697 //Vgc = tcs2gc x Vtcs
698 Quaternion q;
699 vrmlrot4d_to_quaternion(&q,rotate.c);
700 quaternion_inverse(&q,&q);
701 quaternion_rotation3f(V,&q,V);
702 quaternion_rotation3f(A,&q,A);
703 } else {
704 if(0){
705 //convert our TCS/Local to entity
706 //Vbody = tcs2body x Vtcs
707 Quaternion q;
708 vrmlrot4f_to_quaternion(&q,pnode->rotation.c);
709 quaternion_inverse(&q,&q);
710 quaternion_rotation3f(V,&q,V);
711 quaternion_rotation3f(A,&q,A);
712 }else{
713 //keep entity in entity
714 }
715 }
716 vec3f2vector3float(&espdu->entityLinearVelocity,V);
717 vec3f2vector3float(&espdu->deadReckoningParameters.entityLinearAcceleration,A);
718
719 }
720 {
721 //p.667 E.7.4.1.1: rotational velocity is stored as axis*angle
722 //always wrt entity
723 float axis[3];
724 vecnormalize3f(axis,pnode->_angularVelocity.c);
725 vecscale3f(axis,axis,pnode->_angularVelocity.c[3]);
726 vec3f2vector3float(&espdu->deadReckoningParameters.entityAngularVelocity,axis);
727 }
728 //p.675 E.8.2 Use of Other Parameters for standard algorithms 1 through 9
729 switch(pnode->deadReckoning){
730 //fixed rotation
731 case 1:
732 case 2:
733 case 5:
734 case 6:
735 case 9:
736 {
737 float ypr[3];
739 if(pnode->__geoSystem){
740 axisangle2ypr(pnode->rotation.c,ypr); //assume Transform.rotation is wrt TCS/LGS
741 }else{
742 vecset3f(ypr,0.0f,0.0f,0.0f); //we assume we are in local
743 }
744 veccopy3f((float*)&espdu->deadReckoningParameters.otherParameters[3],ypr);
745 }
746 break;
747 //rotating
748 case 3:
749 case 7:
750 case 8:
751 {
752 // p.677 E.8.2.3.2 Issuance of orientation quaternion
753 // a 'squished quaternion'
754 Quaternion qglobal;
755 double quat4d[4];
756 float quat4f[4];
757 unsigned int iquat0;
758 unsigned short iquat16;
760 if(pnode->__geoSystem){
761 //H: W2B = W2L x L2B
762 // World2body = world2local x local2body
763 // where world2local is the gc2tcs (geocentric to topocentric aka local geodetic system) from geospatial
764 // and local2body is the espdu.transform.(translation and rotation) (or its inverse)
765 Quaternion qtcs, qlocal;
766 struct SFVec3d gc, gd, translate;
767 struct SFVec4d rotate;
768 Geosys *gs;
769 gs = GEOSYS(pnode->__geoSystem);
770 user2gc(gs,&pnode->geoCoords,1,&gc);
771 //gc2gd(gs,&gc,1,&gd);
772 //gc2tcs_transform(gs,&gd,&translate,&rotate);
773 gc2tcsB_transform(gs,&gc,&translate,&rotate);
774 vrmlrot4d_to_quaternion(&qtcs,rotate.c);
775 vrmlrot4f_to_quaternion(&qlocal,pnode->rotation.c);
776 quaternion_multiply(&qglobal,&qlocal,&qtcs);
777 }else{
778 vrmlrot_to_quaternion(&qglobal,0.0,1.0,0.0,0.0); //we've already combined DR with global, so additional DR is zero
779 }
780 quat2double(quat4d,&qglobal); //w in last slot of quat4d
781 double2float(&quat4f[1],quat4d,3);
782 quat4f[0] = quat4d[3]; //now w in first slot of quat4f
783 if(quat4f[0] < 0.0f)
784 vecscale4f(quat4f,quat4f,-1.0f);
785
786 iquat0 = (unsigned int)(quat4f[0] * 65536);
787 if(quat4f[0] > 65536) iquat0 = 65535;
788 iquat16 = iquat0;
789 memcpy(&espdu->deadReckoningParameters.otherParameters[1],&iquat16,sizeof(short));
790 memcpy(&espdu->deadReckoningParameters.otherParameters[3],&quat4f[1],3*sizeof(float));
791 }
792 break;
793 default:
794 espdu->deadReckoningParameters.otherParameters[0] = (char)0;
795 break;
796 }
797
798 }else{ //geo
799 //non-geo scene
800 //Apr 22, 2018 we no longer use this, but keeping until benchmark against Brutzman
801 //doesn't necessarily make sense to have no geoSystem or geoCoords = 0,0,0
802 //but some old/existing scenes are like that, so here we handling them
803 //but whether node.translation is meant to be tcs2body or global2body might make a difference?
804 //we don't know because we only have freewrl for testing right now - will wait for brutzman
805 if(0){
806 double local2bodyxyz[3], localxyz[3];
807 float2double(local2bodyxyz,pnode->translation.c,3);
808 tcs2localswizzled(localxyz,local2bodyxyz);
809 vec3d2vector3double(&espdu->entityLocation,localxyz);
810 }else{
811 espdu->entityLocation.x = pnode->translation.c[0];
812 espdu->entityLocation.y = -pnode->translation.c[2]; //??? is this right?
813 espdu->entityLocation.z = pnode->translation.c[1];
814 }
815 //rotation
816 if(0){
817 //theirs:
818 //X PSI
819 //Y THETA
820 //Z PHI
821 //(x, -z, y)
822 //OURS THEIRS THEIRS
823 //x X=x PSI
824 //y Z=y PHI
825 //z -Y=z -THETA
826
827 Quaternion qA;
828 double ypr[3];
829 float *c = pnode->rotation.c;
830 vrmlrot_to_quaternion(&qA,c[0],c[1],c[2],c[3]);
831 quat2euler(ypr,0,&qA);
832 espdu->entityOrientation.psi = ypr[1];
833 espdu->entityOrientation.theta = ypr[2];
834 }
835 if(1){
836 float ypr[3];
837 axisangle2ypr(pnode->rotation.c,ypr);
838 espdu->entityOrientation.psi = -ypr[0]; //gimbal.js shows -yaw
839 espdu->entityOrientation.theta = ypr[1];
840 espdu->entityOrientation.phi = ypr[2];
841 }
842 //dead reckoning > send
843 if(1){
844 //first update linear V,A, angularV
845 //all of which are in Local/TCS for us
846 pnode->_change_count++;
847 if(pnode->_change_count > 1){
848 double dtime;
849 float v1[3], tmp[3], a1[3];
850 dtime = TickTime() - pnode->_lastp0time;
851 vecscale3f(v1,vecdif3f(tmp,pnode->translation.c,pnode->_lastp0.c),1.0f/dtime);
852 //pnode->_change_count = min(pnode->_change_count,2);
853 if(pnode->_change_count > 2){
854 //a = (v1-v0)/dt
855 vecscale3f(a1,vecdif3f(tmp,v1,pnode->linearVelocity.c),1.0f/dtime);
856 veccopy3f(pnode->linearAcceleration.c,a1);
857 //v1 = v0 - 1/2at**2
858
859 }else{
860 vecset3f(pnode->linearAcceleration.c,0.0,0.0,0.0);
861 }
862 veccopy3f(pnode->linearVelocity.c,v1);
863 {
864 //update angular velocity
865 Quaternion qlast,q, qinv, qdif;
866 vrmlrot4f_to_quaternion(&qlast,pnode->_lastr0.c);
867 vrmlrot4f_to_quaternion(&q,pnode->rotation.c);
868 quaternion_inverse(&qinv,&qlast);
869 quaternion_multiply(&qdif,&q,&qinv);
870 quaternion_to_vrmlrot4f(&qdif,pnode->_angularVelocity.c);
871 pnode->_angularVelocity.c[3] *= 1.0f/dtime;
872 }
873 }
874 veccopy3f(pnode->_lastp0.c,pnode->translation.c);
875 veccopy4f(pnode->_lastr0.c,pnode->rotation.c);
876 pnode->_lastp0time = TickTime();
877 }
878 espdu->deadReckoningParameters.deadReckoningAlgorithm = pnode->deadReckoning;
879 vec3f2vector3float(&espdu->entityLinearVelocity,pnode->linearVelocity.c);
880 vec3f2vector3float(&espdu->deadReckoningParameters.entityLinearAcceleration,pnode->linearAcceleration.c);
881
882 {
883 //p.667 E.7.4.1.1: rotational velocity is stored as axis*angle
884 //always wrt entity
885 float axis[3];
886 vecnormalize3f(axis,pnode->_angularVelocity.c);
887 vecscale3f(axis,axis,pnode->_angularVelocity.c[3]);
888 vec3f2vector3float(&espdu->deadReckoningParameters.entityAngularVelocity,axis);
889 }
890 //p.675 E.8.2 Use of Other Parameters for standard algorithms 1 through 9
891 switch(pnode->deadReckoning){
892 //fixed rotation
893 case 1:
894 case 2:
895 case 5:
896 case 6:
897 case 9:
898 {
899 float ypr[3];
901 if(pnode->__geoSystem){
902 axisangle2ypr(pnode->rotation.c,ypr); //assume Transform.rotation is wrt TCS/LGS
903 }else{
904 vecset3f(ypr,0.0f,0.0f,0.0f); //we assume we are in local
905 }
906 veccopy3f((float*)&espdu->deadReckoningParameters.otherParameters[3],ypr);
907 }
908 break;
909 //rotating
910 case 3:
911 case 7:
912 case 8:
913 {
914 // p.677 E.8.2.3.2 Issuance of orientation quaternion
915 // a 'squished quaternion'
916 Quaternion qglobal;
917 double quat4d[4];
918 float quat4f[4];
919 unsigned int iquat0;
920 unsigned short iquat16;
922 if(pnode->__geoSystem){
923 //H: W2B = W2L x L2B
924 // World2body = world2local x local2body
925 // where world2local is the gc2tcs (geocentric to topocentric aka local geodetic system) from geospatial
926 // and local2body is the espdu.transform.(translation and rotation) (or its inverse)
927 Quaternion qtcs, qlocal;
928 struct SFVec3d gc, gd, translate;
929 struct SFVec4d rotate;
930 Geosys *gs;
931 gs = GEOSYS(pnode->__geoSystem);
932 user2gc(gs,&pnode->geoCoords,1,&gc);
933 //gc2gd(gs,&gc,1,&gd);
934 //gc2tcs_transform(gs,&gd,&translate,&rotate);
935 gc2tcsB_transform(gs,&gc,&translate,&rotate);
936 vrmlrot4d_to_quaternion(&qtcs,rotate.c);
937 vrmlrot4f_to_quaternion(&qlocal,pnode->rotation.c);
938 quaternion_multiply(&qglobal,&qlocal,&qtcs);
939 }else{
940 vrmlrot_to_quaternion(&qglobal,0.0,1.0,0.0,0.0); //we've already combined DR with global, so additional DR is zero
941 }
942 quat2double(quat4d,&qglobal); //w in last slot of quat4d
943 double2float(&quat4f[1],quat4d,3);
944 quat4f[0] = quat4d[3]; //now w in first slot of quat4f
945 if(quat4f[0] < 0.0f)
946 vecscale4f(quat4f,quat4f,-1.0f);
947
948 iquat0 = (unsigned int)(quat4f[0] * 65536);
949 if(quat4f[0] > 65536) iquat0 = 65535;
950 iquat16 = iquat0;
951 memcpy(&espdu->deadReckoningParameters.otherParameters[1],&iquat16,sizeof(short));
952 memcpy(&espdu->deadReckoningParameters.otherParameters[3],&quat4f[1],3*sizeof(float));
953 }
954 break;
955 default:
956 espdu->deadReckoningParameters.otherParameters[0] = (char)0;
957 break;
958 }
959 } //if geo else
960 //vecprint3fb("trans=",pnode->translation.c,"\n");
961 pnode->_sent = TRUE;
962 //articuation parameters
963 if(pnode->articulationParameterArray.n){
964 struct ArticulationParameter *ap;
965 int i, np = pnode->articulationParameterArray.n;
966 ap = malloc(np * sizeof(struct ArticulationParameter));
968 //printf("sending %d articulation parameters:\n",np);
969 for(i=0;i<np;i++){
970 ap[i].parameterTypeDesignator = 0; //0 is articulated part
971 ap[i].parameterType = 1029; //1024 - rudder + 5 X
972 ap[i].parameterValue = pnode->articulationParameterArray.p[i];
973 ap[i].partAttachedTo = 0;
974 //printf("%d %f\n",i,pnode->articulationParameterArray.p[i]);
975 }
976 espdu->articulationParameters = (void*)ap;
977 }
978 node2pdu_entityType(&pnode->entityKind,&espdu->entityType);
979
980 //...
981 //printf("new espdu protocol %d type %d\n",espdu->myEntityInformationFamilyPdu.myPdu.protocolVersion,espdu->myEntityInformationFamilyPdu.myPdu.pduType);
982 vector_pushBack(struct Pdu*,pdus,(struct Pdu*)espdu);
983 }
984
985 //ephemerals / expendables - no hearbeat requirements?
986 //FIRE
987 if(pnode->_pduchange_fire){
988 struct FirePdu *fpdu;
989 fpdu = (struct FirePdu *) dis_ctor(type_FirePdu);
990 fpdu->myWarfareFamilyPdu.firingEntityID.entity = pnode->entityID;
991 fpdu->myWarfareFamilyPdu.firingEntityID.application = pnode->applicationID;
992 fpdu->myWarfareFamilyPdu.firingEntityID.site = pnode->siteID;
993 //fpdu->myWarfareFamilyPdu.myPdu;
994 //fpdu->myWarfareFamilyPdu.targetEntityID;
995 printf("FIREPDU ");
996 if(pnode->fired1 || pnode->fired2){
997 pnode->firedTime = TickTime();
998 }
999 //copy from espdutransform node to pdu
1000 fpdu->burstDescriptor.fuse = pnode->fuse;
1001 struct X3D_EspduTransform * muni = (struct X3D_EspduTransform * )dis_find_registered_node_by_entityid(pnode->munitionEntityID,TRUE,FALSE);
1002 if(muni){
1003 fpdu->burstDescriptor.munition.category = muni->entityCategory; //get munition entity from pnode->munitionEntity, then munitionEntity.cateogory.
1004 fpdu->burstDescriptor.munition.country = muni->entityCountry;
1005 fpdu->burstDescriptor.munition.domain = muni->entityDomain;
1006 fpdu->burstDescriptor.munition.entityKind = muni->entityKind;
1007 fpdu->burstDescriptor.munition.extra = muni->entityExtra;
1008 fpdu->burstDescriptor.munition.specific = muni->entitySpecific;
1009 fpdu->burstDescriptor.munition.subcategory = muni->entitySubCategory;
1010 }
1011 fpdu->burstDescriptor.quantity = pnode->munitionQuantity;
1012 fpdu->burstDescriptor.rate = pnode->firingRate;
1013 fpdu->burstDescriptor.warhead = pnode->warhead;
1014
1015 fpdu->eventID.application = 0;
1016 fpdu->eventID.eventNumber = pnode->eventNumber; //dis_next_event_number(); //increment in sender script node
1017 fpdu->eventID.site = 0; //target if known
1018
1019 fpdu->fireMissionIndex = dis_next_fire_mission_index();
1020 {
1021 double loc[3];
1022 float2double(loc,pnode->munitionStartPoint.c,3);
1023 //am I supposed to convert to wworld from local here?
1024 //or can/should I assume that its local to Weapon Espdu here, and local to target scene's copy of Weapon Espdu?
1025 vec3d2vector3double(&fpdu->locationInWorldCoordinates,loc); //is this current location, or starting location?
1026 }
1027 //unique munition entity if known
1028 fpdu->munitionID.application = pnode->munitionApplicationID;
1029 fpdu->munitionID.entity = pnode->munitionEntityID;
1030 fpdu->munitionID.site = pnode->munitionSiteID;
1031
1032 fpdu->range = pnode->firingRange;
1033 {
1034 float delta[3];
1035 vecdif3f(delta,pnode->munitionEndPoint.c,pnode->munitionStartPoint.c);
1036 //lets say 3 seconds to deliver any munition
1037 vecscale3f(delta,delta,1.0f/3.0f);
1038 vec3f2vector3float(&fpdu->velocity,delta);
1039 }
1040 vector_pushBack(struct Pdu*,pdus,(struct Pdu*)fpdu);
1041 }
1042 //COLLISION
1043 if(pnode->_pduchange_collision){
1044 struct CollisionPdu *cpdu;
1045 cpdu = (struct CollisionPdu *) dis_ctor(type_CollisionPdu);
1046 //copy from espdutransform node to pdu
1047 cpdu->issuingEntityID.application = pnode->applicationID;
1048 cpdu->issuingEntityID.site = pnode->siteID;
1049 cpdu->issuingEntityID.entity = pnode->entityID;
1050
1051 cpdu->collidingEntityID.entity = pnode->eventEntityID;
1052 cpdu->collidingEntityID.application = pnode->eventApplicationID;
1053 cpdu->collidingEntityID.site = pnode->eventSiteID;
1054 cpdu->collisionType = pnode->collisionType;
1055 cpdu->eventID.eventNumber = pnode->eventNumber;
1056
1057 vector_pushBack(struct Pdu*,pdus,(struct Pdu*)cpdu);
1058 }
1059 //DETONATION
1060 if(pnode->_pduchange_detonation){
1061 struct DetonationPdu *dpdu;
1062 dpdu = (struct DetonationPdu *) dis_ctor(type_DetonationPdu);
1063 //copy from espdutransform node to pdu
1064
1065 dpdu->myWarfareFamilyPdu.firingEntityID.entity = pnode->entityID;
1066 dpdu->myWarfareFamilyPdu.firingEntityID.application = pnode->applicationID;
1067 dpdu->myWarfareFamilyPdu.firingEntityID.site = pnode->siteID;
1068 //fpdu->myWarfareFamilyPdu.myPdu;
1069 //fpdu->myWarfareFamilyPdu.targetEntityID;
1070
1071 pnode->detonateTime = TickTime();
1072 dpdu->detonationResult = pnode->detonationResult;
1073 //copy from espdutransform node to pdu
1074 dpdu->burstDescriptor.fuse = pnode->fuse;
1075 struct X3D_EspduTransform * muni = (struct X3D_EspduTransform * )dis_find_registered_node_by_entityid(pnode->munitionEntityID,TRUE,FALSE);
1076 if(muni){
1077 dpdu->burstDescriptor.munition.category = muni->entityCategory; //get munition entity from pnode->munitionEntity, then munitionEntity.cateogory.
1078 dpdu->burstDescriptor.munition.country = muni->entityCountry;
1079 dpdu->burstDescriptor.munition.domain = muni->entityDomain;
1080 dpdu->burstDescriptor.munition.entityKind = muni->entityKind;
1081 dpdu->burstDescriptor.munition.extra = muni->entityExtra;
1082 dpdu->burstDescriptor.munition.specific = muni->entitySpecific;
1083 dpdu->burstDescriptor.munition.subcategory = muni->entitySubCategory;
1084 }
1085 dpdu->burstDescriptor.quantity = pnode->munitionQuantity;
1086 dpdu->burstDescriptor.rate = pnode->firingRate;
1087 dpdu->burstDescriptor.warhead = pnode->warhead;
1088
1089 dpdu->eventID.application = 0;
1090 dpdu->eventID.eventNumber = pnode->eventNumber; //dis_next_event_number(); //increment in sender script node
1091 dpdu->eventID.site = 0; //target if known
1092
1093 //articuation parameters
1094 if(pnode->articulationParameterArray.n){
1095 struct ArticulationParameter *ap;
1096 int i, np = pnode->articulationParameterArray.n;
1097 ap = malloc(np * sizeof(struct ArticulationParameter));
1099 //printf("sending %d articulation parameters:\n",np);
1100 for(i=0;i<np;i++){
1101 ap[i].parameterTypeDesignator = 0; //0 is articulated part
1102 ap[i].parameterType = 1029; //1024 - rudder + 5 X
1103 ap[i].parameterValue = pnode->articulationParameterArray.p[i];
1104 ap[i].partAttachedTo = 0;
1105 //printf("%d %f\n",i,pnode->articulationParameterArray.p[i]);
1106 }
1107 dpdu->articulationParameters = (void*)ap;
1108 }
1109
1110 {
1111 double loc[3];
1112 float2double(loc,pnode->detonationLocation.c,3);
1113 //am I supposed to convert to wworld from local here?
1114 //or can/should I assume that its local to Weapon Espdu here, and local to target scene's copy of Weapon Espdu?
1115 vec3d2vector3double(&dpdu->locationInWorldCoordinates,loc);
1116 vec3f2vector3float(&dpdu->locationInEntityCoordinates,pnode->detonationRelativeLocation.c);
1117 }
1118 //unique munition entity if known
1119 dpdu->munitionID.application = pnode->munitionApplicationID;
1120 dpdu->munitionID.entity = pnode->munitionEntityID;
1121 dpdu->munitionID.site = pnode->munitionSiteID;
1122
1123 {
1124 float delta[3];
1125 vecdif3f(delta,pnode->munitionEndPoint.c,pnode->munitionStartPoint.c);
1126 //lets say .5 seconds to detonate any munition
1127 vecscale3f(delta,delta,1.0f/.5f);
1128 vec3f2vector3float(&dpdu->velocity,delta);
1129 }
1130
1131
1132 vector_pushBack(struct Pdu*,pdus,(struct Pdu*)dpdu);
1133 }
1134
1135 return pdus;
1136
1137}
1138
1139struct Vector * dis_node2pdus_receiver(struct X3D_Node *node, int isHeartbeat){
1140 struct Vector *pdus;
1141 struct X3D_ReceiverPdu * pnode = (struct X3D_ReceiverPdu*)node;
1142 pdus = newVector(struct Pdu *, 6);
1143 // Q. what about network sensor>
1144 // Q. what about _geoCoords?
1145 if(pnode->_pduchange_receiver){
1146 struct ReceiverPdu *rpdu;
1147 rpdu = (struct ReceiverPdu *) dis_ctor(type_ReceiverPdu);
1148//SFInt32 [in,out] radioID 0 [0,65535]
1149//SFFloat [in,out] receivedPower 0.0 [0,?)
1150//SFInt32 [in,out] receiverState 0 [0,65535]
1151//SFInt32 [in,out] transmitterApplicationID 1 [0,65535]
1152//SFInt32 [in,out] transmitterEntityID 0 [0,65535]
1153//SFInt32 [in,out] transmitterRadioID 0 [0,65535]
1154//SFInt32 [in,out] transmitterSiteID 0 [0,65535]
1155 rpdu->myRadioCommunicationsFamilyPdu.radioId = pnode->radioID;
1156 rpdu->receivedPoser = pnode->receivedPower;
1157 rpdu->receiverState = pnode->receiverState;
1158 rpdu->transmitterRadioId = pnode->transmitterRadioID;
1159 rpdu->transmitterEntityId.entity = pnode->transmitterEntityID;
1160 rpdu->transmitterEntityId.site = pnode->transmitterSiteID;
1161 rpdu->transmitterEntityId.application = pnode->transmitterSiteID;
1162 vector_pushBack(struct Pdu*,pdus,(struct Pdu*)rpdu);
1163 }
1164 return pdus;
1165}
1166struct Vector * dis_node2pdus_transmitter(struct X3D_Node *node, int isHeartbeat){
1167 struct Vector *pdus;
1168 struct X3D_TransmitterPdu * pnode = (struct X3D_TransmitterPdu*)node;
1169 pdus = newVector(struct Pdu *, 6);
1170
1171 // Q. what about network sensor>
1172 // Q. what about _geoCoords?
1173 if(pnode->_pduchange_transmitter){
1174 struct TransmitterPdu *tpdu;
1175 tpdu = (struct TransmitterPdu *) dis_ctor(type_TransmitterPdu);
1176
1177 //SFVec3f [in,out] antennaLocation 0 0 0 (-8,8)
1178 //SFInt32 [in,out] antennaPatternLength 0 [0,65535]
1179 //SFInt32 [in,out] antennaPatternType 0 [0,65535]
1180 //SFInt32 [in,out] cryptoKeyID 0 [0,65535]
1181 //SFInt32 [in,out] cryptoSystem 0 [0,65535]
1182 //SFInt32 [in,out] frequency 0
1183 //SFInt32 [in,out] inputSource 0 [0,255]
1184 //SFInt32 [in,out] lengthOfModulationParameters 0 [0,255]
1185 //SFInt32 [in,out] modulationTypeDetail 0 [0,65535]
1186 //SFInt32 [in,out] modulationTypeMajor 0 [0,65535]
1187 //SFInt32 [in,out] modulationTypeSpreadSpectrum 0 [0,65535]
1188 //SFInt32 [in,out] modulationTypeSystem 0 [0,65535]
1189 //SFFloat [in,out] power 0.0 [0,8)
1190 //SFInt32 [in,out] radioEntityTypeCategory 0 [0,255]
1191 //SFInt32 [in,out] radioEntityTypeCountry 0 [0,65535]
1192 //SFInt32 [in,out] radioEntityTypeDomain 0 [0,255]
1193 //SFInt32 [in,out] radioEntityTypeKind 0 [0,255]
1194 //SFInt32 [in,out] radioEntityTypeNomenclature 0 [0,255]
1195 //SFInt32 [in,out] radioEntityTypeNomenclatureVersion 0 [0,65535]
1196 //SFInt32 [in,out] radioID 0 [0,255]
1197 //SFVec3f [in,out] relativeAntennaLocation 0 0 0 (-8,8)
1198 //SFFloat [in,out] transmitFrequencyBandwidth 0.0 (-8,8)
1199 //SFInt32 [in,out] transmitState 0 [0,255]
1200 {
1201 double loc[3];
1202 float2double(loc,pnode->antennaLocation.c,3);
1203 vec3d2vector3double(&tpdu->antennaLocation,loc);
1204 vec3f2vector3float(&tpdu->relativeAntennaLocation,pnode->relativeAntennaLocation.c);
1205 }
1206 tpdu->antennaPatternCount = pnode->antennaPatternLength;
1207 tpdu->antennaPatternType = pnode->antennaPatternType;
1208 tpdu->cryptoKeyId = pnode->cryptoKeyID;
1209 tpdu->cryptoSystem = pnode->cryptoSystem;
1210 tpdu->frequency = pnode->frequency;
1211 tpdu->inputSource = pnode->inputSource;
1212 tpdu->modulationType.detail = pnode->modulationTypeDetail;
1213 tpdu->modulationType.major = pnode->modulationTypeMajor;
1214 tpdu->modulationType.spreadSpectrum = pnode->modulationTypeSpreadSpectrum;
1215 tpdu->modulationType.system = pnode->modulationTypeSystem;
1216 // memcpy(tpdu->modulationParametersList, ????) we have no field for it
1217 tpdu->modulationParameterCount = pnode->lengthOfModulationParameters; //==0 since no field for parameters
1218 tpdu->power = pnode->power;
1219 tpdu->radioEntityType.category = pnode->radioEntityTypeCategory;
1220 tpdu->radioEntityType.country = pnode->radioEntityTypeCountry;
1221 tpdu->radioEntityType.domain = pnode->radioEntityTypeDomain;
1222 tpdu->radioEntityType.entityKind = pnode->radioEntityTypeKind;
1223 tpdu->radioEntityType.nomenclature = pnode->radioEntityTypeNomenclature;
1224 tpdu->radioEntityType.nomenclatureVersion = pnode->radioEntityTypeNomenclatureVersion;
1225 tpdu->myRadioCommunicationsFamilyPdu.radioId = pnode->radioID;
1226 tpdu->transmitFrequencyBandwidth = pnode->transmitFrequencyBandwidth;
1227 tpdu->transmitState = pnode->transmitState;
1228
1229 vector_pushBack(struct Pdu*,pdus,(struct Pdu*)tpdu);
1230 }
1231 return pdus;
1232}
1233#define ONE_INT32_PER_SIGNAL_DATA_BYTE TRUE
1234struct Vector * dis_node2pdus_signal(struct X3D_Node *node, int isHeartbeat){
1235 struct Vector *pdus;
1236 struct X3D_SignalPdu * pnode = (struct X3D_SignalPdu*)node;
1237 pdus = newVector(struct Pdu *, 6);
1238
1239 // Q. what about network sensor>
1240 // Q. what about _geoCoords?
1241 if(pnode->_pduchange_signal){
1242 struct SignalPdu *spdu;
1243 spdu = (struct SignalPdu *) dis_ctor(type_SignalPdu);
1244
1245 //MFInt32 [in,out] data [] [0,255]
1246 //SFInt32 [in,out] dataLength 0 [0,65535]
1247 //SFInt32 [in,out] encodingScheme 0 [0,65535]
1248 //SFInt32 [in,out] radioID 0 [0,65535]
1249 //SFInt32 [in,out] sampleRate 0 [0,65535]
1250 //SFInt32 [in,out] samples 0 [0,65535]
1251 //SFInt32 [in,out] tdlType 0 [0,65535]
1252 spdu->data = realloc(spdu->data,pnode->dataLength*sizeof(unsigned char));
1253 if(ONE_INT32_PER_SIGNAL_DATA_BYTE){
1254 int k;
1255 unsigned char *cdata = (unsigned char *)spdu->data;
1256 for(k=0;k<spdu->dataLength;k++){
1257 cdata[k] = (unsigned char)((unsigned int)pnode->data.p[k] % 256);
1258 }
1259 }else{
1260 memcpy(spdu->data,pnode->data.p,pnode->dataLength);
1261 spdu->dataLength = pnode->dataLength;
1262 }
1263 spdu->encodingScheme = pnode->encodingScheme;
1264 spdu->sampleRate = pnode->sampleRate;
1265 spdu->samples = pnode->samples;
1266 spdu->tdlType = pnode->tdlType;
1267 spdu->myRadioCommunicationsFamilyPdu.radioId = pnode->radioID;
1268 spdu->myRadioCommunicationsFamilyPdu.entityId.entity = pnode->entityID;
1269 spdu->myRadioCommunicationsFamilyPdu.entityId.site = pnode->siteID;
1270 spdu->myRadioCommunicationsFamilyPdu.entityId.application = pnode->applicationID;
1271 vector_pushBack(struct Pdu*,pdus,(struct Pdu*)spdu);
1272 }
1273 return pdus;
1274}
1275struct X3D_Node *dis_find_or_create_espdu_by_category(int kind, int domain, int country, int category, int subcategory, int specific, int extra);
1276int dis_pdus2node_espdu(struct X3D_Node *node, struct Vector *pdus){
1277 int i, ihit;
1278 struct Pdu* pdu;
1279 struct X3D_EspduTransform * pnode = (struct X3D_EspduTransform*)node;
1280
1281 ihit = 0;
1282 if(!pdus) return ihit;
1283 for(i=0;i<pdus->n;i++)
1284 {
1285 pdu = vector_get(struct Pdu*,pdus,i);
1286 switch(pdu->pduType){
1287 case PDU_ENTITY_STATE:
1288 {
1289 //ENTITYSTATE
1290 struct EntityStatePdu *espdu;
1291 espdu = (struct EntityStatePdu*)pdu;
1292 if(espdu->entityID.application != pnode->applicationID) break;
1293 if(espdu->entityID.site != pnode->siteID) break;
1294 if(espdu->entityID.entity != pnode->entityID) break;
1295 ihit++;
1296 pnode->_change++; //mark node changed
1297 pnode->timestamp = TickTime();
1298
1299 if(pnode->__geoSystem){
1300 Quaternion qgc2tcs, qtcs2body, qgc2body;
1301 struct SFVec3d gd, gc, translate;
1302 struct SFVec4d rotate;
1303 double localxyz[3], tcsxyz[3], tcs2bodyxyz[3], world2bodyxyz[3];
1304 float xyza[4];
1305 Geosys *gs;
1306 gs = GEOSYS(pnode->__geoSystem);
1307 user2gc(gs,&pnode->geoCoords,1,&gc);
1308 //gc2gd(gs,&gc,1,&gd);
1309 //gc2tcs_transform(gs,&gd,&translate,&rotate);
1310 gc2tcsB_transform(gs,&gc,&translate,&rotate);
1311 //somehow get body/entity into world/gc - rotation and translation
1312 {
1313 //rotation
1314 //assumption (Apr 2018 don't know how Xj3d does it, here's dug9's guess):
1315 // pdu is world2body
1316 // espdutransform.rotation = local2body
1317 // - where local is TCS Topocentric Coord System as described for GeoLocation
1318 // - and world is GC
1319 // local2body = world2local.inverse x world2body
1320 // for freewrl world2local is gc2tcs
1321 Quaternion qtcs2gc, q;
1322 float ypr[3], xyza[4];
1323 ypr[0] = -espdu->entityOrientation.psi;
1324 ypr[1] = espdu->entityOrientation.theta;
1325 ypr[2] = espdu->entityOrientation.phi;
1326 ypr2axisangle(ypr,xyza);
1327 xyza[3] = -xyza[3];
1328 //vecprint4fb("recv xyza",xyza,"\n");
1329
1330 vrmlrot4f_to_quaternion(&qgc2body,xyza);
1331 vrmlrot4d_to_quaternion(&qgc2tcs,rotate.c);
1332 quaternion_inverse(&qtcs2gc,&qgc2tcs);
1333 quaternion_multiply(&qtcs2body,&qtcs2gc,&qgc2body);
1334 quaternion_set(&q,&qtcs2body);
1335 quaternion_to_vrmlrot4f(&q,pnode->rotation.c);
1336 }
1337 {
1338 //translation - dug9 debate: could do it one of 2 ways
1339 enum transmethod {
1340 TRANS_ZERO = 1,
1341 TRANS_LOCATION_MINUS_GEOCOORD = 2
1342 };
1343 //static int transmethod = TRANS_LOCATION_MINUS_GEOCOORD;
1344 static int transmethod = TRANS_ZERO;
1345
1346 vector3double2vec3d(world2bodyxyz,&espdu->entityLocation);
1347 if(transmethod == TRANS_LOCATION_MINUS_GEOCOORD){
1348 //METHOD 1: translation = Location - geoCoords
1349 struct SFVec3d world, tcs;
1350 veccopyd(world.c,world2bodyxyz);
1351 //gc2tcs(gs,&gd,&world,1,&tcs);
1352 gc2tcsB(gs,&gc,&world,1,&tcs);
1353 double2float(pnode->translation.c,tcs.c,3);
1354 }else{
1355 //TRANS_ZERO
1356 //METHOD 2: geoCoords = Location; translation = 000
1357 // x smoothing doesn't work if done in translation / tcs space
1358 struct SFVec3d world, tcs2, tcs1;
1359 double deltatcs[3];
1360 float deltap[3];
1361 static int want_smoothing = 1;
1362 if(want_smoothing){
1363 //gc2tcs(gs,&gd,&gc,1,&tcs1);
1364 gc2tcsB(gs,&gc,&gc,1,&tcs1);
1365 veccopyd(world.c,world2bodyxyz);
1366 gc2tcs(gs,&gd,&world,1,&tcs2);
1367 gc2tcsB(gs,&gc,&world,1,&tcs2);
1368 vecdifd(deltatcs,tcs1.c,tcs2.c);
1369 double2float(deltap,deltatcs,3);
1370 vecadd3f(pnode->_p0.c,pnode->_p0.c,deltap);
1371 }
1372 gc2user(gs,&world,1,&pnode->geoCoords);
1373 //node->_change++;
1374 vecset3f(pnode->translation.c,0.0f,0.0f,0.0f);
1375
1376 }
1377 }
1378 // recv geo dead reckoning
1379 pnode->deadReckoning = espdu->deadReckoningParameters.deadReckoningAlgorithm;
1380 {
1381 float V[3], A[3];
1382 // in entity or world, depending on drmethod
1383 vector3float2vec3f(A,&espdu->deadReckoningParameters.entityLinearAcceleration);
1384 vector3float2vec3f(V,&espdu->entityLinearVelocity);
1385
1386 //convert linear/angular V,A from world or Entity, to local
1387 //http://movesinstitute.org/~mcgredo/MV3500/hla/1278.1-200X%20Draft%2016%20rev%2018.pdf
1388 //p.333, p.329
1389 if(pnode->deadReckoning < 6){
1390 //convert world to TCS/Local
1391 //vtcs = gc2tcs x Vworld
1392 Quaternion q;
1393 vrmlrot4d_to_quaternion(&q,rotate.c);
1394 quaternion_rotation3f(V,&q,V);
1395 quaternion_rotation3f(A,&q,A);
1396 } else {
1397 if(0){
1398 //convert entity to TCS/Local
1399 //Vtcs = body2tcs x Vbody
1400 Quaternion q;
1401 vrmlrot4f_to_quaternion(&q,pnode->rotation.c);
1402 quaternion_rotation3f(V,&q,V);
1403 quaternion_rotation3f(A,&q,A);
1404 }else{
1405 //keep entity in entity
1406 }
1407 }
1408
1409 veccopy3f(pnode->linearAcceleration.c,A);
1410 veccopy3f(pnode->linearVelocity.c,V);
1411
1412 }
1413 {
1414 //p.667 E.7.4.1.1: rotational velocity is stored as axis*angle, in entity space
1415 float axis[3], angle;
1416 vector3float2vec3f(axis,&espdu->deadReckoningParameters.entityAngularVelocity);
1417 angle = veclength3f(axis);
1418 vecnormalize3f(pnode->_angularVelocity.c,axis);
1419 pnode->_angularVelocity.c[3] = angle;
1420 }
1421
1422 }else{
1423 //non-geosystem scene. Apr 22, 2018 we aren't using this now
1424 // -- everything goes through geosystem code above
1425 // -- but keeping this until we benchmark against Brutzman
1426 //translation - assumes companion scenes will have same parent transform stack
1427 //(x, -z, y).
1428 pnode->translation.c[0] = espdu->entityLocation.x;
1429 pnode->translation.c[1] = espdu->entityLocation.z;
1430 pnode->translation.c[2] = -espdu->entityLocation.y;
1431 //rotation
1432 if(0){
1433 Quaternion qA;
1434 float ypr[3];
1435 double r[4];
1436 float *c = pnode->rotation.c;
1437 ypr[0] = espdu->entityOrientation.phi;
1438 ypr[1] = espdu->entityOrientation.psi;
1439 ypr[2] = espdu->entityOrientation.theta;
1440 euler2quat(&qA,ypr[0],ypr[1],ypr[2]);
1441 //quaternion_normalize(&qA);
1442 //vrmlrot_to_quaternion(&qA,c[0],c[1],c[2],c[3]);
1443 quaternion_to_vrmlrot(&qA,&r[0],&r[1],&r[2],&r[3]);
1444 c[0] = (float)r[0];
1445 c[1] = (float)r[1];
1446 c[2] = (float)r[2];
1447 c[3] = (float)r[3];
1448 }
1449 if(1){
1450 float ypr[3];
1451 ypr[0] = -espdu->entityOrientation.psi; //gimbal.js shows -yaw
1452 ypr[1] = espdu->entityOrientation.theta;
1453 ypr[2] = espdu->entityOrientation.phi;
1454 ypr2axisangle(ypr,pnode->rotation.c);
1455 }
1456 // dead reckoning
1457 pnode->deadReckoning = espdu->deadReckoningParameters.deadReckoningAlgorithm;
1458 vector3float2vec3f(pnode->linearAcceleration.c,&espdu->deadReckoningParameters.entityLinearAcceleration);
1459 vector3float2vec3f(pnode->linearVelocity.c,&espdu->entityLinearVelocity);
1460 {
1461 //p.667 E.7.4.1.1: rotational velocity is stored as axis*angle
1462 float axis[3], angle;
1463 vector3float2vec3f(axis,&espdu->deadReckoningParameters.entityAngularVelocity);
1464 angle = veclength3f(axis);
1465 vecnormalize3f(pnode->_angularVelocity.c,axis);
1466 pnode->_angularVelocity.c[3] = angle;
1467 }
1468
1469 }
1470 //articuation parameters
1471 pnode->articulationParameterArray.n = espdu->numberOfArticulationParameters;
1472 //printf("recv art count %d\n",espdu->numberOfArticulationParameters);
1473 if(pnode->articulationParameterArray.n){
1474 struct ArticulationParameter *ap;
1475 float *pp;
1476 int i, np = pnode->articulationParameterArray.n;
1477 ap = espdu->articulationParameters;
1478 pp = malloc(np * sizeof(float));
1479 //printf("received %d articulation parameters:\n",np);
1480 for(i=0;i<np;i++){
1481 //ap[i].parameterTypeDesignator = 0; //0 is articulated part
1482 //ap[i].parameterType = 1029; //1024 - rudder + 5 X
1483 pp[i] = (float)ap[i].parameterValue;
1484 //printf("%d %f\n",i,pp[i]);
1485 //ap[i].partAttachedTo = 0;
1486 switch(i){
1487 case 0: pnode->articulationParameterValue0_changed = pp[i]; break;
1488 case 1: pnode->articulationParameterValue1_changed = pp[i]; break;
1489 case 2: pnode->articulationParameterValue2_changed = pp[i]; break;
1490 case 3: pnode->articulationParameterValue3_changed = pp[i]; break;
1491 case 4: pnode->articulationParameterValue4_changed = pp[i]; break;
1492 case 5: pnode->articulationParameterValue5_changed = pp[i]; break;
1493 case 6: pnode->articulationParameterValue6_changed = pp[i]; break;
1494 case 7: pnode->articulationParameterValue7_changed = pp[i]; break;
1495 default:
1496 break;
1497 }
1498 }
1499 if(pnode->articulationParameterArray.p) free(pnode->articulationParameterArray.p);
1500 pnode->articulationParameterArray.p = pp;
1501 //done in generic mark_changed_fields //MARK_EVENT(X3D_NODE(pnode),offsetof(struct X3D_EspduTransform,articulationParameterArray));
1502 }
1503 pdu2node_entityType(&espdu->entityType,&pnode->entityKind);
1504 pnode->_pduchange_es = TRUE;
1505 if(espdu->entityAppearance | 1 << 20){
1506 //http://movesinstitute.org/~mcgredo/MV3500/hla/1278.1-200X%20Draft%2016%20rev%2018.pdf
1507 //p.50 no dead reckoning if isFrozen bit is set, bit 21 of entityAppearance
1508 //(why can't they just leave dead reckoning parameters 0, and run through formula? H: specs written in 1990s for 80386 processors)
1509 //pnode->_isFrozen = TRUE; //pduchange_es = FALSE;
1510 }
1511
1512 //...
1513 }
1514 break;
1515 case PDU_FIRE:
1516 {
1517 //FIRE
1518 struct FirePdu *fpdu;
1519 fpdu = (struct FirePdu*)pdu;
1520 if(fpdu->myWarfareFamilyPdu.firingEntityID.application != pnode->applicationID) break;
1521 if(fpdu->myWarfareFamilyPdu.firingEntityID.site != pnode->siteID) break;
1522 if(fpdu->myWarfareFamilyPdu.firingEntityID.entity != pnode->entityID) break;
1523
1524 //fpdu->myWarfareFamilyPdu.myPdu;
1525 //fpdu->myWarfareFamilyPdu.targetEntityID;
1526
1527
1528 ihit++;
1529 pnode->_change++; //mark node changed
1530 pnode->timestamp = TickTime();
1531
1532 //if(pnode->fired1 || pnode->fired2){
1533 pnode->firedTime = TickTime();
1534 //}
1535 pnode->fired1 = TRUE;
1536 //copy from espdutransform node to pdu
1537 pnode->fuse = fpdu->burstDescriptor.fuse;
1538 //pnode->munitionEntityID = fpdu->burstDescriptor.munition.
1539 //the following doesn't work in target scene
1540 struct X3D_EspduTransform * muni;
1541 // kind, domain, country, category, subcategory, specific, extra
1542 muni = (struct X3D_EspduTransform * )dis_find_or_create_espdu_by_category(
1549 fpdu->burstDescriptor.munition.extra
1550 );
1551 if(!muni) printf("no muni\n");
1552 else {
1553 printf("got muni\n");
1554 pnode->munitionEntityID = muni->entityID;
1555 pnode->munitionSiteID = muni->siteID;
1556 pnode->munitionApplicationID = muni->applicationID;
1557 }
1558 pnode->munitionQuantity = fpdu->burstDescriptor.quantity;
1559 pnode->firingRate = fpdu->burstDescriptor.rate;
1560 pnode->warhead = fpdu->burstDescriptor.warhead;
1561
1562 //fpdu->eventID.application = 0;
1563 pnode->eventNumber = fpdu->eventID.eventNumber; //dis_next_event_number(); //increment in sender script node
1564 //fpdu->eventID.site = 0; //target if known
1565
1566 pnode->fireMissionIndex = fpdu->fireMissionIndex;
1567 {
1568 double loc[3];
1569 //am I supposed to convert to wworld from local here?
1570 //or can/should I assume that its local to Weapon Espdu here, and local to target scene's copy of Weapon Espdu?
1571 vector3double2vec3d(loc,&fpdu->locationInWorldCoordinates); //is this current location, or starting location?
1572 double2float(pnode->munitionStartPoint.c,loc,3);
1573 }
1574 //unique munition entity if known
1575 pnode->munitionApplicationID = fpdu->munitionID.application;
1576 pnode->munitionEntityID = fpdu->munitionID.entity;
1577 pnode->munitionSiteID = fpdu->munitionID.site;
1578
1579 //fpdu->myWarfareFamilyPdu.firingEntityID;
1580 //fpdu->myWarfareFamilyPdu.myPdu;
1581 //fpdu->myWarfareFamilyPdu.targetEntityID;
1582 pnode->firingRange = fpdu->range;
1583 {
1584 float delta[3];
1585 vector3float2vec3f(delta,&fpdu->velocity);
1586 //lets say 3 seconds to deliver any munition
1587 vecscale3f(delta,delta,3.0f/1.0f);
1588 vecadd3f(pnode->munitionEndPoint.c,pnode->munitionStartPoint.c,delta);
1589 }
1590 pnode->_pduchange_fire = TRUE;
1591 }
1592 break;
1593 case PDU_COLLISION:
1594 {
1595 //COLLISION
1596 struct CollisionPdu *cpdu;
1597 cpdu = (struct CollisionPdu *)pdu;
1598
1599 if(cpdu->issuingEntityID.application != pnode->applicationID) break;
1600 if(cpdu->issuingEntityID.site != pnode->siteID) break;
1601 if(cpdu->issuingEntityID.entity != pnode->entityID) break;
1602 pnode->eventEntityID = cpdu->collidingEntityID.entity;
1603 pnode->eventApplicationID = cpdu->collidingEntityID.application;
1604 pnode->eventSiteID = cpdu->collidingEntityID.site;
1605 pnode->collisionType = cpdu->collisionType;
1606 if(pnode->collisionType) pnode->isCollided = TRUE;
1607 else pnode->isCollided = FALSE;
1608 //cpdu->eventID;
1609 //cpdu->location;
1610 //cpdu->mass;
1611 //cpdu->myEntityInformationFamilyPdu.myPdu.exerciseID;
1612 //cpdu->velocity;
1613 pnode->_pduchange_collision = TRUE;
1614 }
1615 break;
1616 case PDU_DETONATION:
1617 {
1618 //DETONATION
1619 struct DetonationPdu *dpdu;
1620 dpdu = (struct DetonationPdu*)pdu;
1621 if(dpdu->myWarfareFamilyPdu.firingEntityID.application != pnode->applicationID) break;
1622 if(dpdu->myWarfareFamilyPdu.firingEntityID.site != pnode->siteID) break;
1623 if(dpdu->myWarfareFamilyPdu.firingEntityID.entity != pnode->entityID) break;
1624
1625 ihit++;
1626 pnode->_change++; //mark node changed
1627 pnode->timestamp = TickTime();
1628
1629 pnode->detonateTime = TickTime();
1630 pnode->fuse = dpdu->burstDescriptor.fuse;
1631 //pnode->munitionEntityID = fpdu->burstDescriptor.munition.
1632 //the following doesn't work in target scene
1633 struct X3D_EspduTransform * muni;
1634 // kind, domain, country, category, subcategory, specific, extra
1635 muni = (struct X3D_EspduTransform * )dis_find_or_create_espdu_by_category(
1642 dpdu->burstDescriptor.munition.extra
1643 );
1644 if(!muni) printf("no muni\n");
1645 else {
1646 printf("got muni\n");
1647 pnode->munitionEntityID = muni->entityID;
1648 pnode->munitionSiteID = muni->siteID;
1649 pnode->munitionApplicationID = muni->applicationID;
1650 }
1651 pnode->munitionQuantity = dpdu->burstDescriptor.quantity;
1652 pnode->firingRate = dpdu->burstDescriptor.rate;
1653 pnode->warhead = dpdu->burstDescriptor.warhead;
1654
1655 //fpdu->eventID.application = 0;
1656 pnode->eventNumber = dpdu->eventID.eventNumber; //dis_next_event_number(); //increment in sender script node
1657 //unique munition entity if known
1658 pnode->munitionApplicationID = dpdu->munitionID.application;
1659 pnode->munitionEntityID = dpdu->munitionID.entity;
1660 pnode->munitionSiteID = dpdu->munitionID.site;
1661 {
1662 double loc[3];
1663 vector3double2vec3d(loc,&dpdu->locationInWorldCoordinates);
1664 double2float(pnode->detonationLocation.c,loc,3);
1665 vector3float2vec3f(pnode->detonationRelativeLocation.c,&dpdu->locationInEntityCoordinates);
1666 }
1667 pnode->detonationResult = dpdu->detonationResult;
1668
1669 {
1670 float delta[3];
1671 vector3float2vec3f(delta,&dpdu->velocity);
1672 //lets say .5 seconds to explode a munition
1673 vecscale3f(delta,delta,.5f/1.0f);
1674 veccopy3f(pnode->munitionStartPoint.c,pnode->detonationRelativeLocation.c);
1675 vecadd3f(pnode->munitionEndPoint.c,pnode->munitionStartPoint.c,delta);
1676 }
1677 //articuation parameters
1678 pnode->articulationParameterArray.n = dpdu->numberOfArticulationParameters;
1679 //printf("recv art count %d\n",espdu->numberOfArticulationParameters);
1680 if(pnode->articulationParameterArray.n){
1681 struct ArticulationParameter *ap;
1682 float *pp;
1683 int i, np = pnode->articulationParameterArray.n;
1684 ap = dpdu->articulationParameters;
1685 pp = malloc(np * sizeof(float));
1686 //printf("received %d articulation parameters:\n",np);
1687 for(i=0;i<np;i++){
1688 //ap[i].parameterTypeDesignator = 0; //0 is articulated part
1689 //ap[i].parameterType = 1029; //1024 - rudder + 5 X
1690 pp[i] = (float)ap[i].parameterValue;
1691 //printf("%d %f\n",i,pp[i]);
1692 //ap[i].partAttachedTo = 0;
1693 switch(i){
1694 case 0: pnode->articulationParameterValue0_changed = pp[i]; break;
1695 case 1: pnode->articulationParameterValue1_changed = pp[i]; break;
1696 case 2: pnode->articulationParameterValue2_changed = pp[i]; break;
1697 case 3: pnode->articulationParameterValue3_changed = pp[i]; break;
1698 case 4: pnode->articulationParameterValue4_changed = pp[i]; break;
1699 case 5: pnode->articulationParameterValue5_changed = pp[i]; break;
1700 case 6: pnode->articulationParameterValue6_changed = pp[i]; break;
1701 case 7: pnode->articulationParameterValue7_changed = pp[i]; break;
1702 default:
1703 break;
1704 }
1705 }
1706 if(pnode->articulationParameterArray.p) free(pnode->articulationParameterArray.p);
1707 pnode->articulationParameterArray.p = pp;
1708 //done in generic mark_changed_fields //MARK_EVENT(X3D_NODE(pnode),offsetof(struct X3D_EspduTransform,articulationParameterArray));
1709 }
1710 pnode->_pduchange_detonation = TRUE;
1711
1712 }
1713 break;
1714 default:
1715 break;
1716 }
1717 }
1718 return ihit;
1719}
1720
1721int dis_pdus2node_receiver(struct X3D_Node *node, struct Vector *pdus){
1722 int i, ihit;
1723 struct Pdu* pdu;
1724 struct X3D_ReceiverPdu * pnode = (struct X3D_ReceiverPdu*)node;
1725
1726 ihit = 0;
1727 if(!pdus) return ihit;
1728 for(i=0;i<pdus->n;i++)
1729 {
1730 pdu = vector_get(struct Pdu*,pdus,i);
1731 switch(pdu->pduType){
1732 case PDU_RECEIVER:
1733 {
1734 struct ReceiverPdu *rpdu;
1735 rpdu = (struct ReceiverPdu*)pdu;
1736
1737 if(pnode->radioID != rpdu->myRadioCommunicationsFamilyPdu.radioId) break;
1738 ihit++;
1739 pnode->_change++; //mark node changed
1740 pnode->timestamp = TickTime();
1741
1742 pnode->receivedPower = rpdu->receivedPoser; //spelling Poser / Power
1743 pnode->receiverState = rpdu->receiverState;
1744 pnode->transmitterRadioID = rpdu->transmitterRadioId;
1745 pnode->transmitterEntityID = rpdu->transmitterEntityId.entity;
1746 pnode->transmitterSiteID = rpdu->transmitterEntityId.site;
1747 pnode->transmitterSiteID = rpdu->transmitterEntityId.application;
1748 pnode->_pduchange_receiver = TRUE;
1749 }
1750 break;
1751 default:
1752 break;
1753 }
1754 }
1755 return ihit;
1756}
1757int dis_pdus2node_transmitter(struct X3D_Node *node, struct Vector *pdus){
1758 int i, ihit;
1759 struct Pdu* pdu;
1760 struct X3D_TransmitterPdu * pnode = (struct X3D_TransmitterPdu*)node;
1761
1762 ihit = 0;
1763 if(!pdus) return ihit;
1764 for(i=0;i<pdus->n;i++)
1765 {
1766 pdu = vector_get(struct Pdu*,pdus,i);
1767 switch(pdu->pduType){
1768 case PDU_TRANSMITTER:
1769 {
1770 struct TransmitterPdu *tpdu;
1771 tpdu = (struct TransmitterPdu*)pdu;
1772
1773 if(pnode->radioID != tpdu->myRadioCommunicationsFamilyPdu.radioId) break;
1774 if(tpdu->myRadioCommunicationsFamilyPdu.entityId.entity != pnode->entityID) break;
1775 if(tpdu->myRadioCommunicationsFamilyPdu.entityId.site != pnode->siteID) break;
1776 if(tpdu->myRadioCommunicationsFamilyPdu.entityId.application != pnode->applicationID) break;
1777
1778 ihit++;
1779 pnode->_change++; //mark node changed
1780 pnode->timestamp = TickTime();
1781 {
1782 double loc[3];
1783 vector3double2vec3d(loc,&tpdu->antennaLocation);
1784 double2float(pnode->antennaLocation.c,loc,3);
1785 vector3float2vec3f(pnode->relativeAntennaLocation.c,&tpdu->relativeAntennaLocation);
1786 }
1787 pnode->antennaPatternLength = tpdu->antennaPatternCount;
1788 pnode->antennaPatternType = tpdu->antennaPatternType;
1789 pnode->cryptoKeyID = tpdu->cryptoKeyId;
1790 pnode->cryptoSystem = tpdu->cryptoSystem;
1791 pnode->frequency = tpdu->frequency;
1792 pnode->inputSource = tpdu->inputSource;
1793 pnode->modulationTypeDetail = tpdu->modulationType.detail;
1794 pnode->modulationTypeMajor = tpdu->modulationType.major;
1795 pnode->modulationTypeSpreadSpectrum = tpdu->modulationType.spreadSpectrum;
1796 pnode->modulationTypeSystem = tpdu->modulationType.system;
1797 // memcpy(tpdu->modulationParametersList, ????) we have no field for it
1798 pnode->lengthOfModulationParameters = tpdu->modulationParameterCount; //==0 since no field for parameters
1799 pnode->power = tpdu->power;
1800 pnode->radioEntityTypeCategory = tpdu->radioEntityType.category;
1801 pnode->radioEntityTypeCountry = tpdu->radioEntityType.country;
1802 pnode->radioEntityTypeDomain = tpdu->radioEntityType.domain;
1803 pnode->radioEntityTypeKind = tpdu->radioEntityType.entityKind;
1804 pnode->radioEntityTypeNomenclature = tpdu->radioEntityType.nomenclature;
1805 pnode->radioEntityTypeNomenclatureVersion = tpdu->radioEntityType.nomenclatureVersion;
1806 pnode->radioID = tpdu->myRadioCommunicationsFamilyPdu.radioId;
1807 pnode->transmitFrequencyBandwidth = tpdu->transmitFrequencyBandwidth;
1808 pnode->transmitState = tpdu->transmitState;
1809 pnode->_pduchange_transmitter = TRUE;
1810
1811 }
1812 break;
1813 default:
1814 break;
1815 }
1816 }
1817 return ihit;
1818}
1819// #define ONE_INT32_PER_SIGNAL_DATA_BYTE TRUE
1820int dis_pdus2node_signal(struct X3D_Node *node, struct Vector *pdus){
1821 int i, ihit;
1822 struct Pdu* pdu;
1823 struct X3D_SignalPdu * pnode = (struct X3D_SignalPdu*)node;
1824
1825 ihit = 0;
1826 if(!pdus) return ihit;
1827 for(i=0;i<pdus->n;i++)
1828 {
1829 pdu = vector_get(struct Pdu*,pdus,i);
1830 switch(pdu->pduType){
1831 case PDU_SIGNAL:
1832 {
1833 struct SignalPdu *spdu;
1834 spdu = (struct SignalPdu*)pdu;
1835
1836 if(pnode->radioID != spdu->myRadioCommunicationsFamilyPdu.radioId) break;
1837 if(spdu->myRadioCommunicationsFamilyPdu.entityId.entity != pnode->entityID) break;
1838 if(spdu->myRadioCommunicationsFamilyPdu.entityId.site != pnode->siteID) break;
1839 if(spdu->myRadioCommunicationsFamilyPdu.entityId.application != pnode->applicationID) break;
1840
1841 ihit++;
1842 pnode->_change++; //mark node changed
1843 pnode->timestamp = TickTime();
1844 if(ONE_INT32_PER_SIGNAL_DATA_BYTE){
1845 int k;
1846 unsigned char *cdata = (unsigned char *)spdu->data;
1847 pnode->data.p = realloc(pnode->data.p,spdu->dataLength*sizeof(int));
1848 for(k=0;k<spdu->dataLength;k++){
1849 pnode->data.p[k] = (int)(cdata[k]);
1850 }
1851 }else{
1852 memcpy(pnode->data.p,spdu->data,pnode->dataLength);
1853 pnode->data.n = (spdu->dataLength + 4) / 4;
1854 }
1855 pnode->dataLength = spdu->dataLength;
1856 pnode->encodingScheme = spdu->encodingScheme;
1857 pnode->sampleRate = spdu->sampleRate;
1858 pnode->samples = spdu->samples;
1859 pnode->tdlType = spdu->tdlType;
1860 pnode->_pduchange_signal = TRUE;
1861 }
1862 break;
1863 default:
1864 break;
1865 }
1866 }
1867 return ihit;
1868}
1869
1870
1871
1872// Simulation Management PDUs relate to the DISEntityManager node
1873// http://movesinstitute.org/~mcgredo/MV3500/hla/1278.1-200X%20Draft%2016%20rev%2018.pdf
1874//5.6 Simulation management p.85
1875//6.2.82 Simulation Management PDU Header record p.311
1876//- its an abstract type
1877//- the pdutype burried in the standard header part is the implied ACTION. ie create, or remove.
1878//Table 114 p.313:
1879//PDU Reference Originating ID Receiving ID
1880//Create Entity 5.6.5.2 Simulation ID Entity ID or Special Create Entity Identifier
1881//Remove Entity 5.6.5.3 Simulation ID Entity ID
1882//Table 12 p.87
1883//Table 3 p.31 - IDs, including specials: All Simulations, no particular node: ALL_SITES 65535, ALL_APPLIC = 65535, RefID 0
1884//5.6.5.2 Create Entity PDU p.88
1885
1886
1887struct Vector * dis_node2pdus_sm(struct X3D_Node *node, int isHeartbeat){
1888
1889 struct Vector *pdus;
1890 struct X3D_DISEntityManager * pnode = (struct X3D_DISEntityManager*)node;
1891 pdus = newVector(struct Pdu *, 6);
1892
1893 //ENTITYSTATE
1894 //if(pnode->_pduchange_es_articulation || pnode->_pduchange_es_deadreckoning || pnode->_pduchange_es_info || pnode->_pduchange_es_force){
1895 printf("em pduchange create %d remove %d heartbeat %d ticktime %lf\n",pnode->_pduchange_create, pnode->_pduchange_remove, isHeartbeat,TickTime());
1896 if(isHeartbeat){
1897 //lets say someone joins the exercise late.
1898 //how do they get synched up?
1899 }
1900 {
1901 struct SimulationManagementPdu *simanpdu;
1902 }
1903 //CREATE
1904 if(pnode->_pduchange_create){
1905 struct CreateEntityPdu *crpdu;
1906 crpdu = (struct CreateEntityPdu *) dis_ctor(type_CreateEntityPdu);
1907 //copy from espdutransform node to pdu
1908 crpdu->mySimulationManagementFamilyPdu.originatingEntityID.entity = pnode->entityID;
1909 //crpdu->mySimulationManagementFamilyPdu.receivingEntityID = ALL_SITES; ???
1910 //crpdu->requestID = ??
1912 vector_pushBack(struct Pdu*,pdus,(struct Pdu*)crpdu);
1913 }
1914 //REMOVE
1915 if(pnode->_pduchange_remove){
1916 struct RemoveEntityPdu *rmpdu;
1917 rmpdu = (struct RemoveEntityPdu *) dis_ctor(type_RemoveEntityPdu);
1918 //copy from espdutransform node to pdu
1919 vector_pushBack(struct Pdu*,pdus,(struct Pdu*)rmpdu);
1920 }
1921 return pdus;
1922
1923}
1924int dis_pdus2node_sm(struct X3D_Node *node, struct Vector *pdus){
1925 int i, ihit;
1926 struct Pdu* pdu;
1927 struct X3D_DISEntityManager * pnode = (struct X3D_DISEntityManager*)node;
1928
1929 ihit = 0;
1930 if(!pdus) return ihit;
1931 for(i=0;i<pdus->n;i++)
1932 {
1933 pdu = vector_get(struct Pdu*,pdus,i);
1934 switch(pdu->pduType){
1935 case PDU_CREATE_ENTITY:
1936 {
1937 //CREATE
1938 struct CreateEntityPdu *crpdu;
1939 //crpdu->mySimulationManagementFamilyPdu.myPdu.
1940 printf("hi from pdu2node create_entity\n");
1941 pnode->_pduchange_create = TRUE;
1942 }
1943 break;
1944 case PDU_REMOVE_ENTITY:
1945 {
1946 //REMOVE
1947 struct RemoveEntityPdu *rmpdu;
1948 printf("hi from pdu2node remove_entity\n");
1949 pnode->_pduchange_remove = TRUE;
1950 }
1951 break;
1952
1953 default:
1954 break;
1955 }
1956 }
1957 return ihit;
1958}
1959void dis_set_node_lasttime(struct X3D_Node *node, double lasttime){
1960 //4 nodes have the same field order for common fields, can be cast to Espdu
1961 switch(node->_nodeType){
1962 case NODE_ReceiverPdu:
1963 case NODE_TransmitterPdu:
1964 case NODE_SignalPdu:
1965 case NODE_EspduTransform:
1966 case NODE_DISEntityManager:
1967 {
1968 struct X3D_EspduTransform *pnode = (struct X3D_EspduTransform*)node;
1969 pnode->_lasttime = lasttime;
1970 }
1971 break;
1972 break;
1973 }
1974}
1975
1976int dis_pdus2newnode(struct dis_socket *dsock, struct X3D_DISEntityManager *pnode, struct Vector * pdus){
1977 int ihit = 0;
1978 if(pnode){
1979 int i;
1980 // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/dis.html#DISEntityManager
1981 // https://github.com/open-dis/DISTutorial/blob/master/EntityDiscovery.md
1982 // entity discovery happening here
1983 struct Pdu* pdu;
1984 for(i=0;i<pdus->n;i++) {
1985 pdu = vector_get(struct Pdu*,pdus,i);
1986 switch(pdu->pduType){
1987 case PDU_ENTITY_STATE:
1988 case PDU_RECEIVER:
1989 case PDU_TRANSMITTER:
1990 case PDU_SIGNAL:
1991 {
1992 int j, already_done;
1993 int entityID, siteID, applicationID;
1994 struct EntityStatePdu *espdu;
1995 struct X3D_EspduTransform* et;
1996 espdu = (struct EntityStatePdu*)pdu;
1997
1998 //don't send to yourself
1999 if( pnode->applicationID == espdu->entityID.application &&
2000 pnode->siteID == espdu->entityID.site)
2001 continue;
2002
2003 //skip if we already got this entity and are just awaiting creation
2004 already_done = FALSE;
2005 for(j=0;j<pnode->addEntities.n;j++){
2006 struct X3D_Node *candi = (struct X3D_Node*)pnode->addEntities.p[j];
2007 if(candi->_nodeType == NODE_DISEntityTypeMapping){
2008 struct X3D_DISEntityTypeMapping *et = (struct X3D_DISEntityTypeMapping *)candi;
2009 //already_done = FALSE;
2010 }else if(candi->_nodeType == NODE_EspduTransform) {
2011 // || candi->_nodeType == NODE_ReceiverPdu
2012 // || candi->_nodeType == NODE_TransmitterPdu || candi->_nodeType == NODE_SignalPdu){
2013 //else if radio etc
2014 struct X3D_EspduTransform *et = (struct X3D_EspduTransform *)pnode->addEntities.p[j];
2015 if(et->entityID == espdu->entityID.entity &&
2016 et->applicationID == espdu->entityID.application &&
2017 et->siteID == espdu->entityID.site) already_done = TRUE;
2018 if(already_done) break;
2019 }
2020
2021 }
2022 if(already_done)
2023 continue;
2024
2025 //we'll use an EspduTransform struct just as a temp struct, not to register.
2026 // -for the purpose of communicating with whatever can create a local copy
2027 // of a discovered entity.
2028 // right now, that's our EntityManager node.
2029 et = createNewX3DNode0(NODE_EspduTransform); //the 0 creator which does not register the node
2030 int nodetype = 0;
2031 switch(pdu->pduType){
2032 case PDU_ENTITY_STATE: nodetype = NODE_EspduTransform; break;
2033 case PDU_RECEIVER: nodetype = NODE_ReceiverPdu; break;
2034 case PDU_TRANSMITTER: nodetype = NODE_TransmitterPdu; break;
2035 case PDU_SIGNAL: nodetype = NODE_SignalPdu; break;
2036 default: break;
2037 }
2038 //copy world coordinates as approx GC, in case < earths radius / 2 (earths core) test later, we use GC instead of default GD,WE
2039 vector3double2vec3d(et->geoCoords.c,&espdu->entityLocation);
2040
2041 et->_nodeType = nodetype;
2042 et->applicationID = espdu->entityID.application;
2043 et->siteID = espdu->entityID.site;
2044 et->entityID = espdu->entityID.entity;
2045 et->address = newASCIIString(dsock->address);
2046 et->port = dsock->port;
2047 et->multicastRelayHost = newASCIIString(dsock->multicastRelayHost);
2048 et->multicastRelayPort = dsock->multicastRelayPort;
2049 et->entityCategory = espdu->entityType.category;
2050 et->entityCountry = espdu->entityType.country;
2051 et->entityDomain = espdu->entityType.domain;
2052 et->entityKind = espdu->entityType.entityKind;
2053 et->entityExtra = espdu->entityType.extra;
2054 et->entitySpecific = espdu->entityType.specific;
2055 et->entitySubCategory = espdu->entityType.subcategory;
2056
2057 {
2058 void * pp = pnode->addEntities.p;
2059 pnode->addEntities.p = realloc(pp,sizeof(struct X3D_Node*)*upper_power_of_two(pnode->addEntities.n + 1));
2060 pnode->addEntities.p[pnode->addEntities.n] = (struct X3D_Node*)et;
2061 pnode->addEntities.n++;
2062 // >> do I need pnode->_pduchange_create = TRUE;
2063 }
2064 // ?? do I need MARK_EVENT(X3D_NODE(pnode),offsetof (struct X3D_DISEntityManager, addEntities));
2065 //will get mapped and instanced as geom during entityManager scenegraph visit and compile
2066 // >> pnode->_change ++;
2067 ihit = 1;
2068 }
2069 break;
2070 default:
2071 break;
2072 }
2073 }
2074 }
2075 return ihit;
2076}
2077int dis_entity_retire(struct X3D_DISEntityManager *pnode, struct X3D_Node *node){
2078 //we only retire the entities that were created by 'entity_discovery'
2079 int iret = 0;
2080 if(node->_nodeType == NODE_EspduTransform){
2081 if(pnode && pnode->_nodeType == NODE_DISEntityManager){
2082 int i;
2083 static int ADD = 1, REMOVE = 2;
2084 iret = -1;
2085 for(i=0;i<pnode->entities.n;i++){
2086 if(pnode->entities.p[i] == node){
2087 //yes - created by entity discovery
2088 AddRemoveChildren(X3D_NODE(pnode), &pnode->entities, (struct X3D_Node * *)&node, 1, REMOVE,__FILE__,__LINE__);
2089 AddRemoveChildren(X3D_NODE(pnode), &pnode->removedEntities, (struct X3D_Node * *)&node, 1, ADD,__FILE__,__LINE__);
2090
2091 iret = 1;
2092 break;
2093 }
2094 }
2095 }
2096 }
2097 return iret;
2098}
2099struct Vector * dis_node2pdus(struct X3D_Node *node, int isHeartbeat){
2100 struct Vector *pdus = NULL;
2101 switch(node->_nodeType){
2102 case NODE_EspduTransform:
2103 pdus = dis_node2pdus_espdu(node, isHeartbeat);
2104 break;
2105 case NODE_DISEntityManager:
2106 pdus = dis_node2pdus_sm(node,isHeartbeat);
2107 break;
2108 case NODE_ReceiverPdu:
2109 pdus = dis_node2pdus_receiver(node,isHeartbeat);
2110 break;
2111 case NODE_TransmitterPdu:
2112 pdus = dis_node2pdus_transmitter(node,isHeartbeat);
2113 break;
2114 case NODE_SignalPdu:
2115 pdus = dis_node2pdus_signal(node,isHeartbeat);
2116 break;
2117 break;
2118 }
2119 return pdus;
2120}
2121static struct Vector *sockets_send = NULL;
2122static struct Vector *sockets_recv = NULL;
2123
2124struct X3D_Node * dis_find_registered_node_by_entityid(int entityid, int sendlist, int recvlist){
2125 int i,j;
2126 struct X3D_Node *node, *pnode = NULL;
2127 if(sendlist)
2128 for(i=0;i<sockets_send->n;i++){
2129 struct dis_socket *dsock = vector_get_ptr(struct dis_socket,sockets_send,i);
2130 if(dsock->registered){
2131 for(j=0;j<dsock->registered->n;j++){
2132 int ihit;
2133 struct X3D_Node *node = vector_get(struct X3D_Node*,dsock->registered,j);
2134 if(node->_nodeType == NODE_EspduTransform){
2135 struct X3D_EspduTransform *espdu = (struct X3D_EspduTransform *)node;
2136 if(espdu->entityID == entityid){
2137 pnode = node;
2138 break;
2139 }
2140 }
2141 }
2142 }
2143 }
2144 if(recvlist)
2145 for(i=0;i<sockets_recv->n;i++){
2146 struct dis_socket *dsock = vector_get_ptr(struct dis_socket,sockets_recv,i);
2147 if(dsock->registered){
2148 for(j=0;j<dsock->registered->n;j++){
2149 int ihit;
2150 struct X3D_Node *node = vector_get(struct X3D_Node*,dsock->registered,j);
2151 if(node->_nodeType == NODE_EspduTransform){
2152 struct X3D_EspduTransform *espdu = (struct X3D_EspduTransform *)node;
2153 if(espdu->entityID == entityid){
2154 pnode = node;
2155 break;
2156 }
2157 }
2158 }
2159 }
2160 }
2161 return pnode;
2162}
2163
2164
2165 // kind, domain, country, category, subcategory, specific, extra
2166struct X3D_Node *dis_find_or_create_espdu_by_category(int kind, int domain, int country, int category, int subcategory, int specific, int extra){
2167 int i,j,k, ibest, iscore;
2168 struct X3D_EspduTransform *best = NULL;
2169 ibest = -1;
2170 iscore = 0;
2171 //check EM already-instanced list
2172 for(i=0;i<sockets_recv->n;i++){
2173 struct dis_socket *dsock = vector_get_ptr(struct dis_socket,sockets_recv,i);
2174 if(dsock->registered){
2175 for(j=0;j<dsock->registered->n;j++){
2176 int ihit;
2177 struct X3D_Node *node = vector_get(struct X3D_Node*,dsock->registered,j);
2178 if(node->_nodeType == NODE_DISEntityManager){
2179 struct X3D_DISEntityManager *em = (struct X3D_DISEntityManager *)node;
2180 if(em->entities.n){
2181 for(k=0;k<em->entities.n;k++){
2182 struct X3D_EspduTransform *bnode = (struct X3D_EspduTransform *)em->entities.p[k];
2183 if(bnode->_nodeType == NODE_EspduTransform){
2184 int jscore = 0;
2185 if(domain == bnode->entityDomain) jscore++;
2186 if(category == bnode->entityCategory) jscore++;
2187 if(country == bnode->entityCountry) jscore++;
2188 if(kind == bnode->entityKind) jscore++;
2189 if(extra == bnode->entityExtra) jscore++;
2190 if(subcategory == bnode->entitySubCategory) jscore++;
2191 if(specific == bnode->entitySpecific) jscore++;
2192 if(jscore > iscore){
2193 iscore = jscore;
2194 ibest = i;
2195 best = bnode;
2196 }
2197
2198 }
2199 }
2200 }
2201 }
2202 }
2203 }
2204 }
2205 return (struct X3D_Node*)best;
2206}
2207
2208
2209unsigned char buf2[32767];
2210
2211void dis_get_node_lasttime(struct X3D_Node *node, double *lasttime, double *readInterval, double *writeInterval){
2212 //4 nodes have the same field order for common fields, can be cast to Espdu
2213 switch(node->_nodeType){
2214 case NODE_ReceiverPdu:
2215 case NODE_TransmitterPdu:
2216 case NODE_SignalPdu:
2217 case NODE_EspduTransform:
2218 case NODE_DISEntityManager:
2219 {
2220 struct X3D_EspduTransform *pnode = (struct X3D_EspduTransform*)node;
2221 *lasttime = pnode->_lasttime;
2222 *writeInterval = pnode->writeInterval;
2223 *readInterval = pnode->readInterval;
2224 }
2225 break;
2226 default:
2227 break;
2228 }
2229}
2230int node_only_transform_changed(struct X3D_Node *node){
2231 int changed, onlytransform = FALSE;
2232 changed = 0;
2233 if( node->_nodeType == NODE_EspduTransform)
2234 {
2235 struct X3D_EspduTransform *pnode = (struct X3D_EspduTransform *)node;
2236 changed += pnode->_pduchange_es ? 1 : 0;
2237 changed += pnode->_pduchange_collision ? 2:0;
2238 changed += pnode->_pduchange_fire ? 4:0;
2239 changed += pnode->_pduchange_detonation ? 8:0;
2240 }
2241 onlytransform = changed == 1;
2242 return onlytransform;
2243}
2244
2245
2246int node_pdus_changed_by_scene(struct X3D_Node *node){
2247 int changed = FALSE;
2248 switch(node->_nodeType){
2249 case NODE_EspduTransform:
2250 {
2251 struct X3D_EspduTransform *pnode = (struct X3D_EspduTransform *)node;
2252 changed = pnode->_pduchange_es;
2253 changed |= pnode->_pduchange_collision;
2254 changed |= pnode->_pduchange_fire;
2255 changed |= pnode->_pduchange_detonation;
2256 }
2257 break;
2258 case NODE_DISEntityManager:
2259 {
2260 struct X3D_DISEntityManager *pnode = (struct X3D_DISEntityManager *)node;
2261 changed = pnode->_pduchange_create;
2262 changed |= pnode->_pduchange_remove;
2263 }
2264 break;
2265 case NODE_TransmitterPdu:
2266 {
2267 struct X3D_TransmitterPdu *pnode = (struct X3D_TransmitterPdu *)node;
2268 changed = pnode->_pduchange_transmitter;
2269 }
2270 break;
2271 case NODE_SignalPdu:
2272 {
2273 struct X3D_SignalPdu *pnode = (struct X3D_SignalPdu *)node;
2274 changed = pnode->_pduchange_signal;
2275 }
2276 break;
2277 case NODE_ReceiverPdu:
2278 {
2279 struct X3D_ReceiverPdu *pnode = (struct X3D_ReceiverPdu *)node;
2280 changed = pnode->_pduchange_receiver;
2281 }
2282 break;
2283 default:
2284 break;
2285 }
2286 return changed;
2287}
2288void reset_node_pduchanged(struct X3D_Node *node){
2289 switch(node->_nodeType){
2290 case NODE_EspduTransform:
2291 {
2292 struct X3D_EspduTransform *pnode = (struct X3D_EspduTransform *)node;
2293 pnode->_pduchange_es = FALSE;
2294 pnode->_pduchange_collision = FALSE;
2295 pnode->_pduchange_fire = FALSE;
2296 pnode->_pduchange_detonation = FALSE;
2297 }
2298 break;
2299 case NODE_DISEntityManager:
2300 {
2301 struct X3D_DISEntityManager *pnode = (struct X3D_DISEntityManager *)node;
2302 pnode->_pduchange_em_info = FALSE;
2303 pnode->_pduchange_create = FALSE;
2304 pnode->_pduchange_remove = FALSE;
2305 }
2306 break;
2307 case NODE_TransmitterPdu:
2308 {
2309 struct X3D_TransmitterPdu *pnode = (struct X3D_TransmitterPdu *)node;
2310 pnode->_pduchange_transmitter = FALSE;
2311 }
2312 break;
2313 case NODE_SignalPdu:
2314 {
2315 struct X3D_SignalPdu *pnode = (struct X3D_SignalPdu *)node;
2316 pnode->_pduchange_signal = FALSE;
2317 }
2318 break;
2319 case NODE_ReceiverPdu:
2320 {
2321 struct X3D_ReceiverPdu *pnode = (struct X3D_ReceiverPdu *)node;
2322 pnode->_pduchange_receiver = FALSE;
2323 }
2324 break;
2325 default:
2326 break;
2327 }
2328}
2329//in socketutils.c:
2330void socket_open(struct dis_socket *dsock);
2331int sockwrite(SOCKET s, const char *buf, int len);
2332int sockread(SOCKET s, const char *buf, int len);
2333int sockrecvfrom(struct dis_socket *dsock, const char *buf, int len);
2334int socksendto(struct dis_socket *dsock, const char *buf, int len);
2335
2336int write_rtp(unsigned char *buf, struct X3D_Node *node);
2337void dis_sendloop(){
2338 double thistime;
2339 int i,j, nbytes, nb;
2340 if(!sockets_send || sockets_send->n == 0) return;
2341 thistime = TickTime();
2342 for(i=0;i<sockets_send->n;i++){
2343 struct dis_socket *dsock = vector_get_ptr(struct dis_socket,sockets_send,i);
2344 if(dsock->registered){
2345 nbytes = 0;
2346 for(j=0;j<dsock->registered->n;j++){
2347 //options:
2348 //a. each node maintains its own pdus every frame on update/compile, and are merely sent here
2349 //b. on send in here, a function is called to pdu-ize a node before marshaling it
2350 //c. like a and b: each node has its own list of pdus for mem, and are updated in here just before send
2351 double lasttime, dtime, readInterval, writeInterval, isHeartbeat;
2352 struct Vector *pdus;
2353 struct X3D_Node *node = vector_get(struct X3D_Node*,dsock->registered,j);
2354 //printf("registered node type %s\n",stringNodeType(node->_nodeType));
2355 dis_get_node_lasttime(node,&lasttime,&readInterval,&writeInterval);
2356 if(writeInterval == 0.0) continue; //sentinal value 0 means don't write
2357 // finer granularity send decision: a)heartbeat, b)on-change except DR, c) DR dead-reckoning-threshold exceded
2358 // Q. where's our c)dead-reckoning-threshold?
2359 dtime = thistime - lasttime;
2360 isHeartbeat = dtime > writeInterval ? TRUE: FALSE; //a)heartbeat: skip for a while more
2361 if(!isHeartbeat && !node_pdus_changed_by_scene(node)) continue; //b)on-change: no pdus changed since last send, DIS ettiquette says don't send if no change
2362 //if(0) //moved to node _compile/_prep/_child
2363 //if(!isHeartbeat && node_only_transform_changed(node)){
2364 // if(transform_within_DeadReckoningTolerance(node,dtime)) continue;
2365 //}
2366 printf(".");
2367 lasttime = thistime;
2368 dsock->lasttime = thistime; //last time something was sent, not needed
2369 if(j==0) {
2370 nb = write_rtp(&buf2[nbytes],node);
2371 nbytes += nb;
2372 }
2373
2374 //option b.
2375 pdus = dis_node2pdus(node,isHeartbeat);
2376 if(isHeartbeat)
2377 dis_set_node_lasttime(node,lasttime);
2378
2379 if(pdus && pdus->n) {
2380 struct Pdu* pdu = vector_get(struct Pdu*,pdus,0);
2381 //printf("in dis_sendloop pdu protocol %d pdutype %d\n",pdu->protocolVersion,pdu->pduType);
2382 }
2383 nb = dis_write_stream(&buf2[nbytes],pdus);
2384 if(0){
2385 //debug
2386 printf("sendloop >>>>\n");
2387 print_stream(&buf2[nbytes], nb);
2388 printf("<<<< sendloop\n");
2389 }
2390 nbytes += nb;
2391 reset_node_pduchanged(node);
2392 }
2393 if(nbytes) socksendto(dsock,(const char *)buf2,nbytes);
2394 }
2395 }
2396}
2397/* RTP Real-time Transport Protocol
2398 optional header that can be on incoming, or put on outgoing
2399 https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
2400 https://calhoun.nps.edu/bitstream/handle/10945/9147/virtualrealitytr00afon.pdf
2401 appendix F, G show DIS header settings and source code for DIS X3D
2402 Version = 2 (default)
2403 M marker = 0
2404 CC csrc_count = 0
2405 P padding = 0
2406 X extension_bit = 0 (no extension header used)
2407 PT payloadType = 111
2408*/
2409struct rtp_header {
2410 unsigned char toprow[2];
2411 unsigned short sequence;
2412 unsigned int timestamp;
2413 unsigned int ssrc;
2414};
2415unsigned char * rtp_strip_header(unsigned char *buf, int *heard){
2416 unsigned char *carat = buf;
2417 //DIS protocoVersion is 6 (1998) or 7 (2009/2012)
2418 //so if the first byte is bigger than that it might be RTP
2419 *heard = FALSE;
2420 if(carat[0] > 127) {
2421 //its an RTP header - strip
2422 struct rtp_header rtph;
2423 int cc, i, x;
2424 *heard = TRUE;
2425 memcpy(&rtph.toprow,carat,2);
2426 carat += 2;
2427 memcpy(&rtph.sequence,carat,2);
2428 carat += 2;
2429 memcpy(&rtph.timestamp,carat,4);
2430 carat += 4;
2431 memcpy(&rtph.ssrc,carat,4);
2432 carat += 4;
2433 cc = rtph.toprow[0] << 4 >> 4;
2434 x = rtph.toprow[0] & 1 << 4;
2435 for(i=0;i<cc;i++){
2436 //skip scrc identifiers
2437 carat += 4;
2438 }
2439 if(x){
2440 //not implemented: extension header skipping
2441 }
2442 }
2443 //in the future, we could do something fancy with the sequence number, like skip stale packets.
2444 return carat;
2445}
2446unsigned char * rtp_add_header(unsigned char *buf, unsigned int timestamp){
2447 struct rtp_header rtph;
2448 unsigned char PayloadType;
2449 unsigned char *carat = buf;
2450 PayloadType = 111;
2451 memset(&rtph,0,sizeof(struct rtp_header));
2452 rtph.toprow[0] = 2 << 7 | 0 << 6 | 0 << 5 | 0;
2453 rtph.toprow[1] = 0 << 7 | PayloadType;
2454 rtph.sequence = htons(0);
2455 rtph.timestamp = htonl(timestamp);
2456 rtph.ssrc = 0;
2457 memcpy(carat,&rtph.toprow,2);
2458 carat += 2;
2459 memcpy(carat,&rtph.sequence,2);
2460 carat += 2;
2461 memcpy(carat,&rtph.timestamp,4);
2462 carat += 4;
2463 memcpy(carat,&rtph.ssrc,4);
2464 carat += 4;
2465 return carat;
2466}
2467int write_rtp(unsigned char *buf, struct X3D_Node *node){
2468 int nb = 0;
2469 int rtue = FALSE;
2470 switch(node->_nodeType){
2471 case NODE_EspduTransform:
2472 rtue = ((struct X3D_EspduTransform *)node)->rtpHeaderExpected;
2473 break;
2474 case NODE_DISEntityManager:
2475 rtue = ((struct X3D_DISEntityManager *)node)->rtpHeaderExpected;
2476 break;
2477 case NODE_ReceiverPdu:
2478 rtue = ((struct X3D_ReceiverPdu *)node)->rtpHeaderExpected;
2479 break;
2480 case NODE_TransmitterPdu:
2481 rtue = ((struct X3D_TransmitterPdu *)node)->rtpHeaderExpected;
2482 break;
2483 case NODE_SignalPdu:
2484 rtue = ((struct X3D_SignalPdu *)node)->rtpHeaderExpected;
2485 break;
2486 default:
2487 break;
2488 }
2489 if(rtue) {
2490 unsigned char *carat;
2491 unsigned int hours, timestamp;
2492 TickTime2DISTime(TickTime(),1,&hours,&timestamp);
2493 carat = rtp_add_header(buf,timestamp);
2494 nb = carat - buf;
2495 }
2496 return nb;
2497}
2498void set_rtp_heard(struct X3D_Node *node){
2499 //would be nice if we had mulitple inheritance techniques for extracting common interfaces
2500 // dis = interface(node,type_DIS)
2501 // dis->isRtpHeaderHeard = TRUE;
2502 switch(node->_nodeType){
2503 case NODE_EspduTransform:
2504 ((struct X3D_EspduTransform *)node)->isRtpHeaderHeard = TRUE;
2505 break;
2506 case NODE_DISEntityManager:
2507 ((struct X3D_DISEntityManager *)node)->isRtpHeaderHeard = TRUE;
2508 break;
2509 case NODE_ReceiverPdu:
2510 ((struct X3D_ReceiverPdu *)node)->isRtpHeaderHeard = TRUE;
2511 break;
2512 case NODE_TransmitterPdu:
2513 ((struct X3D_TransmitterPdu *)node)->isRtpHeaderHeard = TRUE;
2514 break;
2515 case NODE_SignalPdu:
2516 ((struct X3D_SignalPdu *)node)->isRtpHeaderHeard = TRUE;
2517 break;
2518 default:
2519 break;
2520 }
2521}
2522void dis_set_isActive(struct X3D_Node*node, int ival){
2523 switch(node->_nodeType){
2524 case NODE_EspduTransform:
2525 {
2526 struct X3D_EspduTransform* pnode = (struct X3D_EspduTransform*)node;
2527 if(pnode->isActive != ival){
2528 pnode->isActive = ival;
2529 MARK_EVENT(node,offsetof(struct X3D_EspduTransform,isActive));
2530 }
2531 }
2532 break;
2533 case NODE_DISEntityManager:
2534 {
2535 struct X3D_DISEntityManager* pnode = (struct X3D_DISEntityManager*)node;
2536 if(pnode->isActive != ival){
2537 pnode->isActive = ival;
2538 MARK_EVENT(node,offsetof(struct X3D_DISEntityManager,isActive));
2539 }
2540 }
2541 break;
2542 case NODE_ReceiverPdu:
2543 {
2544 struct X3D_ReceiverPdu* pnode = (struct X3D_ReceiverPdu*)node;
2545 if(pnode->isActive != ival){
2546 pnode->isActive = ival;
2547 MARK_EVENT(node,offsetof(struct X3D_ReceiverPdu,isActive));
2548 }
2549 }
2550 break;
2551 case NODE_TransmitterPdu:
2552 {
2553 struct X3D_TransmitterPdu* pnode = (struct X3D_TransmitterPdu*)node;
2554 if(pnode->isActive != ival){
2555 pnode->isActive = ival;
2556 MARK_EVENT(node,offsetof(struct X3D_TransmitterPdu,isActive));
2557 }
2558 }
2559 break;
2560 case NODE_SignalPdu:
2561 {
2562 struct X3D_SignalPdu* pnode = (struct X3D_SignalPdu*)node;
2563 if(pnode->isActive != ival){
2564 pnode->isActive = ival;
2565 MARK_EVENT(node,offsetof(struct X3D_SignalPdu,isActive));
2566 }
2567 }
2568 break;
2569 default:
2570 break;
2571 }
2572}
2573
2574void dis_set_isNetworkMode(struct X3D_Node*node, int networkMode){
2575 int isStandAlone, isNetworkReader, isNetworkWriter;
2576 isStandAlone = isNetworkReader = isNetworkWriter = 0;
2577 switch(networkMode){
2578 case 0: isStandAlone = TRUE; break;
2579 case 1: isNetworkReader = TRUE; break;
2580 case 2: isNetworkWriter = TRUE; break;
2581 default: break;
2582 }
2583 switch(node->_nodeType){
2584 case NODE_EspduTransform:
2585 {
2586 struct X3D_EspduTransform* pnode = (struct X3D_EspduTransform*)node;
2587 if(pnode->isStandAlone != isStandAlone){
2588 pnode->isStandAlone = isStandAlone;
2589 MARK_EVENT(node,offsetof(struct X3D_EspduTransform,isStandAlone));
2590 }
2591 if(pnode->isNetworkReader != isNetworkReader){
2592 pnode->isNetworkReader = isNetworkReader;
2593 MARK_EVENT(node,offsetof(struct X3D_EspduTransform,isNetworkReader));
2594 }
2595 if(pnode->isNetworkWriter != isNetworkWriter){
2596 pnode->isNetworkWriter = isNetworkWriter;
2597 MARK_EVENT(node,offsetof(struct X3D_EspduTransform,isNetworkWriter));
2598 }
2599 }
2600 break;
2601 case NODE_DISEntityManager:
2602 {
2603 struct X3D_DISEntityManager* pnode = (struct X3D_DISEntityManager*)node;
2604 if(pnode->isStandAlone != isStandAlone){
2605 pnode->isStandAlone = isStandAlone;
2606 MARK_EVENT(node,offsetof(struct X3D_DISEntityManager,isStandAlone));
2607 }
2608 if(pnode->isNetworkReader != isNetworkReader){
2609 pnode->isNetworkReader = isNetworkReader;
2610 MARK_EVENT(node,offsetof(struct X3D_DISEntityManager,isNetworkReader));
2611 }
2612 if(pnode->isNetworkWriter != isNetworkWriter){
2613 pnode->isNetworkWriter = isNetworkWriter;
2614 MARK_EVENT(node,offsetof(struct X3D_DISEntityManager,isNetworkWriter));
2615 }
2616 }
2617 break;
2618 case NODE_ReceiverPdu:
2619 {
2620 struct X3D_ReceiverPdu* pnode = (struct X3D_ReceiverPdu*)node;
2621 if(pnode->isStandAlone != isStandAlone){
2622 pnode->isStandAlone = isStandAlone;
2623 MARK_EVENT(node,offsetof(struct X3D_EspduTransform,isStandAlone));
2624 }
2625 if(pnode->isNetworkReader != isNetworkReader){
2626 pnode->isNetworkReader = isNetworkReader;
2627 MARK_EVENT(node,offsetof(struct X3D_EspduTransform,isNetworkReader));
2628 }
2629 if(pnode->isNetworkWriter != isNetworkWriter){
2630 pnode->isNetworkWriter = isNetworkWriter;
2631 MARK_EVENT(node,offsetof(struct X3D_EspduTransform,isNetworkWriter));
2632 }
2633 }
2634 break;
2635 case NODE_TransmitterPdu:
2636 {
2637 struct X3D_TransmitterPdu* pnode = (struct X3D_TransmitterPdu*)node;
2638 if(pnode->isStandAlone != isStandAlone){
2639 pnode->isStandAlone = isStandAlone;
2640 MARK_EVENT(node,offsetof(struct X3D_EspduTransform,isStandAlone));
2641 }
2642 if(pnode->isNetworkReader != isNetworkReader){
2643 pnode->isNetworkReader = isNetworkReader;
2644 MARK_EVENT(node,offsetof(struct X3D_EspduTransform,isNetworkReader));
2645 }
2646 if(pnode->isNetworkWriter != isNetworkWriter){
2647 pnode->isNetworkWriter = isNetworkWriter;
2648 MARK_EVENT(node,offsetof(struct X3D_EspduTransform,isNetworkWriter));
2649 }
2650 }
2651 break;
2652 case NODE_SignalPdu:
2653 {
2654 struct X3D_SignalPdu* pnode = (struct X3D_SignalPdu*)node;
2655 if(pnode->isStandAlone != isStandAlone){
2656 pnode->isStandAlone = isStandAlone;
2657 MARK_EVENT(node,offsetof(struct X3D_EspduTransform,isStandAlone));
2658 }
2659 if(pnode->isNetworkReader != isNetworkReader){
2660 pnode->isNetworkReader = isNetworkReader;
2661 MARK_EVENT(node,offsetof(struct X3D_EspduTransform,isNetworkReader));
2662 }
2663 if(pnode->isNetworkWriter != isNetworkWriter){
2664 pnode->isNetworkWriter = isNetworkWriter;
2665 MARK_EVENT(node,offsetof(struct X3D_EspduTransform,isNetworkWriter));
2666 }
2667 }
2668 break;
2669 default:
2670 break;
2671 }
2672}
2673int dis_read_stream(unsigned char * datastream, int streamsize, struct Vector *pdus, int *heard)
2674{
2675 int pdutype, bytesread;
2676 unsigned char *carat, *carat2;
2677 static char pdubuffer[10000];
2678 unsigned char *pdubuf;
2679 struct Pdu* pdu;
2680 bytesread = 0;
2681 carat = &datastream[0];
2682 carat = rtp_strip_header(carat,heard);
2683 while(bytesread < streamsize){
2684 int i, distype, nbytes;
2685 if(0) for(i=0;i<210;i+=10){
2686 int j;
2687 printf("%d\t",i);
2688 for(j=0;j<10;j++){
2689 printf("%5d",(int)carat[i+j]);
2690 }
2691 printf("\n");
2692 }
2693 pdutype = (int)(carat[2]);
2694 distype = pduToDis(pdutype);
2695 //printf("pdu type=%d distype=%d",(int)pdutype, distype);
2696
2697 pdubuf = dis_ctor(distype);
2698 carat2 = dis_unmarshal(carat,pdubuf,distype);
2699 nbytes = (carat2 - carat);
2700 pdu = (struct Pdu*)pdubuf;
2701 //printf("un-marshed version %d pdutype= %d\n",pdu->protocolVersion,pdu->pduType);
2702 vector_pushBack(struct Pdu*,pdus,pdu);
2703 //printf("unmarshed bits %d bytes %d\n",nbytes*8,nbytes);
2704
2705 if(0){
2706 //try marshalling, then compare bytestreams
2707 unsigned char buf3[32000];
2708 unsigned char *carat3;
2709 int b3size;
2710 carat3 = dis_marshal(buf3,pdubuf,distype);
2711 b3size = carat3 - buf3;
2712 printf("marshed bits %d bytes %d\n",b3size*8,b3size);
2713
2714 if(memcmp(carat,buf3,b3size) == 0)
2715 printf("bravo\n");
2716 else{
2717 printf("youch\n");
2718 for(i=0;i<210;i+=10){
2719 int j;
2720 printf("%d\t",i);
2721 for(j=0;j<10;j++){
2722 printf("%5d",(int)buf3[i+j]);
2723 }
2724 printf("\n");
2725 }
2726 }
2727
2728 }
2729
2730
2731 if(0) if(pdutype == 1){
2732 int n;
2733 struct EntityStatePdu* p = (struct EntityStatePdu*)pdubuf;
2734 printf("loc %lf %lf %lf rot %f %f %f\n",
2737#ifdef DIS2012
2738 n = p->numberOfVariableParameters;
2739#else //DIS1998
2741#endif
2742 if(n){
2743 //unsigned char recordType;
2745 //double variableParameterFields1;
2747 //unsigned int variableParameterFields2;
2749 //unsigned short variableParameterFields3;
2751 //unsigned char variableParameterFields4;
2752 //struct VariableParameter *v;
2753
2754#ifdef DIS2012
2755 struct ArticulatedParts *v;
2756 v = (struct ArticulatedParts*)p->variableParameters;
2757 printf("v address = %p\n",v);
2758 //v = *vlist;
2759 for(i=0;i<n;i++){
2760 printf("%d %d %d %d %d %lf\n",
2761 i,
2762 (int)v[i].recordType,
2763 (int)v[i].changeIndicator,
2764 (int)v[i].partAttachedTo,
2765 (int)v[i].parameterType,
2766 v[i].parameterValue
2767 );
2768 }
2769#else //DIS1998
2770 struct ArticulationParameter *v;
2772 printf("v address = %p\n",v);
2773 //v = *vlist;
2774 for(i=0;i<n;i++){
2775 printf("%d %d %d %d %d %lf\n",
2776 i,
2777 (int)v[i].parameterTypeDesignator,
2778 (int)v[i].changeIndicator,
2779 (int)v[i].partAttachedTo,
2780 (int)v[i].parameterType,
2781 v[i].parameterValue
2782 );
2783 }
2784#endif
2785 }
2786 }
2787 //dis_dtor(pdubuf,distype);
2788 bytesread += nbytes;
2789 carat = carat2;
2790 //printf("bytes left = %d - %d = %d\n",streamsize, (int)(carat - datastream), streamsize - (int)(carat-datastream));
2791 //printf("\n");
2792 //if(0) for(i=0;i<npdus;i++){
2793 // if(registeredPdus[i]->pduType == pdutype){
2794 // //I think there should be more filtering here
2795 // //for example is it the right target IP + port + entityID?
2796 // memcpy(registeredPdus[i],pdubuffer,nbytes);
2797 // break;
2798 // }
2799 //}
2800 }
2801 return 0; //maybe an error number will be returned here in future
2802}
2803
2804int dis_write_stream(unsigned char * datastream, struct Vector *pdus)
2805{
2806 //missing maxsize on buffer
2807 int i, nbytes;
2808 unsigned char *carat;
2809 carat = datastream;
2810 nbytes = 0;
2811 if(pdus && pdus->n){
2812 for(i=0;i<pdus->n;i++){
2813 struct Pdu *pdu = vector_get(struct Pdu*,pdus,i);
2814 //printf("dis_wrt_str protocol %d pdutype %d\n",pdu->protocolVersion,pdu->pduType);
2815 int distype = pduToDis(pdu->pduType);
2816 carat = dis_marshal(carat,(unsigned char*)pdu,distype);
2817 //printf("pdu %d wrote %d bytes\n",i,nbytes);
2818 }
2819 // *streamsize = nbytes;
2820 nbytes = (int)(carat - datastream);
2821 }
2822 return nbytes;
2823}
2824
2825
2826
2827static double lasttime;
2828static char buf[32768];
2829static struct Vector *pdus = NULL;
2830void dis_recvloop(){
2831 //there are a few ways to do non-blocking recv
2832 //1. ioctlsocket non-blocking - set socket to not block
2833 //2. select() - select itself blocks, so should have its own thread
2834 //3. PEEK flag in recvfrom
2835 //Oct 24, 2017 choice: 1.
2836 // - because we aren't doing a separate thread yet, so 1 or 3, and 3 worked when tried first
2837 int i,j,nbytes, more, heard;
2838 static int count = 0;
2839 double thistime, dtime;
2840 if(!sockets_recv || sockets_recv->n == 0) return;
2841 thistime = TickTime();
2842 dtime = thistime - lasttime;
2843 if(!pdus) pdus = newVector(struct Pdu*,20);
2844
2845 //since not select()ing we have to check all sockets (if readInterval?)
2846 //for 'Entity Discovery' at least one DIS node needs to be in scene, with IP/port to check
2847 for(i=0;i<sockets_recv->n;i++){
2848 struct dis_socket *dsock = vector_get_ptr(struct dis_socket,sockets_recv,i);
2849 //things may have built up in the input socket, so we loop till flushed
2850 do{
2851 struct X3D_DISEntityManager* sockem = NULL;
2852 heard = FALSE;
2853 more = FALSE;
2854 nbytes = sockrecvfrom(dsock,buf,32000);
2855 if(nbytes > 0){
2856 int nhit = 0;
2857 more = TRUE;
2858 dsock->lasttime = thistime;
2859 //printf("sock read nbytes = %d\n",nbytes);
2860 //free last round
2861 for(j=0;j<pdus->n;j++){
2862 struct Pdu* pdu = vector_get(struct Pdu*,pdus,j);
2863 dis_dtor((unsigned char *)pdu,pduToDis(pdu->pduType));
2864 }
2865 pdus->n = 0;
2866 dis_read_stream((unsigned char *)buf,nbytes,pdus,&heard);
2867 //print some stuff to the console, to prove we got a state update
2868 //printf("hallelluha %d\n",count++);
2869 //check pdus against all nodes registered on the port
2870 // in case the message is for an existing node
2871
2872 if(dsock->registered){
2873 for(j=0;j<dsock->registered->n;j++){
2874 int ihit;
2875 struct X3D_Node *node = vector_get(struct X3D_Node*,dsock->registered,j);
2876 //check site and application ID
2877 //distribute to registered nodes by entityID
2878 ihit = 0;
2879 switch(node->_nodeType){
2880 case NODE_EspduTransform:
2881 ihit = dis_pdus2node_espdu(node, pdus);
2882 break;
2883 case NODE_DISEntityManager:
2884 sockem = (struct X3D_DISEntityManager*) node;
2885 ihit = dis_pdus2node_sm(node, pdus);
2886 break;
2887 case NODE_ReceiverPdu:
2888 ihit = dis_pdus2node_receiver(node, pdus);
2889 break;
2890 case NODE_TransmitterPdu:
2891 ihit = dis_pdus2node_transmitter(node, pdus);
2892 break;
2893 case NODE_SignalPdu:
2894 ihit = dis_pdus2node_signal(node, pdus);
2895 break;
2896 default:
2897 break;
2898 }
2899 if(ihit){
2900 if(heard) set_rtp_heard(node);
2901 dis_set_isActive(node,TRUE);
2902 dis_set_node_lasttime(node,thistime);
2903 nhit += ihit;
2904 }
2905 }
2906 }
2907 if(nhit == 0){
2908 // any 'left-over' pdus might be 'entity discovery' candidates
2909 printf("leftovers ...");
2910 nhit = dis_pdus2newnode(dsock,sockem, pdus);
2911 printf(" %d used\n",nhit);
2912 }
2913 }
2914 }while(more);
2915 if(dsock->registered){
2916 //check if any node listeners have gone inactive
2917 struct X3D_DISEntityManager* sockem = NULL;
2918 for(j=0;j<dsock->registered->n;j++){
2919 struct X3D_Node *node = vector_get(struct X3D_Node*,dsock->registered,j);
2920 if(node->_nodeType == NODE_DISEntityManager){
2921 sockem = (struct X3D_DISEntityManager*)node;
2922 }
2923 if(sockem) break;
2924 }
2925 for(j=0;j<dsock->registered->n;j++){
2926 //update isActive
2927 double readinterval, writeinterval, lasttime;
2928 struct X3D_Node *node = vector_get(struct X3D_Node*,dsock->registered,j);
2929 dis_get_node_lasttime(node,&lasttime,&readinterval,&writeinterval);
2930 if(thistime - lasttime > 5.0) {
2931 //5 second rule: if a node recvs nothing for 5 seconds, turn isActive to FALSE.
2932 dis_set_isActive(node,FALSE);
2933 }
2934 //if its been several (?) heartbeat increments since we last heard from an entity
2935 // the DIS specs talk about removing (opposite of adding by 'entity discovery')
2936 if(thistime - lasttime > (5.0 * 3) ){
2937 //if in entitymanager state.entities, removeChildren
2938 int ihit = 0;
2939 if(sockem && node->_nodeType == NODE_EspduTransform ){
2940 ihit = dis_entity_retire(sockem,node);
2941 }
2942 if(ihit == 1) {
2943 printf(" retired one\n");
2944 //printf("thisttime %lf lasttime %lf\n",thistime,lasttime);
2945 }
2946 //if(ihit == -1) printf(" cetiree not in EM list\n");
2947 }
2948 }
2949 if(sockem && sockem->removedEntities.n) {
2950 //printf("removedEntities.n=%d\n",node->removedEntities.n);
2951 MARK_EVENT(X3D_NODE(sockem),offsetof(struct X3D_DISEntityManager,removedEntities));
2952 }
2953
2954 }
2955 }
2956
2957}
2958
2959void dis_open_socket(struct dis_socket* dsock){
2960 if(dsock->multicastRelayHost && strlen(dsock->multicastRelayHost)){
2961 printf("[%s]\n",dsock->multicastRelayHost);
2962 printf("\n");
2963 //direct socket
2964 }else{
2965 socket_open(dsock);
2966 }
2967
2968}
2969void *dis_register(struct X3D_Node* node,char *address,int applicationID,int entityID,char *multicastRelayHost,
2970 int multicastRelayPort,
2971 char *networkMode, int port,double readInterval,int rtpHeaderExpected,int siteID,double writeInterval){
2972 void *preg; //something to store in the node, to say which socket its registerd in
2973 int inetworkmode = 0;
2974 if(!strcmp(networkMode,"standAlone")) inetworkmode = 0;
2975 else if(!strcmp(networkMode,"networkReader")) inetworkmode = 1;
2976 else if(!strcmp(networkMode,"networkWriter")) inetworkmode = 2;
2977 preg = NULL;
2978 if(inetworkmode == 0) preg = NULL; //not joined/registered to any socket
2979 if(inetworkmode == 1){
2980 int i, j, ifound;
2981 struct dis_socket *dsock;
2982 if(!sockets_recv) sockets_recv = newVector(struct dis_socket,10);
2983 //if theres a (networkMode,address,port) tuple already registered, then we join
2984 ifound = -1;
2985 dsock = NULL;
2986 for(i=0;i<sockets_recv->n;i++){
2987 dsock = vector_get_ptr(struct dis_socket,sockets_recv,i);
2988 if(!strcmp(dsock->address,address) && dsock->port == port){
2989 //if(dsock->registered){
2990 // for(j=0;j<dsock->registered->n;j++){
2991 // we assume its not registered
2992 // }
2993 //}
2994 ifound = i;
2995 break;
2996 }
2997 }
2998 if(ifound == -1){
2999 //create a socket
3000 struct dis_socket asock;
3001 memset(&asock,0,sizeof(struct dis_socket));
3002 vector_pushBack(struct dis_socket,sockets_recv,asock);
3003 dsock = vector_get_ptr(struct dis_socket,sockets_recv,sockets_recv->n-1);
3004 dsock->address = address;
3005 dsock->port = port;
3006 dsock->multicastRelayHost = multicastRelayHost;
3007 dsock->multicastRelayPort = multicastRelayPort;
3008 dsock->idir = inetworkmode;
3009 //open port
3010 dis_open_socket(dsock);
3011 }
3012 //join socket
3013 if(!dsock->registered) dsock->registered = newVector(struct X3D_Node*,20);
3014 vector_pushBack(struct X3D_Node*,dsock->registered,node);
3015 preg = (void*)dsock;
3016 }
3017 if(inetworkmode==2){
3018 int i, j, ifound;
3019 struct dis_socket *dsock;
3020 if(!sockets_send) sockets_send = newVector(struct dis_socket,10);
3021 //if theres a (networkMode,address,port) tuple already registered, then we join
3022 ifound = -1;
3023 dsock = NULL;
3024 for(i=0;i<sockets_send->n;i++){
3025 dsock = vector_get_ptr(struct dis_socket,sockets_send,i);
3026 if(!strcmp(dsock->address,address) && dsock->port == port){
3027 //if(dsock->registered){
3028 // for(j=0;j<dsock->registered->n;j++){
3029 // we assume its not registered
3030 // }
3031 //}
3032 ifound = i;
3033 break;
3034 }
3035 }
3036 if(ifound == -1){
3037 //create a socket
3038 struct dis_socket asock;
3039 memset(&asock,0,sizeof(struct dis_socket));
3040 vector_pushBack(struct dis_socket,sockets_send,asock);
3041 dsock = vector_get_ptr(struct dis_socket,sockets_send,sockets_send->n-1);
3042 dsock->address = address;
3043 dsock->port = port;
3044 dsock->multicastRelayHost = multicastRelayHost;
3045 dsock->multicastRelayPort = multicastRelayPort;
3046 dsock->idir = inetworkmode;
3047 //open port
3048 dis_open_socket(dsock);
3049 }
3050 //join socket
3051 if(!dsock->registered) dsock->registered = newVector(struct X3D_Node*,20);
3052 vector_pushBack(struct X3D_Node*,dsock->registered,node);
3053 preg = (void*)dsock;
3054 }
3055 dis_set_isNetworkMode(node, inetworkmode);
3056 return preg;
3057}
3058void dis_unregister(struct dis_socket * dsock, struct X3D_Node* node){
3059 //unregister / un-join node from socket
3060 int j;
3061 if(dsock->registered){
3062 for(j=0;j<dsock->registered->n;j++){
3063 if(vector_get(struct X3D_Node*,dsock->registered,j)==node){
3064 vector_remove_elem(struct X3D_Node*,dsock->registered,j);
3065 break;
3066 }
3067 }
3068 }
3069}
3070int dis_check_socket_change(struct dis_socket* dsock,char *address, int port,
3071 char *multicastRelayHost, int multicastRelayPort, char *networkMode){
3072 //do the node fields still jive/match with the socket it joined?
3073 //(a weakness of the freewrl architecture: there's no per-field change flag
3074 //so if a node with a zillion fields is flagged as changed, we have to
3075 //re-'compile' the whole node, or save old values in _old fields on the node for comparison,
3076 //or (more normally) MARK_EVENT(node,offset) which runs through lists of registered routes.
3077 //here we are comparing a few fields with 'what they must have been when registered')
3078 //IDEA: save a duplicate of the node in _oldNode field, so can compare 1:1 with any field
3079
3080 int inetworkmode = 0;
3081 if(!strcmp(networkMode,"standAlone")) inetworkmode = 0;
3082 else if(!strcmp(networkMode,"networkReader")) inetworkmode = 1;
3083 else if(!strcmp(networkMode,"networkWriter")) inetworkmode = 2;
3084 if(inetworkmode == 0 && dsock == NULL) return FALSE; //not registered, and no need to register
3085 if(dsock == NULL) return TRUE; //need to register
3086 if(inetworkmode != dsock->idir) return TRUE; //change of direction
3087 if(strcmp(address,dsock->address)) return TRUE; //change of address
3088 if(port != dsock->port) return TRUE; //change of port
3089 if(strcmp(multicastRelayHost,dsock->multicastRelayHost)) return TRUE;
3090 if(multicastRelayPort != dsock->multicastRelayPort) return TRUE;
3091
3092 return FALSE;
3093}
3094// freewrl problem: _changed flag is per-node
3095// x but its bad DIS ettiquette to resend pdus that haven't changed
3096// to detect per-pdu changes:
3097// 1. during node_compile
3098// 1.a do once: create node->_oldstate and register for disposal, copy node to _oldstate
3099// 1.b compare _oldState and node
3100// - compare fields per-pdu, and flag per-pdu
3101// common flags:
3102// _pduchange_networksensor
3103// per-pdu flags:
3104// espdu
3105// _pduchange_deadreckoning
3106// _pduchange_articulationparameters
3107// _pduchange_collision
3108// _pduchange_fire
3109// _pduchange_detonation
3110// recieverpdu
3111// _pduchange_receiver
3112// signalpdu
3113// _pduchange_signal
3114// transmitterpdu
3115// _pduchange_transmitter
3116// 1.c copy node fields to _oldState
3117// 1.d mark node compiled
3118// 2. in dis_sendloop only send pdus that changed
3119void shallow_copy_node(struct X3D_Node *copy, struct X3D_Node *original )
3120{
3121 //we just want to copy the public fields, not our private _ fields
3122 // which include things like _pduchange_espdutransform etc
3123 // same for later when we compare, just the public fields
3124 const int *offset;
3125 unsigned char *src, *dest;
3126 src = (unsigned char *)original;
3127 dest = (unsigned char *)copy;
3128
3129 offset = NODE_OFFSETS[original->_nodeType];
3130 while(offset[0] > -1){
3131 if(offset[4] > 0){
3132 //offset[4] is the specs attribute, and if its a private field ie _name then it should have 0
3133 // we just want the public fields here
3134 union anyVrml *anysrc, *anydest;
3135 anysrc = (union anyVrml*)(src + offset[1]);
3136 anydest = (union anyVrml*)(dest + offset[1]);
3137 shallow_copy_field(offset[2],anysrc,anydest);
3138 }
3139 offset += 6;
3140 };
3141}
3142int shallow_compare_field(int typeIndex, union anyVrml* source, union anyVrml* dest)
3143{
3144 int i, isize, has_changed;
3145 int sftype, isMF;
3146 struct Multi_Node *mfs,*mfd;
3147 has_changed = FALSE;
3148
3149 isMF = typeIndex % 2;
3150 sftype = typeIndex - isMF;
3151 //from EAI_C_CommonFunctions.c
3152 //isize = returnElementLength(sftype) * returnElementRowSize(sftype);
3153 isize = sizeofSForMF(sftype);
3154 if(isMF)
3155 {
3156 int nele;
3157 char *ps, *pd;
3158 mfs = (struct Multi_Node*)source;
3159 mfd = (struct Multi_Node*)dest;
3160 //self assignment is no-op
3161 if(mfs->n != mfd->n){
3162 has_changed = TRUE;
3163 }else{
3164 ps = (char *)mfs->p;
3165 pd = (char *)mfd->p;
3166 for(i=0;i<mfs->n;i++)
3167 {
3168 has_changed = shallow_compare_field(sftype,(union anyVrml*)ps,(union anyVrml*)pd);
3169 ps += isize;
3170 pd += isize;
3171 }
3172 }
3173 }else{
3174 //isSF
3175 switch(typeIndex)
3176 {
3177 case FIELDTYPE_SFString:
3178 {
3179 //go deep, same as copy_field
3180 struct Uni_String **ss, **sd;
3181 if(source != dest){
3182 has_changed = TRUE;
3183 }else{
3184 ss = (struct Uni_String **)source;
3185 sd = (struct Uni_String **)dest;
3186 if(*ss && *sd){
3187 has_changed = memcmp(*sd,*ss,sizeof(struct Uni_String)) ? TRUE : FALSE;
3188 }
3189 }
3190 }
3191 break;
3192 default:
3193 //memcpy(dest,source,sizeof(union anyVrml));
3194 has_changed = memcmp(dest,source,isize) ? TRUE : FALSE;
3195 break;
3196 }
3197 }
3198 return has_changed;
3199} //return copy_field
3200
3201int shallow_compare_node_fields(struct X3D_Node *node, struct X3D_Node *old, const int *PFIELDS){
3202 const int *fname, *offset;
3203 unsigned char *src, *dest;
3204 int k, has_changed;
3205
3206 src = (unsigned char *)old;
3207 dest = (unsigned char *)node;
3208 fname = PFIELDS;
3209 k = 0;
3210 has_changed = 0;
3211 while(fname[k] > -1){
3212 offset = NODE_OFFSETS[node->_nodeType];
3213 while(offset[0] > -1){
3214 if(offset[0] == fname[k]){
3215 union anyVrml *anysrc, *anydest;
3216 anysrc = (union anyVrml*)(src + offset[1]);
3217 anydest = (union anyVrml*)(dest + offset[1]);
3218 has_changed += shallow_compare_field(offset[2],anysrc,anydest);
3219 break;
3220 }
3221 offset += 6;
3222 };
3223 k++;
3224 };
3225 return has_changed ? TRUE : FALSE;
3226}
3227
3228int mark_changed_node_fields(struct X3D_Node *node, struct X3D_Node *old, const int *PFIELDS){
3229 const int *fname, *offset;
3230 unsigned char *src, *dest;
3231 int k, count;
3232
3233 src = (unsigned char *)old;
3234 dest = (unsigned char *)node;
3235 fname = PFIELDS;
3236 k = 0;
3237 count = 0;
3238 while(fname[k] > -1){
3239 offset = NODE_OFFSETS[node->_nodeType];
3240 while(offset[0] > -1){
3241 if(offset[0] == fname[k]){
3242 union anyVrml *anysrc, *anydest;
3243 anysrc = (union anyVrml*)(src + offset[1]);
3244 anydest = (union anyVrml*)(dest + offset[1]);
3245 if(shallow_compare_field(offset[2],anysrc,anydest)){
3246 MARK_EVENT(node,offset[1]);
3247 count++;
3248 }
3249 break;
3250 }
3251 offset += 6;
3252 };
3253 k++;
3254 };
3255 return count;
3256}
3257
3258//here are some per-pdu lists of public fields, useful for detecting per-pdu field changes
3259
3260const int FIELDS_networksensor [] = {
3261 FIELDNAMES_enabled,
3262 FIELDNAMES_isActive,
3263 FIELDNAMES_timestamp,
3264 FIELDNAMES_address,
3265 FIELDNAMES_port,
3266 FIELDNAMES_multicastRelayHost,
3267 FIELDNAMES_multicastRelayPort,
3268 FIELDNAMES_networkMode,
3269 FIELDNAMES_isNetworkReader,
3270 FIELDNAMES_isNetworkWriter,
3271 FIELDNAMES_isStandAlone,
3272 FIELDNAMES_readInterval,
3273 FIELDNAMES_writeInterval,
3274 FIELDNAMES_rtpHeaderExpected,
3275 FIELDNAMES_isRtpHeaderHeard,
3276 //FIELDNAMES__registered, //not the private fields
3277 //FIELDNAMES__dsock,
3278 //FIELDNAMES__lasttime,
3279 -1,
3280};
3281
3282const int FIELDS_entity [] = {
3283 FIELDNAMES_entityID,
3284 FIELDNAMES_applicationID,
3285 FIELDNAMES_siteID,
3286 -1,
3287};
3288
3289const int FIELDS_geo [] = {
3290 FIELDNAMES_geoSystem,
3291 FIELDNAMES_geoCoords,
3292 -1,
3293};
3294const int FIELDS_geosys [] = {
3295 FIELDNAMES_geoSystem,
3296 -1,
3297};
3298const int FIELDS_geocoord [] = {
3299 FIELDNAMES_geoCoords,
3300 -1,
3301};
3302
3303
3304const int FIELDS_em_info [] = {
3305 FIELDNAMES_entityCategory,
3306 FIELDNAMES_entityCountry,
3307 FIELDNAMES_entityDomain,
3308 FIELDNAMES_entityExtra,
3309 FIELDNAMES_entityKind,
3310 FIELDNAMES_entitySpecific,
3311 FIELDNAMES_entitySubCategory,
3312 -1,
3313};
3314const int FIELDS_create [] = {
3315 FIELDNAMES_addedEntities,
3316 -1,
3317};
3318const int FIELDS_remove [] = {
3319 FIELDNAMES_removedEntities,
3320 -1,
3321};
3322
3323const int FIELDS_es_force [] = {
3324 FIELDNAMES_forceID,
3325 //FIELDNAMES_marking,
3326 -1,
3327};
3328
3329const int FIELDS_es_transform [] = {
3330 FIELDNAMES_center,
3331 FIELDNAMES_children,
3332 FIELDNAMES_rotation,
3333 FIELDNAMES_scale,
3334 FIELDNAMES_scaleOrientation,
3335 FIELDNAMES_translation,
3336 //FIELDNAMES_bboxCenter,
3337 //FIELDNAMES_bboxSize,
3338 -1,
3339};
3340
3341
3342const int FIELDS_es_deadreckoning [] = {
3343 FIELDNAMES_deadReckoning,
3344 FIELDNAMES_linearVelocity,
3345 FIELDNAMES_linearAcceleration,
3346 -1,
3347};
3348
3349const int FIELDS_es_articulation [] = {
3350 FIELDNAMES_set_articulationParameterValue0,
3351 FIELDNAMES_set_articulationParameterValue1,
3352 FIELDNAMES_set_articulationParameterValue2,
3353 FIELDNAMES_set_articulationParameterValue3,
3354 FIELDNAMES_set_articulationParameterValue4,
3355 FIELDNAMES_set_articulationParameterValue5,
3356 FIELDNAMES_set_articulationParameterValue6,
3357 FIELDNAMES_set_articulationParameterValue7,
3358 FIELDNAMES_articulationParameterCount,
3359 FIELDNAMES_articulationParameterDesignatorArray,
3360 FIELDNAMES_articulationParameterChangeIndicatorArr,
3361 FIELDNAMES_articulationParameterIdPartAttachedToAr,
3362 FIELDNAMES_articulationParameterTypeArray,
3363 FIELDNAMES_articulationParameterArray,
3364 FIELDNAMES_articulationParameterValue0_changed,
3365 FIELDNAMES_articulationParameterValue1_changed,
3366 FIELDNAMES_articulationParameterValue2_changed,
3367 FIELDNAMES_articulationParameterValue3_changed,
3368 FIELDNAMES_articulationParameterValue4_changed,
3369 FIELDNAMES_articulationParameterValue5_changed,
3370 FIELDNAMES_articulationParameterValue6_changed,
3371 FIELDNAMES_articulationParameterValue7_changed,
3372 -1,
3373};
3374
3375const int FIELDS_collision [] = {
3376 FIELDNAMES_collisionType,
3377 FIELDNAMES_collideTime,
3378 FIELDNAMES_isCollided,
3379 -1,
3380};
3381
3382const int FIELDS_events [] = {
3383 FIELDNAMES_eventEntityID,
3384 FIELDNAMES_eventApplicationID,
3385 FIELDNAMES_eventSiteID,
3386 FIELDNAMES_eventNumber,
3387 -1,
3388};
3389
3390const int FIELDS_fire [] = {
3391 FIELDNAMES_fired1,
3392 FIELDNAMES_fired2,
3393 FIELDNAMES_fireMissionIndex,
3394 FIELDNAMES_firingRange,
3395 FIELDNAMES_firedTime,
3396 -1,
3397};
3398
3399const int FIELDS_detonation [] = {
3400 FIELDNAMES_detonationLocation,
3401 FIELDNAMES_detonationRelativeLocation,
3402 FIELDNAMES_detonationResult,
3403 FIELDNAMES_detonateTime,
3404 FIELDNAMES_isDetonated,
3405 -1,
3406};
3407
3408const int FIELDS_munition [] = {
3409 FIELDNAMES_munitionEntityID,
3410 FIELDNAMES_munitionApplicationID,
3411 FIELDNAMES_munitionSiteID,
3412 FIELDNAMES_munitionStartPoint,
3413 FIELDNAMES_munitionEndPoint,
3414 FIELDNAMES_munitionQuantity,
3415 -1,
3416};
3417const int FIELDS_rate [] = {
3418 FIELDNAMES_firingRate,
3419 FIELDNAMES_fuse,
3420 FIELDNAMES_warhead,
3421 -1,
3422};
3423
3424const int FIELDS_receiver [] = {
3425 FIELDNAMES_radioID,
3426 FIELDNAMES_whichGeometry,
3427 FIELDNAMES_receiverState,
3428 FIELDNAMES_receivedPower,
3429 FIELDNAMES_transmitterEntityID,
3430 FIELDNAMES_transmitterApplicationID,
3431 FIELDNAMES_transmitterSiteID,
3432 FIELDNAMES_transmitterRadioID,
3433 -1,
3434};
3435
3436const int FIELDS_signal [] = {
3437 FIELDNAMES_radioID,
3438 FIELDNAMES_whichGeometry,
3439 FIELDNAMES_data,
3440 FIELDNAMES_dataLength,
3441 FIELDNAMES_encodingScheme,
3442 FIELDNAMES_sampleRate,
3443 FIELDNAMES_samples,
3444 FIELDNAMES_tdlType,
3445 -1,
3446};
3447
3448const int FIELDS_transmitter [] = {
3449 FIELDNAMES_radioID,
3450 FIELDNAMES_whichGeometry,
3451 FIELDNAMES_radioEntityTypeCategory,
3452 FIELDNAMES_radioEntityTypeCountry,
3453 FIELDNAMES_radioEntityTypeDomain,
3454 FIELDNAMES_radioEntityTypeKind,
3455 FIELDNAMES_radioEntityTypeNomenclature,
3456 FIELDNAMES_radioEntityTypeNomenclatureVersion,
3457 FIELDNAMES_antennaLocation,
3458 FIELDNAMES_antennaPatternLength,
3459 FIELDNAMES_antennaPatternType,
3460 FIELDNAMES_relativeAntennaLocation,
3461 FIELDNAMES_inputSource,
3462 FIELDNAMES_transmitState,
3463 FIELDNAMES_power,
3464 FIELDNAMES_frequency,
3465 FIELDNAMES_transmitFrequencyBandwidth,
3466 FIELDNAMES_lengthOfModulationParameters,
3467 FIELDNAMES_modulationTypeDetail,
3468 FIELDNAMES_modulationTypeMajor,
3469 FIELDNAMES_modulationTypeMajor,
3470 FIELDNAMES_modulationTypeSpreadSpectrum,
3471 FIELDNAMES_modulationTypeSystem,
3472 FIELDNAMES_cryptoSystem,
3473 FIELDNAMES_cryptoKeyID,
3474 -1,
3475};
3476
3477void compile_DIS_network(struct X3D_EspduTransform *node){
3478 if(node->_oldState == NULL){
3479 //change detection
3480 //later we'll copy the entire node after we detect any changed fields
3481 struct X3D_Node *old;
3482 old = createNewX3DNode0(node->_nodeType);
3483 //shallow_copy_node(old,X3D_NODE(node));
3484 node->_oldState = old; //I think one underscore means dispose
3485 }
3486 if(!node->_registered){
3487 void *psock;
3488 psock = dis_register(X3D_NODE(node),node->address->strptr,node->applicationID,node->entityID,node->multicastRelayHost->strptr,
3489 node->multicastRelayPort,
3490 node->networkMode->strptr, node->port,node->readInterval,node->rtpHeaderExpected,node->siteID,node->writeInterval);
3491 node->_registered = TRUE;
3492 node->_dsock = psock;
3493 }
3494 if(node->_registered){
3495 //almost every field is [in,out] so can be changed at runtime
3496 //IDEA: save duplicate of nodetype in _oldnode field
3497 if(shallow_compare_node_fields(X3D_NODE(node),node->_oldState,FIELDS_networksensor)){
3498 int changed;
3499 changed = dis_check_socket_change((struct dis_socket*)node->_dsock,node->address->strptr, node->port,
3500 node->multicastRelayHost->strptr,node->multicastRelayPort, node->networkMode->strptr);
3501 if(changed){
3502 dis_unregister((struct dis_socket*)node->_dsock,X3D_NODE(node));
3503 node->_registered = FALSE;
3504 node->_dsock = NULL;
3505 }
3506 }
3507 }
3508}
3509void compile_DIS_geo(struct X3D_EspduTransform *node){
3510 //Apr 2018 interpretation of geoSystem/geoCoords for DIS:
3511 //- world2body = world2tcs + tcs2body where tcs2body == translation
3512 // Scene
3513 // geoCoords used like GeoLocation, to convert ordinary nodes to geospatial
3514 // transform using DIS
3515 // children
3516 if(TRUE){
3517 //if(veclengthd(node->geoCoords.c) != 0.0){
3518 if(!node->__geoSystem || shallow_compare_node_fields(X3D_NODE(node),node->_oldState,FIELDS_geosys)){
3519 compile_geoSystem(X3D_NODE(node),node->_nodeType,&node->geoSystem,&node->__geoSystem);
3520 update_origin(GEOSYS(node->__geoSystem), X3D_NODE(node), &node->geoCoords, NULL);
3521 }
3522 }
3523}
3524void compile_DIS_common(struct X3D_EspduTransform *node){
3525 //INITIALIZE_EXTENT;
3526 compile_DIS_network(node);
3527 compile_DIS_geo(node);
3528}
3529void compile_DIS_common_OLD(struct X3D_EspduTransform *node){
3530 if(node->_oldState == NULL){
3531 //change detection
3532 //later we'll copy the entire node after we detect any changed fields
3533 struct X3D_Node *old;
3534 old = createNewX3DNode0(node->_nodeType);
3535 //shallow_copy_node(old,X3D_NODE(node));
3536 node->_oldState = old; //I think one underscore means dispose
3537 }
3538 if(!node->_registered){
3539 void *psock;
3540 psock = dis_register(X3D_NODE(node),node->address->strptr,node->applicationID,node->entityID,node->multicastRelayHost->strptr,
3541 node->multicastRelayPort,
3542 node->networkMode->strptr, node->port,node->readInterval,node->rtpHeaderExpected,node->siteID,node->writeInterval);
3543 node->_registered = TRUE;
3544 node->_dsock = psock;
3545 }
3546 if(node->_registered){
3547 //almost every field is [in,out] so can be changed at runtime
3548 //IDEA: save duplicate of nodetype in _oldnode field
3549 if(shallow_compare_node_fields(X3D_NODE(node),node->_oldState,FIELDS_networksensor)){
3550 int changed;
3551 changed = dis_check_socket_change((struct dis_socket*)node->_dsock,node->address->strptr, node->port,
3552 node->multicastRelayHost->strptr,node->multicastRelayPort, node->networkMode->strptr);
3553 if(changed){
3554 dis_unregister((struct dis_socket*)node->_dsock,X3D_NODE(node));
3555 node->_registered = FALSE;
3556 node->_dsock = NULL;
3557 }
3558 }
3559 }
3560 //Apr 2018 interpretation of geoSystem/geoCoords for DIS:
3561 //- world2body = world2tcs + tcs2body where tcs2body == translation
3562 // Scene
3563 // geoCoords used like GeoLocation, to convert ordinary nodes to geospatial
3564 // transform using DIS
3565 // children
3566 if(TRUE){
3567 //if(veclengthd(node->geoCoords.c) != 0.0){
3568 if(!node->__geoSystem || shallow_compare_node_fields(X3D_NODE(node),node->_oldState,FIELDS_geosys)){
3569 compile_geoSystem(X3D_NODE(node),node->_nodeType,&node->geoSystem,&node->__geoSystem);
3570 update_origin(GEOSYS(node->__geoSystem), X3D_NODE(node), &node->geoCoords, NULL);
3571 }
3572 }
3573}
3574// >> RADIO
3575void compile_TransmitterPdu0(struct X3D_TransmitterPdu *node){
3576 if(node->isNetworkReader){
3577 mark_changed_node_fields(X3D_NODE(node), node->_oldState, FIELDS_transmitter);
3578 }else if(node->isNetworkWriter){
3579 if(shallow_compare_node_fields(X3D_NODE(node),node->_oldState,FIELDS_transmitter)){
3580 node->_pduchange_transmitter = TRUE;
3581 }
3582 }
3583 freeMallocedNodeFields(node->_oldState);
3584 shallow_copy_node(node->_oldState,X3D_NODE(node));
3585}
3586void compile_SignalPdu0(struct X3D_SignalPdu *node){
3587 if(node->isNetworkReader){
3588 mark_changed_node_fields(X3D_NODE(node), node->_oldState, FIELDS_signal);
3589 }else if(node->isNetworkWriter){
3590 if(shallow_compare_node_fields(X3D_NODE(node),node->_oldState,FIELDS_signal)){
3591 node->_pduchange_signal = TRUE;
3592 }
3593 }
3594 freeMallocedNodeFields(node->_oldState);
3595 shallow_copy_node(node->_oldState,X3D_NODE(node));
3596}
3597void compile_ReceiverPdu0(struct X3D_ReceiverPdu *node){
3598 if(node->isNetworkReader){
3599 mark_changed_node_fields(X3D_NODE(node), node->_oldState, FIELDS_receiver);
3600 }else if(node->isNetworkWriter){
3601 if(shallow_compare_node_fields(X3D_NODE(node),node->_oldState,FIELDS_receiver)){
3602 node->_pduchange_receiver = TRUE;
3603 }
3604 }
3605 freeMallocedNodeFields(node->_oldState);
3606 shallow_copy_node(node->_oldState,X3D_NODE(node));
3607}
3608// << RADIO
3609
3610void compile_EspduTransform0(struct X3D_EspduTransform *node){
3611 //we use the same _pduchange flags and _oldState for both receiving and sending
3612 // but could be split if needed
3613 if(node->isNetworkReader){
3614 if(node->_pduchange_es){
3615 mark_changed_node_fields(X3D_NODE(node), node->_oldState, FIELDS_em_info);
3616 mark_changed_node_fields(X3D_NODE(node), node->_oldState, FIELDS_es_force);
3617 mark_changed_node_fields(X3D_NODE(node), node->_oldState, FIELDS_es_deadreckoning);
3618 mark_changed_node_fields(X3D_NODE(node), node->_oldState, FIELDS_es_articulation);
3619 //mark_changed_node_fields(X3D_NODE(node), node->_oldState, FIELDS_es_transform);
3620 }
3621 if(node->_pduchange_collision){
3622 mark_changed_node_fields(X3D_NODE(node), node->_oldState, FIELDS_collision);
3623 }
3624 if(node->_pduchange_fire){
3625 mark_changed_node_fields(X3D_NODE(node), node->_oldState, FIELDS_fire);
3626 }
3627 if(node->_pduchange_fire || node->_pduchange_collision){
3628 //mark_changed_node_fields(X3D_NODE(node), node->_oldState, FIELDS_events);
3629 }
3630 if(node->_pduchange_detonation){
3631 mark_changed_node_fields(X3D_NODE(node), node->_oldState, FIELDS_detonation);
3632 }
3633 if(node->_pduchange_fire || node->_pduchange_detonation){
3634 mark_changed_node_fields(X3D_NODE(node), node->_oldState, FIELDS_munition);
3635 mark_changed_node_fields(X3D_NODE(node), node->_oldState, FIELDS_rate);
3636 }
3637
3638 reset_node_pduchanged(X3D_NODE(node));
3639
3640 }else if(node->isNetworkWriter){
3641 int es_info, es_force, es_deadreckoning, es_articulation;
3642 es_info = es_force = es_deadreckoning = es_articulation = FALSE;
3643 if(shallow_compare_node_fields(X3D_NODE(node),node->_oldState,FIELDS_em_info)){
3644 es_info = TRUE;
3645 }
3646 if(shallow_compare_node_fields(X3D_NODE(node),node->_oldState,FIELDS_es_force)){
3647 es_force = TRUE;
3648 }
3649 if(shallow_compare_node_fields(X3D_NODE(node),node->_oldState,FIELDS_es_deadreckoning)){
3650 es_deadreckoning = FALSE; //we'll do it elsewhere TRUE;
3651 }
3652 if(shallow_compare_node_fields(X3D_NODE(node),node->_oldState,FIELDS_es_articulation)){
3653 int i,n;
3654 struct X3D_EspduTransform *old = (struct X3D_EspduTransform *)node->_oldState;
3655 es_articulation = TRUE;
3656 node->articulationParameterArray.p = realloc(node->articulationParameterArray.p,16*sizeof(float));
3657 n = node->articulationParameterArray.n;
3658 for(i=0;i<8;i++){
3659 switch(i){
3660 case 0:
3661 if(node->set_articulationParameterValue0 != old->set_articulationParameterValue0)
3662 node->articulationParameterArray.p[i] = node->set_articulationParameterValue0;
3663 n=max(n,i);
3664 break;
3665 case 1:
3666 if(node->set_articulationParameterValue0 != old->set_articulationParameterValue1)
3667 node->articulationParameterArray.p[i] = node->set_articulationParameterValue1;
3668 n=max(n,i);
3669 break;
3670 case 2:
3671 if(node->set_articulationParameterValue0 != old->set_articulationParameterValue2)
3672 node->articulationParameterArray.p[i] = node->set_articulationParameterValue2;
3673 n=max(n,i);
3674 break;
3675 case 3:
3676 if(node->set_articulationParameterValue0 != old->set_articulationParameterValue3)
3677 node->articulationParameterArray.p[i] = node->set_articulationParameterValue3;
3678 n=max(n,i);
3679 break;
3680 case 4:
3681 if(node->set_articulationParameterValue0 != old->set_articulationParameterValue4)
3682 node->articulationParameterArray.p[i] = node->set_articulationParameterValue4;
3683 n=max(n,i);
3684 break;
3685 case 5:
3686 if(node->set_articulationParameterValue0 != old->set_articulationParameterValue5)
3687 node->articulationParameterArray.p[i] = node->set_articulationParameterValue5;
3688 n=max(n,i);
3689 break;
3690 case 6:
3691 if(node->set_articulationParameterValue0 != old->set_articulationParameterValue6)
3692 node->articulationParameterArray.p[i] = node->set_articulationParameterValue6;
3693 n=max(n,i);
3694 break;
3695 case 7:
3696 if(node->set_articulationParameterValue0 != old->set_articulationParameterValue7)
3697 node->articulationParameterArray.p[i] = node->set_articulationParameterValue7;
3698 n=max(n,i);
3699 break;
3700 default:
3701 break;
3702 }
3703 }
3704 node->articulationParameterCount = node->articulationParameterArray.n;
3705 }
3706 //printf("es %d inf %d for %d dr %d art %d\n ",node->_pduchange_es,es_info,es_force,es_deadreckoning,es_articulation);
3707 node->_pduchange_es = node->_pduchange_es || es_info || es_force || es_deadreckoning || es_articulation ? TRUE : FALSE;
3708 if(shallow_compare_node_fields(X3D_NODE(node),node->_oldState,FIELDS_collision)){
3709 node->_pduchange_collision = TRUE;
3710 }
3711 if(shallow_compare_node_fields(X3D_NODE(node),node->_oldState,FIELDS_events)){
3712 //node->_pduchange_collision = TRUE;
3713 //node->_pduchange_fire = TRUE;
3714 }
3715 if(shallow_compare_node_fields(X3D_NODE(node),node->_oldState,FIELDS_fire)){
3716 node->_pduchange_fire = TRUE;
3717 }
3718 if(shallow_compare_node_fields(X3D_NODE(node),node->_oldState,FIELDS_detonation)){
3719 node->_pduchange_detonation = TRUE;
3720 }
3721 if(shallow_compare_node_fields(X3D_NODE(node),node->_oldState,FIELDS_munition)){
3722 node->_pduchange_fire = TRUE;
3723 node->_pduchange_detonation = TRUE;
3724 }
3725 if(shallow_compare_node_fields(X3D_NODE(node),node->_oldState,FIELDS_rate)){
3726 node->_pduchange_fire = TRUE;
3727 node->_pduchange_detonation = TRUE;
3728 }
3729 }
3730 freeMallocedNodeFields(node->_oldState);
3731 shallow_copy_node(node->_oldState,X3D_NODE(node));
3732
3733}
3734//void prep_EspduTransform0(struct X3D_EspduTransform *node){
3735// //if(!renderstate()->render_vp) {
3736// geoprep(GEOSYS(node->__geoSystem),&node->geoCoords);
3737// /* did either we or the Viewpoint move since last time? */
3738// //RECORD_DISTANCE
3739// //if(renderstate()->render_boxes) extent6f_draw(node->_extent);
3740// //}
3741//
3742//}
3743//void fin_EspduTransform0(struct X3D_EspduTransform *node){
3744// geofin(GEOSYS(node->__geoSystem),&node->geoCoords);
3745//}
3746
3747void compile_DISEntityManager0(struct X3D_DISEntityManager *node){
3748 //we use the same _pduchange flags and _oldState for both receiving and sending
3749 // but could be split if needed
3750 if(node->isNetworkReader){
3751 if(node->_pduchange_em_info){
3752 mark_changed_node_fields(X3D_NODE(node), node->_oldState, FIELDS_em_info);
3753 }
3754 if(node->_pduchange_create){
3755 if(node->addedEntities.n > 0)
3756 mark_changed_node_fields(X3D_NODE(node), node->_oldState, FIELDS_create);
3757 }
3758 if(node->_pduchange_remove){
3759 if(node->removedEntities.n > 0)
3760 mark_changed_node_fields(X3D_NODE(node), node->_oldState, FIELDS_remove);
3761 }
3762 reset_node_pduchanged(X3D_NODE(node));
3763
3764 }else if(node->isNetworkWriter){
3765 if(shallow_compare_node_fields(X3D_NODE(node),node->_oldState,FIELDS_em_info)){
3766 node->_pduchange_em_info = TRUE;
3767 }
3768 if(shallow_compare_node_fields(X3D_NODE(node),node->_oldState,FIELDS_create)){
3769 if(node->addedEntities.n > 0)
3770 node->_pduchange_create = TRUE;
3771 }
3772 if(shallow_compare_node_fields(X3D_NODE(node),node->_oldState,FIELDS_remove)){
3773 if(node->removedEntities.n > 0)
3774 node->_pduchange_remove = TRUE;
3775 }
3776 }
3777 freeMallocedNodeFields(node->_oldState);
3778 shallow_copy_node(node->_oldState,X3D_NODE(node));
3779}
3780
3781
3782
3783
3784
3785// http://movesinstitute.org/~mcgredo/MV3500/hla/1278.1-200X%20Draft%2016%20rev%2018.pdf
3786// p.663 DR formula naming:
3787// rotation: fixed (F), rotating (R)
3788// order of position function: rate of position (P) (first order), rate of velocity (V) (second order)
3789// coords: world coordinates (W) body axis coordinates (B)
3790// p.665 dead reckoning formulas
3791enum {
3792STATIC = 1,
3793DRM_FPW = 2,
3794DRM_RPW = 3,
3795DRM_RVW = 4,
3796DRM_FVW = 5, //P = P0 + V0*dt + 1/2*A*dt^2 in world coords
3797DRM_FPB = 6,
3798DRM_RPB = 7,
3799DRM_RVB = 8,
3800DRM_FVB = 9, //P = P0 + (local2world)x(V0b*dt + 1/2*Ab*dt^2) convert to world after computing in local/entity/b=body space
3801};
3802void dead_reckon(int drmethod, double dtime, float *p1, float *R1xyza, float *p0, float *v0, float *a0, float *R0xyza, float *RVxyza){
3803 // freewrl: when we say world here, we mean TCS.
3804 // TCS == topocentric coordinate system, aka LGS Local Geodetic System, see Geospatial component, GeoLocation
3805 // LCS == local coordinate system - see Geospatial component, precision requirements, == TCS of geoOrigin / autoOrigin
3806 // DIS Local ~= web3d TCS, except with axes swizzled (DIS -Z up, X north, X3D Y up, -Z north)
3807 // we convert DR parameters in world system to/from web3d geo TCS system during pdu2node / node2pdu
3808 // so all below formula world coords are in TCS
3809 // any DR (dead reckoning) parameters in DIS-Local system are swizzled to/from web3d TCS convention in node2pdu and pdu2node
3810 // drmethod 1 - 9
3811 // dtime - time in seconds since last frame ie .01
3812 // p1 - output new location (TCS)
3813 // R1xyza - output new orientation (body2tcs)
3814 // p0 - location on last frame
3815 // v0 - linear velocity set on last send/recv
3816 // a0 - linear acceleration set on last send/recv
3817 // R0xyza - orientation on last frame Rbw
3818 // RVxyza - angular velocity, in entity/body
3819 switch(drmethod){
3820 //world coords
3821 case STATIC: //1
3822 veccopy3f(p1,p0);
3823 veccopy4f(R1xyza,R0xyza);
3824 break;
3825 case DRM_FPW: //2
3826 {
3827 float tmp[3];
3828 //update position
3829 // P = P0 + V0*dt
3830 vecadd3f(p1,p0,vecscale3f(tmp,v0,dtime));
3831 veccopy4f(R1xyza,R0xyza);
3832 }
3833 break;
3834 case DRM_RPW: //3
3835
3836 {
3837 float tmp[3];
3838 Quaternion qv, q1, q0;
3839 //update position
3840 // P = P0 + V0*dt
3841 vecadd3f(p1,p0,vecscale3f(tmp,v0,dtime));
3842 //update rotation
3843 // Rwb1 = DR(dt) * Rwb0
3844 vrmlrot4f_to_quaternion(&q0,R0xyza);
3845 vrmlrot_to_quaternion(&qv,RVxyza[0],RVxyza[1],RVxyza[2],RVxyza[3]*dtime);
3846 quaternion_multiply(&q1,&q0,&qv);
3847 quaternion_to_vrmlrot4f(&q1,R1xyza);
3848
3849 }
3850 break;
3851 case DRM_RVW: //4
3852 {
3853 //update position
3854 //P = P0 + V0*dt + 1/2*A*dt^2 in world coords
3855 float tmp3[3],tmp2[3],tmp1[3];
3856 Quaternion qv, q1, q0;
3857
3858 vecadd3f(p1,p0,vecadd3f(tmp3,vecscale3f(tmp2,v0,dtime),vecscale3f(tmp1,a0,.5f*dtime*dtime)));
3859 //update rotation
3860 // Rwb1 = DR(dt) * Rwb0
3861 vrmlrot4f_to_quaternion(&q0,R0xyza);
3862 vrmlrot_to_quaternion(&qv,RVxyza[0],RVxyza[1],RVxyza[2],RVxyza[3]*dtime);
3863 quaternion_multiply(&q1,&q0,&qv);
3864 quaternion_to_vrmlrot4f(&q1,R1xyza);
3865
3866 }
3867 break;
3868 case DRM_FVW: //5
3869
3870 {
3871 //F=fixed rotation, V = 2nd order, W=world coords
3872 //E.7.2.2 p.666
3873 //update position
3874 //P = P0 + V0*dt + 1/2*A*dt^2 in world coords
3875 float tmp3[3],tmp2[3],tmp1[3];
3876 vecadd3f(p1,p0,vecadd3f(tmp3,vecscale3f(tmp2,v0,dtime),vecscale3f(tmp1,a0,.5f*dtime*dtime)));
3877 //update rotation
3878 veccopy4f(R1xyza,R0xyza);
3879 }
3880 break;
3881
3882 //body/entity > A,V in body coords
3883 case DRM_FPB: //6
3884 {
3885 Quaternion qv, qa, q1, qbw;
3886 float deltap[3], att[3], tmp[3], tmp1[3], tmp2[3], tmp3[3];
3887
3888 vrmlrot_to_quaternion(&qv,RVxyza[0],RVxyza[1],RVxyza[2],RVxyza[3]*dtime);
3889 vrmlrot4f_to_quaternion(&qbw,R0xyza);
3890 vecscale3f(tmp3,v0,dtime);
3891 quaternion_rotation3f(deltap,&qv,tmp3);
3892 quaternion_rotation3f(tmp2,&qbw,deltap); //world2body
3893 vecadd3f(p1,p0,tmp2);
3894
3895 //update rotation
3896 veccopy4f(R1xyza,R0xyza);
3897
3898 }
3899 break;
3900 case DRM_RPB: //7
3901 {
3902 Quaternion qv, qa, q1, qbw;
3903 float deltap[3], att[3], tmp[3], tmp1[3], tmp2[3], tmp3[3];
3904
3905 vrmlrot_to_quaternion(&qv,RVxyza[0],RVxyza[1],RVxyza[2],RVxyza[3]*dtime);
3906 vrmlrot4f_to_quaternion(&qbw,R0xyza);
3907 vecscale3f(tmp3,v0,dtime);
3908 quaternion_rotation3f(deltap,&qv,tmp3);
3909 quaternion_rotation3f(tmp2,&qbw,deltap); //world2body
3910 vecadd3f(p1,p0,tmp2);
3911
3912 //update rotation
3913 // Rwb1 = DR(dt) * Rwb0
3914 quaternion_multiply(&q1,&qbw,&qv);
3915 quaternion_to_vrmlrot4f(&q1,R1xyza);
3916
3917 }
3918 break;
3919 case DRM_RVB: //8
3920 {
3921 //p.669
3922 //I think I see 2 problems with the formula they give:
3923 //1. their R1, R2 formula divide by |w|^n and when |w| is 0, that's divide by zero
3924 // - should produce Identity matrix when |w| is zero
3925 //2. P = P0 + Rbw*(R1*Vb + R2*Ab)
3926 // problem: when R1, R2 are Identity (when |w| 0), it doesn't look like V0*t + 1/2*A*t^2
3927 // should be:
3928 // P = P0 + Rbw*(R1*Vb*dt + R2*.5*Ab*dt*dt)
3929 // proposed simplification:
3930 // Rbb = Rv*dt (and maybe + Ra*.5*t^2) where bb means body pose update with dt
3931 // P = P0 + Rbw x Rbb(Vb*dt + Ab*.5*dt*dt)
3932 Quaternion qv, qa, q1, qbw;
3933 float deltap[3], att[3], tmp[3], tmp1[3], tmp2[3], tmp3[3];
3934
3935 vrmlrot_to_quaternion(&qv,RVxyza[0],RVxyza[1],RVxyza[2],RVxyza[3]*dtime);
3936 vrmlrot4f_to_quaternion(&qbw,R0xyza);
3937 vecadd3f(tmp3,vecscale3f(tmp2,v0,dtime),vecscale3f(tmp1,a0,.5f*dtime*dtime));
3938 quaternion_rotation3f(deltap,&qv,tmp3);
3939 quaternion_rotation3f(tmp2,&qbw,deltap); //world2body
3940 vecadd3f(p1,p0,tmp2);
3941
3942 //update rotation
3943 // Rwb1 = DR(dt) * Rwb0
3944 quaternion_multiply(&q1,&qbw,&qv);
3945 quaternion_to_vrmlrot4f(&q1,R1xyza);
3946
3947 }
3948 break;
3949 case DRM_FVB: //9
3950 {
3951 //P = P0 + (local2world)x(V0b*dt + 1/2*Ab*dt^2) convert to world after computing in local/entity/b=body space
3952 Quaternion qv, qa, q1, qbw;
3953 float deltap[3], att[3], tmp[3], tmp1[3], tmp2[3], tmp3[3];
3954
3955 vrmlrot_to_quaternion(&qv,RVxyza[0],RVxyza[1],RVxyza[2],RVxyza[3]*dtime);
3956 vrmlrot4f_to_quaternion(&qbw,R0xyza);
3957 vecadd3f(tmp3,vecscale3f(tmp2,v0,dtime),vecscale3f(tmp1,a0,.5f*dtime*dtime));
3958 quaternion_rotation3f(deltap,&qv,tmp3);
3959 quaternion_rotation3f(tmp2,&qbw,deltap); //world2body
3960 vecadd3f(p1,p0,tmp2);
3961
3962 //update rotation
3963 veccopy4f(R1xyza,R0xyza); //no update for 9
3964
3965 }
3966 break;
3967
3968 default:
3969 //update translation
3970 veccopy3f(p1,p0);
3971 //update rotation
3972 veccopy4f(R1xyza,R0xyza);
3973 break;
3974 }
3975
3976}
3977#define DRA_POS_THRSH 1.5
3978#define DRA_ORIENT_THRSH .175 //RADIANS about 10 degrees
3979
3980int transform_within_DeadReckoningTolerance1(struct X3D_EspduTransform *node){
3981 int withintol = TRUE;
3982 float p0[3], gap[3];
3983 struct X3D_EspduTransform *oldstate = (struct X3D_EspduTransform *)node->_oldState;
3984 veccopy3f(p0,node->_p0.c); //oldstate->translation.c);
3985
3986 vecdif3f(gap,p0,node->translation.c);
3987 if(veclength3f(gap) > DRA_POS_THRSH)
3988 withintol = FALSE;
3989 return withintol;
3990}
3991
3992void compile_EspduTransform1 (struct X3D_EspduTransform *node) {
3993 if(node->isNetworkReader){
3994 if(node->_pduchange_es){
3995 mark_changed_node_fields(X3D_NODE(node), node->_oldState, FIELDS_es_transform);
3996 mark_changed_node_fields(X3D_NODE(node), node->_oldState, FIELDS_geo);
3997 }
3998 }else if(node->isNetworkWriter){
3999 if(shallow_compare_node_fields(X3D_NODE(node),node->_oldState,FIELDS_es_transform)
4000 || shallow_compare_node_fields(X3D_NODE(node),node->_oldState,FIELDS_geo)) {
4001 //node->_pduchange_es = TRUE;
4002 if(!transform_within_DeadReckoningTolerance1(node)) {
4003 node->_pduchange_es = TRUE;
4004 }
4005 }
4006 }
4007 //whether its reader, writer or standalone, we need to compile if it changed state
4008 if(shallow_compare_node_fields(X3D_NODE(node),node->_oldState,FIELDS_es_transform)){
4009
4010 INITIALIZE_EXTENT;
4011
4012 /* printf ("changed Transform for node %u\n",node); */
4013 node->__do_center = verify_translate ((GLfloat *)node->center.c);
4014 node->__do_trans = verify_translate ((GLfloat *)node->translation.c);
4015 node->__do_scale = verify_scale ((GLfloat *)node->scale.c);
4016 node->__do_rotation = verify_rotate ((GLfloat *)node->rotation.c);
4017 node->__do_scaleO = verify_rotate ((GLfloat *)node->scaleOrientation.c);
4018
4019 node->__do_anything = (node->__do_center ||
4020 node->__do_trans ||
4021 node->__do_scale ||
4022 node->__do_rotation ||
4023 node->__do_scaleO);
4024
4025 REINITIALIZE_SORTED_NODES_FIELD(node->children,node->_sortedChildren);
4026 MARK_NODE_COMPILED
4027 }
4028
4029}
4030void compile_EspduTransform (struct X3D_EspduTransform *node) {
4031 compile_DIS_common(node); // must be first in case need to initialize _oldState
4032 compile_EspduTransform1(node);
4033 compile_EspduTransform0(node); //must be last to re-copy node to oldstate
4034 MARK_NODE_COMPILED
4035}
4036
4037void espdu_update_by_dead_reckoning (struct X3D_EspduTransform *node) {
4038 int drmethod, wasTransmitted;
4039 float p1[3],v1[3],a1[3], RVxyza[4], R0xyza[4], R1xyza[4];
4040 float p0[3],v0[3],a0[3];
4041 double dtime;
4042 static int smoothing_frames = 230; //frame count, at 60fps would be 4 seconds, ideally this would be a smoothing time in seconds
4043 static int want_smoothing = 1; //0;
4044
4045
4046 wasTransmitted = FALSE;
4047 if(node->isNetworkReader){
4048 if(node->_lasttime == 0.0)
4049 return;
4050 if(node->_pduchange_es){
4051 //node start or node received
4052 node->_change_count++;
4053 wasTransmitted = TRUE;
4054 if(want_smoothing && node->_change_count){
4055 vecdif3f(node->_smoothingDelta.c,node->translation.c,node->_p0.c);
4056 node->_smoothingCount = smoothing_frames;
4057 if(node->_change_count > 1)
4058 node->_smoothingCount = 0;
4059 }
4060 veccopy3f(node->_p0.c,node->translation.c);
4061 veccopy4f(node->_r0.c,node->rotation.c);
4062 }
4063 veccopy3f(p0,node->_p0.c);
4064 //veccopy3f(p0,node->translation.c);
4065 veccopy3f(v0,node->linearVelocity.c);
4066 veccopy3f(a0,node->linearAcceleration.c);
4067 veccopy4f(RVxyza,node->_angularVelocity.c);
4068 veccopy4f(R0xyza,node->_r0.c);
4069
4070 }
4071 if(node->isStandAlone){
4072 veccopy3f(p0,node->translation.c);
4073 veccopy3f(v0,node->linearVelocity.c);
4074 veccopy3f(a0,node->linearAcceleration.c);
4075 veccopy4f(RVxyza,node->_angularVelocity.c);
4076 veccopy4f(R0xyza,node->rotation.c);
4077 }
4078 if(node->isNetworkWriter){
4079 if(node->_sent){
4080 //to be fair, only use what you send
4081 wasTransmitted = TRUE;
4082 node->_sent = FALSE;
4083 veccopy3f(node->_p0.c,node->translation.c);
4084 veccopy4f(node->_r0.c,node->rotation.c);
4085 }
4086 veccopy3f(p0,node->_p0.c);
4087 veccopy3f(v0,node->linearVelocity.c);
4088 veccopy3f(a0,node->linearAcceleration.c);
4089 veccopy4f(RVxyza,node->_angularVelocity.c);
4090 veccopy4f(R0xyza,node->_r0.c);
4091 }
4092 if(node->_lastframetime == 0.0)
4093 veccopy3f(node->_p0.c,p0);
4094 if(node->_lastframetime > 0.0){
4095 dtime = TickTime() - node->_lastframetime; //lastime();
4096 drmethod = node->deadReckoning;
4097 //if(drmethod)
4098 // if(!node->__geoSystem) drmethod = DRM_FVW; //if no geocoords, we'll assume transform is already in world coords
4099 dead_reckon(drmethod, dtime, p1, R1xyza, p0, v0, a0, R0xyza, RVxyza);
4100 veccopy3f(node->_p0.c,p1);
4101 veccopy4f(node->_r0.c,R1xyza);
4102 MARK_EVENT(X3D_NODE(node),offsetof(struct X3D_EspduTransform,_p0));
4103 }
4104 node->_lastframetime = TickTime();
4105 if(node->isNetworkReader){
4106 //update translation based on DR
4107 if(want_smoothing){
4108 //E.9 Smoothing p.678
4109 //just done on the receiver/isNetworkReader
4110 float psmooth[3], pzero[3], alpha;
4111 int n, i;
4112 node->_change++;
4113 i = node->_smoothingCount;
4114 n = smoothing_frames;
4115 alpha = 1.0f - (float)min(i,n)/(float)n;
4116 vecset3f(pzero,0.0f,0.0f,0.0f);
4117 veclerp3f(psmooth,pzero,node->_smoothingDelta.c,alpha);
4118 vecdif3f(node->translation.c,node->_p0.c,psmooth);
4119 node->_smoothingCount++;
4120 }else{
4121 veccopy3f(node->translation.c,node->_p0.c);
4122 }
4123 veccopy4f(node->rotation.c,node->_r0.c);
4124 }
4125}
4126
4127/* do transforms, calculate the distance */
4128void prep_EspduTransform (struct X3D_EspduTransform *node) {
4129 if(node->isNetworkReader) espdu_update_by_dead_reckoning(node);
4130 COMPILE_IF_REQUIRED
4131 if(node->__geoSystem)
4132 geoprep(GEOSYS(node->__geoSystem),&node->geoCoords); //prep_EspduTransform0(node); //has render_vp filter
4133 if(!node->isNetworkReader) espdu_update_by_dead_reckoning(node);
4134 /* rendering the viewpoint means doing the inverse transformations in reverse order (while poping stack),
4135 * so we do nothing here in that case -ncoder */
4136
4137
4138 /* printf ("prep_Transform, render_hier vp %d geom %d light %d sens %d blend %d prox %d col %d\n",
4139 render_vp,render_geom,render_light,render_sensitive,render_blend,render_proximity,render_collision); */
4140
4141 /* do we have any geometry visible, and are we doing anything with geometry? */
4142 OCCLUSIONTEST
4143
4144 if(!renderstate()->render_vp) {
4145 /* do we actually have any thing to rotate/translate/scale?? */
4146
4147
4148 if (node->__do_anything) {
4149
4150 FW_GL_PUSH_MATRIX();
4151
4152 /* TRANSLATION */
4153 if (node->__do_trans)
4154 FW_GL_TRANSLATE_F(node->translation.c[0],node->translation.c[1],node->translation.c[2]);
4155
4156 /* CENTER */
4157 if (node->__do_center)
4158 FW_GL_TRANSLATE_F(node->center.c[0],node->center.c[1],node->center.c[2]);
4159
4160 /* ROTATION */
4161 if (node->__do_rotation) {
4162 FW_GL_ROTATE_RADIANS(node->rotation.c[3], node->rotation.c[0],node->rotation.c[1],node->rotation.c[2]);
4163 }
4164
4165 /* SCALEORIENTATION */
4166 if (node->__do_scaleO) {
4167 FW_GL_ROTATE_RADIANS(node->scaleOrientation.c[3], node->scaleOrientation.c[0], node->scaleOrientation.c[1],node->scaleOrientation.c[2]);
4168 }
4169
4170
4171 /* SCALE */
4172 if (node->__do_scale)
4173 FW_GL_SCALE_F(node->scale.c[0],node->scale.c[1],node->scale.c[2]);
4174
4175 /* REVERSE SCALE ORIENTATION */
4176 if (node->__do_scaleO)
4177 FW_GL_ROTATE_RADIANS(-node->scaleOrientation.c[3], node->scaleOrientation.c[0], node->scaleOrientation.c[1],node->scaleOrientation.c[2]);
4178
4179 /* REVERSE CENTER */
4180 if (node->__do_center)
4181 FW_GL_TRANSLATE_F(-node->center.c[0],-node->center.c[1],-node->center.c[2]);
4182 }
4183
4184 RECORD_DISTANCE
4185 if(renderstate()->render_boxes) extent6f_draw(node->_extent);
4186 }
4187
4188}
4189
4190
4191void fin_EspduTransform (struct X3D_EspduTransform *node) {
4192 OCCLUSIONTEST
4193
4194 if(!renderstate()->render_vp) {
4195 if (node->__do_anything) {
4196 FW_GL_POP_MATRIX();
4197 }
4198 } else {
4199 /*Rendering the viewpoint only means finding it, and calculating the reverse WorldView matrix.*/
4200 if((node->_renderFlags & VF_Viewpoint) == VF_Viewpoint) {
4201 FW_GL_TRANSLATE_F(((node->center).c[0]),((node->center).c[1]),((node->center).c[2])
4202 );
4203 FW_GL_ROTATE_RADIANS(((node->scaleOrientation).c[3]),((node->scaleOrientation).c[0]),((node->scaleOrientation).c[1]),((node->scaleOrientation).c[2])
4204 );
4205 FW_GL_SCALE_F((float)1.0/(((node->scale).c[0])),(float)1.0/(((node->scale).c[1])),(float)1.0/(((node->scale).c[2]))
4206 );
4207 FW_GL_ROTATE_RADIANS(-(((node->scaleOrientation).c[3])),((node->scaleOrientation).c[0]),((node->scaleOrientation).c[1]),((node->scaleOrientation).c[2])
4208 );
4209 FW_GL_ROTATE_RADIANS(-(((node->rotation).c[3])),((node->rotation).c[0]),((node->rotation).c[1]),((node->rotation).c[2])
4210 );
4211 FW_GL_TRANSLATE_F(-(((node->center).c[0])),-(((node->center).c[1])),-(((node->center).c[2]))
4212 );
4213 FW_GL_TRANSLATE_F(-(((node->translation).c[0])),-(((node->translation).c[1])),-(((node->translation).c[2]))
4214 );
4215 }
4216 }
4217 if(node->__geoSystem)
4218 geofin(GEOSYS(node->__geoSystem),&node->geoCoords); //has vp_render filters //fin_EspduTransform0(node);
4219
4220}
4221void render_munitions(struct X3D_EspduTransform *node){
4222 //I have no ideas. something about quantity, velocity, start/end or startpoint
4223 //a) update locations based on time and trajectory - like partical physics
4224 //b) render each munition instance
4225 if(!renderstate()->render_vp) {
4226
4227 if(node->fired1){
4228 int i;
4229 struct X3D_EspduTransform * mnode;
4230 static int eventNumber = 0;
4231 if(node->eventNumber > eventNumber){
4232 node->firedTime = TickTime();
4233 eventNumber = node->eventNumber;
4234 }
4235 double dtime = TickTime() - (double)node->munitionQuantity/(double)max(1,node->firingRate) - node->firedTime ;
4236 if(dtime > 5.0) return; //already finished
4237 mnode = (struct X3D_EspduTransform*)dis_find_registered_node_by_entityid(node->munitionEntityID,TRUE,TRUE);
4238 if(mnode){
4239 for(i=0;i<node->munitionQuantity;i++){
4240 //how about a 1 second gap between burst pals
4241 dtime = max(0.0,TickTime() - (double)i/(double)max(1,node->firingRate) - node->firedTime);
4242 dtime = min(5.0,dtime);
4243 float delta[3], velocity[3], progress[3], loc[3];
4244 vecdif3f(delta,node->munitionEndPoint.c,node->munitionStartPoint.c);
4245 vecscale3f(velocity,delta,1.0f/3.0f);
4246 vecscale3f(progress,velocity,(float)dtime);
4247 if(veclength3f(progress) > veclength3f(delta)) {
4248 // detonate or whatever you do when munition reaches target
4249 veccopy3f(loc,node->munitionEndPoint.c);
4250 if(i==(node->munitionQuantity-1)){
4251 node->fired1 = FALSE; //last munition in burst hit target
4252 node->detonateTime = TickTime();
4253 }
4254 } else {
4255 vecadd3f(loc,node->munitionStartPoint.c,progress);
4256 // render munition instance
4257 }
4258 FW_GL_PUSH_MATRIX();
4259 FW_GL_TRANSLATE_F(loc[0],loc[1],loc[2]);
4260 //static int k = 0;
4261 //if(k++ % 120 == 0)
4262 // printf("%lf %lf %lf\n",loc[0],loc[1],loc[2]);
4263 //strip espdu wrapper (otherwise we have geoLocation wrapping geoLocation - double geo transform
4264 normalChildren(mnode->children);
4265 FW_GL_POP_MATRIX();
4266 }
4267 }
4268 }
4269 }
4270}
4271void render_detonation(struct X3D_EspduTransform *node){
4272 //I have no ideas. something about quantity, velocity, start/end or startpoint
4273 //a) update locations based on time and trajectory - like partical physics
4274 //b) render each munition instance
4275 if(!renderstate()->render_vp) {
4276 double dtime = TickTime() - node->detonateTime;
4277 if( dtime > 0.0 && dtime < .5){
4278 int i;
4279 struct X3D_EspduTransform * mnode;
4280 mnode = (struct X3D_EspduTransform*)dis_find_registered_node_by_entityid(node->munitionEntityID,TRUE,TRUE);
4281 if(mnode){
4282 for(i=0;i<node->munitionQuantity;i++){
4283 float loc[3], fscale;
4284 //how about a 1 second gap between burst pals
4285 veccopy3f(loc,node->detonationRelativeLocation.c);
4286 FW_GL_PUSH_MATRIX();
4287 FW_GL_TRANSLATE_F(loc[0],loc[1],loc[2]);
4288 fscale = dtime * 10.0f;
4289 FW_GL_SCALE_F(fscale,fscale,fscale);
4290 normalChildren(mnode->children);
4291 FW_GL_POP_MATRIX();
4292 }
4293 }
4294 }
4295 }
4296}
4297void dis_register_collide(struct X3D_Node* node,double *transform);
4298void child_EspduTransform (struct X3D_EspduTransform *node) {
4299 //LOCAL_LIGHT_SAVE
4300 CHILDREN_COUNT
4301 OCCLUSIONTEST
4302
4303 RETURN_FROM_CHILD_IF_NOT_FOR_ME
4304
4305 /* any children at all? */
4306 if (nc==0) return;
4307 {
4308 double modelviewMatrix[16];
4309 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelviewMatrix);
4310 dis_register_collide(X3D_NODE(node),modelviewMatrix);
4311 }
4312 //if(node->__sibAffectors.n)
4313 // printf("have transform sibaffectors\n");
4314 prep_sibAffectors((struct X3D_Node*)node,&node->__sibAffectors);
4315
4316
4317 //profile_start("local_light_kids");
4318 /* do we have a local light for a child? */
4319// LOCAL_LIGHT_CHILDREN(node->_sortedChildren);
4320 //profile_end("local_light_kids");
4321 /* now, just render the non-directionalLight children */
4322
4323 /* printf ("Transform %d, flags %d, render_sensitive %d\n",
4324 node,node->_renderFlags,render_sensitive); */
4325
4326 #ifdef CHILDVERBOSE
4327 printf ("transform - doing normalChildren\n");
4328 #endif
4329
4330 normalChildren(node->_sortedChildren);
4331
4332 //render munitions
4333 render_munitions(node);
4334 //render detonations
4335 render_detonation(node);
4336 //render collisions
4337
4338
4339 #ifdef CHILDVERBOSE
4340 printf ("transform - done normalChildren\n");
4341 #endif
4342
4343// LOCAL_LIGHT_OFF
4344 fin_sibAffectors((struct X3D_Node*)node,&node->__sibAffectors);
4345}
4346
4347
4348// >> RADIO
4349// first parts of radio node structs ynchronized so as to match Espdu struct so
4350// the 3 radio nodes can be cast to EspduTransform for common field handling
4351void compile_TransmitterPdu (struct X3D_TransmitterPdu *node) {
4352 compile_DIS_common((struct X3D_EspduTransform *)node); //assumes transform padding in transmitter node
4353 compile_TransmitterPdu0(node);
4354 MARK_NODE_COMPILED
4355}
4356void compile_SignalPdu (struct X3D_SignalPdu *node) {
4357 compile_DIS_common((struct X3D_EspduTransform *)node); //assumes transform padding in signal node
4358 compile_SignalPdu0(node);
4359 MARK_NODE_COMPILED
4360}
4361void compile_ReceiverPdu (struct X3D_ReceiverPdu *node) {
4362 compile_DIS_common((struct X3D_EspduTransform *)node); //assumes transform padding in receiver node
4363 compile_ReceiverPdu0(node);
4364 MARK_NODE_COMPILED
4365}
4366
4367void child_TransmitterPdu (struct X3D_TransmitterPdu *node) {
4368 COMPILE_IF_REQUIRED
4369 geoprep(GEOSYS(node->__geoSystem),&node->geoCoords);
4370 //do stuff
4371 geofin(GEOSYS(node->__geoSystem),&node->geoCoords);
4372 if(renderstate()->render_boxes) extent6f_draw(node->_extent);
4373}
4374void child_SignalPdu (struct X3D_SignalPdu *node) {
4375 COMPILE_IF_REQUIRED
4376 geoprep(GEOSYS(node->__geoSystem),&node->geoCoords);
4377 //do stuff
4378 geofin(GEOSYS(node->__geoSystem),&node->geoCoords);
4379 if(renderstate()->render_boxes) extent6f_draw(node->_extent);
4380}
4381void child_ReceiverPdu (struct X3D_ReceiverPdu *node) {
4382 COMPILE_IF_REQUIRED
4383 geoprep(GEOSYS(node->__geoSystem),&node->geoCoords);
4384 //do stuff
4385 geofin(GEOSYS(node->__geoSystem),&node->geoCoords);
4386 if(renderstate()->render_boxes) extent6f_draw(node->_extent);
4387}
4388
4389//<< RADIO
4390
4391void print_entitymapping(struct X3D_DISEntityTypeMapping *anode){
4392 ConsoleMessage("domain %d category %d country %d kind %d extra %d subcat %d spec %d\n",
4393 anode->domain, anode->category,anode->country, anode->kind, anode->extra, anode->subcategory, anode->specific);
4394}
4395void compile_DISEntityManager(struct X3D_DISEntityManager *node){
4396 compile_DIS_network((struct X3D_EspduTransform *)node);
4397 compile_DISEntityManager0(node);
4398 MARK_NODE_COMPILED
4399}
4400static int app_entity_last_id = 0;
4401int newEntityID(){
4402//for current app instance
4403 app_entity_last_id++;
4404 return app_entity_last_id;
4405}
4406#define GEOEL_WE_A (double)6378137
4407void child_DISEntityManager(struct X3D_DISEntityManager *node){
4408 //Problem: web3d doesn't have a sender entitymanager. So its dependant on other (unknown) ?commercial? programs.
4409 //Solution 1: modify DISEntityManager to have networkMode='networkWriter'
4410 // and an MFnode initializeOnly field of EntityTypeMapping nodes
4411 //Solution 2: 'entity discovery' by listening -> entity manager for creation
4412 // - done in the pdu receive loop, if there are 'leftover pdus' they are
4413 // examined as candidates for entity discovery, and sent here via .addEntities
4414 static int ADD = 1, REMOVE = 2;
4415 COMPILE_IF_REQUIRED
4416 //like add remove children in opengl utils
4417 if(node->addEntities.n){
4418 int i,j;
4419 struct Multi_Node* mfn = &node->entities;
4420 node->addedEntities.n = 0;
4421 for(j=0;j<node->addEntities.n;j++){
4422 int ibest,iscore,jscore;
4423 int entityID, applicationID, siteID;
4424 int port, multicastRelayPort;
4425 struct Uni_String *address, *networkMode, *multicastRelayHost;
4426 struct X3D_Node *candi;
4427 struct X3D_DISEntityTypeMapping *best;
4428 int use_GC = FALSE;
4429
4430 // = (struct X3D_DISEntityTypeMapping *)node->addEntities.p[j];
4431 ibest = -1;
4432 iscore = 0;
4433 best = NULL;
4434 candi = node->addEntities.p[j];
4435 if(candi->_nodeType == NODE_DISEntityTypeMapping)
4436 {
4437 //problem: the DISEntityTypeMapping doesn't have a field for entityID
4438 // - that's OK when we are just told to create-and-own a new entity
4439 // -we can assign our siteID, applicationID and increment our entityID count for entityID
4440 // x but not for entity discovery
4441 // * so we added some fields _entityID,_applicationID,_siteID for copying from sniffed pdu
4442 // and sending to the .addEntities list
4443 //print_entitymapping(anode);
4444 struct X3D_DISEntityTypeMapping *anode = (struct X3D_DISEntityTypeMapping *)node->addEntities.p[j];
4445 for(i=0;i<node->mapping.n;i++){
4446 struct X3D_DISEntityTypeMapping *bnode = (struct X3D_DISEntityTypeMapping *)node->mapping.p[i];
4447 //printf("compare %d",i);
4448 //print_entitymapping(bnode);
4449 jscore = 0;
4450 if(anode->domain == bnode->domain) jscore++;
4451 if(anode->category == bnode->category) jscore++;
4452 if(anode->country == bnode->country) jscore++;
4453 if(anode->kind == bnode->kind) jscore++;
4454 if(anode->extra == bnode->extra) jscore++;
4455 if(anode->subcategory == bnode->subcategory) jscore++;
4456 if(anode->specific == bnode->specific) jscore++;
4457 if(jscore > iscore){
4458 iscore = jscore;
4459 ibest = i;
4460 best = bnode;
4461 }
4462 }
4463 if(ibest > -1){
4464 applicationID = node->applicationID;
4465 siteID = node->siteID;
4466 entityID = newEntityID(); //anode->_entityID;
4467 address = node->address;
4468 port = node->port;
4469 networkMode = newASCIIString ("networkWriter"); //if we're ordered to create, usually that also means own
4470 multicastRelayHost = node->multicastRelayHost;
4471 multicastRelayPort = node->multicastRelayPort;
4472
4473 }
4474 } else if(candi->_nodeType == NODE_EspduTransform) {
4475 // || candi->_nodeType == NODE_ReceiverPdu
4476 // || candi->_nodeType == NODE_TransmitterPdu || candi->_nodeType == NODE_SignalPdu){
4477 //this comes from 'entity discovery' from leftovver pdus
4478 struct X3D_EspduTransform *anode = (struct X3D_EspduTransform *)node->addEntities.p[j];
4479 for(i=0;i<node->mapping.n;i++){
4480 struct X3D_DISEntityTypeMapping *bnode = (struct X3D_DISEntityTypeMapping *)node->mapping.p[i];
4481 //printf("compare %d",i);
4482 //print_entitymapping(bnode);
4483 jscore = 0;
4484 if(anode->entityDomain == bnode->domain) jscore++;
4485 if(anode->entityCategory == bnode->category) jscore++;
4486 if(anode->entityCountry == bnode->country) jscore++;
4487 if(anode->entityKind == bnode->kind) jscore++;
4488 if(anode->entityExtra == bnode->extra) jscore++;
4489 if(anode->entitySubCategory == bnode->subcategory) jscore++;
4490 if(anode->entitySpecific == bnode->specific) jscore++;
4491 if(jscore > iscore){
4492 iscore = jscore;
4493 ibest = i;
4494 best = bnode;
4495 }
4496 }
4497 if(ibest > -1){
4498 applicationID = anode->applicationID;
4499 siteID = anode->siteID;
4500 entityID = anode->entityID;
4501 address = anode->address;
4502 port = anode->port;
4503 networkMode = newASCIIString ("networkReader"); //if we discovered entity by its heartbeats, then we're reading
4504 multicastRelayHost = anode->multicastRelayHost;
4505 multicastRelayPort = anode->multicastRelayPort;
4506 if(veclengthd(anode->geoCoords.c) < GEOEL_WE_A/2.0) use_GC = TRUE; //earths core GD,WE doesn't work well here
4507 }
4508 }
4509
4510 if(ibest > -1){
4511 int isgroup = 0;
4512 //printf("ibest = %d iscore= %d url=%s\n",ibest,iscore,best->url.p[0]->strptr);
4513 //if (best->_child == NULL) {
4514 struct X3D_Inline * iline;
4515 struct X3D_EspduTransform *espdu;
4516 //struct X3D_Group *grp;
4517 iline = createNewX3DNode(NODE_Inline); //this assigns a parent resource using parsing thread methods, which is wrong for rendering thread
4518 //resource_item_t *pres = iline->_parentResource;
4519 iline->_parentResource = X3D_PROTO(node->_executionContext)->_parentResource; //for rendering-thread creation of inlines, use the parent context's parentResource
4520 //if(isgroup){
4521 // grp = createNewX3DNode(NODE_Group);
4522 //}else{
4523 //this is 'normal' according to specs we are supposed to generate espdus
4524 espdu = createNewX3DNode(NODE_EspduTransform);
4525 if(use_GC) {
4526 espdu->geoSystem.p[0] = newASCIIString("GC");
4527 espdu->geoSystem.n = 1;
4528 }
4529 //populate entity fields - so it starts swallowing the heartbeat and update pdus of the entity
4530 espdu->enabled = TRUE;
4531 espdu->isActive = TRUE;
4532 espdu->entityID = entityID;
4533 espdu->applicationID = applicationID;
4534 espdu->siteID = siteID;
4535 espdu->port = port;
4536 espdu->address = address;
4537 espdu->multicastRelayHost = multicastRelayHost;
4538 espdu->multicastRelayPort = multicastRelayPort;
4539 espdu->networkMode = networkMode;
4540 dis_set_node_lasttime(X3D_NODE(espdu),TickTime());
4541
4542 /*
4543 void *dis_register(struct X3D_Node* node,char *address,int applicationID,int entityID,char *multicastRelayHost,
4544 int multicastRelayPort,
4545 char *networkMode, int port,double readInterval,int rtpHeaderExpected,int siteID,double writeInterval)
4546 */
4547 dis_register(X3D_NODE(espdu),address->strptr,applicationID,entityID,multicastRelayHost->strptr,multicastRelayPort,
4548 networkMode->strptr,port,5.0,FALSE,siteID,5.0);
4549 //}
4550 //if(best->_executionContext){
4551 add_node_to_broto_context(X3D_PROTO(node->_executionContext),X3D_NODE(iline));
4552 //if(isgroup)
4553 // add_node_to_broto_context(X3D_PROTO(node->_executionContext),X3D_NODE(grp));
4554 //else
4555 add_node_to_broto_context(X3D_PROTO(node->_executionContext),X3D_NODE(espdu));
4556 //}
4557 //best->_child = isgroup ? X3D_NODE(grp) : X3D_NODE(espdu);
4558
4559 //ADD_PARENT(X3D_NODE(best->_child), X3D_NODE(best));
4560 //if(isgroup)
4561 // AddRemoveChildren(X3D_NODE(grp), &grp->children, (struct X3D_Node * *)&iline, 1, ADD,__FILE__,__LINE__);
4562 //else
4563 AddRemoveChildren(X3D_NODE(espdu), &espdu->children, (struct X3D_Node * *)&iline, 1, ADD,__FILE__,__LINE__);
4564 /* copy over the URL from parent */
4565 shallow_copy_field(FIELDTYPE_MFString,(union anyVrml*)&best->url,(union anyVrml*)&iline->url);
4566 iline->load = TRUE;
4567 //}
4568
4569 AddRemoveChildren(X3D_NODE(node), mfn, (struct X3D_Node * *)&espdu, 1, ADD,__FILE__,__LINE__);
4570 //AddRemoveChildren(X3D_NODE(node), &node->addedEntities, (struct X3D_Node * *)&best->_child, 1, ADD,__FILE__,__LINE__);
4571 AddRemoveChildren(X3D_NODE(node), &node->addedEntities, (struct X3D_Node * *)&espdu, 1, ADD,__FILE__,__LINE__);
4572
4573 }
4574
4575 }
4576 if(node->addedEntities.n) MARK_EVENT(X3D_NODE(node),offsetof(struct X3D_DISEntityManager,addedEntities));
4577 node->addEntities.n = 0;
4578 FREE_IF_NZ(node->addEntities.p);
4579 }
4580 if(node->removeEntities.n){
4581 int i,j;
4582 struct Multi_Node* mfn = &node->entities;
4583 node->removedEntities.n = 0;
4584 for(j=0;j<node->removeEntities.n;j++){
4585 if(node->removeEntities.p[j]->_nodeType == NODE_DISEntityTypeMapping){
4586 int ibest,iscore,jscore;
4587 struct X3D_DISEntityTypeMapping *best, *anode = (struct X3D_DISEntityTypeMapping *)node->removeEntities.p[j];
4588 ibest = -1;
4589 iscore = 0;
4590 best = NULL;
4591 for(i=0;i<node->mapping.n;i++){
4592 if(node->mapping.p[i]->_nodeType == NODE_DISEntityTypeMapping){
4593 struct X3D_DISEntityTypeMapping *bnode = (struct X3D_DISEntityTypeMapping *)node->mapping.p[i];
4594 jscore = 0;
4595 if(anode->domain == bnode->domain) jscore++;
4596 if(anode->category == bnode->category) jscore++;
4597 if(anode->country == bnode->country) jscore++;
4598 if(anode->kind == bnode->kind) jscore++;
4599 if(anode->extra == bnode->extra) jscore++;
4600 if(anode->subcategory == bnode->subcategory) jscore++;
4601 if(anode->specific == bnode->specific) jscore++;
4602 if(jscore > iscore){
4603 iscore = jscore;
4604 ibest = i;
4605 best = bnode;
4606 }
4607 }
4608 }
4609 if(ibest > -1){
4610 //printf("remove: ibest = %d iscore= %d url=%s\n",ibest,iscore,best->url.p[0]->strptr);
4611 AddRemoveChildren(X3D_NODE(node), mfn, (struct X3D_Node * *)&best, 1, REMOVE,__FILE__,__LINE__);
4612 if(best->_child)
4613 AddRemoveChildren(X3D_NODE(node), &node->removedEntities, (struct X3D_Node * *)&best->_child, 1, ADD,__FILE__,__LINE__);
4614 }
4615 //else
4616 // printf("remove: no match found\n");
4617 }
4618 }
4619 if(node->removedEntities.n) {
4620 //printf("removedEntities.n=%d\n",node->removedEntities.n);
4621 MARK_EVENT(X3D_NODE(node),offsetof(struct X3D_DISEntityManager,removedEntities));
4622 }
4623 node->removeEntities.n = 0;
4624 }
4625}
4626Stack *dis_collide_stack = NULL;
4627void dis_collide(){
4628 int i,j;
4629 if(dis_collide_stack){
4630 for(i=0;i<dis_collide_stack->n;i++){
4631 int ihit;
4632 float ee[6];
4633 double mvmInverse[16], m2m[16];
4634 struct X3D_EspduTransform *espdu;
4635
4636 usehit *uhit = vector_get_ptr(usehit,dis_collide_stack,i);
4637 espdu = (struct X3D_EspduTransform*)uhit->node;
4638 if(espdu->isNetworkReader) continue; //do only OWNED/isWriter,isNeutral, listen for the rest
4639 ihit = 0;
4640 //invert matrix
4641 matinverseAFFINE(mvmInverse,uhit->mvm);
4642 extent6f_copy(ee,uhit->node->_extent);
4643 for(j=0;j<dis_collide_stack->n;j++){
4644 if(j != i){
4645 float eeb[6],eeba[6],eaXb[6];
4646 usehit *uhitb = vector_get_ptr(usehit,dis_collide_stack,j);
4647 extent6f_copy(eeb,uhitb->node->_extent);
4648 if(extent6f_isSet(eeb)){
4649 //multiply matrices
4650 matmultiplyAFFINE(m2m,mvmInverse,uhitb->mvm);
4651 //convert B extent to A-space
4652 extent6f_mattransform4d(eeba,eeb,m2m);
4653 //compare extents
4654 extent6f_intersect_extent6f(eaXb,ee,eeba);
4655 if(extent6f_isSet(eaXb)){
4656 //they overlap/intersect/collide
4657 //extent6f_printf(ee); printf("ee \n");
4658 //extent6f_printf(eeb); printf("eeb \n");
4659 //extent6f_printf(eeba); printf("eeba\n");
4660 //extent6f_printf(eaXb); printf("eaXb\n");
4661 //we'll just change A, and just for its collistion with B
4662 struct X3D_EspduTransform *espdub = (struct X3D_EspduTransform*)uhitb->node;
4663 if(espdu->isCollided == FALSE){
4664 espdu->collideTime = TickTime();
4665 espdu->eventNumber = dis_next_event_number();
4666 }
4667 espdu->collisionType = 33;
4668 espdu->isCollided = TRUE;
4669 espdu->eventSiteID = espdub->siteID;
4670 espdu->eventApplicationID = espdub->applicationID;
4671 espdu->eventEntityID = espdub->entityID;
4672 ihit++;
4673 //H we automatically do this during node compile:
4674 MARK_EVENT(X3D_NODE(espdu),offsetof(struct X3D_EspduTransform,isCollided));
4675 break;
4676 }
4677 }
4678 }
4679 }
4680 if(ihit == 0) {
4681 if(espdu->isCollided){
4682 espdu->isCollided = FALSE;
4683 espdu->collideTime = 0.0;
4684 espdu->collisionType = 0;
4685 espdu->eventSiteID = 0;
4686 espdu->eventApplicationID = 0;
4687 espdu->eventEntityID = 0;
4688 MARK_EVENT(X3D_NODE(espdu),offsetof(struct X3D_EspduTransform,isCollided));
4689 }
4690 }
4691 }
4692 }
4693}
4694void dis_clear_collide(){
4695 if(dis_collide_stack) dis_collide_stack->n = 0;
4696}
4697void dis_register_collide(struct X3D_Node* node,double *transform){
4698 //call from child_espduTransform
4699 int i, ifound;
4700 if(!dis_collide_stack) dis_collide_stack = newStack(usehit);
4701 ifound = -1;
4702 for(i=0;i<dis_collide_stack->n;i++){
4703 usehit *uhit = vector_get_ptr(usehit,dis_collide_stack,i);
4704 if(uhit->node == node){
4705 ifound = i;
4706 break;
4707 }
4708 }
4709 if(ifound == -1){
4710 usehit uhit;
4711 uhit.node = node;
4712 memcpy(uhit.mvm,transform,16*sizeof(double));
4713 uhit.userdata = NULL;
4714 vector_pushBack(usehit,dis_collide_stack,uhit);
4715 }
4716
4717}
4718#else //WITH_DIS
4719
4720void compile_DISEntityManager(struct X3D_DISEntityManager *node){}
4721void child_DISEntityManager(struct X3D_DISEntityManager *node){}
4722void compile_TransmitterPdu(struct X3D_TransmitterPdu *node){}
4723void child_TransmitterPdu(struct X3D_TransmitterPdu *node){}
4724void compile_SignalPdu(struct X3D_SignalPdu *node){}
4725void child_SignalPdu(struct X3D_SignalPdu *node){}
4726void compile_ReceiverPdu(struct X3D_ReceiverPdu *node){}
4727void child_ReceiverPdu(struct X3D_ReceiverPdu *node){}
4728void compile_EspduTransform (struct X3D_EspduTransform *node) {}
4729void prep_EspduTransform(struct X3D_EspduTransform *node){}
4730void fin_EspduTransform(struct X3D_EspduTransform *node){}
4731void child_EspduTransform(struct X3D_EspduTransform *node){}
4732
4733#endif //WITH_DIS
4734
4735void fwl_sendreceive_DIS(){
4736 //just the buffer in/out is handled here
4737 //the interpretation/parsing/packing of pdus is done in the backend
4738 //this might need to be in the front end so platforms with sandbox restrictions on communication
4739 //can do this in the native language/technology if necessary - I'll find out later.
4740/* pseudo code design:
4741 if(dis_sendlist.n > 0){
4742 //backend will queue up pdus to send,
4743 //frontend fetches them one by one from the queue
4744 //this isolates potentialy platform-specific things like networking in frontend
4745 //while avoiding having the backend call into the frontend which is often in a dfferent
4746 //language technology
4747 loop over sendlist:
4748 (n,buf,ip,port) = get_next_send_from_backend()
4749 sendTo(buf,n,ip,port)
4750 // flushing queue should be done in BACKEND, start of each loop
4751 // so if no frontend capability, the queue doesn't overflow
4752 }
4753 if(dis_recvlist.n > 0){
4754 loop over all recv channels or connect-switch or libevent
4755 if(not yet opened)
4756 open
4757 non-blocking recv or recvfrom or recv with short timeout
4758 if(got something) dis_incoming_to_backend(ip,port,stream,len)
4759 }
4760*/
4761 if(allow_DIS){
4762#ifdef WITH_DIS
4763 //printf("yo from fwl_sendreceive_DIS\n");
4764 dis_collide();
4765 dis_sendloop();
4766 dis_recvloop();
4767 dis_clear_collide();
4768#endif //WITH_DIS
4769 }
4770}
4771//
4772//#ifdef WITH_DIS
4773//#include "../DIS/DIS.c"
4774//#endif //WITH_DIS
unsigned short quantity
how many of the munition were fired
Definition DIS.h:840
unsigned short rate
rate at which the munition was fired
Definition DIS.h:842
struct EntityType munition
What munition was used in the burst.
Definition DIS.h:834
unsigned short warhead
type of warhead
Definition DIS.h:836
unsigned short fuse
type of fuse used
Definition DIS.h:838
unsigned char collisionType
ID of event.
Definition DIS.h:1807
struct EventID eventID
ID of event.
Definition DIS.h:1805
struct EntityID issuingEntityID
ID of the entity that issued the collision PDU.
Definition DIS.h:1801
struct EntityID collidingEntityID
ID of entity that has collided with the issuing entity ID.
Definition DIS.h:1803
struct Vector3Float entityAngularVelocity
angular velocity of the entity
Definition DIS.h:742
struct Vector3Float entityLinearAcceleration
Linear acceleration of the entity.
Definition DIS.h:740
unsigned char deadReckoningAlgorithm
enumeration of what dead reckoning algorighm to use
Definition DIS.h:736
char otherParameters[15]
other parameters to use in the dead reckoning algorithm
Definition DIS.h:738
struct Vector3Float locationInEntityCoordinates
location of the detonation or impact in the target entity's coordinate system.
Definition DIS.h:1749
struct BurstDescriptor burstDescriptor
Describes munition used.
Definition DIS.h:1747
struct Vector3Double locationInWorldCoordinates
where the detonation is, in world coordinates
Definition DIS.h:1745
unsigned char detonationResult
result of the explosion
Definition DIS.h:1751
struct EventID eventID
ID firing event.
Definition DIS.h:1741
unsigned char numberOfArticulationParameters
How many articulation parameters we have.
Definition DIS.h:1753
struct EntityID munitionID
ID of muntion that was fired.
Definition DIS.h:1739
struct Vector3Float velocity
ID firing event.
Definition DIS.h:1743
unsigned short application
The application ID.
Definition DIS.h:575
unsigned short site
The site ID.
Definition DIS.h:573
unsigned short entity
the entity ID
Definition DIS.h:577
struct Vector3Float entityLinearVelocity
Describes the speed of the entity in the world.
Definition DIS.h:2145
struct EntityType entityType
Describes the type of entity in the world.
Definition DIS.h:2142
struct EntityID entityID
Unique ID for an entity that is tied to this state information.
Definition DIS.h:2136
void * articulationParameters
variable length list of articulation parameters
Definition DIS.h:2159
struct Orientation entityOrientation
describes the orientation of the entity, in euler angles
Definition DIS.h:2149
int entityAppearance
a series of bit flags that are used to help draw the entity, such as smoking, on fire,...
Definition DIS.h:2151
struct Vector3Double entityLocation
describes the location of the entity in the world
Definition DIS.h:2147
struct DeadReckoningParameter deadReckoningParameters
parameters used for dead reckoning
Definition DIS.h:2153
char numberOfArticulationParameters
How many articulation parameters are in the variable length list.
Definition DIS.h:2140
unsigned char domain
Domain of entity (air, surface, subsurface, space, etc)
Definition DIS.h:482
unsigned short country
country to which the design of the entity is attributed
Definition DIS.h:484
unsigned char entityKind
Kind of entity.
Definition DIS.h:480
unsigned char specific
specific info based on subcategory field
Definition DIS.h:490
unsigned char category
category of entity
Definition DIS.h:486
unsigned char subcategory
subcategory of entity
Definition DIS.h:488
unsigned short application
The application ID.
Definition DIS.h:226
unsigned short eventNumber
the number of the event
Definition DIS.h:228
unsigned short site
The site ID.
Definition DIS.h:224
struct BurstDescriptor burstDescriptor
Describes munitions used in the firing event.
Definition DIS.h:1846
struct EntityID munitionID
ID of the munition that is being shot.
Definition DIS.h:1839
struct Vector3Float velocity
Velocity of the ammunition.
Definition DIS.h:1848
struct EventID eventID
ID of event.
Definition DIS.h:1841
struct Vector3Double locationInWorldCoordinates
location of the firing event
Definition DIS.h:1844
float range
range to the target
Definition DIS.h:1850
unsigned short system
system
Definition DIS.h:346
unsigned short detail
detail
Definition DIS.h:344
unsigned short spreadSpectrum
spread spectrum, 16 bit boolean array
Definition DIS.h:340
unsigned short major
major
Definition DIS.h:342
Definition DIS.h:597
unsigned char pduType
Type of pdu, unique for each PDU class.
Definition DIS.h:603
unsigned short radioId
particular radio within an entity
Definition DIS.h:881
struct EntityID entityId
ID of the entitythat is the source of the communication.
Definition DIS.h:879
unsigned short country
country to which the design of the entity is attributed
Definition DIS.h:174
unsigned char domain
Domain of entity (air, surface, subsurface, space, etc)
Definition DIS.h:172
unsigned char entityKind
Kind of entity.
Definition DIS.h:170
unsigned char category
category of entity
Definition DIS.h:176
unsigned char nomenclatureVersion
specific info based on subcategory field
Definition DIS.h:178
struct EntityID transmitterEntityId
ID of transmitter.
Definition DIS.h:1863
unsigned short transmitterRadioId
ID of transmitting radio.
Definition DIS.h:1865
unsigned short receiverState
encoding scheme used, and enumeration
Definition DIS.h:1857
float receivedPoser
received power
Definition DIS.h:1861
void * data
list of eight bit values
Definition DIS.h:1939
unsigned int sampleRate
sample rate
Definition DIS.h:1933
unsigned short encodingScheme
encoding scheme used, and enumeration
Definition DIS.h:1929
short dataLength
length od data
Definition DIS.h:1935
unsigned short tdlType
tdl type
Definition DIS.h:1931
short samples
number of samples
Definition DIS.h:1937
struct EntityID originatingEntityID
Entity that is sending message.
Definition DIS.h:801
unsigned char modulationParameterCount
how many modulation parameters we have
Definition DIS.h:1261
unsigned short antennaPatternType
antenna pattern type
Definition DIS.h:1245
unsigned char transmitState
transmit state
Definition DIS.h:1235
float power
transmission power
Definition DIS.h:1253
unsigned short cryptoSystem
crypto system enumeration
Definition DIS.h:1257
float transmitFrequencyBandwidth
transmit frequency Bandwidth
Definition DIS.h:1251
struct RadioEntityType radioEntityType
linear accelleration of entity
Definition DIS.h:1233
struct Vector3Double antennaLocation
Location of antenna.
Definition DIS.h:1241
struct Vector3Float relativeAntennaLocation
relative location of antenna
Definition DIS.h:1243
unsigned short cryptoKeyId
crypto system key identifer
Definition DIS.h:1259
unsigned char inputSource
input source
Definition DIS.h:1237
unsigned short antennaPatternCount
atenna pattern length
Definition DIS.h:1247
unsigned long long frequency
frequency
Definition DIS.h:1249
struct ModulationType modulationType
modulation
Definition DIS.h:1255
double x
X value.
Definition DIS.h:589
double y
Y value.
Definition DIS.h:591
double z
Z value.
Definition DIS.h:593
float z
Z value.
Definition DIS.h:334
float y
y Value
Definition DIS.h:332
float x
X value.
Definition DIS.h:330
struct EntityID firingEntityID
ID of the entity that shot.
Definition DIS.h:997