doxygen: gameengine/Expressions tagged.
[blender-staging.git] / source / gameengine / Expressions / Operator2Expr.cpp
1 /** \file gameengine/Expressions/Operator2Expr.cpp
2  *  \ingroup expressions
3  */
4 // Operator2Expr.cpp: implementation of the COperator2Expr class.
5 /*
6  * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
7  *
8  * Permission to use, copy, modify, distribute and sell this software
9  * and its documentation for any purpose is hereby granted without fee,
10  * provided that the above copyright notice appear in all copies and
11  * that both that copyright notice and this permission notice appear
12  * in supporting documentation.  Erwin Coumans makes no
13  * representations about the suitability of this software for any
14  * purpose.  It is provided "as is" without express or implied warranty.
15  *
16  */
17 // 31 dec 1998 - big update: try to use the cached data for updating, instead of
18 // rebuilding completely it from left and right node. Modified flags and bounding boxes
19 // have to do the trick
20 // when expression is cached, there will be a call to UpdateCalc() instead of Calc()
21
22 #include "Operator2Expr.h"
23 #include "StringValue.h"
24 #include "VoidValue.h"
25
26 //////////////////////////////////////////////////////////////////////
27 // Construction/Destruction
28 //////////////////////////////////////////////////////////////////////
29
30 COperator2Expr::COperator2Expr(VALUE_OPERATOR op, CExpression *lhs, CExpression *rhs)
31 :       
32 m_rhs(rhs),
33 m_lhs(lhs),
34 m_cached_calculate(NULL),
35 m_op(op)
36 /*
37 pre:
38 effect: constucts a COperator2Expr with op, lhs and rhs in it
39 */
40 {
41
42 }
43
44 COperator2Expr::COperator2Expr():
45 m_rhs(NULL),
46 m_lhs(NULL),
47 m_cached_calculate(NULL)
48
49 /*
50 pre:
51 effect: constucts an empty COperator2Expr
52 */
53 {
54         
55 }
56
57 COperator2Expr::~COperator2Expr()
58 /*
59 pre:
60 effect: deletes the object
61 */
62 {
63         if (m_lhs)
64                 m_lhs->Release();
65         if (m_rhs)
66                 m_rhs->Release();
67         if (m_cached_calculate)
68                 m_cached_calculate->Release();
69         
70 }
71 CValue* COperator2Expr::Calculate()
72 /*
73 pre:
74 ret: a new object containing the result of applying operator m_op to m_lhs
75 and m_rhs
76 */
77 {
78         
79         bool leftmodified,rightmodified;
80         leftmodified = m_lhs->NeedsRecalculated();
81         rightmodified = m_rhs->NeedsRecalculated();
82         
83         // if no modifications on both left and right subtree, and result is already calculated
84         // then just return cached result...
85         if (!leftmodified && !rightmodified && (m_cached_calculate))
86         {
87                 // not modified, just return m_cached_calculate
88         } else {
89                 // if not yet calculated, or modified...
90                 
91                 
92                 if (m_cached_calculate) {
93                         m_cached_calculate->Release();
94                         m_cached_calculate=NULL;
95                 }
96                 
97                 CValue* ffleft = m_lhs->Calculate();
98                 CValue* ffright = m_rhs->Calculate();
99                 
100                 ffleft->SetOwnerExpression(this);//->m_pOwnerExpression=this;
101                 ffright->SetOwnerExpression(this);//->m_pOwnerExpression=this;
102                 
103                 m_cached_calculate = ffleft->Calc(m_op,ffright);
104                 
105                 //if (m_cached_calculate)                               
106                 //      m_cached_calculate->Action(CValue::SETOWNEREXPR,&CVoidValue(this,false,CValue::STACKVALUE));
107
108                 ffleft->Release();
109                 ffright->Release();
110         }
111         
112         return m_cached_calculate->AddRef();
113         
114 }
115
116 /*
117 bool COperator2Expr::IsInside(float x, float y, float z,bool bBorderInclude)
118 {
119         bool inside;
120         inside = false;
121         
122         switch (m_op) 
123         {
124         case VALUE_ADD_OPERATOR: {
125         //      inside = first || second; // optimized with early out if first is inside
126                 // todo: calculate smallest leaf first ! is much faster...
127                         
128                 bool second;//first ;//,second;
129                 
130                 //first = m_lhs->IsInside(x,y,z) ;
131                 second = m_rhs->IsInside(x,y,z,bBorderInclude) ;
132                 if (second)
133                         return true; //early out
134         
135         //      second = m_rhs->IsInside(x,y,z) ;
136
137                 return m_lhs->IsInside(x,y,z,bBorderInclude) ;
138                         
139                 break;
140                                                          }
141                 
142         case VALUE_SUB_OPERATOR: {
143                 //inside = first && !second; // optimized with early out
144                 // todo: same as with add_operator: calc smallest leaf first
145
146                 bool second;//first ;//,second;
147                 //first = m_lhs->IsInside(x,y,z) ;
148                 second = m_rhs->IsInside(x,y,z,bBorderInclude);
149                 if (second)
150                         return false;
151
152                 // second space get subtracted -> negate!
153                 //second = m_rhs->IsInside(x,y,z);
154
155                 return (m_lhs->IsInside(x,y,z,bBorderInclude));
156
157                 
158                 break;
159                                                          }
160         default:{
161                 assert(false);
162                 // not yet implemented, only add or sub csg operations
163                         }
164         }
165         
166         return inside;  
167 }
168
169
170
171 bool COperator2Expr::IsRightInside(float x, float y, float z,bool bBorderInclude) {
172         
173         return m_rhs->IsInside(x,y,z,bBorderInclude) ;
174         
175 }
176
177 bool COperator2Expr::IsLeftInside(float x, float y, float z,bool bBorderInclude) {
178         return m_lhs->IsInside(x,y,z,bBorderInclude);
179 }
180 */
181 bool COperator2Expr::NeedsRecalculated() {
182         // added some lines, just for debugging purposes, it could be a one-liner :)
183         //bool modleft
184         //bool modright;
185         assertd(m_lhs);
186         assertd(m_rhs);
187
188         //modright = m_rhs->NeedsRecalculated();
189         if (m_rhs->NeedsRecalculated()) // early out
190                 return true;
191         return m_lhs->NeedsRecalculated();
192         //modleft = m_lhs->NeedsRecalculated();
193         //return (modleft || modright);
194         
195 }
196
197
198
199 CExpression* COperator2Expr::CheckLink(std::vector<CBrokenLinkInfo*>& brokenlinks) {
200 // if both children are 'dead', return NULL
201 // if only one child is alive, return that child
202 // if both childresn are alive, return this
203
204
205 //      bool leftalive = true,rightalive=true;
206         /* Does this mean the function will always bomb? */
207         assertd(false);
208         assert(m_lhs);
209         assert(m_rhs);
210 /*
211         if (m_cached_calculate)
212                 m_cached_calculate->Action(CValue::REFRESH_CACHE);
213         
214         CExpression* newlhs = m_lhs->CheckLink(brokenlinks);
215         CExpression* newrhs = m_rhs->CheckLink(brokenlinks);
216
217         if (m_lhs != newlhs)
218         {
219                 brokenlinks.push_back(new CBrokenLinkInfo(&m_lhs,m_lhs));
220         }
221
222         if (m_rhs != newrhs)
223         {
224                 brokenlinks.push_back(new CBrokenLinkInfo(&m_rhs,m_rhs));
225         }
226
227
228
229         m_lhs = newlhs;
230         m_rhs = newrhs;
231
232         if (m_lhs && m_rhs) {
233                 return this;
234         }
235         
236         AddRef();
237         if (m_lhs) 
238                 return Release(m_lhs->AddRef());
239         
240         if (m_rhs)
241                 return Release(m_rhs->AddRef());
242 /               
243
244   */
245   return Release();
246
247   
248         
249 }
250
251
252 bool COperator2Expr::MergeExpression(CExpression *otherexpr)
253 {
254         if (m_lhs)
255         {
256                 if (m_lhs->GetExpressionID() == CExpression::CCONSTEXPRESSIONID)
257                 {
258                         // cross fingers ;) replace constexpr by new tree...
259                         m_lhs->Release();
260                         m_lhs = otherexpr->AddRef();
261                         return true;
262                 }
263         }
264
265         assertd(false);
266         return false;
267 }
268
269
270 void COperator2Expr::BroadcastOperators(VALUE_OPERATOR op)
271 {
272         if (m_lhs)
273                 m_lhs->BroadcastOperators(m_op);
274         if (m_rhs)
275                 m_rhs->BroadcastOperators(m_op);
276 }