1 /** @file finaleanimwidget.cpp InFine animation system, FinaleAnimWidget.
2 *
3 * @authors Copyright © 2003-2017 Jaakko Keränen <jaakko.keranen@iki.fi>
4 * @authors Copyright © 2005-2014 Daniel Swanson <danij@dengine.net>
5 *
6 * @par License
7 * GPL: http://www.gnu.org/licenses/gpl.html
8 *
9 * <small>This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version. This program is distributed in the hope that it
13 * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15 * Public License for more details. You should have received a copy of the GNU
16 * General Public License along with this program; if not, write to the Free
17 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18 * 02110-1301 USA</small>
19 */
20
21 #include <de/vector1.h>
22 #include <doomsday/res/Textures>
23 #include "ui/infine/finaleanimwidget.h"
24
25 #include "dd_main.h" // App_Resources()
26 #include "api_sound.h"
27
28 #ifdef __CLIENT__
29 # include "gl/gl_main.h"
30 # include "gl/gl_texmanager.h" // GL_PrepareRawTexture()
31 # include "render/r_draw.h" // Rend_PatchTextureSpec()
32 # include "render/rend_main.h" // filterUI
33 # include "MaterialAnimator"
34 # include <de/GLInfo>
35 #endif
36
37 using namespace de;
38
Frame()39 FinaleAnimWidget::Frame::Frame()
40 : tics (0)
41 , type (PFT_MATERIAL)
42 , sound(0)
43 {
44 de::zap(flags);
45 de::zap(texRef);
46 }
47
~Frame()48 FinaleAnimWidget::Frame::~Frame()
49 {
50 #ifdef __CLIENT__
51 if (type == PFT_XIMAGE)
52 {
53 DGL_DeleteTextures(1, (DGLuint *)&texRef.tex);
54 }
55 #endif
56 }
57
DENG2_PIMPL_NOREF(FinaleAnimWidget)58 DENG2_PIMPL_NOREF(FinaleAnimWidget)
59 {
60 bool animComplete = true;
61 bool animLooping = false; ///< @c true= loop back to the start when the end is reached.
62 int tics = 0;
63 int curFrame = 0;
64 Frames frames;
65
66 animatorvector4_t color;
67
68 /// For rectangle-objects.
69 animatorvector4_t otherColor;
70 animatorvector4_t edgeColor;
71 animatorvector4_t otherEdgeColor;
72
73 Impl()
74 {
75 AnimatorVector4_Init(color, 1, 1, 1, 1);
76 AnimatorVector4_Init(otherColor, 0, 0, 0, 0);
77 AnimatorVector4_Init(edgeColor, 0, 0, 0, 0);
78 AnimatorVector4_Init(otherEdgeColor, 0, 0, 0, 0);
79 }
80
81 static Frame *makeFrame(Frame::Type type, int tics, void *texRef, short sound, bool flagFlipH)
82 {
83 Frame *f = new Frame;
84 f->flags.flip = flagFlipH;
85 f->type = type;
86 f->tics = tics;
87 f->sound = sound;
88
89 switch (f->type)
90 {
91 case Frame::PFT_MATERIAL: f->texRef.material = ((world::Material *)texRef); break;
92 case Frame::PFT_PATCH: f->texRef.patch = *((patchid_t *)texRef); break;
93 case Frame::PFT_RAW: f->texRef.lumpNum = *((lumpnum_t *)texRef); break;
94 case Frame::PFT_XIMAGE: f->texRef.tex = *((DGLuint *)texRef); break;
95
96 default: throw Error("FinaleAnimWidget::makeFrame", "Unknown frame type #" + String::number(type));
97 }
98
99 return f;
100 }
101 };
102
FinaleAnimWidget(String const & name)103 FinaleAnimWidget::FinaleAnimWidget(String const &name)
104 : FinaleWidget(name)
105 , d(new Impl)
106 {}
107
~FinaleAnimWidget()108 FinaleAnimWidget::~FinaleAnimWidget()
109 {
110 clearAllFrames();
111 }
112
animationComplete() const113 bool FinaleAnimWidget::animationComplete() const
114 {
115 return d->animComplete;
116 }
117
setLooping(bool yes)118 FinaleAnimWidget &FinaleAnimWidget::setLooping(bool yes)
119 {
120 d->animLooping = yes;
121 return *this;
122 }
123
124 #ifdef __CLIENT__
useColor(animator_t const * color,int components)125 static void useColor(animator_t const *color, int components)
126 {
127 if (components == 3)
128 {
129 DGL_Color3f(color[0].value, color[1].value, color[2].value);
130 }
131 else if (components == 4)
132 {
133 DGL_Color4f(color[0].value, color[1].value, color[2].value, color[3].value);
134 }
135 }
136
buildGeometry(float const[3],dd_bool flipTextureS,Vector4f const & bottomColor,Vector4f const & topColor,Vector3f ** posCoords,Vector4f ** colorCoords,Vector2f ** texCoords)137 static int buildGeometry(float const /*dimensions*/[3], dd_bool flipTextureS,
138 Vector4f const &bottomColor, Vector4f const &topColor, Vector3f **posCoords,
139 Vector4f **colorCoords, Vector2f **texCoords)
140 {
141 static Vector3f posCoordBuf[4];
142 static Vector4f colorCoordBuf[4];
143 static Vector2f texCoordBuf[4];
144
145 // 0 - 1
146 // | / | Vertex layout
147 // 2 - 3
148
149 posCoordBuf[0] = Vector3f(0, 0, 0);
150 posCoordBuf[1] = Vector3f(1, 0, 0);
151 posCoordBuf[2] = Vector3f(0, 1, 0);
152 posCoordBuf[3] = Vector3f(1, 1, 0);
153
154 texCoordBuf[0] = Vector2f((flipTextureS? 1:0), 0);
155 texCoordBuf[1] = Vector2f((flipTextureS? 0:1), 0);
156 texCoordBuf[2] = Vector2f((flipTextureS? 1:0), 1);
157 texCoordBuf[3] = Vector2f((flipTextureS? 0:1), 1);
158
159 colorCoordBuf[0] = bottomColor;
160 colorCoordBuf[1] = bottomColor;
161 colorCoordBuf[2] = topColor;
162 colorCoordBuf[3] = topColor;
163
164 *posCoords = posCoordBuf;
165 *texCoords = texCoordBuf;
166 *colorCoords = colorCoordBuf;
167
168 return 4;
169 }
170
drawGeometry(int numVerts,Vector3f const * posCoords,Vector4f const * colorCoords,Vector2f const * texCoords)171 static void drawGeometry(int numVerts, Vector3f const *posCoords,
172 Vector4f const *colorCoords, Vector2f const *texCoords)
173 {
174 DGL_Begin(DGL_TRIANGLE_STRIP);
175 Vector3f const *posIt = posCoords;
176 Vector4f const *colorIt = colorCoords;
177 Vector2f const *texIt = texCoords;
178 for (int i = 0; i < numVerts; ++i, posIt++, colorIt++, texIt++)
179 {
180 if (texCoords)
181 DGL_TexCoord2f(0, texIt->x, texIt->y);
182
183 if (colorCoords)
184 DGL_Color4f(colorIt->x, colorIt->y, colorIt->z, colorIt->w);
185
186 DGL_Vertex3f(posIt->x, posIt->y, posIt->z);
187 }
188 DGL_End();
189 }
190
uiMaterialSpec_FinaleAnim()191 static inline MaterialVariantSpec const &uiMaterialSpec_FinaleAnim()
192 {
193 return App_Resources().materialSpec(UiContext, 0, 0, 0, 0,
194 GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE,
195 0, -3, 0, false, false, false, false);
196 }
197
drawPicFrame(FinaleAnimWidget * p,uint frame,float const _origin[3],float scale[3],float const rgba[4],float const rgba2[4],float angle,Vector3f const & worldOffset)198 static void drawPicFrame(FinaleAnimWidget *p, uint frame, float const _origin[3],
199 float /*const*/ scale[3], float const rgba[4], float const rgba2[4], float angle,
200 Vector3f const &worldOffset)
201 {
202 vec3f_t offset = { 0, 0, 0 }, dimensions, origin, originOffset, center;
203 vec2f_t texScale = { 1, 1 };
204 vec2f_t rotateCenter = { .5f, .5f };
205 dd_bool showEdges = true, flipTextureS = false;
206 dd_bool mustPopTextureMatrix = false;
207 dd_bool textureEnabled = false;
208 int numVerts;
209 Vector3f *posCoords;
210 Vector4f *colorCoords;
211 Vector2f *texCoords;
212
213 if (p->frameCount())
214 {
215 /// @todo Optimize: Texture/Material searches should be NOT be done here -ds
216 FinaleAnimWidget::Frame *f = p->allFrames().at(frame);
217
218 flipTextureS = (f->flags.flip != 0);
219 showEdges = false;
220
221 switch (f->type)
222 {
223 case FinaleAnimWidget::Frame::PFT_RAW: {
224 rawtex_t *rawTex = ClientResources::get().declareRawTexture(f->texRef.lumpNum);
225 if (rawTex)
226 {
227 DGLuint glName = GL_PrepareRawTexture(*rawTex);
228 V3f_Set(offset, 0, 0, 0);
229 // Raw images are always considered to have a logical size of 320x200
230 // even though the actual texture resolution may be different.
231 V3f_Set(dimensions, 320 /*rawTex->width*/, 200 /*rawTex->height*/, 0);
232 // Rotation occurs around the center of the screen.
233 V2f_Set(rotateCenter, 160, 100);
234 GL_BindTextureUnmanaged(glName, gl::ClampToEdge, gl::ClampToEdge,
235 (filterUI ? gl::Linear : gl::Nearest));
236 if (glName)
237 {
238 DGL_Enable(DGL_TEXTURE_2D);
239 textureEnabled = true;
240 }
241 }
242 break; }
243
244 case FinaleAnimWidget::Frame::PFT_XIMAGE:
245 V3f_Set(offset, 0, 0, 0);
246 V3f_Set(dimensions, 1, 1, 0);
247 V2f_Set(rotateCenter, .5f, .5f);
248 GL_BindTextureUnmanaged(f->texRef.tex, gl::ClampToEdge, gl::ClampToEdge,
249 (filterUI ? gl::Linear : gl::Nearest));
250 if (f->texRef.tex)
251 {
252 DGL_Enable(DGL_TEXTURE_2D);
253 textureEnabled = true;
254 }
255 break;
256
257 case FinaleAnimWidget::Frame::PFT_MATERIAL:
258 if (ClientMaterial *mat = static_cast<ClientMaterial *>(f->texRef.material))
259 {
260 /// @todo Utilize *all* properties of the Material.
261 MaterialAnimator &matAnimator = mat->getAnimator(uiMaterialSpec_FinaleAnim());
262
263 // Ensure we've up to date info about the material.
264 matAnimator.prepare();
265
266 Vector2ui const &matDimensions = matAnimator.dimensions();
267 TextureVariant *tex = matAnimator.texUnit(MaterialAnimator::TU_LAYER0).texture;
268 int const texBorder = tex->spec().variant.border;
269
270 GL_BindTexture(tex);
271 DGL_Enable(DGL_TEXTURE_2D);
272 textureEnabled = true;
273
274 V3f_Set(dimensions, matDimensions.x + texBorder * 2, matDimensions.y + texBorder * 2, 0);
275 V2f_Set(rotateCenter, dimensions[VX] / 2, dimensions[VY] / 2);
276 tex->glCoords(&texScale[VX], &texScale[VY]);
277
278 // Apply a sprite-texture origin offset?
279 bool const texIsSprite = !tex->base().manifest().scheme().name().compareWithoutCase("Sprites");
280 if (texIsSprite)
281 {
282 V3f_Set(offset, tex->base().origin().x, tex->base().origin().y, 0);
283 }
284 else
285 {
286 V3f_Set(offset, 0, 0, 0);
287 }
288 }
289 break;
290
291 case FinaleAnimWidget::Frame::PFT_PATCH: {
292 res::TextureManifest &manifest = res::Textures::get().textureScheme("Patches")
293 .findByUniqueId(f->texRef.patch);
294 if (manifest.hasTexture())
295 {
296 res::Texture &tex = manifest.texture();
297 TextureVariantSpec const &texSpec =
298 Rend_PatchTextureSpec(0 | (tex.isFlagged(res::Texture::Monochrome) ? TSF_MONOCHROME : 0)
299 | (tex.isFlagged(res::Texture::UpscaleAndSharpen) ? TSF_UPSCALE_AND_SHARPEN : 0));
300 GL_BindTexture(static_cast<ClientTexture &>(tex).prepareVariant(texSpec));
301 DGL_Enable(DGL_TEXTURE_2D);
302 textureEnabled = true;
303
304 V3f_Set(offset, tex.origin().x, tex.origin().y, 0);
305 V3f_Set(dimensions, tex.width(), tex.height(), 0);
306 V2f_Set(rotateCenter, dimensions[VX]/2, dimensions[VY]/2);
307 }
308 break; }
309
310 default:
311 App_Error("drawPicFrame: Invalid FI_PIC frame type %i.", int(f->type));
312 }
313 }
314
315 // If we've not chosen a texture by now set some defaults.
316 /// @todo This is some seriously funky logic... refactor or remove.
317 if (!textureEnabled)
318 {
319 V3f_Copy(dimensions, scale);
320 V3f_Set(scale, 1, 1, 1);
321 V2f_Set(rotateCenter, dimensions[VX] / 2, dimensions[VY] / 2);
322 }
323
324 V3f_Set(center, dimensions[VX] / 2, dimensions[VY] / 2, dimensions[VZ] / 2);
325
326 V3f_Sum(origin, _origin, center);
327 V3f_Subtract(origin, origin, offset);
328 for (int i = 0; i < 3; ++i) { origin[i] += worldOffset[i]; }
329
330 V3f_Subtract(originOffset, offset, center);
331 offset[VX] *= scale[VX]; offset[VY] *= scale[VY]; offset[VZ] *= scale[VZ];
332 V3f_Sum(originOffset, originOffset, offset);
333
334 numVerts = buildGeometry(dimensions, flipTextureS, rgba, rgba2, &posCoords, &colorCoords, &texCoords);
335
336 // Setup the transformation.
337 DGL_MatrixMode(DGL_MODELVIEW);
338 DGL_PushMatrix();
339 //glScalef(.1f/SCREENWIDTH, .1f/SCREENWIDTH, 1);
340
341 // Move to the object origin.
342 DGL_Translatef(origin[VX], origin[VY], origin[VZ]);
343
344 // Translate to the object center.
345 /// @todo Remove this; just go to origin directly. Rotation origin is
346 /// now separately in 'rotateCenter'. -jk
347 DGL_Translatef(originOffset[VX], originOffset[VY], originOffset[VZ]);
348
349 DGL_Scalef(scale[VX], scale[VY], scale[VZ]);
350
351 if (angle != 0)
352 {
353 DGL_Translatef(rotateCenter[VX], rotateCenter[VY], 0);
354
355 // With rotation we must counter the VGA aspect ratio.
356 DGL_Scalef(1, 200.0f / 240.0f, 1);
357 DGL_Rotatef(angle, 0, 0, 1);
358 DGL_Scalef(1, 240.0f / 200.0f, 1);
359
360 DGL_Translatef(-rotateCenter[VX], -rotateCenter[VY], 0);
361 }
362
363 DGL_MatrixMode(DGL_MODELVIEW);
364 // Scale up our unit-geometry to the desired dimensions.
365 DGL_Scalef(dimensions[VX], dimensions[VY], dimensions[VZ]);
366
367 if (texScale[0] != 1 || texScale[1] != 1)
368 {
369 DGL_MatrixMode(DGL_TEXTURE);
370 DGL_PushMatrix();
371 DGL_Scalef(texScale[0], texScale[1], 1);
372 mustPopTextureMatrix = true;
373 }
374
375 drawGeometry(numVerts, posCoords, colorCoords, texCoords);
376
377 GL_SetNoTexture();
378
379 if (mustPopTextureMatrix)
380 {
381 DGL_MatrixMode(DGL_TEXTURE);
382 DGL_PopMatrix();
383 }
384
385 if (showEdges)
386 {
387 DGL_Begin(DGL_LINES);
388 useColor(p->edgeColor(), 4);
389 DGL_Vertex2f(0, 0);
390 DGL_Vertex2f(1, 0);
391 DGL_Vertex2f(1, 0);
392
393 useColor(p->otherEdgeColor(), 4);
394 DGL_Vertex2f(1, 1);
395 DGL_Vertex2f(1, 1);
396 DGL_Vertex2f(0, 1);
397 DGL_Vertex2f(0, 1);
398
399 useColor(p->edgeColor(), 4);
400 DGL_Vertex2f(0, 0);
401 DGL_End();
402 }
403
404 // Restore original transformation.
405 DGL_MatrixMode(DGL_MODELVIEW);
406 DGL_PopMatrix();
407 }
408
draw(Vector3f const & offset)409 void FinaleAnimWidget::draw(Vector3f const &offset)
410 {
411 // Fully transparent pics will not be drawn.
412 if (!(d->color[3].value > 0)) return;
413
414 vec3f_t _scale, _origin;
415 V3f_Set(_origin, origin()[VX].value, origin()[VY].value, origin()[VZ].value);
416 V3f_Set(_scale, scale()[VX].value, scale()[VY].value, scale()[VZ].value);
417
418 vec4f_t rgba, rgba2;
419 V4f_Set(rgba, d->color[0].value, d->color[1].value, d->color[2].value, d->color[3].value);
420 if (!frameCount())
421 {
422 V4f_Set(rgba2, d->otherColor[0].value, d->otherColor[1].value, d->otherColor[2].value, d->otherColor[3].value);
423 }
424 else
425 {
426 V4f_Set(rgba2, 0, 0, 0, 0);
427 }
428 drawPicFrame(this, d->curFrame, _origin, _scale, rgba, (!frameCount()? rgba2 : rgba), angle().value, offset);
429 }
430 #endif
431
runTicks()432 void FinaleAnimWidget::runTicks(/*timespan_t timeDelta*/)
433 {
434 FinaleWidget::runTicks(/*timeDelta*/);
435
436 AnimatorVector4_Think(d->color);
437 AnimatorVector4_Think(d->otherColor);
438 AnimatorVector4_Think(d->edgeColor);
439 AnimatorVector4_Think(d->otherEdgeColor);
440
441 if (!(d->frames.count() > 1)) return;
442
443 // If animating, decrease the sequence timer.
444 if (d->frames.at(d->curFrame)->tics > 0)
445 {
446 if (--d->tics <= 0)
447 {
448 Frame *f;
449 // Advance the sequence position. k = next pos.
450 uint next = d->curFrame + 1;
451
452 if (next == uint(d->frames.count()))
453 {
454 // This is the end.
455 d->animComplete = true;
456
457 // Stop the sequence?
458 if (d->animLooping)
459 {
460 next = 0; // Rewind back to beginning.
461 }
462 else // Yes.
463 {
464 d->frames.at(next = d->curFrame)->tics = 0;
465 }
466 }
467
468 // Advance to the next pos.
469 f = d->frames.at(d->curFrame = next);
470 d->tics = f->tics;
471
472 // Play a sound?
473 if (f->sound > 0)
474 S_LocalSound(f->sound, 0);
475 }
476 }
477 }
478
newFrame(Frame::Type type,int tics,void * texRef,short sound,bool flagFlipH)479 int FinaleAnimWidget::newFrame(Frame::Type type, int tics, void *texRef, short sound, bool flagFlipH)
480 {
481 d->frames.append(d->makeFrame(type, tics, texRef, sound, flagFlipH));
482 // The addition of a new frame means the animation has not yet completed.
483 d->animComplete = false;
484 return d->frames.count();
485 }
486
allFrames() const487 FinaleAnimWidget::Frames const &FinaleAnimWidget::allFrames() const
488 {
489 return d->frames;
490 }
491
clearAllFrames()492 FinaleAnimWidget &FinaleAnimWidget::clearAllFrames()
493 {
494 qDeleteAll(d->frames); d->frames.clear();
495 d->curFrame = 0;
496 d->animComplete = true; // Nothing to animate.
497 d->animLooping = false; // Yeah?
498 return *this;
499 }
500
resetAllColors()501 FinaleAnimWidget &FinaleAnimWidget::resetAllColors()
502 {
503 // Default colors.
504 AnimatorVector4_Init(d->color, 1, 1, 1, 1);
505 AnimatorVector4_Init(d->otherColor, 1, 1, 1, 1);
506
507 // Edge alpha is zero by default.
508 AnimatorVector4_Init(d->edgeColor, 1, 1, 1, 0);
509 AnimatorVector4_Init(d->otherEdgeColor, 1, 1, 1, 0);
510 return *this;
511 }
512
color() const513 animator_t const *FinaleAnimWidget::color() const
514 {
515 return d->color;
516 }
517
setColor(Vector3f const & newColor,int steps)518 FinaleAnimWidget &FinaleAnimWidget::setColor(Vector3f const &newColor, int steps)
519 {
520 AnimatorVector3_Set(d->color, newColor.x, newColor.y, newColor.z, steps);
521 return *this;
522 }
523
setAlpha(float newAlpha,int steps)524 FinaleAnimWidget &FinaleAnimWidget::setAlpha(float newAlpha, int steps)
525 {
526 Animator_Set(&d->color[3], newAlpha, steps);
527 return *this;
528 }
529
setColorAndAlpha(Vector4f const & newColorAndAlpha,int steps)530 FinaleAnimWidget &FinaleAnimWidget::setColorAndAlpha(Vector4f const &newColorAndAlpha, int steps)
531 {
532 AnimatorVector4_Set(d->color, newColorAndAlpha.x, newColorAndAlpha.y, newColorAndAlpha.z, newColorAndAlpha.w, steps);
533 return *this;
534 }
535
edgeColor() const536 animator_t const *FinaleAnimWidget::edgeColor() const
537 {
538 return d->edgeColor;
539 }
540
setEdgeColor(Vector3f const & newColor,int steps)541 FinaleAnimWidget &FinaleAnimWidget::setEdgeColor(Vector3f const &newColor, int steps)
542 {
543 AnimatorVector3_Set(d->edgeColor, newColor.x, newColor.y, newColor.z, steps);
544 return *this;
545 }
546
setEdgeAlpha(float newAlpha,int steps)547 FinaleAnimWidget &FinaleAnimWidget::setEdgeAlpha(float newAlpha, int steps)
548 {
549 Animator_Set(&d->edgeColor[3], newAlpha, steps);
550 return *this;
551 }
552
setEdgeColorAndAlpha(Vector4f const & newColorAndAlpha,int steps)553 FinaleAnimWidget &FinaleAnimWidget::setEdgeColorAndAlpha(Vector4f const &newColorAndAlpha, int steps)
554 {
555 AnimatorVector4_Set(d->edgeColor, newColorAndAlpha.x, newColorAndAlpha.y, newColorAndAlpha.z, newColorAndAlpha.w, steps);
556 return *this;
557 }
558
otherColor() const559 animator_t const *FinaleAnimWidget::otherColor() const
560 {
561 return d->otherColor;
562 }
563
setOtherColor(de::Vector3f const & newColor,int steps)564 FinaleAnimWidget &FinaleAnimWidget::setOtherColor(de::Vector3f const &newColor, int steps)
565 {
566 AnimatorVector3_Set(d->otherColor, newColor.x, newColor.y, newColor.z, steps);
567 return *this;
568 }
569
setOtherAlpha(float newAlpha,int steps)570 FinaleAnimWidget &FinaleAnimWidget::setOtherAlpha(float newAlpha, int steps)
571 {
572 Animator_Set(&d->otherColor[3], newAlpha, steps);
573 return *this;
574 }
575
setOtherColorAndAlpha(Vector4f const & newColorAndAlpha,int steps)576 FinaleAnimWidget &FinaleAnimWidget::setOtherColorAndAlpha(Vector4f const &newColorAndAlpha, int steps)
577 {
578 AnimatorVector4_Set(d->otherColor, newColorAndAlpha.x, newColorAndAlpha.y, newColorAndAlpha.z, newColorAndAlpha.w, steps);
579 return *this;
580 }
581
otherEdgeColor() const582 animator_t const *FinaleAnimWidget::otherEdgeColor() const
583 {
584 return d->otherEdgeColor;
585 }
586
setOtherEdgeColor(de::Vector3f const & newColor,int steps)587 FinaleAnimWidget &FinaleAnimWidget::setOtherEdgeColor(de::Vector3f const &newColor, int steps)
588 {
589 AnimatorVector3_Set(d->otherEdgeColor, newColor.x, newColor.y, newColor.z, steps);
590 return *this;
591 }
592
setOtherEdgeAlpha(float newAlpha,int steps)593 FinaleAnimWidget &FinaleAnimWidget::setOtherEdgeAlpha(float newAlpha, int steps)
594 {
595 Animator_Set(&d->otherEdgeColor[3], newAlpha, steps);
596 return *this;
597 }
598
setOtherEdgeColorAndAlpha(Vector4f const & newColorAndAlpha,int steps)599 FinaleAnimWidget &FinaleAnimWidget::setOtherEdgeColorAndAlpha(Vector4f const &newColorAndAlpha, int steps)
600 {
601 AnimatorVector4_Set(d->otherEdgeColor, newColorAndAlpha.x, newColorAndAlpha.y, newColorAndAlpha.z, newColorAndAlpha.w, steps);
602 return *this;
603 }
604