1 #ifndef __GNUC__
2 #pragma once
3 #endif
4 #ifndef __XR_INFLUENCE_H__
5 #define __XR_INFLUENCE_H__
6 
7 #include <algorithm>
8 #include "xr_fixed_vector.h"
9 #include "xr_skeleton.h"
10 
11 namespace xray_re {
12 
13 template<typename Tb, typename Tw> struct _bone_weight {
14 			_bone_weight();
15 			_bone_weight(Tb _bone, Tw _weight);
16 	bool		operator==(const _bone_weight<Tb, Tw>& right) const;
17 	bool		operator<(const _bone_weight<Tb, Tw>& right) const;
18 	Tb		bone;
19 	Tw		weight;
20 };
21 
22 typedef _bone_weight<uint32_t, float> fbone_weight;
23 
24 // up to 2 influences in SoC, and up to 4 in CS.
25 template<typename Tb, typename Tw> struct _influence: public _svector<_bone_weight<Tb, Tw>, 4> {
26 	void		set(uint32_t bone0);
27 	void		set(uint16_t bone0, uint16_t bone1, float weight0);
28 	void		set_wo_reorder(uint16_t bone0, uint16_t bone1, float weight0);
29 	void		set(size_t num_bones, const uint16_t* bones, const float* weights);
30 	void		reorder();
31 };
32 
33 typedef _influence<uint32_t, float> finfluence;
34 
_bone_weight()35 template<typename Tb, typename Tw> inline _bone_weight<Tb, Tw>::_bone_weight():
36 	bone(0), weight(Tw(1)) {}
37 
_bone_weight(Tb _bone,Tw _weight)38 template<typename Tb, typename Tw> inline _bone_weight<Tb, Tw>::_bone_weight(Tb _bone, Tw _weight):
39 	bone(_bone), weight(_weight) {}
40 
41 template<typename Tb, typename Tw> inline
42 bool _bone_weight<Tb, Tw>::operator==(const _bone_weight<Tb, Tw>& right) const
43 {
44 	return bone == right.bone && weight == right.weight;
45 }
46 
47 template<typename Tb, typename Tw> inline
48 bool _bone_weight<Tb, Tw>::operator<(const _bone_weight<Tb, Tw>& right) const
49 {
50 	return bone < right.bone || (bone == right.bone && weight < right.weight);
51 }
52 
set(uint32_t bone0)53 template<typename Tb, typename Tw> inline void _influence<Tb, Tw>::set(uint32_t bone0)
54 {
55 	this->push_back(_bone_weight<Tb, Tw>(bone0, Tw(1)));
56 }
57 
58 template<typename Tb, typename Tw>
set(uint16_t bone0,uint16_t bone1,float weight0)59 void _influence<Tb, Tw>::set(uint16_t bone0, uint16_t bone1, float weight0)
60 {
61 #if 0
62 	assert(weight0 >= 0.f && weight0 <= 1.f);
63 	assert(bone0 < MAX_BONES && bone1 < MAX_BONES);
64 #endif
65 	if (bone0 == bone1) {
66 		this->push_back(_bone_weight<Tb, Tw>(bone0, Tw(1)));
67 	} else {
68 		_bone_weight<Tb, Tw> bw0(bone0, Tw(1.f - weight0));
69 		_bone_weight<Tb, Tw> bw1(bone1, Tw(weight0));
70 #if 0
71 		xr_assert(weight0 != 0);
72 		xr_assert(1.f != weight0);
73 		xr_assert(!equivalent<Tw>(weight0, 0));
74 		xr_assert(!equivalent<Tw>(1.f - weight0, 0));
75 #endif
76 		if (bw0 < bw1) {
77 			this->push_back(bw0);
78 			this->push_back(bw1);
79 		} else {
80 			this->push_back(bw1);
81 			this->push_back(bw0);
82 		}
83 	}
84 }
85 
86 template<typename Tb, typename Tw>
set_wo_reorder(uint16_t bone0,uint16_t bone1,float weight0)87 void _influence<Tb, Tw>::set_wo_reorder(uint16_t bone0, uint16_t bone1, float weight0)
88 {
89 	if (bone0 == bone1) {
90 		this->push_back(_bone_weight<Tb, Tw>(bone0, Tw(1)));
91 	} else {
92 		_bone_weight<Tb, Tw> bw0(bone0, Tw(1.f - weight0));
93 		_bone_weight<Tb, Tw> bw1(bone1, Tw(weight0));
94 		this->push_back(bw0);
95 		this->push_back(bw1);
96 	}
97 }
98 
99 template<typename Tb, typename Tw>
set(size_t num_bones,const uint16_t * bones,const float * weights)100 void _influence<Tb, Tw>::set(size_t num_bones, const uint16_t* bones, const float* weights)
101 {
102 	for (float sum = 0, w; num_bones;) {
103 		if (--num_bones == 0) {
104 			w = 1.f - sum;
105 		} else {
106 			w = *weights++;
107 			sum += w;
108 		}
109 		_bone_weight<Tb, Tw> bw(*bones++, w);
110 		for (typename _influence<Tb, Tw>::iterator it = _influence<Tb, Tw>::begin(),
111 				last = _influence<Tb, Tw>::end(); it != last; ++it) {
112 			if (it->bone == bw.bone) {
113 #if 0
114 				if (!equivalent<Tw>(w, 0)) {
115 					msg("bone%u, w=%f", bw.bone, w);
116 				}
117 				xr_assert(equivalent<Tw>(w, 0));
118 #endif
119 				goto skip;
120 			}
121 		}
122 		this->push_back(bw);
123 skip:;
124 	}
125 	reorder();
126 }
127 
reorder()128 template<typename Tb, typename Tw> void _influence<Tb, Tw>::reorder()
129 {
130 	std::sort(_influence<Tb, Tw>::begin(), _influence<Tb, Tw>::end());
131 }
132 
133 } // end of namespace xray_re
134 
135 #endif
136