<?xml version="1.0" encoding="ISO-8859-1"?>
<rdf:RDF
	xmlns="http://purl.org/rss/1.0/"
	xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
	xmlns:dc="http://purl.org/dc/elements/1.1/">
	<channel rdf:about="http://feeds.garagegames.com/rss/blogs/developer/111021/">
		<title>Blog for Nerrad Weil at GarageGames.com</title>
		<description>Blog feeds for Gamers and Developers in the GarageGames community.</description>
		<link>http://www.garagegames.com/</link>
		<image rdf:resource="http://www.garagegames.com/images/GarageGames_logo_small_w.gif" />
		<dc:date>2008-08-29T18:13:50+00:00</dc:date>
		<items>
			<rdf:Seq>
				<rdf:li rdf:resource="http://www.garagegames.com/blogs/111021/14629"/>
				<rdf:li rdf:resource="http://www.garagegames.com/blogs/111021/14113"/>
			</rdf:Seq>
		</items>
	</channel>
	<item rdf:about="http://www.garagegames.com/blogs/111021/14629">
		<dc:format>text/html</dc:format>
		<dc:date>2008-04-21T16:14:52+00:00</dc:date>
		<dc:creator>Nerrad Weil</dc:creator>
		<title>Enabling animation transition in ShapeBase object</title>
		<link>http://www.garagegames.com/blogs/111021/14629</link>
		<description>In my previous post I has discussed the technique to enable transition in ShapeBase animation, and it seems to be helpful to someone, in this post I would like to give more information about the technique i'd used&lt;br&gt;&lt;br&gt;1) add a field in struct Thread in ShapeBase.h&lt;br&gt;&lt;br&gt;&lt;div class='codeblock'&gt;&lt;pre&gt;struct Thread {&lt;br&gt;	...&lt;br&gt;	bool transit;	// transit addon&lt;br&gt;};&lt;/pre&gt;&lt;/div&gt;&lt;br&gt;&lt;br&gt;2) initialize Thread::transit in ShapeBase constructor&lt;br&gt;&lt;br&gt;&lt;div class='codeblock'&gt;&lt;pre&gt;ShapeBase::ShapeBase {&lt;br&gt;	...&lt;br&gt;	for (i = 0; i &amp;lt; MaxScriptThreads; i++) {&lt;br&gt;		...&lt;br&gt;		mScriptThread[i].transit = false;	// transit addon&lt;br&gt;	}&lt;br&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br&gt;&lt;br&gt;3) in the exisitng ShapeBase::setThreadSequence() add this line&lt;br&gt;&lt;br&gt;&lt;div class='codeblock'&gt;&lt;pre&gt;bool ShapeBase::setThreadSequence(U32 slot, S32 seq, bool reset)&lt;br&gt;{&lt;br&gt;	...&lt;br&gt;   if (seq &amp;lt; MaxSequenceIndex) {&lt;br&gt;      setMaskBits(ThreadMaskN &amp;lt;&amp;lt; slot);&lt;br&gt;      st.sequence = seq;&lt;br&gt;      st.transit = false; // transit addon&lt;br&gt;	...&lt;br&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br&gt;&lt;br&gt;4) create a new method in ShapeBase, which is similar to setThreadSequence but with animation transition modification&lt;br&gt;&lt;br&gt;in ShapeBase.cc&lt;br&gt;&lt;br&gt;&lt;div class='codeblock'&gt;&lt;pre&gt;bool ShapeBase::setThreadTransitSequence(U32 slot,S32 seq, F32 duration, bool continuePlay, bool reset)&lt;br&gt;{&lt;br&gt;   Thread&amp;amp; st = mScriptThread[slot];&lt;br&gt;   if (st.thread &amp;amp;&amp;amp; st.sequence == seq &amp;amp;&amp;amp; st.state == Thread::Play)&lt;br&gt;      return true;&lt;br&gt;&lt;br&gt;   if (seq &amp;lt; MaxSequenceIndex) {&lt;br&gt;      setMaskBits(ThreadMaskN &amp;lt;&amp;lt; slot);&lt;br&gt;      st.sequence = seq;&lt;br&gt;	  st.transit = true;&lt;br&gt;      if (reset) {&lt;br&gt;         st.state = Thread::Play;&lt;br&gt;         st.atEnd = false;&lt;br&gt;         st.forward = true;&lt;br&gt;      }&lt;br&gt;      if (mShapeInstance) {&lt;br&gt;         if (!st.thread)&lt;br&gt;            st.thread = mShapeInstance-&amp;gt;addThread();&lt;br&gt;         stopThreadSound(st);&lt;br&gt;         updateThread(st);&lt;br&gt;         mShapeInstance-&amp;gt;transitionToSequence(st.thread,seq,0, duration, continuePlay);&lt;br&gt;      }&lt;br&gt;      return true;&lt;br&gt;   }&lt;br&gt;   return false;&lt;br&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br&gt;&lt;br&gt;in ShapeBase.h&lt;br&gt;&lt;br&gt;&lt;div class='codeblock'&gt;&lt;pre&gt;   bool setThreadTransitSequence(U32 slot, S32 seq, F32 duration, bool continuePlay = true, bool reset = true);&lt;/pre&gt;&lt;/div&gt;&lt;br&gt;&lt;br&gt;5) in ShapeBase::packUpdate() method&lt;br&gt;&lt;br&gt;&lt;div class='codeblock'&gt;&lt;pre&gt;ShapeBase::packUpdate()&lt;br&gt;{&lt;br&gt;	...&lt;br&gt;	if (stream-&amp;gt;writeFlag(mask &amp;amp; ThreadMask)) {&lt;br&gt;		...&lt;br&gt;		stream-&amp;gt;writeFlag(st.atEnd);&lt;br&gt;		stream-&amp;gt;writeFlag(st.transit); // transit addon&lt;br&gt;		...&lt;br&gt;	}&lt;br&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br&gt;&lt;br&gt;6) in ShapeBase::unpackUpdate()&lt;br&gt;&lt;br&gt;&lt;div class='codeblock'&gt;&lt;pre&gt;void ShapeBase::unpackUpdate(NetConnection *con, BitStream *stream)&lt;br&gt;{&lt;br&gt;	...&lt;br&gt;   if (stream-&amp;gt;readFlag()) {&lt;br&gt;      for (S32 i = 0; i &amp;lt; MaxScriptThreads; i++) {&lt;br&gt;         if (stream-&amp;gt;readFlag()) {&lt;br&gt;            Thread&amp;amp; st = mScriptThread[i];&lt;br&gt;            U32 seq = stream-&amp;gt;readInt(ThreadSequenceBits);&lt;br&gt;            st.state = stream-&amp;gt;readInt(2);&lt;br&gt;            st.forward = stream-&amp;gt;readFlag();&lt;br&gt;            st.atEnd = stream-&amp;gt;readFlag();&lt;br&gt;            st.transit = stream-&amp;gt;readFlag();&lt;br&gt;&lt;br&gt;            if (st.sequence != seq)&lt;br&gt;            {&lt;br&gt;               if (st.transit)&lt;br&gt;                  setThreadTransitSequence(i,seq,0.5,false,false);&lt;br&gt;               else&lt;br&gt;                  setThreadSequence(i,seq,false);&lt;br&gt;            }&lt;br&gt;            else&lt;br&gt;               updateThread(st);&lt;br&gt;			&lt;br&gt;         }&lt;br&gt;      }&lt;br&gt;   }&lt;br&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br&gt;&lt;br&gt;hope this is more informative than my previous post ;)</description>
	</item>
	<item rdf:about="http://www.garagegames.com/blogs/111021/14113">
		<dc:format>text/html</dc:format>
		<dc:date>2008-01-06T16:23:10+00:00</dc:date>
		<dc:creator>Nerrad Weil</dc:creator>
		<title>Journal of a young adventurer 06/Jan/08</title>
		<link>http://www.garagegames.com/blogs/111021/14113</link>
		<description>I bought TGE + AFX few months back together with 2 torque reference books. but only recently i have time to fool around with TGE. &lt;br&gt;&lt;br&gt;my TGE project goal is to create a multiplayer online dancing game, something similar to Audition Online, but much smaller scale, but even that it's quite a undertaking for me. i guess this would be a long and tough journey, but i hope unleast it won't be a lonely journey. i would like to use this space to note down the changes i have made to TGE and hope that some TGE veterans could give some guidance to me.&lt;br&gt;&lt;br&gt;#1 problem&lt;br&gt;my project required &amp;quot;multi threaded&amp;quot; animations, e.g. a dance sequence consists of a set of head, body and legs animations. i find that Player::setActionThread() alone is very difficult to achieve the desired result and i have no confidence to hack player class without broken things&lt;br&gt;&lt;br&gt;#1 problem's solution&lt;br&gt;my solution is ShapeBase::playThread() function, shapebase's animation functions are more primitive and easier to hack. i also noted that sequence priority play a big role here, for my case legs should has highest priority and head should has the least priority.&lt;br&gt;&lt;br&gt;#2 problem&lt;br&gt;shapebase can't play the same animation consecutively&lt;br&gt;&lt;br&gt;#2 problem's solution&lt;br&gt;after spamming breakpoints, i discovered this problem was caused by animation sequence didn't rewind properly at end and the sequence did't marked as Thread::Stop. therefore  ShapeBase::advanceThreads() always prohibit the same animation sequence being played consecutively.&lt;br&gt;&lt;br&gt;to solve this problem i added&lt;br&gt;&lt;br&gt;&lt;div class='codeblock'&gt;&lt;pre&gt; if (!mShapeInstance-&amp;gt;getShape()-&amp;gt;sequences[st.sequence].isCyclic() &amp;amp;&amp;amp; !st.atEnd &amp;amp;&amp;amp;&lt;br&gt;	 (st.forward? mShapeInstance-&amp;gt;getPos(st.thread) &amp;gt;= 1.0:&lt;br&gt;	  mShapeInstance-&amp;gt;getPos(st.thread) &amp;lt;= 0)) {&lt;br&gt;	st.atEnd = true;&lt;br&gt;	updateThread(st);&lt;br&gt;	st.state = Thread::Stop; // new line&lt;br&gt;	if (!isGhost()) {&lt;br&gt;	   char slot[16];&lt;br&gt;	   dSprintf(slot,sizeof(slot),&amp;quot;%d&amp;quot;,i);&lt;br&gt;	   Con::executef(mDataBlock,3,&amp;quot;onEndSequence&amp;quot;,scriptThis(),slot);&lt;br&gt;	}&lt;br&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;br&gt;after ShapeBase::advanceThreads() marked the thread as atEnd and updated the thread's state.&lt;br&gt;&lt;br&gt;to ensure the thread was rewind properly at the end, add these lines to ShapeBase::updateThread() under Thread::Play case, where st.atEnd != true&lt;br&gt;&lt;br&gt;&lt;div class='codeblock'&gt;&lt;pre&gt;TSShape::Sequence seq = mShapeInstance-&amp;gt;getShape()-&amp;gt;sequences[st.sequence];&lt;br&gt;if (!seq.isCyclic() &amp;amp;&amp;amp; !st.transit &amp;amp;&amp;amp; &lt;br&gt;(st.forward? mShapeInstance-&amp;gt;getPos(st.thread) &amp;gt;= 1.0 : mShapeInstance-&amp;gt;getPos(st.thread) &amp;lt;= 0)) {&lt;br&gt;    mShapeInstance-&amp;gt;setPos(st.thread,st.forward? 0: 1);&lt;br&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br&gt;&lt;br&gt;#3 problem&lt;br&gt;shapebase doesn't support animation transition but this is a must have feature for my project&lt;br&gt;&lt;br&gt;#3 problem's solution&lt;br&gt;the solution is simple, expose the TSShapeinstance::transitionToSequence to script. one thing to take note is the transitionToSequence() must called after timeScale being set properly. for my case, i do it in this order&lt;br&gt;&lt;br&gt;&lt;div class='codeblock'&gt;&lt;pre&gt;updateThread(st);&lt;br&gt;mShapeInstance-&amp;gt;transitionToSequence(st.thread,seq,0, duration, continuePlay); // must call after setTimeScale(), updateThread() contains setTimeScale()&lt;/pre&gt;&lt;/div&gt;&lt;br&gt;&lt;br&gt;#4 problem&lt;br&gt;after all these changes, now the avatar lost full body animation such as root and walk animation, this due to shapebase's animations have higher piority than player's animation&lt;br&gt;&lt;br&gt;#4 problem's solution&lt;br&gt;to solve this problem we need to &amp;quot;disable&amp;quot; shapebase's animation thread when player's animations are needed. for my case, i added in a bool variable called disabled into TSThread class in tsShapeInstance.h&lt;br&gt;and then in S32 TSThread::operator&amp;lt;(const TSThread &amp;amp; th2) const add in these lines&lt;br&gt;&lt;br&gt;&lt;div class='codeblock'&gt;&lt;pre&gt;   if (disabled &amp;amp;&amp;amp; !th2.disabled) &lt;br&gt;	   return 1;&lt;br&gt;   if (th2.disabled &amp;amp;&amp;amp; !disabled) &lt;br&gt;	   return -1;&lt;/pre&gt;&lt;/div&gt;&lt;br&gt;and also expose a method in shapebase class to script, to do that add in these few lines into shapeBase.cc&lt;br&gt;&lt;br&gt;&lt;div class='codeblock'&gt;&lt;pre&gt;bool ShapeBase::disableThread(U32 slot,bool disable)&lt;br&gt;{&lt;br&gt;	if (mShapeInstance) {&lt;br&gt;		Thread&amp;amp; st = mScriptThread[slot];&lt;br&gt;		if (st.thread)&lt;br&gt;		{&lt;br&gt;			TSThread * th = st.thread;&lt;br&gt;			if (th-&amp;gt;isDisable() == disable) return disable;&lt;br&gt;			setMaskBits(ThreadMaskN &amp;lt;&amp;lt; slot);&lt;br&gt;			return th-&amp;gt;disableThread(disable);&lt;br&gt;		}&lt;br&gt;	}&lt;br&gt;	return false;&lt;br&gt;}&lt;br&gt;&lt;br&gt;ConsoleMethod( ShapeBase, disableThread, bool, 4, 4, &amp;quot;(int slot, bool disable)&amp;quot;)&lt;br&gt;{&lt;br&gt;   int slot = dAtoi(argv[2]);&lt;br&gt;   if (slot &amp;gt;= 0 &amp;amp;&amp;amp; slot &amp;lt; ShapeBase::MaxScriptThreads) {&lt;br&gt;      if (object-&amp;gt;disableThread(slot,dAtob(argv[3])))&lt;br&gt;         return true;&lt;br&gt;   }&lt;br&gt;   return false;&lt;br&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br&gt;btw, TSShapeInstance::animate(S32 dl) is a great place to study the threads' order, just put some breakpoints after sortThreads(mThreadList);&lt;br&gt;&lt;br&gt;one last point is don't forget to modify your ShapeBase::packUpdate() and ShapeBase::unpackUpdate() methods. for my case, they become these at the end&lt;br&gt;&lt;br&gt;&lt;div class='codeblock'&gt;&lt;pre&gt;// packData&lt;br&gt;if (stream-&amp;gt;writeFlag(mask &amp;amp; ThreadMask)) {&lt;br&gt;  for (int i = 0; i &amp;lt; MaxScriptThreads; i++) {&lt;br&gt;	 Thread&amp;amp; st = mScriptThread[i];&lt;br&gt;	 if (stream-&amp;gt;writeFlag(st.sequence != -1 &amp;amp;&amp;amp; (mask &amp;amp; (ThreadMaskN &amp;lt;&amp;lt; i)))) {&lt;br&gt;		stream-&amp;gt;writeInt(st.sequence,ThreadSequenceBits);&lt;br&gt;		stream-&amp;gt;writeInt(st.state,2);&lt;br&gt;		stream-&amp;gt;writeFlag(st.forward);&lt;br&gt;		stream-&amp;gt;writeFlag(st.atEnd);&lt;br&gt;		stream-&amp;gt;writeInt (st.speed*1000, 11);&lt;br&gt;		stream-&amp;gt;writeFlag(st.transit);&lt;br&gt;		stream-&amp;gt;writeInt(st.duration*100, 10);&lt;br&gt;		stream-&amp;gt;writeFlag(st.simulPlay);&lt;br&gt;		stream-&amp;gt;writeFlag(st.thread ? st.thread-&amp;gt;isDisable() : false);&lt;br&gt;	 }&lt;br&gt;  }&lt;br&gt;&lt;br&gt;// unpackData&lt;br&gt;if (stream-&amp;gt;readFlag()) {&lt;br&gt;for (S32 i = 0; i &amp;lt; MaxScriptThreads; i++) {&lt;br&gt; if (stream-&amp;gt;readFlag()) {&lt;br&gt;	Thread&amp;amp; st = mScriptThread[i];&lt;br&gt;	U32 seq = stream-&amp;gt;readInt(ThreadSequenceBits);&lt;br&gt;	st.state = stream-&amp;gt;readInt(2);&lt;br&gt;	st.forward = stream-&amp;gt;readFlag();&lt;br&gt;	st.atEnd = stream-&amp;gt;readFlag();&lt;br&gt;	st.speed = stream-&amp;gt;readInt(11)*0.001f; &lt;br&gt;	st.transit = stream-&amp;gt;readFlag();&lt;br&gt;	st.duration = stream-&amp;gt;readInt(10)*0.01f; &lt;br&gt;	st.simulPlay = stream-&amp;gt;readFlag();&lt;br&gt;	bool disable = stream-&amp;gt;readFlag();&lt;br&gt;&lt;br&gt;	if (st.sequence != seq)&lt;br&gt;	{&lt;br&gt;	   if (st.transit)&lt;br&gt;		   setThreadTransitSequence(i,seq,st.duration,st.simulPlay,false);&lt;br&gt;	   else&lt;br&gt;		   setThreadSequence(i,seq,false);&lt;br&gt;	}&lt;br&gt;	else&lt;br&gt;	   updateThread(st);&lt;br&gt;	&lt;br&gt;	disableThread(i, disable);&lt;br&gt; }&lt;br&gt;}&lt;/pre&gt;&lt;/div&gt;</description>
	</item>
</rdf:RDF>
