276 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			276 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /** \file gameengine/Expressions/Operator2Expr.cpp
 | |
|  *  \ingroup expressions
 | |
|  */
 | |
| // Operator2Expr.cpp: implementation of the COperator2Expr class.
 | |
| /*
 | |
|  * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
 | |
|  *
 | |
|  * Permission to use, copy, modify, distribute and sell this software
 | |
|  * and its documentation for any purpose is hereby granted without fee,
 | |
|  * provided that the above copyright notice appear in all copies and
 | |
|  * that both that copyright notice and this permission notice appear
 | |
|  * in supporting documentation.  Erwin Coumans makes no
 | |
|  * representations about the suitability of this software for any
 | |
|  * purpose.  It is provided "as is" without express or implied warranty.
 | |
|  *
 | |
|  */
 | |
| // 31 dec 1998 - big update: try to use the cached data for updating, instead of
 | |
| // rebuilding completely it from left and right node. Modified flags and bounding boxes
 | |
| // have to do the trick
 | |
| // when expression is cached, there will be a call to UpdateCalc() instead of Calc()
 | |
| 
 | |
| #include "Operator2Expr.h"
 | |
| #include "StringValue.h"
 | |
| #include "VoidValue.h"
 | |
| 
 | |
| //////////////////////////////////////////////////////////////////////
 | |
| // Construction/Destruction
 | |
| //////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| COperator2Expr::COperator2Expr(VALUE_OPERATOR op, CExpression *lhs, CExpression *rhs)
 | |
| : 	
 | |
| m_rhs(rhs),
 | |
| m_lhs(lhs),
 | |
| m_cached_calculate(NULL),
 | |
| m_op(op)
 | |
| /*
 | |
| pre:
 | |
| effect: constucts a COperator2Expr with op, lhs and rhs in it
 | |
| */
 | |
| {
 | |
| 
 | |
| }
 | |
| 
 | |
| COperator2Expr::COperator2Expr():
 | |
| m_rhs(NULL),
 | |
| m_lhs(NULL),
 | |
| m_cached_calculate(NULL)
 | |
| 
 | |
| /*
 | |
| pre:
 | |
| effect: constucts an empty COperator2Expr
 | |
| */
 | |
| {
 | |
| 	
 | |
| }
 | |
| 
 | |
| COperator2Expr::~COperator2Expr()
 | |
| /*
 | |
| pre:
 | |
| effect: deletes the object
 | |
| */
 | |
| {
 | |
| 	if (m_lhs)
 | |
| 		m_lhs->Release();
 | |
| 	if (m_rhs)
 | |
| 		m_rhs->Release();
 | |
| 	if (m_cached_calculate)
 | |
| 		m_cached_calculate->Release();
 | |
| 	
 | |
| }
 | |
| CValue* COperator2Expr::Calculate()
 | |
| /*
 | |
| pre:
 | |
| ret: a new object containing the result of applying operator m_op to m_lhs
 | |
| and m_rhs
 | |
| */
 | |
| {
 | |
| 	
 | |
| 	bool leftmodified,rightmodified;
 | |
| 	leftmodified = m_lhs->NeedsRecalculated();
 | |
| 	rightmodified = m_rhs->NeedsRecalculated();
 | |
| 	
 | |
| 	// if no modifications on both left and right subtree, and result is already calculated
 | |
| 	// then just return cached result...
 | |
| 	if (!leftmodified && !rightmodified && (m_cached_calculate))
 | |
| 	{
 | |
| 		// not modified, just return m_cached_calculate
 | |
| 	} else {
 | |
| 		// if not yet calculated, or modified...
 | |
| 		
 | |
| 		
 | |
| 		if (m_cached_calculate) {
 | |
| 			m_cached_calculate->Release();
 | |
| 			m_cached_calculate=NULL;
 | |
| 		}
 | |
| 		
 | |
| 		CValue* ffleft = m_lhs->Calculate();
 | |
| 		CValue* ffright = m_rhs->Calculate();
 | |
| 		
 | |
| 		ffleft->SetOwnerExpression(this);//->m_pOwnerExpression=this;
 | |
| 		ffright->SetOwnerExpression(this);//->m_pOwnerExpression=this;
 | |
| 		
 | |
| 		m_cached_calculate = ffleft->Calc(m_op,ffright);
 | |
| 		
 | |
| 		//if (m_cached_calculate)				
 | |
| 		//	m_cached_calculate->Action(CValue::SETOWNEREXPR,&CVoidValue(this,false,CValue::STACKVALUE));
 | |
| 
 | |
| 		ffleft->Release();
 | |
| 		ffright->Release();
 | |
| 	}
 | |
| 	
 | |
| 	return m_cached_calculate->AddRef();
 | |
| 	
 | |
| }
 | |
| 
 | |
| /*
 | |
| bool COperator2Expr::IsInside(float x, float y, float z,bool bBorderInclude)
 | |
| {
 | |
| 	bool inside;
 | |
| 	inside = false;
 | |
| 	
 | |
| 	switch (m_op) 
 | |
| 	{
 | |
| 	case VALUE_ADD_OPERATOR: {
 | |
| 	//	inside = first || second; // optimized with early out if first is inside
 | |
| 		// todo: calculate smallest leaf first ! is much faster...
 | |
| 			
 | |
| 		bool second;//first ;//,second;
 | |
| 		
 | |
| 		//first = m_lhs->IsInside(x,y,z);
 | |
| 		second = m_rhs->IsInside(x,y,z,bBorderInclude);
 | |
| 		if (second)
 | |
| 			return true; //early out
 | |
| 	
 | |
| 	//	second = m_rhs->IsInside(x,y,z);
 | |
| 
 | |
| 		return m_lhs->IsInside(x,y,z,bBorderInclude);
 | |
| 			
 | |
| 		break;
 | |
| 							 }
 | |
| 		
 | |
| 	case VALUE_SUB_OPERATOR: {
 | |
| 		//inside = first && !second; // optimized with early out
 | |
| 		// todo: same as with add_operator: calc smallest leaf first
 | |
| 
 | |
| 		bool second;//first ;//,second;
 | |
| 		//first = m_lhs->IsInside(x,y,z);
 | |
| 		second = m_rhs->IsInside(x,y,z,bBorderInclude);
 | |
| 		if (second)
 | |
| 			return false;
 | |
| 
 | |
| 		// second space get subtracted -> negate!
 | |
| 		//second = m_rhs->IsInside(x,y,z);
 | |
| 
 | |
| 		return (m_lhs->IsInside(x,y,z,bBorderInclude));
 | |
| 
 | |
| 		
 | |
| 		break;
 | |
| 							 }
 | |
| 	default:{
 | |
| 		assert(false);
 | |
| 		// not yet implemented, only add or sub csg operations
 | |
| 			}
 | |
| 	}
 | |
| 	
 | |
| 	return inside;	
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| bool COperator2Expr::IsRightInside(float x, float y, float z,bool bBorderInclude)
 | |
| {
 | |
| 	return m_rhs->IsInside(x,y,z,bBorderInclude);
 | |
| }
 | |
| 
 | |
| bool COperator2Expr::IsLeftInside(float x, float y, float z,bool bBorderInclude)
 | |
| {
 | |
| 	return m_lhs->IsInside(x,y,z,bBorderInclude);
 | |
| }
 | |
| */
 | |
| bool COperator2Expr::NeedsRecalculated()
 | |
| {
 | |
| 	// added some lines, just for debugging purposes, it could be a one-liner :)
 | |
| 	//bool modleft
 | |
| 	//bool modright;
 | |
| 	assertd(m_lhs);
 | |
| 	assertd(m_rhs);
 | |
| 
 | |
| 	//modright = m_rhs->NeedsRecalculated();
 | |
| 	if (m_rhs->NeedsRecalculated()) // early out
 | |
| 		return true;
 | |
| 	return m_lhs->NeedsRecalculated();
 | |
| 	//modleft = m_lhs->NeedsRecalculated();
 | |
| 	//return (modleft || modright);
 | |
| 	
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| CExpression* COperator2Expr::CheckLink(std::vector<CBrokenLinkInfo*>& brokenlinks)
 | |
| {
 | |
| // if both children are 'dead', return NULL
 | |
| // if only one child is alive, return that child
 | |
| // if both childresn are alive, return this
 | |
| 
 | |
| 
 | |
| //  	bool leftalive = true,rightalive=true;
 | |
| 	/* Does this mean the function will always bomb? */
 | |
| 	assertd(false);
 | |
| 	assert(m_lhs);
 | |
| 	assert(m_rhs);
 | |
| /*
 | |
| 	if (m_cached_calculate)
 | |
| 		m_cached_calculate->Action(CValue::REFRESH_CACHE);
 | |
| 	
 | |
| 	CExpression* newlhs = m_lhs->CheckLink(brokenlinks);
 | |
| 	CExpression* newrhs = m_rhs->CheckLink(brokenlinks);
 | |
| 
 | |
| 	if (m_lhs != newlhs)
 | |
| 	{
 | |
| 		brokenlinks.push_back(new CBrokenLinkInfo(&m_lhs,m_lhs));
 | |
| 	}
 | |
| 
 | |
| 	if (m_rhs != newrhs)
 | |
| 	{
 | |
| 		brokenlinks.push_back(new CBrokenLinkInfo(&m_rhs,m_rhs));
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 
 | |
| 	m_lhs = newlhs;
 | |
| 	m_rhs = newrhs;
 | |
| 
 | |
| 	if (m_lhs && m_rhs) {
 | |
| 		return this;
 | |
| 	}
 | |
| 	
 | |
| 	AddRef();
 | |
| 	if (m_lhs) 
 | |
| 		return Release(m_lhs->AddRef());
 | |
| 	
 | |
| 	if (m_rhs)
 | |
| 		return Release(m_rhs->AddRef());
 | |
| /		
 | |
| 
 | |
|   */
 | |
| 	return Release();
 | |
| }
 | |
| 
 | |
| 
 | |
| bool COperator2Expr::MergeExpression(CExpression *otherexpr)
 | |
| {
 | |
| 	if (m_lhs)
 | |
| 	{
 | |
| 		if (m_lhs->GetExpressionID() == CExpression::CCONSTEXPRESSIONID)
 | |
| 		{
 | |
| 			// cross fingers ;) replace constexpr by new tree...
 | |
| 			m_lhs->Release();
 | |
| 			m_lhs = otherexpr->AddRef();
 | |
| 			return true;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	assertd(false);
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| 
 | |
| void COperator2Expr::BroadcastOperators(VALUE_OPERATOR op)
 | |
| {
 | |
| 	if (m_lhs)
 | |
| 		m_lhs->BroadcastOperators(m_op);
 | |
| 	if (m_rhs)
 | |
| 		m_rhs->BroadcastOperators(m_op);
 | |
| }
 |