1 /*
2 Copyright (C) 2007, 2010 - Bit-Blot
3
4 This file is part of Aquaria.
5
6 Aquaria is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
15 See the GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21 #include "RenderObject.h"
22 #include "Core.h"
23 #include "MathFunctions.h"
24
25 #include <assert.h>
26 #include <algorithm>
27
28 #ifdef BBGE_USE_GLM
29 #include "glm/glm.hpp"
30 #include "glm/gtx/transform.hpp"
31 #endif
32
33 bool RenderObject::renderCollisionShape = false;
34 int RenderObject::lastTextureApplied = 0;
35 bool RenderObject::lastTextureRepeat = false;
36 bool RenderObject::renderPaths = false;
37
38 const bool RENDEROBJECT_SHAREATTRIBUTES = true;
39 const bool RENDEROBJECT_FASTTRANSFORM = false;
40
41 RenderObjectLayer *RenderObject::rlayer = 0;
42
toggleAlpha(float t)43 void RenderObject::toggleAlpha(float t)
44 {
45 if (alpha.x < 0.5f)
46 alpha.interpolateTo(1,t);
47 else
48 alpha.interpolateTo(0,t);
49 }
50
getTopLayer()51 int RenderObject::getTopLayer()
52 {
53 if (parent)
54 {
55 return parent->getTopLayer();
56 }
57 return layer;
58 }
59
applyBlendType()60 void RenderObject::applyBlendType()
61 {
62 #ifdef BBGE_BUILD_OPENGL
63 if (blendEnabled)
64 {
65 glEnable(GL_BLEND);
66 switch (blendType)
67 {
68 case BLEND_DEFAULT:
69 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
70 break;
71 case BLEND_ADD:
72 glBlendFunc(GL_SRC_ALPHA,GL_ONE);
73 break;
74 case BLEND_SUB:
75 glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
76 break;
77 case BLEND_MULT:
78 glBlendFunc(GL_ZERO, GL_SRC_COLOR);
79 break;
80 }
81 }
82 else
83 {
84 glDisable(GL_BLEND);
85 glDisable(GL_ALPHA_TEST);
86 }
87 #endif
88 #ifdef BBGE_BUILD_DIRECTX
89 if (blendEnabled)
90 {
91 core->getD3DDevice()->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
92 switch (blendType)
93 {
94 case BLEND_DEFAULT:
95 core->getD3DDevice()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
96 core->getD3DDevice()->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
97 //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
98 break;
99 case BLEND_ADD:
100 core->getD3DDevice()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
101 core->getD3DDevice()->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
102 //glBlendFunc(GL_SRC_ALPHA,GL_ONE);
103 break;
104 case BLEND_SUB:
105 core->getD3DDevice()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
106 core->getD3DDevice()->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCALPHA);
107 //glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
108 break;
109 }
110
111 core->getD3DDevice()->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
112 core->getD3DDevice()->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
113 }
114 else
115 {
116 core->getD3DDevice()->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
117 /*
118 glDisable(GL_BLEND);
119 glDisable(GL_ALPHA_TEST);
120 */
121 }
122 #endif
123 }
124
setColorMult(const Vector & color,const float alpha)125 void RenderObject::setColorMult(const Vector &color, const float alpha)
126 {
127 if (colorIsSaved)
128 {
129 debugLog("setColorMult() WARNING: can't do nested multiplies");
130 return;
131 }
132 this->colorIsSaved = true;
133 this->savedColor.x = this->color.x;
134 this->savedColor.y = this->color.y;
135 this->savedColor.z = this->color.z;
136 this->savedAlpha = this->alpha.x;
137 this->color *= color;
138 this->alpha.x *= alpha;
139 for (Children::iterator i = children.begin(); i != children.end(); i++)
140 {
141 (*i)->setColorMult(color, alpha);
142 }
143 }
144
clearColorMult()145 void RenderObject::clearColorMult()
146 {
147 if (!colorIsSaved)
148 {
149 debugLog("clearColorMult() WARNING: no saved color to restore");
150 return;
151 }
152 this->color.x = this->savedColor.x;
153 this->color.y = this->savedColor.y;
154 this->color.z = this->savedColor.z;
155 this->alpha.x = this->savedAlpha;
156 this->colorIsSaved = false;
157 for (Children::iterator i = children.begin(); i != children.end(); i++)
158 {
159 (*i)->clearColorMult();
160 }
161 }
162
RenderObject()163 RenderObject::RenderObject()
164 {
165 addType(SCO_RENDEROBJECT);
166 useOldDT = false;
167
168 updateAfterParent = false;
169 ignoreUpdate = false;
170 overrideRenderPass = OVERRIDE_NONE;
171 renderPass = 0;
172 overrideCullRadiusSqr = 0;
173 repeatTexture = false;
174 alphaMod = 1;
175 collisionMaskRadius = 0;
176 collideRadius = 0;
177 motionBlurTransition = false;
178 motionBlurFrameOffsetCounter = 0;
179 motionBlurFrameOffset = 0;
180 motionBlur = false;
181 idx = -1;
182 #ifdef BBGE_BUILD_DIRECTX
183 useDXTransform = false;
184 #endif
185 _fv = false;
186 _fh = false;
187 updateCull = -1;
188 //rotateFirst = true;
189 layer = LR_NONE;
190 cull = true;
191
192 pm = PM_NONE;
193
194 positionSnapTo = 0;
195
196 //updateMultiplier = 1;
197 blendEnabled = true;
198 texture = 0;
199 width = 0;
200 height = 0;
201 scale = Vector(1,1,1);
202 color = Vector(1,1,1);
203 alpha.x = 1;
204 //mode = 0;
205 life = maxLife = 1;
206 decayRate = 0;
207 _dead = false;
208 _hidden = false;
209 _static = false;
210 fadeAlphaWithLife = false;
211 blendType = BLEND_DEFAULT;
212 //lifeAlphaFadeMultiplier = 1;
213 followCamera = 0;
214 stateData = 0;
215 parent = 0;
216 //useColor = true;
217 renderBeforeParent = false;
218 //followXOnly = false;
219 //renderOrigin = false;
220 colorIsSaved = false;
221 shareAlphaWithChildren = false;
222 shareColorWithChildren = false;
223 motionBlurTransitionTimer = 0;
224 }
225
~RenderObject()226 RenderObject::~RenderObject()
227 {
228 }
229
getWorldPosition()230 Vector RenderObject::getWorldPosition()
231 {
232 return getWorldCollidePosition();
233 }
234
getTopParent()235 RenderObject* RenderObject::getTopParent()
236 {
237 RenderObject *p = parent;
238 RenderObject *lastp=0;
239 while (p)
240 {
241 lastp = p;
242 p = p->parent;
243 }
244 return lastp;
245 }
246
isPieceFlippedHorizontal()247 bool RenderObject::isPieceFlippedHorizontal()
248 {
249 RenderObject *p = getTopParent();
250 if (p)
251 return p->isfh();
252 return isfh();
253 }
254
255
getInvRotPosition(const Vector & vec)256 Vector RenderObject::getInvRotPosition(const Vector &vec)
257 {
258 #ifdef BBGE_BUILD_OPENGL
259 glPushMatrix();
260 glLoadIdentity();
261
262 std::vector<RenderObject*>chain;
263 RenderObject *p = this;
264 while(p)
265 {
266 chain.push_back(p);
267 p = p->parent;
268 }
269
270 for (int i = chain.size()-1; i >= 0; i--)
271 {
272 glRotatef(-(chain[i]->rotation.z+chain[i]->rotationOffset.z), 0, 0, 1);
273
274 if (chain[i]->isfh())
275 {
276 //glDisable(GL_CULL_FACE);
277 glRotatef(180, 0, 1, 0);
278 }
279 }
280
281 if (vec.x != 0 || vec.y != 0)
282 {
283 //glRotatef(this->rotation.z, 0,0,1,this->rotation.z);
284 glTranslatef(vec.x, vec.y, 0);
285 }
286
287 float m[16];
288 glGetFloatv(GL_MODELVIEW_MATRIX, m);
289 float x = m[12];
290 float y = m[13];
291 float z = m[14];
292
293 glPopMatrix();
294 return Vector(x,y,z);
295 #elif BBGE_BUILD_DIRECTX
296 return vec;
297 #endif
298 }
299
300 #ifdef BBGE_USE_GLM
matrixChain(const RenderObject * ro)301 static glm::mat4 matrixChain(const RenderObject *ro)
302 {
303 glm::mat4 tranformMatrix = glm::scale(
304 glm::translate(
305 glm::rotate(
306 glm::translate(
307 ro->getParent() ? matrixChain(ro->getParent()) : glm::mat4(1.0f),
308 glm::vec3(ro->position.x+ro->offset.x, ro->position.y+ro->offset.y, 0)
309 ),
310 ro->rotation.z + ro->rotationOffset.z,
311 glm::vec3(0, 0, 1)
312 ),
313 glm::vec3(ro->beforeScaleOffset.x, ro->beforeScaleOffset.y, 0.0f)
314 ),
315 glm::vec3(ro->scale.x, ro->scale.y, 0.0f)
316 );
317
318 if (ro->isfh())
319 tranformMatrix *= glm::rotate(180.0f, glm::vec3(0.0f, 1.0f, 0.0f));
320
321 tranformMatrix *= glm::translate(glm::vec3(ro->internalOffset.x, ro->internalOffset.y, 0.0f));
322 return tranformMatrix;
323 }
324 #else
matrixChain(RenderObject * ro)325 static void matrixChain(RenderObject *ro)
326 {
327 if (RenderObject *parent = ro->getParent())
328 matrixChain(parent);
329
330 #ifdef BBGE_BUILD_OPENGL
331 glTranslatef(ro->position.x+ro->offset.x, ro->position.y+ro->offset.y, 0);
332 glRotatef(ro->rotation.z+ro->rotationOffset.z, 0, 0, 1);
333 glTranslatef(ro->beforeScaleOffset.x, ro->beforeScaleOffset.y, 0);
334 glScalef(ro->scale.x, ro->scale.y, 0);
335 if (ro->isfh())
336 {
337 //glDisable(GL_CULL_FACE);
338 glRotatef(180, 0, 1, 0);
339 }
340 glTranslatef(ro->internalOffset.x, ro->internalOffset.y, 0);
341 #endif
342 }
343 #endif
344
getWorldRotation()345 float RenderObject::getWorldRotation()
346 {
347 Vector up = getWorldCollidePosition(Vector(0,1));
348 Vector orig = getWorldPosition();
349 float rot = 0;
350 MathFunctions::calculateAngleBetweenVectorsInDegrees(orig, up, rot);
351 return rot;
352 }
353
getWorldPositionAndRotation()354 Vector RenderObject::getWorldPositionAndRotation()
355 {
356 Vector up = getWorldCollidePosition(Vector(0,1));
357 Vector orig = getWorldPosition();
358 MathFunctions::calculateAngleBetweenVectorsInDegrees(orig, up, orig.z);
359 return orig;
360 }
361
getWorldCollidePosition(const Vector & vec)362 Vector RenderObject::getWorldCollidePosition(const Vector &vec)
363 {
364 #ifdef BBGE_USE_GLM
365 glm::mat4 transformMatrix = glm::translate(
366 matrixChain(this),
367 glm::vec3(collidePosition.x + vec.x, collidePosition.y + vec.y, 0.0f)
368 );
369
370 return Vector(transformMatrix[3][0], transformMatrix[3][1], 0);
371 #else
372 #ifdef BBGE_BUILD_OPENGL
373 glPushMatrix();
374 glLoadIdentity();
375
376 matrixChain(this);
377 glTranslatef(collidePosition.x+vec.x, collidePosition.y+vec.y, 0);
378
379 float m[16];
380 glGetFloatv(GL_MODELVIEW_MATRIX, m);
381 float x = m[12];
382 float y = m[13];
383
384 glPopMatrix();
385 return Vector(x,y,0);
386 #elif BBGE_BUILD_DIRECTX
387 return vec;
388 #endif
389 #endif
390 }
391
fhTo(bool fh)392 void RenderObject::fhTo(bool fh)
393 {
394 if ((fh && !_fh) || (!fh && _fh))
395 {
396 flipHorizontal();
397 }
398 }
399
flipHorizontal()400 void RenderObject::flipHorizontal()
401 {
402 bool wasFlippedHorizontal = _fh;
403
404 _fh = !_fh;
405
406 if (wasFlippedHorizontal != _fh)
407 {
408 onFH();
409 }
410 /*
411 if (wasFlippedHorizontal && !_fh)
412 for (int i = 0; i < this->collisionMask.size(); i++)
413 collisionMask[i].x = -collisionMask[i].x;
414 else if (!wasFlippedHorizontal && _fh)
415 for (int i = 0; i < this->collisionMask.size(); i++)
416 collisionMask[i].x = -collisionMask[i].x;
417 */
418 }
419
flipVertical()420 void RenderObject::flipVertical()
421 {
422 //bool wasFlippedVertical = _fv;
423 _fv = !_fv;
424 /*
425 if (wasFlippedVertical && !_fv)
426 for (int i = 0; i < this->collisionMask.size(); i++)
427 collisionMask[i].y = -collisionMask[i].y;
428 else if (!wasFlippedVertical && _fv)
429 for (int i = 0; i < this->collisionMask.size(); i++)
430 collisionMask[i].y = -collisionMask[i].y;
431 */
432 }
433
destroy()434 void RenderObject::destroy()
435 {
436 for (Children::iterator i = children.begin(); i != children.end(); i++)
437 {
438 // must do this first
439 // otherwise child will try to remove THIS
440 (*i)->parent = 0;
441 switch ((*i)->pm)
442 {
443 case PM_STATIC:
444 (*i)->destroy();
445 break;
446 case PM_POINTER:
447 (*i)->destroy();
448 delete (*i);
449 break;
450 }
451 }
452 children.clear();
453
454 if (parent)
455 {
456 parent->removeChild(this);
457 parent = 0;
458 }
459
460 texture = NULL;
461 }
462
copyProperties(RenderObject * target)463 void RenderObject::copyProperties(RenderObject *target)
464 {
465 this->color = target->color;
466 this->position = target->position;
467 this->alpha = target->alpha;
468 this->velocity = target->velocity;
469 }
470
operator =(const RenderObject & r)471 const RenderObject &RenderObject::operator=(const RenderObject &r)
472 {
473 errorLog("Operator= not defined for RenderObject. Use 'copyProperties'");
474 return *this;
475 }
476
getRealPosition()477 Vector RenderObject::getRealPosition()
478 {
479 if (parent)
480 {
481 return position + offset + parent->getRealPosition();
482 }
483 return position + offset;
484 }
485
getRealScale()486 Vector RenderObject::getRealScale()
487 {
488 if (parent)
489 {
490 return scale * parent->getRealScale();
491 }
492 return scale;
493 }
494
setStateDataObject(StateData * state)495 void RenderObject::setStateDataObject(StateData *state)
496 {
497 stateData = state;
498 }
499
500
toggleCull(bool value)501 void RenderObject::toggleCull(bool value)
502 {
503 cull = value;
504 }
505
moveToFront()506 void RenderObject::moveToFront()
507 {
508 if(RenderObject *p = parent)
509 {
510 if(p->children.size() && p->children[p->children.size()-1] != this)
511 {
512 p->removeChild(this);
513 p->addChild(this, (ParentManaged)this->pm, RBP_NONE, CHILD_BACK); // To back of list -> rendered on top
514 }
515 }
516 else if (layer != -1)
517 core->renderObjectLayers[this->layer].moveToFront(this);
518 }
519
moveToBack()520 void RenderObject::moveToBack()
521 {
522 if(RenderObject *p = parent)
523 {
524 if(p->children.size() && p->children[0] != this)
525 {
526 p->removeChild(this);
527 p->addChild(this, (ParentManaged)this->pm, RBP_NONE, CHILD_FRONT); // To front of list -> rendered first, below everything else
528 }
529 }
530 else if (layer != -1)
531 core->renderObjectLayers[this->layer].moveToBack(this);
532 }
533
enableMotionBlur(int sz,int off)534 void RenderObject::enableMotionBlur(int sz, int off)
535 {
536 motionBlur = true;
537 motionBlurPositions.resize(sz);
538 motionBlurFrameOffsetCounter = 0;
539 motionBlurFrameOffset = off;
540 for (int i = 0; i < motionBlurPositions.size(); i++)
541 {
542 motionBlurPositions[i].position = position;
543 motionBlurPositions[i].rotz = rotation.z;
544 }
545 }
546
disableMotionBlur()547 void RenderObject::disableMotionBlur()
548 {
549 motionBlurTransition = true;
550 motionBlurTransitionTimer = 1.0;
551 motionBlur = false;
552 }
553
isfhr()554 bool RenderObject::isfhr()
555 {
556 RenderObject *p = this;
557 bool fh = false;
558 do
559 if (p->isfh())
560 fh = !fh;
561 while ((p = p->parent));
562 return fh;
563
564 }
565
isfvr()566 bool RenderObject::isfvr()
567 {
568 RenderObject *p = this;
569 bool fv = false;
570 do
571 if (p->isfv())
572 fv = !fv;
573 while ((p = p->parent));
574 return fv;
575
576 }
577
hasRenderPass(const int pass)578 bool RenderObject::hasRenderPass(const int pass)
579 {
580 if (pass == renderPass)
581 return true;
582 for (Children::iterator i = children.begin(); i != children.end(); i++)
583 {
584 if (!(*i)->isDead() && (*i)->hasRenderPass(pass))
585 return true;
586 }
587 return false;
588 }
589
render()590 void RenderObject::render()
591 {
592 if (isHidden()) return;
593
594 /// new (breaks anything?)
595 if (alpha.x == 0 || alphaMod == 0) return;
596
597 if (core->currentLayerPass != RENDER_ALL && renderPass != RENDER_ALL)
598 {
599 RenderObject *top = getTopParent();
600 if (top == NULL && this->overrideRenderPass != OVERRIDE_NONE)
601 {
602 // FIXME: overrideRenderPass is not applied to the
603 // node itself in the original check (below); is
604 // that intentional? Doing the same thing here
605 // for the time being. --achurch
606 if (core->currentLayerPass != this->renderPass
607 && core->currentLayerPass != this->overrideRenderPass)
608 return;
609 }
610 else if (top != NULL && top->overrideRenderPass != OVERRIDE_NONE)
611 {
612 if (core->currentLayerPass != top->overrideRenderPass)
613 return;
614 }
615 else
616 {
617 if (!hasRenderPass(core->currentLayerPass))
618 return;
619 }
620 }
621
622 if (motionBlur || motionBlurTransition)
623 {
624 Vector oldPos = position;
625 float oldAlpha = alpha.x;
626 float oldRotZ = rotation.z;
627 for (int i = 0; i < motionBlurPositions.size(); i++)
628 {
629 position = motionBlurPositions[i].position;
630 rotation.z = motionBlurPositions[i].rotz;
631 alpha = 1.0f-(float(i)/float(motionBlurPositions.size()));
632 alpha *= 0.5f;
633 if (motionBlurTransition)
634 {
635 alpha *= motionBlurTransitionTimer;
636 }
637 renderCall();
638 }
639 position = oldPos;
640 alpha.x = oldAlpha;
641 rotation.z = oldRotZ;
642
643 renderCall();
644 }
645 else
646 renderCall();
647 }
648
renderCall()649 void RenderObject::renderCall()
650 {
651
652 //RenderObjectLayer *rlayer = core->getRenderObjectLayer(getTopLayer());
653
654 if (positionSnapTo)
655 this->position = *positionSnapTo;
656
657 position += offset;
658
659 #ifdef BBGE_BUILD_DIRECTX
660 if (!RENDEROBJECT_FASTTRANSFORM)
661 core->getD3DMatrixStack()->Push();
662 #endif
663
664 #ifdef BBGE_BUILD_OPENGL
665 if (!RENDEROBJECT_FASTTRANSFORM)
666 glPushMatrix();
667 if (!RENDEROBJECT_SHAREATTRIBUTES)
668 {
669 glPushAttrib(GL_ALL_ATTRIB_BITS);
670 }
671 #endif
672
673
674 if (!RENDEROBJECT_FASTTRANSFORM)
675 {
676 if (layer != LR_NONE)
677 {
678 RenderObjectLayer *l = &core->renderObjectLayers[layer];
679 if (l->followCamera != NO_FOLLOW_CAMERA)
680 {
681 followCamera = l->followCamera;
682 }
683 }
684 if (followCamera!=0 && !parent)
685 {
686 if (followCamera == 1)
687 {
688 #ifdef BBGE_BUILD_OPENGL
689 glLoadIdentity();
690 glScalef(core->globalResolutionScale.x, core->globalResolutionScale.y,0);
691 glTranslatef(position.x, position.y, position.z);
692 if (isfh())
693 {
694 //glDisable(GL_CULL_FACE);
695 glRotatef(180, 0, 1, 0);
696 }
697
698 glRotatef(rotation.z+rotationOffset.z, 0, 0, 1);
699 #endif
700 #ifdef BBGE_BUILD_DIRECTX
701 core->getD3DMatrixStack()->LoadIdentity();
702 core->scaleMatrixStack(core->globalResolutionScale.x, core->globalResolutionScale.y,0);
703 core->translateMatrixStack(position.x, position.y, 0);
704 if (isfh())
705 {
706 //HACK: disable cull ->
707 core->getD3DMatrixStack()->RotateAxisLocal(&D3DXVECTOR3(0, 1, 0), D3DXToRadian(180));
708 }
709 core->rotateMatrixStack(rotation.z + rotationOffset.z);
710 #endif
711 }
712 else
713 {
714 Vector pos = getFollowCameraPosition();
715
716 #ifdef BBGE_BUILD_OPENGL
717 glTranslatef(pos.x, pos.y, pos.z);
718 if (isfh())
719 {
720 //glDisable(GL_CULL_FACE);
721 glRotatef(180, 0, 1, 0);
722 }
723 glRotatef(rotation.z+rotationOffset.z, 0, 0, 1);
724 #endif
725 #ifdef BBGE_BUILD_DIRECTX
726 core->translateMatrixStack(pos.x, pos.y, 0);
727 if (isfh())
728 {
729 //HACK: disable cull ->
730 core->getD3DMatrixStack()->RotateAxisLocal(&D3DXVECTOR3(0, 1, 0), D3DXToRadian(180));
731 }
732 core->rotateMatrixStack(rotation.z + rotationOffset.z);
733 #endif
734 }
735 }
736 else
737 {
738
739 #ifdef BBGE_BUILD_OPENGL
740 glTranslatef(position.x, position.y, position.z);
741 #endif
742 #ifdef BBGE_BUILD_DIRECTX
743 core->translateMatrixStack(position.x, position.y, 0);
744 #endif
745
746 #ifdef BBGE_BUILD_OPENGL
747 if (RenderObject::renderPaths && position.data && position.data->path.getNumPathNodes() > 0)
748 {
749 glLineWidth(4);
750 glEnable(GL_BLEND);
751
752 int i = 0;
753 glColor4f(1.0f, 1.0f, 1.0f, 0.5f);
754 glBindTexture(GL_TEXTURE_2D, 0);
755
756 glBegin(GL_LINES);
757 for (i = 0; i < position.data->path.getNumPathNodes()-1; i++)
758 {
759 glVertex2f(position.data->path.getPathNode(i)->value.x-position.x, position.data->path.getPathNode(i)->value.y-position.y);
760 glVertex2f(position.data->path.getPathNode(i+1)->value.x-position.x, position.data->path.getPathNode(i+1)->value.y-position.y);
761 }
762 glEnd();
763
764 glPointSize(20);
765 glBegin(GL_POINTS);
766 glColor4f(0.5,0.5,1,1);
767 for (i = 0; i < position.data->path.getNumPathNodes(); i++)
768 {
769 glVertex2f(position.data->path.getPathNode(i)->value.x-position.x, position.data->path.getPathNode(i)->value.y-position.y);
770 }
771 glEnd();
772 }
773 #endif
774 #ifdef BBGE_BUILD_OPENGL
775
776 glRotatef(rotation.z+rotationOffset.z, 0, 0, 1);
777 if (isfh())
778 {
779 //glDisable(GL_CULL_FACE);
780 glRotatef(180, 0, 1, 0);
781 }
782 #endif
783 #ifdef BBGE_BUILD_DIRECTX
784 //core->getD3DMatrixStack()->RotateAxisLocal(&D3DXVECTOR3(0, 0, 1), rotation.z+rotationOffset.z);
785 core->rotateMatrixStack(rotation.z + rotationOffset.z);
786 if (isfh())
787 {
788 //HACK: disable cull
789 core->getD3DDevice()->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
790 //core->getD3DMatrixStack()->Scale(-1, 1, 1);
791 //core->applyMatrixStackToWorld();
792 core->getD3DMatrixStack()->RotateAxisLocal(&D3DXVECTOR3(0, 1, 0), D3DXToRadian(180));
793 //core->applyMatrixStackToWorld();
794 }
795 #endif
796 }
797
798 #ifdef BBGE_BUILD_OPENGL
799 glTranslatef(beforeScaleOffset.x, beforeScaleOffset.y, beforeScaleOffset.z);
800 glScalef(scale.x, scale.y, 1);
801 glTranslatef(internalOffset.x, internalOffset.y, internalOffset.z);
802 #endif
803 #ifdef BBGE_BUILD_DIRECTX
804 core->translateMatrixStack(beforeScaleOffset.x, beforeScaleOffset.y, 0);
805 core->scaleMatrixStack(scale.x, scale.y, 1);
806 core->translateMatrixStack(internalOffset.x, internalOffset.y, 0);
807
808 core->applyMatrixStackToWorld();
809 #endif
810
811
812 //glDisable(GL_CULL_FACE);
813 /* Never set anywhere. --achurch
814 if (renderOrigin)
815 {
816 #ifdef BBGE_BUILD_OPENGL
817 glBegin(GL_TRIANGLES);
818 glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
819 glVertex3f(0.0f, 5.0f, 0.0f);
820 glVertex3f(50.0f, 0.0f, 0.0f);
821 glVertex3f(0.0f, -5.0f, 0.0f);
822
823 glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
824 glVertex3f(0.0f, 0.0f, 5.0f);
825 glVertex3f(0.0f, 50.0f, 0.0f);
826 glVertex3f(0.0f, 0.0f, -5.0f);
827
828 glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
829 glVertex3f(5.0f, 0.0f, 0.0f);
830 glVertex3f(0.0f, 0.0f, 50.0f);
831 glVertex3f(-5.0f, 0.0f, 0.0f);
832 glEnd();
833 #endif
834 }
835 */
836 }
837
838 for (Children::iterator i = children.begin(); i != children.end(); i++)
839 {
840 if (!(*i)->isDead() && (*i)->renderBeforeParent)
841 (*i)->render();
842 }
843
844
845 //if (useColor)
846 {
847 #ifdef BBGE_BUILD_OPENGL
848 if (rlayer)
849 glColor4f(color.x * rlayer->color.x, color.y * rlayer->color.y, color.z * rlayer->color.z, alpha.x*alphaMod);
850 else
851 glColor4f(color.x, color.y, color.z, alpha.x*alphaMod);
852 #elif defined(BBGE_BUILD_DIRECTX)
853 core->setColor(color.x, color.y, color.z, alpha.x*alphaMod);
854 #endif
855 }
856
857 if (texture)
858 {
859
860 #ifdef BBGE_BUILD_OPENGL
861 if (texture->textures[0] != lastTextureApplied || repeatTexture != lastTextureRepeat)
862 {
863 texture->apply(repeatTexture);
864 lastTextureRepeat = repeatTexture;
865 lastTextureApplied = texture->textures[0];
866 }
867 #endif
868 #ifdef BBGE_BUILD_DIRECTX
869 texture->apply(repeatTexture);
870 #endif
871 }
872 else
873 {
874 if (lastTextureApplied != 0 || repeatTexture != lastTextureRepeat)
875 {
876 #ifdef BBGE_BUILD_OPENGL
877 glBindTexture(GL_TEXTURE_2D, 0);
878 #endif
879 #ifdef BBGE_BUILD_DIRECTX
880 core->bindTexture(0, 0);
881 #endif
882 lastTextureApplied = 0;
883 lastTextureRepeat = repeatTexture;
884 }
885 }
886
887 applyBlendType();
888
889
890 bool doRender = true;
891 int pass = renderPass;
892 if (core->currentLayerPass != RENDER_ALL && renderPass != RENDER_ALL)
893 {
894 RenderObject *top = getTopParent();
895 if (top)
896 {
897 if (top->overrideRenderPass != OVERRIDE_NONE)
898 pass = top->overrideRenderPass;
899 }
900
901 doRender = (core->currentLayerPass == pass);
902 }
903
904 if (renderCollisionShape)
905 renderCollision();
906
907 if (doRender)
908 onRender();
909
910 //collisionShape.render();
911 if (!RENDEROBJECT_SHAREATTRIBUTES)
912 {
913 glPopAttrib();
914 }
915
916 for (Children::iterator i = children.begin(); i != children.end(); i++)
917 {
918 if (!(*i)->isDead() && !(*i)->renderBeforeParent)
919 (*i)->render();
920 }
921
922
923 if (!RENDEROBJECT_FASTTRANSFORM)
924 {
925 #ifdef BBGE_BUILD_OPENGL
926 glPopMatrix();
927 #endif
928 #ifdef BBGE_BUILD_DIRECTX
929 core->getD3DMatrixStack()->Pop();
930 core->applyMatrixStackToWorld();
931 #endif
932 }
933
934
935 position -= offset;
936 }
937
renderCollision()938 void RenderObject::renderCollision()
939 {
940 if (!collisionRects.empty())
941 {
942 #ifdef BBGE_BUILD_OPENGL
943 glPushAttrib(GL_ALL_ATTRIB_BITS);
944 glPushMatrix();
945 glBindTexture(GL_TEXTURE_2D, 0);
946
947 //glLoadIdentity();
948 //core->setupRenderPositionAndScale();
949
950 glEnable(GL_BLEND);
951 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
952 glColor4f(1.0f, 0.5f, 1.0f, 0.5f);
953 glPointSize(5);
954
955 for (int i = 0; i < collisionRects.size(); i++)
956 {
957 RectShape *r = &collisionRects[i];
958
959 glBegin(GL_QUADS);
960 glVertex3f(r->x1, r->y1, 0);
961 glVertex3f(r->x1, r->y2, 0);
962 glVertex3f(r->x2, r->y2, 0);
963 glVertex3f(r->x2, r->y1, 0);
964 glEnd();
965 glBegin(GL_POINTS);
966 glVertex3f(r->x1, r->y1, 0);
967 glVertex3f(r->x1, r->y2, 0);
968 glVertex3f(r->x2, r->y2, 0);
969 glVertex3f(r->x2, r->y1, 0);
970 glEnd();
971 }
972
973 glPopMatrix();
974 glDisable(GL_BLEND);
975
976 glPopAttrib();
977 #endif
978 }
979
980 if (!collisionMask.empty())
981 {
982 #ifdef BBGE_BUILD_OPENGL
983 glPushAttrib(GL_ALL_ATTRIB_BITS);
984 glPushMatrix();
985 glBindTexture(GL_TEXTURE_2D, 0);
986
987 /*
988 glTranslatef(-offset.x, -offset.y,0);
989 glTranslatef(collidePosition.x, collidePosition.y,0);
990 */
991
992
993 glLoadIdentity();
994 core->setupRenderPositionAndScale();
995
996
997 glEnable(GL_BLEND);
998 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
999
1000 glColor4f(1,1,0,0.5);
1001
1002 for (int i = 0; i < transformedCollisionMask.size(); i++)
1003 {
1004 Vector collide = this->transformedCollisionMask[i];
1005 //Vector collide = getWorldCollidePosition(collisionMask[i]);
1006 //Vector collide = collisionMask[i];
1007 /*
1008 if (isPieceFlippedHorizontal())
1009 {
1010 collide.x = -collide.x;
1011 }
1012 */
1013 glTranslatef(collide.x, collide.y, 0);
1014 RenderObject *parent = this->getTopParent();
1015 if (parent)
1016 drawCircle(collideRadius*parent->scale.x, 45);
1017 glTranslatef(-collide.x, -collide.y, 0);
1018 }
1019
1020 //glTranslatef(-collidePosition.x, -collidePosition.y,0);
1021 glDisable(GL_BLEND);
1022 glPopMatrix();
1023 glPopAttrib();
1024
1025 //glTranslatef(offset.x, offset.y,0);
1026 #endif
1027 }
1028 else if (collideRadius > 0)
1029 {
1030 glPushMatrix();
1031 glLoadIdentity();
1032 core->setupRenderPositionAndScale();
1033 glBindTexture(GL_TEXTURE_2D, 0);
1034 glTranslatef(position.x+offset.x, position.y+offset.y, 0);
1035 //glScalef(scale.x, scale.y, 0);
1036 glTranslatef(internalOffset.x, internalOffset.y, 0);
1037 glEnable(GL_BLEND);
1038 //glTranslatef(collidePosition.x, collidePosition.y,0);
1039 //glEnable(GL_ALPHA_TEST);
1040 //glAlphaFunc(GL_GREATER, 0);
1041 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1042 glColor4f(1,0,0,0.5);
1043 drawCircle(collideRadius, 8);
1044 glDisable(GL_BLEND);
1045 glTranslatef(offset.x, offset.y,0);
1046 glPopMatrix();
1047 }
1048 }
1049
addDeathNotify(RenderObject * r)1050 void RenderObject::addDeathNotify(RenderObject *r)
1051 {
1052 deathNotifications.remove(r);
1053 deathNotifications.push_back(r);
1054 }
1055
deathNotify(RenderObject * r)1056 void RenderObject::deathNotify(RenderObject *r)
1057 {
1058 deathNotifications.remove(r);
1059 }
1060
getCollisionMaskNormal(int index)1061 Vector RenderObject::getCollisionMaskNormal(int index)
1062 {
1063 Vector sum;
1064 int num=0;
1065 for (int i = 0; i < this->transformedCollisionMask.size(); i++)
1066 {
1067 if (i != index)
1068 {
1069 Vector diff = transformedCollisionMask[index] - transformedCollisionMask[i];
1070 if (diff.isLength2DIn(128))
1071 {
1072 sum += diff;
1073 num++;
1074 }
1075 }
1076 }
1077 if (!sum.isZero())
1078 {
1079 sum /= num;
1080
1081 sum.normalize2D();
1082
1083 /*
1084 std::ostringstream os;
1085 os << "found [" << num << "] circles, got normal [" << sum.x << ", " << sum.y << "]";
1086 debugLog(os.str());
1087 */
1088 }
1089
1090 return sum;
1091 }
1092
lookAt(const Vector & pos,float t,float minAngle,float maxAngle,float offset)1093 void RenderObject::lookAt(const Vector &pos, float t, float minAngle, float maxAngle, float offset)
1094 {
1095 Vector myPos = this->getWorldPosition();
1096 float angle = 0;
1097
1098 if (myPos.x == pos.x && myPos.y == pos.y)
1099 {
1100 return;
1101 }
1102 MathFunctions::calculateAngleBetweenVectorsInDegrees(myPos, pos, angle);
1103
1104 RenderObject *p = parent;
1105 while (p)
1106 {
1107 angle -= p->rotation.z;
1108 p = p->parent;
1109 }
1110
1111 if (isPieceFlippedHorizontal())
1112 {
1113 angle = 180-angle;
1114
1115 /*
1116 minAngle = -minAngle;
1117 maxAngle = -maxAngle;
1118 std::swap(minAngle, maxAngle);
1119 */
1120 //std::swap(minAngle, maxAngle);
1121 /*
1122 minAngle = -(180+minAngle);
1123 maxAngle = -(180+maxAngle);
1124 */
1125 /*
1126 if (minAngle > maxAngle)
1127 std::swap(minAngle, maxAngle);
1128 */
1129 offset = -offset;
1130 }
1131 angle += offset;
1132 if (angle < minAngle)
1133 angle = minAngle;
1134 if (angle > maxAngle)
1135 angle = maxAngle;
1136
1137 int amt = 10;
1138 if (isPieceFlippedHorizontal())
1139 {
1140 if (pos.x < myPos.x-amt)
1141 {
1142 angle = 0;
1143 }
1144 }
1145 else
1146 {
1147 if (pos.x > myPos.x+amt)
1148 {
1149 angle = 0;
1150 }
1151 }
1152
1153 rotation.interpolateTo(Vector(0,0,angle), t);
1154 }
1155
update(float dt)1156 void RenderObject::update(float dt)
1157 {
1158 if (ignoreUpdate)
1159 {
1160 return;
1161 }
1162 if (useOldDT)
1163 {
1164 dt = core->get_old_dt();
1165 }
1166 if (!isDead())
1167 {
1168 //dt *= updateMultiplier;
1169 onUpdate(dt);
1170
1171 if (isHidden())
1172 return;
1173
1174 for (Children::iterator i = children.begin(); i != children.end(); i++)
1175 {
1176 if ((*i)->updateAfterParent && (((*i)->pm == PM_POINTER) || ((*i)->pm == PM_STATIC)))
1177 {
1178 (*i)->update(dt);
1179 }
1180 }
1181 }
1182 }
1183
removeChild(RenderObject * r)1184 void RenderObject::removeChild(RenderObject *r)
1185 {
1186 r->parent = 0;
1187 Children::iterator oldend = children.end();
1188 Children::iterator newend = std::remove(children.begin(), oldend, r);
1189 if(oldend != newend)
1190 {
1191 children.resize(std::distance(children.begin(), newend));
1192 return;
1193 }
1194
1195 for (Children::iterator i = children.begin(); i != children.end(); i++)
1196 {
1197 (*i)->removeChild(r);
1198 }
1199 }
1200
enqueueChildDeletion(RenderObject * r)1201 void RenderObject::enqueueChildDeletion(RenderObject *r)
1202 {
1203 if (r->parent == this)
1204 {
1205 childGarbage.push_back(r);
1206 }
1207 }
1208
safeKill()1209 void RenderObject::safeKill()
1210 {
1211 alpha = 0;
1212 life = 0;
1213 onEndOfLife();
1214 //deathEvent.call();
1215 for (RenderObjectList::iterator i = deathNotifications.begin(); i != deathNotifications.end(); i++)
1216 {
1217 (*i)->deathNotify(this);
1218 }
1219 //dead = true;
1220 if (this->parent)
1221 {
1222 parent->enqueueChildDeletion(this);
1223 /*
1224 parent->removeChild(this);
1225 core->enqueueRenderObjectDeletion(this);
1226 */
1227 }
1228 else
1229 {
1230 if (stateData)
1231 stateData->removeRenderObject(this);
1232 else
1233 core->enqueueRenderObjectDeletion(this);
1234 }
1235 }
1236
getNormal()1237 Vector RenderObject::getNormal()
1238 {
1239 float a = MathFunctions::toRadians(getAbsoluteRotation().z);
1240 return Vector(sinf(a),cosf(a));
1241 }
1242
1243 // HACK: this is probably a slow implementation
getForward()1244 Vector RenderObject::getForward()
1245 {
1246 Vector v = getWorldCollidePosition(Vector(0,-1, 0));
1247 Vector r = v - getWorldCollidePosition();
1248 r.normalize2D();
1249
1250 /*
1251 std::ostringstream os;
1252 os << "forward v(" << v.x << ", " << v.y << ") ";
1253 os << "r(" << r.x << ", " << r.y << ") ";
1254 debugLog(os.str());
1255 */
1256 return r;
1257 }
1258
getAbsoluteRotation()1259 Vector RenderObject::getAbsoluteRotation()
1260 {
1261 Vector r = rotation;
1262 if (parent)
1263 {
1264 return parent->getAbsoluteRotation() + r;
1265 }
1266 return r;
1267 }
1268
onUpdate(float dt)1269 void RenderObject::onUpdate(float dt)
1270 {
1271 if (isDead()) return;
1272 //collisionShape.updatePosition(position);
1273 updateLife(dt);
1274
1275 // FIXME: We might not need to do lifetime checks either; I just
1276 // left that above for safety since I'm not certain. --achurch
1277 if (isHidden()) return;
1278
1279 position += velocity * dt;
1280 velocity += gravity * dt;
1281 position.update(dt);
1282 velocity.update(dt);
1283 scale.update(dt);
1284 rotation.update(dt);
1285 color.update(dt);
1286 alpha.update(dt);
1287 offset.update(dt);
1288 internalOffset.update(dt);
1289 beforeScaleOffset.update(dt);
1290 rotationOffset.update(dt);
1291
1292 for (Children::iterator i = children.begin(); i != children.end(); i++)
1293 {
1294 if (shareAlphaWithChildren)
1295 (*i)->alpha.x = this->alpha.x;
1296 if (shareColorWithChildren)
1297 (*i)->color = this->color;
1298
1299 if (!(*i)->updateAfterParent && (((*i)->pm == PM_POINTER) || ((*i)->pm == PM_STATIC)))
1300 {
1301 (*i)->update(dt);
1302 }
1303 }
1304
1305 if (!childGarbage.empty())
1306 {
1307 for (Children::iterator i = childGarbage.begin(); i != childGarbage.end(); i++)
1308 {
1309 removeChild(*i);
1310 (*i)->destroy();
1311 delete (*i);
1312 }
1313 childGarbage.clear();
1314 }
1315
1316 if (motionBlur)
1317 {
1318 if (motionBlurFrameOffsetCounter >= motionBlurFrameOffset)
1319 {
1320 motionBlurFrameOffsetCounter = 0;
1321 motionBlurPositions[0].position = position;
1322 motionBlurPositions[0].rotz = rotation.z;
1323 for (int i = motionBlurPositions.size()-1; i > 0; i--)
1324 {
1325 motionBlurPositions[i] = motionBlurPositions[i-1];
1326 }
1327 }
1328 else
1329 motionBlurFrameOffsetCounter ++;
1330 }
1331 if (motionBlurTransition)
1332 {
1333 motionBlurTransitionTimer -= dt*2;
1334 if (motionBlurTransitionTimer <= 0)
1335 {
1336 motionBlur = motionBlurTransition = false;
1337 motionBlurTransitionTimer = 0;
1338 }
1339 }
1340
1341 // updateCullVariables();
1342 }
1343
unloadDevice()1344 void RenderObject::unloadDevice()
1345 {
1346 for (Children::iterator i = children.begin(); i != children.end(); i++)
1347 {
1348 (*i)->unloadDevice();
1349 }
1350 }
1351
reloadDevice()1352 void RenderObject::reloadDevice()
1353 {
1354 for (Children::iterator i = children.begin(); i != children.end(); i++)
1355 {
1356 (*i)->reloadDevice();
1357 }
1358 }
1359
setTexture(const std::string & n)1360 bool RenderObject::setTexture(const std::string &n)
1361 {
1362 std::string name = n;
1363 stringToLowerUserData(name);
1364
1365 if (name.empty())
1366 {
1367 setTexturePointer(NULL);
1368 return false;
1369 }
1370
1371 if(texture && name == texture->name)
1372 return true; // no texture change
1373
1374 TextureLoadResult res = TEX_FAILED;
1375 CountedPtr<Texture> tex = core->addTexture(name, &res);
1376 setTexturePointer(tex);
1377 return !!tex && res != TEX_FAILED;
1378 }
1379
getSortDepth()1380 float RenderObject::getSortDepth()
1381 {
1382 return position.y;
1383 }
1384
addChild(RenderObject * r,ParentManaged pm,RenderBeforeParent rbp,ChildOrder order)1385 void RenderObject::addChild(RenderObject *r, ParentManaged pm, RenderBeforeParent rbp, ChildOrder order)
1386 {
1387 if (r->parent)
1388 {
1389 errorLog("Engine does not support multiple parents");
1390 return;
1391 }
1392
1393 if (order == CHILD_BACK)
1394 children.push_back(r);
1395 else
1396 children.insert(children.begin(), r);
1397
1398 r->pm = pm;
1399
1400 if (rbp == RBP_OFF)
1401 r->renderBeforeParent = 0;
1402 else if (rbp == RBP_ON)
1403 r->renderBeforeParent = 1;
1404
1405 r->parent = this;
1406 }
1407
getStateData()1408 StateData *RenderObject::getStateData()
1409 {
1410 if (parent)
1411 {
1412 return parent->getStateData();
1413 }
1414 else
1415 return stateData;
1416 }
1417
setPositionSnapTo(InterpolatedVector * positionSnapTo)1418 void RenderObject::setPositionSnapTo(InterpolatedVector *positionSnapTo)
1419 {
1420 this->positionSnapTo = positionSnapTo;
1421 }
1422
setOverrideCullRadius(float ovr)1423 void RenderObject::setOverrideCullRadius(float ovr)
1424 {
1425 overrideCullRadiusSqr = ovr * ovr;
1426 }
1427
isCoordinateInRadius(const Vector & pos,float r)1428 bool RenderObject::isCoordinateInRadius(const Vector &pos, float r)
1429 {
1430 Vector d = pos-getRealPosition();
1431
1432 return (d.getSquaredLength2D() < r*r);
1433 }
1434