载入中...
搜索中...
未找到
AnimTrail.cpp
浏览该文件的文档.
3
4#include "common/Exception.h"
5#include "graphics/Graphics.h"
6
7#include <algorithm>
8#include <cmath>
9
10namespace eve::animation {
11
12// Color lives in eve::graphics (see graphics/Canvas.h); keep the unqualified form.
14
15AnimTrail::AnimTrail(int capacity) {
16 setCapacity(capacity);
17}
18
19void AnimTrail::setCapacity(int capacity) {
20 if (capacity < 2) throw Exception("AnimTrail.setCapacity: capacity must be >= 2");
21 capacity_ = capacity;
22 while (static_cast<int>(points_.size()) > capacity_) {
23 points_.erase(points_.begin());
24 }
25}
26
27void AnimTrail::setDuration(float seconds) {
28 duration_ = seconds;
29}
30
31void AnimTrail::setMinDistance(float distance) {
32 if (distance < 0.f) throw Exception("AnimTrail.setMinDistance: must be >= 0");
33 minDistance_ = distance;
34}
35
36void AnimTrail::setWidth(float pixels) {
37 if (pixels <= 0.f) throw Exception("AnimTrail.setWidth: must be > 0");
38 width_ = pixels;
39}
40
41void AnimTrail::setColor(float r, float g, float b, float a) {
42 colorR_ = r;
43 colorG_ = g;
44 colorB_ = b;
45 colorA_ = a;
46}
47
48void AnimTrail::setFade(bool enable) { fade_ = enable; }
49
50void AnimTrail::setStyle(const std::string &style) {
51 if (style == "line") {
52 style_ = Style::Line;
53 return;
54 }
55 if (style == "points") {
56 style_ = Style::Points;
57 return;
58 }
59 throw Exception("AnimTrail.setStyle: unknown style '%s' (use line|points)", style.c_str());
60}
61
62std::string AnimTrail::getStyle() const {
63 return style_ == Style::Line ? "line" : "points";
64}
65
66void AnimTrail::setDrawScale(float sx, float sy) {
67 drawScaleX_ = sx;
68 drawScaleY_ = sy;
69}
70
71void AnimTrail::setDrawOffset(float ox, float oy) {
72 drawOffsetX_ = ox;
73 drawOffsetY_ = oy;
74}
75
76void AnimTrail::addPoint(float x, float y) { pushPoint(x, y, 0.f); }
77
78void AnimTrail::addPoint3(float x, float y, float z) { pushPoint(x, y, z); }
79
80void AnimTrail::projectPlane(float x, float y, float z, const std::string &plane, float *outX,
81 float *outY) const {
82 if (!outX || !outY) return;
83 if (plane == "xy" || plane.empty()) {
84 *outX = x;
85 *outY = y;
86 return;
87 }
88 if (plane == "xz") {
89 *outX = x;
90 *outY = z;
91 return;
92 }
93 if (plane == "yz") {
94 *outX = y;
95 *outY = z;
96 return;
97 }
98 throw Exception("AnimTrail: unknown plane '%s' (use xy|xz|yz)", plane.c_str());
99}
100
101void AnimTrail::sampleBone(const AnimPose *pose, int boneIndex, const std::string &plane) {
102 sampleBoneOffset(pose, boneIndex, 0.f, 0.f, 0.f, plane);
103}
104
105void AnimTrail::sampleBoneOffset(const AnimPose *pose, int boneIndex, float ox, float oy, float oz,
106 const std::string &plane) {
107 if (!pose) throw Exception("AnimTrail.sampleBone: pose is null");
108 if (boneIndex < 0 || boneIndex >= pose->getBoneCount()) {
109 throw Exception("AnimTrail.sampleBone: boneIndex %d out of range (count=%d)", boneIndex,
110 pose->getBoneCount());
111 }
112 const float wx = pose->getWorldPositionX(boneIndex) + ox;
113 const float wy = pose->getWorldPositionY(boneIndex) + oy;
114 const float wz = pose->getWorldPositionZ(boneIndex) + oz;
115 float px = 0.f, py = 0.f;
116 projectPlane(wx, wy, wz, plane, &px, &py);
117 pushPoint(px, py, plane == "xy" || plane.empty() ? wz : (plane == "xz" ? wy : wx));
118}
119
120void AnimTrail::pushPoint(float x, float y, float z) {
121 if (!points_.empty() && minDistance_ > 0.f) {
122 const Point &last = points_.back();
123 const float dx = x - last.x;
124 const float dy = y - last.y;
125 const float dz = z - last.z;
126 if (dx * dx + dy * dy + dz * dz < minDistance_ * minDistance_) return;
127 }
128 Point p;
129 p.x = x;
130 p.y = y;
131 p.z = z;
132 p.age = 0.f;
133 points_.push_back(p);
134 while (static_cast<int>(points_.size()) > capacity_) {
135 points_.erase(points_.begin());
136 }
137}
138
139void AnimTrail::clear() { points_.clear(); }
140
141void AnimTrail::update(float dt) {
142 if (dt < 0.f) dt = 0.f;
143 for (Point &p : points_) p.age += dt;
144 if (duration_ > 0.f) {
145 auto it = points_.begin();
146 while (it != points_.end()) {
147 if (it->age > duration_) {
148 it = points_.erase(it);
149 } else {
150 ++it;
151 }
152 }
153 }
154}
155
156void AnimTrail::requireIndex(int index) const {
157 if (index < 0 || index >= getPointCount()) {
158 throw Exception("AnimTrail: point index %d out of range (count=%d)", index, getPointCount());
159 }
160}
161
162float AnimTrail::getPointX(int index) const {
163 requireIndex(index);
164 return points_[static_cast<size_t>(index)].x;
165}
166
167float AnimTrail::getPointY(int index) const {
168 requireIndex(index);
169 return points_[static_cast<size_t>(index)].y;
170}
171
172float AnimTrail::getPointZ(int index) const {
173 requireIndex(index);
174 return points_[static_cast<size_t>(index)].z;
175}
176
177float AnimTrail::getPointAge(int index) const {
178 requireIndex(index);
179 return points_[static_cast<size_t>(index)].age;
180}
181
182float AnimTrail::alphaFor(const Point &p) const {
183 if (!fade_ || duration_ <= 0.f) return colorA_;
184 const float t = 1.f - std::min(1.f, p.age / duration_);
185 return colorA_ * t;
186}
187
188float AnimTrail::getPointAlpha(int index) const {
189 requireIndex(index);
190 return alphaFor(points_[static_cast<size_t>(index)]);
191}
192
193void AnimTrail::toScreen(float x, float y, float *sx, float *sy) const {
194 if (!sx || !sy) return;
195 *sx = x * drawScaleX_ + drawOffsetX_;
196 *sy = y * drawScaleY_ + drawOffsetY_;
197}
198
199void AnimTrail::drawDot(graphics::Graphics *gfx, float x, float y, float alpha) const {
200 if (!gfx || alpha <= 0.f) return;
201 float sx = 0.f, sy = 0.f;
202 toScreen(x, y, &sx, &sy);
203 const float half = width_ * 0.5f;
204 gfx->drawSolidRect(sx - half, sy - half, width_, width_,
205 Color(colorR_, colorG_, colorB_, alpha));
206}
207
208void AnimTrail::drawSegment(graphics::Graphics *gfx, float x0, float y0, float x1, float y1,
209 float a0, float a1) const {
210 if (!gfx) return;
211 float sx0 = 0.f, sy0 = 0.f, sx1 = 0.f, sy1 = 0.f;
212 toScreen(x0, y0, &sx0, &sy0);
213 toScreen(x1, y1, &sx1, &sy1);
214 const float dx = sx1 - sx0;
215 const float dy = sy1 - sy0;
216 const float len = std::sqrt(dx * dx + dy * dy);
217 if (len < 1e-4f) {
218 drawDot(gfx, x1, y1, a1);
219 return;
220 }
221 const float step = std::max(1.f, width_ * 0.75f);
222 const int steps = std::max(1, int(len / step));
223 const float half = width_ * 0.5f;
224 for (int i = 0; i <= steps; ++i) {
225 const float t = float(i) / float(steps);
226 const float a = a0 + (a1 - a0) * t;
227 if (a <= 0.f) continue;
228 const float px = sx0 + dx * t;
229 const float py = sy0 + dy * t;
230 gfx->drawSolidRect(px - half, py - half, width_, width_,
231 Color(colorR_, colorG_, colorB_, a));
232 }
233}
234
236 if (!gfx || points_.empty()) return;
237
238 if (style_ == Style::Points) {
239 for (const Point &p : points_) {
240 drawDot(gfx, p.x, p.y, alphaFor(p));
241 }
242 return;
243 }
244
245 // Line: connect oldest → newest with per-vertex fade.
246 for (size_t i = 1; i < points_.size(); ++i) {
247 const Point &a = points_[i - 1];
248 const Point &b = points_[i];
249 drawSegment(gfx, a.x, a.y, b.x, b.y, alphaFor(a), alphaFor(b));
250 }
251 // Emphasize the head.
252 if (!points_.empty()) {
253 const Point &head = points_.back();
254 drawDot(gfx, head.x, head.y, alphaFor(head));
255 }
256}
257
258} // namespace eve::animation
int y
Definition Grass.cpp:135
int z
Definition Grass.cpp:135
int x
Definition Grass.cpp:135
std::vector< Colorf > px
uint32_t a
uint32_t b
glm::vec4 p[6]
float step
Definition TreeMesh.cpp:196
Evaluated local (and optional world) pose for an AnimSkeleton. Script type: AnimPose.
Definition AnimPose.h:15
float getWorldPositionZ(int boneIndex) const
Definition AnimPose.cpp:176
int getBoneCount() const
Definition AnimPose.h:25
float getWorldPositionX(int boneIndex) const
Definition AnimPose.cpp:168
float getWorldPositionY(int boneIndex) const
Definition AnimPose.cpp:172
std::string getStyle() const
Definition AnimTrail.cpp:62
void setDuration(float seconds)
How long each sample lives (seconds). <= 0 keeps until capacity eviction.
Definition AnimTrail.cpp:27
void setCapacity(int capacity)
Max retained samples (ring). Clamped to >= 2.
Definition AnimTrail.cpp:19
void setWidth(float pixels)
Definition AnimTrail.cpp:36
void update(float dt)
Age samples by dt; drop expired (when duration > 0).
void addPoint3(float x, float y, float z)
Append a 3D sample (draw uses set plane / first two mapped axes via sampleBone).
Definition AnimTrail.cpp:78
void setDrawOffset(float ox, float oy)
Definition AnimTrail.cpp:71
int getPointCount() const
Definition AnimTrail.h:98
void setMinDistance(float distance)
Skip new samples closer than this distance to the newest point (0 = always add).
Definition AnimTrail.cpp:31
void draw(graphics::Graphics *gfx)
Draw trajectory in 2D pixel/world space via Graphics.
void setColor(float r, float g, float b, float a=1.f)
Head (newest) color; alpha fades toward 0 along the trail when fade is on.
Definition AnimTrail.cpp:41
float getPointZ(int index) const
void sampleBone(const AnimPose *pose, int boneIndex, const std::string &plane="xy")
Sample bone world position after pose->computeWorld. plane maps axes to draw (x,y): "xy" | "xz" | "yz...
void setStyle(const std::string &style)
"line" | "points". Invalid → exception.
Definition AnimTrail.cpp:50
void setFade(bool enable)
Definition AnimTrail.cpp:48
float getPointAlpha(int index) const
Effective draw alpha in [0, colorA] after fade.
float getPointX(int index) const
Index 0 = oldest retained sample; count-1 = newest.
void setDrawScale(float sx, float sy)
Applied at draw time: screen = (x,y) * scale + offset. Useful when sampling bone world units into pix...
Definition AnimTrail.cpp:66
float getPointY(int index) const
float getPointAge(int index) const
void sampleBoneOffset(const AnimPose *pose, int boneIndex, float ox, float oy, float oz, const std::string &plane="xy")
void addPoint(float x, float y)
Append a 2D sample (z stored as 0).
Definition AnimTrail.cpp:76
AnimTrail(int capacity=64)
Definition AnimTrail.cpp:15
virtual void drawSolidRect(float x, float y, float w, float h, const Color &color, BlendMode blend=BlendMode::Alpha)=0
Internal immediate-mode helper used by RenderSystem / Batcher.
glm::vec4 Color
RGBA color used by every graphics draw call. Lives inside eve::graphics so including a graphics heade...
Definition Color.h:13