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