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