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