1 /*--License:
2 Kyra Sprite Engine
3 Copyright Lee Thomason (Grinning Lizard Software) 2001-2005
4 www.grinninglizard.com/kyra
5 www.sourceforge.net/projects/kyra
6
7 Kyra is provided under the LGPL.
8
9 I kindly request you display a splash screen (provided in the HTML documentation)
10 to promote Kyra and acknowledge the software and everyone who has contributed to it,
11 but it is not required by the license.
12
13 --- LGPL License --
14
15 This library is free software; you can redistribute it and/or
16 modify it under the terms of the GNU Lesser General Public
17 License as published by the Free Software Foundation; either
18 version 2.1 of the License, or (at your option) any later version.
19
20 This library is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 Lesser General Public License for more details.
24
25 You should have received a copy of the GNU Lesser General Public
26 License along with this library; if not, write to the Free Software
27 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28
29 The full text of the license can be found in lgpl.txt
30 */
31
32 #include "imnode.h"
33 #include "SDL.h"
34 #include "engine.h"
35 #include "../../grinliz/glgeometry.h"
36
37 #ifdef _MSC_VER
38 #pragma warning ( disable : 4355 )
39 #endif
40
41 using namespace grinliz;
42
43
KrImNode()44 KrImNode::KrImNode() : treeNode( this )
45 {
46 parent = 0;
47 engine = 0;
48 depth = 0;
49 nodeId = -1;
50 userData = 0;
51
52 for( int i=0; i<KR_MAX_WINDOWS; ++i )
53 {
54 invalid[i] = true;
55 visible[i] = true;
56 xTransform[i].Set();
57 compositeXForm[i].Set();
58 quality[i] = KrQualityNone;
59 compositeQuality[i] = KrQualityFast;
60
61 compositeBounds[i].SetInvalid();
62 bounds[i].SetInvalid();
63 }
64 }
65
66
SetNodeName(const std::string & name)67 void KrImNode::SetNodeName( const std::string& name )
68 {
69 if ( engine )
70 {
71 if ( !nodeName.empty() )
72 engine->Tree()->RemoveNodeNameHash( nodeName );
73 engine->Tree()->AddNodeNameHash( name, this );
74 }
75 nodeName = name;
76 }
77
78
SetNodeId(int id)79 void KrImNode::SetNodeId( int id )
80 {
81 if ( engine )
82 {
83 engine->Tree()->RemoveNodeIdHash( nodeId );
84 engine->Tree()->AddNodeIdHash( id, this );
85 }
86 nodeId = id;
87 }
88
89
SetPos(int x,int y,int win)90 void KrImNode::SetPos( int x, int y, int win )
91 {
92 #ifdef DEBUG
93 // There are no reason for these limits rather that
94 // a way to check for bad input -- the engine can handle
95 // inputs much larger than this.
96 GLASSERT( x > -40000 && x < 40000 );
97 GLASSERT( y > -40000 && y < 40000 );
98 #endif
99
100 GLASSERT( win >= KR_ALL_WINDOWS && win < KR_MAX_WINDOWS );
101 int start = 0;
102 int end = KR_MAX_WINDOWS;
103
104 if ( win != KR_ALL_WINDOWS )
105 {
106 start = win;
107 end = win + 1;
108 }
109 else if(Engine())
110 {
111 end = Engine()->NumWindows();
112 }
113
114 for( int i=start; i<end; ++i )
115 {
116 if ( x != xTransform[i].x || y != xTransform[i].y )
117 {
118 xTransform[i].x = x;
119 xTransform[i].y = y;
120 invalid[i] = true;
121 }
122 }
123 }
124
125
SetScale(GlFixed xScale,GlFixed yScale,int win)126 void KrImNode::SetScale( GlFixed xScale, GlFixed yScale, int win )
127 {
128 #ifdef DEBUG
129 GLASSERT( xScale > 0 );
130 GLASSERT( yScale > 0 );
131 #endif
132
133 GLASSERT( win >= KR_ALL_WINDOWS && win < KR_MAX_WINDOWS );
134 int start = 0;
135 int end = Engine() ? Engine()->NumWindows() : KR_MAX_WINDOWS;
136
137 if ( win != KR_ALL_WINDOWS )
138 {
139 start = win;
140 end = win + 1;
141 }
142
143 for( int i=start; i<end; ++i )
144 {
145 if ( xScale != xTransform[i].xScale || yScale != xTransform[i].yScale )
146 {
147 xTransform[i].xScale = xScale;
148 xTransform[i].yScale = yScale;
149 invalid[i] = true;
150 }
151 }
152 }
153
154
SetTransform(KrMatrix2 & xForm,int win)155 void KrImNode::SetTransform( KrMatrix2& xForm, int win )
156 {
157 #ifdef DEBUG
158 GLASSERT( xForm.xScale > 0 );
159 GLASSERT( xForm.yScale > 0 );
160 #endif
161
162 GLASSERT( win >= KR_ALL_WINDOWS && win < KR_MAX_WINDOWS );
163 int start = 0;
164 int end = Engine() ? Engine()->NumWindows() : KR_MAX_WINDOWS;
165
166 if ( win != KR_ALL_WINDOWS )
167 {
168 start = win;
169 end = win + 1;
170 }
171
172 for( int i=start; i<end; ++i )
173 {
174 if ( xForm != xTransform[i] )
175 {
176 xTransform[i] = xForm;
177 invalid[i] = true;
178 }
179 }
180 }
181
182
SetColor(const KrColorTransform & color,int win)183 void KrImNode::SetColor( const KrColorTransform& color, int win )
184 {
185 GLASSERT( win >= KR_ALL_WINDOWS && win < KR_MAX_WINDOWS );
186 int start = 0;
187 int end = Engine() ? Engine()->NumWindows() : KR_MAX_WINDOWS;
188
189 if ( win != KR_ALL_WINDOWS )
190 {
191 start = win;
192 end = win + 1;
193 }
194
195 for( int i=start; i<end; ++i )
196 {
197 if ( color != cTransform[i] )
198 {
199 cTransform[i] = color;
200 invalid[i] = true;
201 }
202 }
203 }
204
205
Invalidate(int win)206 void KrImNode::Invalidate( int win )
207 {
208 GLASSERT( win >= KR_ALL_WINDOWS && win < KR_MAX_WINDOWS );
209 int start = 0;
210 int end = Engine() ? Engine()->NumWindows() : KR_MAX_WINDOWS;
211
212 if ( win != KR_ALL_WINDOWS )
213 {
214 start = win;
215 end = win + 1;
216 }
217
218 for( int i=start; i<end; ++i )
219 {
220 invalid[i] = true;
221 }
222 }
223
224
SetQuality(int _quality,int win)225 void KrImNode::SetQuality( int _quality, int win )
226 {
227 GLASSERT( win >= KR_ALL_WINDOWS && win < KR_MAX_WINDOWS );
228 int start = 0;
229 int end = Engine() ? Engine()->NumWindows() : KR_MAX_WINDOWS;
230
231 if ( win != KR_ALL_WINDOWS )
232 {
233 start = win;
234 end = win + 1;
235 }
236
237 for( int i=start; i<end; ++i )
238 {
239 if ( _quality != quality[i] )
240 {
241 quality[i] = _quality;
242 invalid[i] = true;
243 }
244 }
245 }
246
247
Resort(KrImNode * resortMe)248 void KrImNode::Resort( KrImNode* resortMe )
249 {
250 // See if we need to move at all. If so, take ourselves out
251 // of the list and scoot up or down.
252 int depth = resortMe->ZDepth();
253 GlInsideNodeIt< KrImNode* > it( child );
254
255 // resortMe should always be a child of this.
256 it.SetCurrent( resortMe->treeNode.next );
257 #ifdef DEBUG
258 if ( !it.Done() ) GLASSERT( it.CurrentData()->Parent() == this );
259 #endif
260
261 if ( !it.Done()
262 && depth > it.CurrentData()->ZDepth() )
263 {
264 // Resort me is removed, so we need a new current
265 it.Next();
266 resortMe->treeNode.Remove();
267
268 while ( !it.Done()
269 && depth > it.CurrentData()->ZDepth() )
270 {
271 it.Next();
272 }
273 it.InsertBefore( resortMe->treeNode );
274 }
275
276 it.SetCurrent( resortMe->treeNode.prev );
277 #ifdef DEBUG
278 if ( !it.Done() ) GLASSERT( it.CurrentData()->Parent() == this );
279 #endif
280
281 if ( !it.Done()
282 && depth < it.CurrentData()->ZDepth() )
283 {
284 it.Prev();
285 resortMe->treeNode.Remove();
286
287 while ( !it.Done()
288 && depth < it.CurrentData()->ZDepth() )
289 {
290 it.Prev();
291 }
292 it.InsertAfter( resortMe->treeNode );
293 }
294 #ifdef VALIDATE_DEBUG
295 GlInsideNodeIt< KrImNode* > testIt( child );
296
297 testIt.Begin();
298 int testZ = testIt.CurrentData()->ZDepth();
299
300 // GLOUTPUT( "zdepth " );
301 for( ; !testIt.Done(); testIt.Next() )
302 {
303 GLASSERT( testIt.CurrentData()->ZDepth() >= testZ );
304 // GLOUTPUT( "%x=%d ", testIt.CurrentData(), testIt.CurrentData()->ZDepth() );
305 testZ = testIt.CurrentData()->ZDepth();
306 }
307 // GLOUTPUT( "\n" );
308 #endif
309 }
310
311
CalcTransform(int i)312 void KrImNode::CalcTransform( int i )
313 {
314 // Running performance on this gave about equal
315 // time consumption in the 3 sections. Color, quality, position.
316
317 // Now transform this.
318 compositeXForm[i] = xTransform[i];
319 compositeCForm[i] = cTransform[i];
320
321 if ( parent )
322 {
323 // Spacial
324 compositeXForm[i].Composite( parent->CompositeXForm( i ) );
325
326 // Color
327 // This can actually be a little expensive, so check that
328 // we don't have an identity first.
329 if ( !parent->CompositeCForm( i ).IsIdentity() )
330 {
331 compositeCForm[i].Composite( parent->CompositeCForm( i ) );
332 }
333
334 // Transform the quality
335 if ( compositeXForm[i].IsScaled() )
336 {
337 compositeQuality[i] = quality[i];
338 if ( compositeQuality[i] == KrQualityNone )
339 {
340 KrImNode* node;
341 for( node = parent; node; node = node->parent )
342 {
343 if ( node->quality[i] != KrQualityNone )
344 {
345 compositeQuality[i] = node->quality[i];
346 break;
347 }
348 }
349 }
350 if ( compositeQuality[i] == KrQualityNone )
351 {
352 compositeQuality[i] = KrQualityFast;
353 }
354 }
355 else
356 {
357 compositeQuality[i] = KrQualityFast;
358 }
359 }
360 // GLOUTPUT( "KrImNode '%s' win=%d rel=%f,%f composite=%f,%f\n",
361 // NodeName().c_str(),
362 // i,
363 // xTransform[i].x.ToDouble(),
364 // xTransform[i].y.ToDouble(),
365 // compositeXForm[i].x.ToDouble(),
366 // compositeXForm[i].y.ToDouble() );
367 }
368
369
SetZDepth(int z)370 void KrImNode::SetZDepth( int z )
371 {
372 if ( z != depth )
373 {
374 depth = z;
375
376 // int count = KR_MAX_WINDOWS;
377 // if ( Engine() ) count = Engine()->NumWindows();
378 // for( int i=0; i<count; ++i )
379 // {
380 // invalid[i] = true;
381 // }
382 Invalidate( KR_ALL_WINDOWS );
383
384 // If there is no parent, this node is not in a tree. That's
385 // fine -- we'll sort it in correctly when it gets added.
386 if ( parent )
387 {
388 // Ask our parent to move us to the correct z-position.
389 parent->Resort( this );
390 }
391 }
392 }
393
394
IsVisible(int window)395 bool KrImNode::IsVisible( int window )
396 {
397 KrImNode* node;
398
399 for( node = this; node; node = node->parent )
400 {
401 if ( node->visible[window] == false )
402 return false;
403 }
404 return true;
405 }
406
407
SetVisible(bool _visible,int win)408 void KrImNode::SetVisible( bool _visible, int win )
409 {
410 GLASSERT( win >= KR_ALL_WINDOWS && win < KR_MAX_WINDOWS );
411
412 if ( win == KR_ALL_WINDOWS )
413 {
414 int count = KR_MAX_WINDOWS;
415 if ( Engine() ) count = Engine()->NumWindows();
416
417 for( int i=0; i<count; ++i )
418 {
419 if ( visible[i] != _visible )
420 {
421 visible[i] = _visible;
422 invalid[i] = true;
423 }
424 }
425 }
426 else
427 {
428 if ( visible[win] != _visible )
429 {
430 visible[win] = _visible;
431 invalid[win] = true;
432 }
433 }
434 }
435
436
ScreenToObject(int x,int y,Vector2<GlFixed> * object,int i)437 void KrImNode::ScreenToObject( int x, int y, Vector2< GlFixed >* object, int i )
438 {
439 object->x = ( GlFixed( x ) - compositeXForm[i].x ) / compositeXForm[i].xScale;
440 object->y = ( GlFixed( y ) - compositeXForm[i].y ) / compositeXForm[i].yScale;
441 }
442
443
AddedtoTree()444 void KrImNode::AddedtoTree()
445 {
446 GLASSERT( Engine() );
447 for( int i=0; i<Engine()->NumWindows(); ++i )
448 {
449 CalcTransform( i );
450 Invalidate( i );
451 }
452 }
453
454
LeavingTree()455 void KrImNode::LeavingTree()
456 {
457 // Nothing!
458 }
459
460
461 //KrWidget* KrImNode::TopWidget()
462 //{
463 // KrWidget* w = 0;
464 // for( KrImNode* node = Parent();
465 // node;
466 // node = node->Parent() )
467 // {
468 // if ( node->ToWidget() )
469 // w = node->ToWidget();
470 // else
471 // break; // if it's not a widget, it will never recurse down to this object,
472 // // so it can't be our parent.
473 // }
474 // return w;
475 //}
476
477
478 //KrWidget* KrImNode::GetWidget()
479 //{
480 // if ( ToWidget() )
481 // return ToWidget();
482 // else if ( Parent() && Parent()->ToWidget() )
483 // return Parent()->ToWidget();
484 // else
485 // return 0;
486 //}
487
488
Clone()489 KrImNode* KrImNode::Clone()
490 {
491 return new KrImNode();
492 }
493