Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F632839
node.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Authored By
Unknown
Size
14 KB
Referenced Files
None
Subscribers
None
node.cpp
View Options
#include
"scene/node.h"
#include
"compat/misc.h"
#include
"threads.h"
#include
"main/references.h"
#include
"main/logging.h"
#include
"render/driver.h"
#include
"obj/object.h"
#include
"empire.h"
#include
"physics/physics_world.h"
#include
"aabbox.h"
#include
"memory/AllocOnlyPool.h"
#include
<map>
#include
<set>
extern
double
frameTime_s
;
extern
unsigned
frameNumber
;
Colorf
fallbackNodeColor
;
Object
*
fallbackNodeObject
;
//Produce a vaguely unique value per node, consistent per node
void
shader_unique
(
float
*
values
,
unsigned
short
,
void
*
)
{
if
(
auto
*
node
=
scene
::
renderingNode
)
values
[
0
]
=
(
float
)(((
node
-
(
scene
::
Node
*
)
0
)
>>
4
)
&
0xff
)
/
255.f
;
else
values
[
0
]
=
0.5f
;
}
void
shader_node_color
(
float
*
colors
,
unsigned
short
,
void
*
)
{
if
(
auto
*
node
=
scene
::
renderingNode
)
*
(
Colorf
*
)
colors
=
node
->
color
;
else
*
(
Colorf
*
)
colors
=
fallbackNodeColor
;
}
void
shader_node_distance
(
float
*
distance
,
unsigned
short
,
void
*
)
{
if
(
auto
*
node
=
scene
::
renderingNode
)
*
distance
=
(
float
)
node
->
sortDistance
;
else
*
distance
=
0.f
;
}
void
shader_node_scale
(
float
*
scale
,
unsigned
short
,
void
*
)
{
if
(
auto
*
node
=
scene
::
renderingNode
)
*
scale
=
(
float
)
node
->
abs_scale
;
else
*
scale
=
1.f
;
}
void
shader_node_selected
(
float
*
value
,
unsigned
short
,
void
*
)
{
if
(
auto
*
node
=
scene
::
renderingNode
)
{
Object
*
obj
=
node
->
obj
;
if
(
obj
&&
obj
->
getFlag
(
objSelected
))
*
(
float
*
)
value
=
1.f
;
else
*
(
float
*
)
value
=
0.f
;
}
else
*
(
float
*
)
value
=
0.f
;
}
void
shader_obj_velocity
(
float
*
value
,
unsigned
short
,
void
*
)
{
if
(
auto
*
node
=
scene
::
renderingNode
)
{
Object
*
obj
=
node
->
obj
;
if
(
obj
)
*
(
float
*
)
value
=
(
obj
->
velocity
+
obj
->
acceleration
*
(
frameTime_s
-
obj
->
lastTick
)).
getLength
();
else
*
(
float
*
)
value
=
0.f
;
}
else
if
(
fallbackNodeObject
)
{
*
(
float
*
)
value
=
(
fallbackNodeObject
->
velocity
+
fallbackNodeObject
->
acceleration
*
(
frameTime_s
-
fallbackNodeObject
->
lastTick
)).
getLength
();
}
else
*
(
float
*
)
value
=
0.f
;
}
void
shader_obj_position
(
float
*
value
,
unsigned
short
,
void
*
)
{
if
(
auto
*
node
=
scene
::
renderingNode
)
{
Object
*
obj
=
node
->
obj
;
if
(
obj
)
{
value
[
0
]
=
obj
->
position
.
x
;
value
[
1
]
=
obj
->
position
.
y
;
value
[
2
]
=
obj
->
position
.
z
;
}
else
{
value
[
0
]
=
0.f
;
value
[
1
]
=
0.f
;
value
[
2
]
=
0.f
;
}
}
else
if
(
fallbackNodeObject
)
{
value
[
0
]
=
fallbackNodeObject
->
position
.
x
;
value
[
1
]
=
fallbackNodeObject
->
position
.
y
;
value
[
2
]
=
fallbackNodeObject
->
position
.
z
;
}
else
{
value
[
0
]
=
0.f
;
value
[
1
]
=
0.f
;
value
[
2
]
=
0.f
;
}
}
void
shader_obj_rotation
(
float
*
value
,
unsigned
short
,
void
*
)
{
if
(
auto
*
node
=
scene
::
renderingNode
)
{
Object
*
obj
=
node
->
obj
;
if
(
obj
)
{
value
[
0
]
=
obj
->
rotation
.
xyz
.
x
;
value
[
1
]
=
obj
->
rotation
.
xyz
.
y
;
value
[
2
]
=
obj
->
rotation
.
xyz
.
z
;
value
[
3
]
=
obj
->
rotation
.
w
;
}
else
{
value
[
0
]
=
0.f
;
value
[
1
]
=
0.f
;
value
[
2
]
=
0.f
;
value
[
3
]
=
1.f
;
}
}
else
if
(
fallbackNodeObject
)
{
value
[
0
]
=
fallbackNodeObject
->
rotation
.
xyz
.
x
;
value
[
1
]
=
fallbackNodeObject
->
rotation
.
xyz
.
y
;
value
[
2
]
=
fallbackNodeObject
->
rotation
.
xyz
.
z
;
value
[
3
]
=
fallbackNodeObject
->
rotation
.
w
;
}
else
{
value
[
0
]
=
0.f
;
value
[
1
]
=
0.f
;
value
[
2
]
=
0.f
;
value
[
3
]
=
1.f
;
}
}
void
shader_node_position
(
float
*
value
,
unsigned
short
,
void
*
)
{
if
(
auto
*
node
=
scene
::
renderingNode
)
{
value
[
0
]
=
node
->
abs_position
.
x
;
value
[
1
]
=
node
->
abs_position
.
y
;
value
[
2
]
=
node
->
abs_position
.
z
;
}
else
if
(
fallbackNodeObject
)
{
value
[
0
]
=
fallbackNodeObject
->
position
.
x
;
value
[
1
]
=
fallbackNodeObject
->
position
.
y
;
value
[
2
]
=
fallbackNodeObject
->
position
.
z
;
}
else
{
value
[
0
]
=
0.f
;
value
[
1
]
=
0.f
;
value
[
2
]
=
0.f
;
}
}
void
shader_node_rotation
(
float
*
value
,
unsigned
short
,
void
*
)
{
if
(
auto
*
node
=
scene
::
renderingNode
)
{
value
[
0
]
=
node
->
abs_rotation
.
xyz
.
x
;
value
[
1
]
=
node
->
abs_rotation
.
xyz
.
y
;
value
[
2
]
=
node
->
abs_rotation
.
xyz
.
z
;
value
[
3
]
=
node
->
abs_rotation
.
w
;
}
else
if
(
fallbackNodeObject
)
{
value
[
0
]
=
fallbackNodeObject
->
rotation
.
xyz
.
x
;
value
[
1
]
=
fallbackNodeObject
->
rotation
.
xyz
.
y
;
value
[
2
]
=
fallbackNodeObject
->
rotation
.
xyz
.
z
;
value
[
3
]
=
fallbackNodeObject
->
rotation
.
w
;
}
else
{
value
[
0
]
=
0.f
;
value
[
1
]
=
0.f
;
value
[
2
]
=
0.f
;
value
[
3
]
=
1.f
;
}
}
void
shader_obj_acceleration
(
float
*
value
,
unsigned
short
,
void
*
)
{
if
(
auto
*
node
=
scene
::
renderingNode
)
{
Object
*
obj
=
node
->
obj
;
if
(
obj
)
*
(
float
*
)
value
=
obj
->
acceleration
.
getLength
();
else
*
(
float
*
)
value
=
0.f
;
}
else
if
(
fallbackNodeObject
)
{
*
(
float
*
)
value
=
fallbackNodeObject
->
acceleration
.
getLength
();
}
else
*
(
float
*
)
value
=
0.f
;
}
void
shader_emp_flag
(
int
*
value
,
unsigned
short
,
void
*
)
{
if
(
auto
*
node
=
scene
::
renderingNode
)
{
Object
*
obj
=
node
->
obj
;
if
(
obj
)
{
Empire
*
owner
=
obj
->
owner
;
if
(
owner
)
*
(
int
*
)
value
=
(
int
)
owner
->
flagID
;
else
*
(
int
*
)
value
=
0
;
}
else
{
*
(
int
*
)
value
=
0
;
}
}
else
if
(
fallbackNodeObject
)
{
Empire
*
owner
=
fallbackNodeObject
->
owner
;
if
(
owner
)
*
(
int
*
)
value
=
(
int
)
owner
->
flagID
;
else
*
(
int
*
)
value
=
0
;
}
else
*
(
int
*
)
value
=
0
;
}
void
shader_obj_id
(
int
*
value
,
unsigned
short
,
void
*
)
{
if
(
auto
*
node
=
scene
::
renderingNode
)
{
Object
*
obj
=
node
->
obj
;
if
(
obj
)
*
(
int
*
)
value
=
obj
->
id
;
else
*
(
int
*
)
value
=
0
;
}
else
if
(
fallbackNodeObject
)
{
*
(
int
*
)
value
=
fallbackNodeObject
->
id
;
}
else
*
(
int
*
)
value
=
0
;
}
namespace
scene
{
const
char
*
typeNames
[
NT_ScriptBase
]
=
{
"Misc Node"
,
"Culling Node"
,
"Particle System"
,
"Mesh Node"
,
"Mesh+Icon Node"
};
extern
const
char
*
getScriptNodeName
(
unsigned
id
);
#ifdef PROFILE_ANIMATION
volatile
double
nodeAnimTimes
[
32
]
=
{
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
};
threads
::
atomic_int
nodeAnimCounts
[
32
];
void
dumpAnimationProfile
()
{
for
(
unsigned
i
=
0
;
i
<
32
;
++
i
)
{
int
count
=
nodeAnimCounts
[
i
];
double
total
=
nodeAnimTimes
[
i
];
if
(
count
==
0
)
continue
;
nodeAnimTimes
[
i
]
=
0
;
nodeAnimCounts
[
i
]
=
0
;
const
char
*
name
=
nullptr
;
if
(
i
<
NT_ScriptBase
)
name
=
typeNames
[
i
];
else
name
=
getScriptNodeName
(
i
-
NT_ScriptBase
);
print
(
"%s: %.1lf ms (%.1lf us per)"
,
name
,
total
*
1.0e3
,
total
*
1.0e6
/
double
(
count
));
}
}
#endif
const
char
*
Node::getName
()
const
{
unsigned
typeIndex
=
(
unsigned
)
getType
();
if
(
typeIndex
<
NT_ScriptBase
)
return
typeNames
[
typeIndex
];
else
return
getScriptNodeName
(
typeIndex
-
NT_ScriptBase
);
}
Node
*
renderingNode
;
threads
::
Mutex
nodeEventLock
;
std
::
vector
<
NodeEvent
*>*
pushQueue
=
new
std
::
vector
<
NodeEvent
*>
,
*
activeQueue
=
new
std
::
vector
<
NodeEvent
*>
;
memory
::
AllocOnlyRegion
<
threads
::
Mutex
>
nodeEventMemory
(
2048
);
void
*
NodeEvent
::
operator
new
(
size_t
bytes
)
{
return
nodeEventMemory
.
alloc
(
bytes
);
}
void
NodeEvent
::
operator
delete
(
void
*
p
)
{
nodeEventMemory
.
dealloc
((
unsigned
char
*
)
p
);
}
void
queueNodeEvent
(
NodeEvent
*
evt
)
{
nodeEventLock
.
lock
();
pushQueue
->
push_back
(
evt
);
nodeEventLock
.
release
();
}
void
clearNodeEvents
()
{
nodeEventLock
.
lock
();
for
(
auto
i
=
activeQueue
->
begin
(),
end
=
activeQueue
->
end
();
i
!=
end
;
++
i
)
delete
*
i
;
for
(
auto
i
=
pushQueue
->
begin
(),
end
=
pushQueue
->
end
();
i
!=
end
;
++
i
)
delete
*
i
;
activeQueue
->
clear
();
pushQueue
->
clear
();
nodeEventLock
.
release
();
}
void
processNodeEvents
()
{
if
(
pushQueue
->
empty
())
return
;
nodeEventLock
.
lock
();
std
::
swap
(
pushQueue
,
activeQueue
);
nodeEventLock
.
release
();
for
(
auto
i
=
activeQueue
->
begin
(),
end
=
activeQueue
->
end
();
i
!=
end
;
++
i
)
{
NodeEvent
*
evt
=
*
i
;
evt
->
process
();
delete
evt
;
}
activeQueue
->
clear
();
}
NodeEvent
::
NodeEvent
(
Node
*
node
)
:
node
(
node
)
{
if
(
node
)
node
->
grab
();
}
NodeEvent
::~
NodeEvent
()
{
if
(
node
)
node
->
drop
();
}
void
Node
::
markForDeletion
()
{
//TODO: This might be unsafe if the bool is packed alongside another member
queuedDelete
=
true
;
}
class
ReparentNode
:
public
NodeEvent
{
heldPointer
<
Node
>
parent
;
public
:
ReparentNode
(
Node
*
reparent
,
Node
*
toParent
)
:
NodeEvent
(
reparent
),
parent
(
toParent
)
{
}
void
process
()
override
{
node
->
setParent
(
parent
);
node
->
rebuildTransformation
();
node
->
sortDistance
=
node
->
abs_position
.
distanceTo
(
devices
.
render
->
cam_pos
);
}
};
void
Node::queueReparent
(
Node
*
newParent
)
{
if
(
newParent
==
0
)
newParent
=
devices
.
scene
;
queueNodeEvent
(
new
ReparentNode
(
this
,
newParent
));
}
class
ReparentToObject
:
public
NodeEvent
{
public
:
heldPointer
<
Object
>
object
;
ReparentToObject
(
Node
*
reparent
,
Object
*
obj
)
:
NodeEvent
(
reparent
),
object
(
obj
)
{
}
void
process
()
override
{
//The object can't be destroyed here, so the node should stay valid too
//TODO: Check that assumption in all cases. (True in practice now because
//region nodes are never destroyed in game)
Node
*
other
=
object
->
node
;
if
(
other
)
{
node
->
setParent
(
other
);
node
->
rebuildTransformation
();
node
->
sortDistance
=
node
->
abs_position
.
distanceTo
(
devices
.
render
->
cam_pos
);
}
}
};
void
Node::hintParentObject
(
Object
*
obj
,
bool
checkDistance
)
{
if
(
!
obj
||
!
obj
->
node
)
{
//We shouldn't be parented to anything
if
(
parent
&&
parent
!=
devices
.
scene
)
queueReparent
(
nullptr
);
}
else
{
//Check that we're completely inside this object
double
maxDist
=
obj
->
radius
-
abs_scale
;
if
(
!
checkDistance
||
abs_position
.
distanceToSQ
(
obj
->
position
)
<
maxDist
*
maxDist
)
{
//Accessing the random object's node pointer is
//not technically safe here, but because we're only checking
//for equality it won't break.
if
(
parent
!=
obj
->
node
)
queueNodeEvent
(
new
ReparentToObject
(
this
,
obj
));
}
else
{
//We're too big to be in this node, leave
if
(
parent
&&
parent
!=
devices
.
scene
)
queueReparent
(
nullptr
);
}
}
if
(
obj
)
obj
->
drop
();
}
bool
Node::getFlag
(
NodeFlag
flag
)
const
{
return
(
flags
&
flag
)
!=
0
;
}
void
Node::setFlag
(
NodeFlag
flag
,
bool
val
)
{
if
(
val
)
flags
|=
flag
;
else
flags
&=
~
flag
;
}
bool
Node::isChild
(
Node
*
check
)
{
foreach
(
child
,
children
)
{
if
(
*
child
==
check
)
return
true
;
}
return
false
;
}
void
Node::addChild
(
Node
*
child
)
{
child
->
grab
();
children
.
push_back
(
child
);
child
->
setFlag
(
NF_Dirty
,
true
);
child
->
parent
=
this
;
}
void
Node::removeChild
(
Node
*
check
)
{
foreach
(
child
,
children
)
{
if
(
*
child
==
check
)
{
children
.
erase
(
child
);
check
->
parent
=
0
;
check
->
drop
();
return
;
}
}
}
void
Node::setParent
(
Node
*
newParent
)
{
if
(
newParent
==
parent
)
return
;
Node
*
oldParent
=
parent
;
if
(
newParent
)
newParent
->
addChild
(
this
);
if
(
oldParent
)
oldParent
->
removeChild
(
this
);
parent
=
newParent
;
if
(
newParent
&&
oldParent
)
animate
();
}
void
Node::destroyTree
()
{
foreach
(
child
,
children
)
(
*
child
)
->
destroyTree
();
children
.
clear
();
parent
=
0
;
}
void
Node::destroy
()
{
if
(
physics
)
{
devices
.
nodePhysics
->
unregisterItem
(
*
physics
);
physics
=
0
;
drop
();
}
if
(
obj
)
{
obj
->
drop
();
obj
=
0
;
}
animator
=
0
;
parent
=
0
;
}
void
Node::flagDirty
()
{
if
(
!
getFlag
(
NF_Dirty
))
{
setFlag
(
NF_Dirty
,
true
);
foreach
(
child
,
children
)
(
*
child
)
->
flagDirty
();
}
}
bool
nodeSort
(
scene
::
Node
*
a
,
scene
::
Node
*
b
)
{
return
*
a
<
*
b
;
}
void
Node::animate
()
{
#ifdef PROFILE_ANIMATION
double
start
=
devices
.
driver
->
getAccurateTime
();
#endif
if
(
animator
)
animator
->
animate
(
this
);
if
(
flags
&
NF_Dirty
)
rebuildTransformation
();
if
(
flags
&
NF_AnimOnlyVisible
)
frameVisible
=
visible
&&
preRender
(
*
devices
.
render
);
else
frameVisible
=
preRender
(
*
devices
.
render
)
&&
visible
;
#ifdef PROFILE_ANIMATION
double
end
=
devices
.
driver
->
getAccurateTime
();
double
duration
=
end
-
start
;
auto
type
=
getType
();
nodeAnimCounts
[
type
]
++
;
volatile
double
&
curTime
=
nodeAnimTimes
[
type
];
while
(
true
)
{
double
prev
=
curTime
;
double
result
=
prev
+
duration
;
if
(
threads
::
compare_and_swap
((
long
long
*
)
&
curTime
,
*
(
long
long
*
)
&
prev
,
*
(
long
long
*
)
&
result
)
==
*
(
long
long
*
)
&
prev
)
break
;
}
#endif
if
(
frameVisible
)
{
foreach
(
child
,
children
)
(
*
child
)
->
animate
();
if
(
children
.
size
()
>
1
)
std
::
sort
(
children
.
begin
(),
children
.
end
(),
nodeSort
);
}
}
void
Node::sortChildren
()
{
if
(
children
.
size
()
>
1
)
std
::
sort
(
children
.
begin
(),
children
.
end
(),
nodeSort
);
}
void
Node::rebuildTransformation
()
{
setFlag
(
NF_Dirty
,
false
);
if
(
parent
&&
!
getFlag
(
NF_Independent
))
{
if
(
getFlag
(
NF_ParentScale
))
{
abs_position
=
parent
->
abs_position
+
(
parent
->
abs_rotation
*
position
)
*
parent
->
abs_scale
;
abs_rotation
=
parent
->
abs_rotation
*
rotation
;
abs_scale
=
parent
->
abs_scale
*
scale
;
}
else
{
abs_position
=
parent
->
abs_position
+
position
;
abs_rotation
=
rotation
;
abs_scale
=
scale
;
}
}
else
{
abs_position
=
position
;
abs_rotation
=
rotation
;
abs_scale
=
scale
;
}
if
(
!
getFlag
(
NF_NoMatrix
))
abs_rotation
.
toTransform
(
transformation
,
abs_position
,
abs_scale
);
if
(
physics
)
{
auto
bbox
=
AABBoxd
::
fromCircle
(
abs_position
,
abs_scale
);
if
(
physics
->
bound
!=
bbox
)
devices
.
nodePhysics
->
updateItem
(
*
physics
,
bbox
);
}
}
Node
::
Node
()
:
flags
(
NF_Dirty
|
NF_Independent
),
lastUpdate
(
frameTime_s
),
sortDistance
(
0
),
scale
(
1
),
abs_scale
(
1
),
distanceCutoff
(
1.0e8
),
obj
(
0
),
physics
(
0
),
visible
(
true
),
frameVisible
(
true
),
queuedDelete
(
false
),
remembered
(
false
)
{}
Node
::~
Node
()
{
destroy
();
}
void
Node
::
setObject
(
Object
*
Obj
)
{
if
(
Obj
==
obj
)
return
;
if
(
Obj
)
Obj
->
grab
();
if
(
obj
)
obj
->
drop
();
obj
=
Obj
;
}
Object
*
Node
::
getObject
()
{
if
(
obj
)
obj
->
grab
();
return
obj
;
}
void
Node
::
createPhysics
()
{
if
(
physics
||
!
devices
.
nodePhysics
)
return
;
rebuildTransformation
();
grab
();
physics
=
devices
.
nodePhysics
->
registerItem
(
AABBoxd
::
fromCircle
(
abs_position
,
abs_scale
),
this
);
}
bool
Node
::
operator
<
(
const
scene
::
Node
&
other
)
const
{
if
(
frameVisible
&&
other
.
frameVisible
)
{
bool
alpha
=
getFlag
(
NF_Transparent
);
if
(
alpha
!=
other
.
getFlag
(
NF_Transparent
))
{
if
(
alpha
)
return
false
;
else
return
true
;
}
else
if
(
alpha
)
{
return
sortDistance
>
other
.
sortDistance
;
}
else
{
return
sortDistance
<
other
.
sortDistance
;
}
}
else
if
(
frameVisible
)
{
return
true
;
}
else
{
return
false
;
}
}
void
Node
::
_render
(
render
::
RenderDriver
&
driver
)
{
renderingNode
=
this
;
render
(
driver
);
if
(
auto
cnt
=
children
.
size
())
{
for
(
decltype
(
cnt
)
i
=
0
;
i
<
cnt
;)
{
scene
::
Node
*
child
=
children
[
i
];
if
(
!
child
->
queuedDelete
)
{
++
i
;
if
(
child
->
frameVisible
)
child
->
_render
(
driver
);
}
else
{
child
->
destroy
();
child
->
drop
();
children
[
i
]
=
children
[
cnt
-1
];
--
cnt
;
}
}
if
(
cnt
!=
children
.
size
())
children
.
resize
(
cnt
);
}
}
};
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Sun, Nov 15, 3:27 PM (1 d, 12 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
131035
Default Alt Text
node.cpp (14 KB)
Attached To
Mode
R80 StarRuler2-Source
Attached
Detach File
Event Timeline