private void bProsegui_Click(object sender, EventArgs e) { cacheFileName.Clear(); UUIDanim.Clear(); UUIDList.Clear(); if (!fromList) { DateTime wrDDT = DateStart.AddHours((double)UpDownFromHour.Value); // DateStart = DateStart.AddMinutes((double)UpDownFromMin.Value); timeStart = TotalSecondsFromEpoch(wrDDT.AddMinutes((double)UpDownFromMin.Value)); wrDDT = DateEnd.AddHours((double)UpDownToHour.Value); // DateEnd = DateEnd.AddMinutes((double)UpDownToMin.Value); timeEnd = TotalSecondsFromEpoch(wrDDT.AddMinutes((double)UpDownToMin.Value)); } // la classe ViewerNames popola l'array aViewer[] con i path delle possibili // directory ove possono risiedere i file index.db2 MyviewerNames = new ViewerCacheNames(); if (MyviewerNames.noOS != false) { lfilescreated.Text = "OS not recognized"; return; } // si cercano i file index.db2 nelle singole directory e si popola il dizionario // cacheFileName int n = 0; for (int k = 0; k < MyviewerNames.aViewerP.Length; k++) { if (Directory.Exists(MyviewerNames.aViewerP[k])) { string[] aIdba = Directory.GetFiles(MyviewerNames.aViewerP[k] + SC, "index.db2.*"); for (int ij = 0; ij < aIdba.Length; ++ij) { cacheFileName.Add(n, aIdba[ij]); n++; } } } if (fromList) { string xAnim = CacheDB2.Text; // la classe ReadList popola l'array aUUIDList con la lista delle // UUID lette dal file di testo ReadList MyReadlist = new ReadList(xAnim); // L'array viene trasferito al dictionary per una migliore gestione for (int i = 0; i < MyReadlist.aUUIDList.Length; ++i) { UUIDList.Add(MyReadlist.aUUIDList[i], false); } this.UUIDtotal.Text = UUIDList.Count().ToString(); } // si scorrono i file index.db2. Per tutti i tipo 20 (animazioni), si verifica se // fanno parte di quelle ricercate e contenute nell'array aUUIDList della classe ReadList // Se trovata si aggiunge al dizionario con chiave UUID e con valore la struttura contenente // offset e lunghezza byte[] fileData; foreach (KeyValuePair <int, string> pair in cacheFileName) { fileData = System.IO.File.ReadAllBytes(pair.Value); MyIndexDB2 = new SLCacheIndexRead(fileData); for (int i = 0; i < MyIndexDB2.SLCacheRecordIndex.Length; i++) { if (MyIndexDB2.SLCacheRecordIndex[i].wType == 20) { // if (UUIDList.ContainsKey(MyIndexDB2.SLCacheRecordIndex[i].sUUID)) if (!UUIDanim.ContainsKey(MyIndexDB2.SLCacheRecordIndex[i].sUUID)) { UUIDdata Utmp = new UUIDdata(); Utmp.Udir = pair.Key; Utmp.Uoffset = (Int32)MyIndexDB2.SLCacheRecordIndex[i].dwOffset; Utmp.Ulenght = (Int32)MyIndexDB2.SLCacheRecordIndex[i].dwSize; Utmp.Utime = (uint)MyIndexDB2.SLCacheRecordIndex[i].time_t; if (fromList) { if (UUIDList.ContainsKey(MyIndexDB2.SLCacheRecordIndex[i].sUUID)) { UUIDanim.Add(MyIndexDB2.SLCacheRecordIndex[i].sUUID, Utmp); } } else if ((Utmp.Utime >= timeStart) && (Utmp.Utime <= timeEnd)) { UUIDanim.Add(MyIndexDB2.SLCacheRecordIndex[i].sUUID, Utmp); } } } } this.UUIDfound.Text = UUIDanim.Count().ToString(); } // bProsegui.Enabled = false; bBVH.Enabled = UUIDanim.Count > 0; }
private void bBVH_Click(object sender, EventArgs e) { bBVH.Enabled = false; string stUUID; foreach (var pair in UUIDanim) { UUIDdata Utmp = new UUIDdata(); byte[] by; stUUID = pair.Key; Utmp = pair.Value; int pos = Utmp.Uoffset; int required = Utmp.Ulenght; string str = cacheFileName[Utmp.Udir]; int i = str.LastIndexOf("index.db2"); str = str.Substring(0, i) + "data.db2" + str.Substring(i + 9); using (BinaryReader b = new BinaryReader(File.Open(str, FileMode.Open))) { b.BaseStream.Seek(pos, SeekOrigin.Begin); by = b.ReadBytes(required); } string xAnim = stUUID; try { // Read the file .anim and creates the structure MyBinBVH // Use the class myBinBVHAnimationReader OpenMetaverse (amended). // The structure contains the data formats .anim already serialized myBinBVHAnimationReader MyBinBVH = new myBinBVHAnimationReader(by); uint numJoints = MyBinBVH.JointCount; // Reads the key position (x) of the first frame of the first joint // By definition belongs to the frame 2. // Frame time == second frame time/2. double wTime = MyBinBVH.joints[0].rotationkeys[0].time; double mFrameTime = wTime * 0.5; // dividing the total duration (lentgh) by the frame time // the number of frames is obtained. double mDuration = MyBinBVH.Length; uint mNumFrames = (uint)Math.Floor(mDuration / mFrameTime + .5); // The class creates a JointBVH structure intended to receive // processed data to transform the Vector3 of rot // in degrees and Vector3 of Pos in inches. // The structure is initialized with Frames*(19) // structures Pos [3], Rot [3] all set to zero, except // Pos[1] of the joint [0], for every frame, is placed // equal to 43.5285 ([Y] position) JointBVH myTSBVH = new JointBVH((int)mNumFrames); // numJoint contains the number of joint of file .anim // myTSBVH is filled with data read from anim.ini // indent will be used later to indent the BVH file header int[] indent = new int[19] { 1, 2, 3, 4, 5, 4, 5, 6, 7, 4, 5, 6, 7, 2, 3, 4, 2, 3, 4 }; uint jji; int j = 0; for (jji = 0; jji < trans.mTranslation.Length; ++jji) { if (trans.mTranslation[jji].mIgnore) { continue; } myTSBVH.mJoints[j].mName = trans.mTranslation[jji].mName; myTSBVH.mJoints[j].mOutName = trans.mTranslation[jji].mOutName; myTSBVH.mJoints[j].mIndent = indent[j]; ++j; } // Value are processed for each of the joint for (i = 0; i < numJoints; ++i) { uint joint; Order order; Quaternion last_rot = new Quaternion(); string jointName = MyBinBVH.joints[i].Name; uint ji; // The joints of the anim file may be in different order // from the BVH Header model used // in this procedure. It was therefore I decided to carry out // search by the name of the joint. for (ji = 0; ji < 19; ji++) { joint = ji; if (myTSBVH.mJoints[ji].mOutName == jointName) { break; } } if (ji == 19) { continue; } else { joint = ji; } uint last_frame = 1; order = StringToOrder(myTSBVH.mJoints[joint].mOrder); // we analyze every frame of the file anim joint for (j = 0; j < (MyBinBVH.joints[i].rotationkeys.Length); ++j) { if (j == 0) // first key // the first key of the file anim // refers to the frame 2 as SL eliminates the // frame 1 from the original BVH file { last_frame = 1; // we are in the frame 2 // last_rot (first frame) is not available // so we start with an identity quaternion last_rot = Quaternion.Identity; myTSBVH.mJoints[joint].mPosRotKeys[0].mIgnorePos = true; myTSBVH.mJoints[joint].mPosRotKeys[0].mIgnoreRot = true; } // The frame no.is equal to the time of the frame/FrameTime float time_short = MyBinBVH.joints[i].rotationkeys[j].time; double time = time_short; uint frame; frame = (uint)Math.Floor(time / mFrameTime + 0.5f); // rot_vec is set to the rotation vector of the frame examined Vector3 rot_vec; rot_vec.X = MyBinBVH.joints[i].rotationkeys[j].key_element.X; rot_vec.Y = MyBinBVH.joints[i].rotationkeys[j].key_element.Y; rot_vec.Z = MyBinBVH.joints[i].rotationkeys[j].key_element.Z; // we compute the inverse of quaternion framematrix // and offsetmatrix Quaternion outRot; Quaternion inRot; Quaternion frameRot = myTSBVH.mFrameMatrix; Quaternion frameRotInv; frameRotInv.X = frameRot.X * -1f; frameRotInv.Y = frameRot.Y * -1f; frameRotInv.Z = frameRot.Z * -1f; frameRotInv.W = frameRot.W; Quaternion offsetRot = myTSBVH.mOffsetMatrix; Quaternion offsetRotInv; offsetRotInv.X = offsetRot.X * -1f; offsetRotInv.Y = offsetRot.Y * -1f; offsetRotInv.Z = offsetRot.Z * -1f; offsetRotInv.W = offsetRot.W; // Quaternion outRot is derived from the vector rot_vec outRot.X = rot_vec.X; outRot.Y = rot_vec.Y; outRot.Z = rot_vec.Z; double t = 1.0 - (rot_vec.X * rot_vec.X + rot_vec.Y * rot_vec.Y + rot_vec.Z * rot_vec.Z); if (t > 0) { outRot.W = (float)Math.Sqrt(t); } else { outRot.W = 0; } // rotation is corrected by the rotation matrices inRot = frameRotInv * offsetRotInv * outRot * frameRot; // recalculates the rotation vector. // revMayaQ returns values in degrees and set the axes // XYZ values based on the contents of the enumerator order rot_vec = revMayaQ(inRot, order); // the vector obtained is saved for use in // when writing the file BVH myTSBVH.mJoints[joint].mPosRotKeys[frame - 1].mRot.X = rot_vec.X; myTSBVH.mJoints[joint].mPosRotKeys[frame - 1].mRot.Y = rot_vec.Y; myTSBVH.mJoints[joint].mPosRotKeys[frame - 1].mRot.Z = rot_vec.Z; // If SL has missed because of little significance, // some frames, they are reconstructed with interpolation // If frames have been skipped by SL, // frame is greater than last_frame + 1 uint n; uint num = frame - last_frame; Quaternion interp = new Quaternion(); for (n = last_frame + 1; n < frame; ++n) { // interpolation for each frame missing interp = nlerp((1f / num) * (n - last_frame), last_rot, inRot); // we also need the value in degrees // revMayaQ returns values in degrees and set the axes // XYZ values based on the contents of the enumerator order rot_vec = revMayaQ(interp, order); // the vector obtained is saved for use in // when writing the file BVH myTSBVH.mJoints[joint].mPosRotKeys[n - 1].mRot.X = rot_vec.X; myTSBVH.mJoints[joint].mPosRotKeys[n - 1].mRot.Y = rot_vec.Y; myTSBVH.mJoints[joint].mPosRotKeys[n - 1].mRot.Z = rot_vec.Z; } last_frame = frame; // comparison values for the next cycle last_rot = inRot; } // Now we go to test the positions. // the test is done for every joint. The activity is redundant // because when we write the BVH file will take only // the first joint value (hip) Vector3 last_pos = new Vector3(); Vector3 current_pos = new Vector3(); // rel_key represents the relative position. // In fact anim file contains the changes with respect // to the relative position Vector3 relkey = new Vector3(0f, 43.5285f, 0f); for (j = 0; j < (MyBinBVH.joints[i].positionkeys.Length); ++j) { float time_short = MyBinBVH.joints[i].positionkeys[j].time; double time = time_short; // Only for the hip frame 1 contains the value of the relative position. // values for all other joint can remain set to zero. if (j == 0) { last_pos.X = 0f; last_pos.Y = 43.5285f; last_pos.Z = 0; last_frame = 1; } uint frame; frame = (uint)Math.Floor(time / mFrameTime + 0.5f); // current_pos.X = MyBinBVH.joints[i].positionkeys[j].key_element.X / 0.02540005f; current_pos.Y = MyBinBVH.joints[i].positionkeys[j].key_element.Y / 0.02540005f; current_pos.Z = MyBinBVH.joints[i].positionkeys[j].key_element.Z / 0.02540005f; // All we need is the frame matrix and its inverse Quaternion frameRot = myTSBVH.mFrameMatrix; Quaternion frameRotInv; frameRotInv.X = -frameRot.X; frameRotInv.Y = -frameRot.Y; frameRotInv.Z = -frameRot.Z; frameRotInv.W = frameRot.W; // current_pos = (current_pos * frameRotInv) + relkey; // // myTSBVH.mJoints[joint].mPosRotKeys[frame - 1].mPos.X = current_pos.X; myTSBVH.mJoints[joint].mPosRotKeys[frame - 1].mPos.Y = current_pos.Y; myTSBVH.mJoints[joint].mPosRotKeys[frame - 1].mPos.Z = current_pos.Z; // // uint n; uint num = frame - last_frame; Vector3 interp; for (n = last_frame + 1; n < frame; ++n) { interp = Vector3.Lerp(last_pos, current_pos, 1f / num * (n - last_frame)); myTSBVH.mJoints[joint].mPosRotKeys[n - 1].mPos.X = interp.X; myTSBVH.mJoints[joint].mPosRotKeys[n - 1].mPos.Y = interp.Y; myTSBVH.mJoints[joint].mPosRotKeys[n - 1].mPos.Z = interp.Z; } // last_pos = current_pos; last_frame = frame; } } // all values were calculated // we can and write the file BVH string nRotation = "rotation "; string nOffset = "OFFSET "; string nChannels = "CHANNELS 3 "; string nJoint = "JOINT "; string nEnd = "End Site"; char nOpenP = '{'; char nCloseP = '}'; char nTab = '\t'; // anim file does not contain the offset value to the joints // We use the following standard. // The BVH file is Text format, so it is useless // use numeric values string[] aOffset = new string[19] { "0.000000 0.000000 0.000000", "0.000000 3.422050 0.000000", "0.000000 8.486693 -0.684411", "0.000000 10.266162 -0.273764", "0.000000 3.148285 0.000000", "3.422053 6.707223 -0.821293", "3.285171 0.000000 0.000000", "10.129278 0.000000 0.000000", "8.486692 0.000000 0.000000", "-3.558935 6.707223 -0.821293", "-3.148289 0.000000 0.000000", "-10.266159 0.000000 0.000000", "-8.349810 0.000000 0.000000", "5.338403 -1.642589 1.368821", "-2.053232 -20.121670 0.000000", "0.000000 -19.300380 -1.231939", "-5.338403 -1.642589 1.368821", "2.053232 -20.121670 0.000000", "0.000000 -19.300380 -1.231939" }; // Offset value to the 5 knots End Side string[] aOffsetEnd = new string[5] { "0.000000 3.148289 0.000000", "4.106464 0.000000 0.000000", "-4.106464 0.000000 0.000000", "0.000000 -2.463878 4.653993", "0.000000 -2.463878 4.653993" }; StringBuilder llsd = new StringBuilder(); string NL = "\r\n"; llsd.Append("HIERARCHY" + NL); // The hip joint is special - use ROOT instead of JOINT llsd.Append("ROOT hip" + NL); llsd.Append(nOpenP + NL); llsd.Append(nTab + nOffset + aOffset[0] + NL); // CHANNELS for the hip joint is special llsd.Append("\tCHANNELS 6 Xposition Yposition Zposition Xrotation Zrotation Yrotation " + NL); int wExInd = 0; int wInd; j = 0; // We start from the second joint - hip has already been created. for (i = 1; i < myTSBVH.mJoints.Length; ++i) { wInd = myTSBVH.mJoints[i].mIndent; // End Side is identified with the transition to a lower indent if (wInd < wExInd) // End Side { llsd.Append(nTab, wExInd); llsd.Append(nEnd); llsd.Append(NL); llsd.Append(nTab, wExInd); llsd.Append(nOpenP); llsd.Append(NL); llsd.Append(nTab, wExInd + 1); llsd.Append(nOffset); llsd.Append(aOffsetEnd[j]); llsd.Append(NL); ++j; // The difference with the previous indent determines the number of "}" for (int vj = wExInd; vj > wInd - 2; --vj) { llsd.Append(nTab, vj); llsd.Append(nCloseP); llsd.Append(NL); } } // It' a new Joint - we proceed to write llsd.Append(nTab, wInd - 1); llsd.Append(nJoint); llsd.Append(myTSBVH.mJoints[i].mName); llsd.Append(NL); llsd.Append(nTab, wInd - 1); llsd.Append(nOpenP); llsd.Append(NL); llsd.Append(nTab, wInd); llsd.Append(nOffset); llsd.Append(aOffset[i]); llsd.Append(NL); llsd.Append(nTab, wInd); llsd.Append(nChannels); // The order of rotations following the arbitrary default llsd.Append(myTSBVH.mJoints[i].mOrder[0]); llsd.Append(nRotation); llsd.Append(myTSBVH.mJoints[i].mOrder[1]); llsd.Append(nRotation); llsd.Append(myTSBVH.mJoints[i].mOrder[2]); llsd.Append(nRotation); llsd.Append(NL); wExInd = wInd; } // This is the last End Side llsd.Append(nTab, wExInd); llsd.Append(nEnd); llsd.Append(NL); llsd.Append(nTab, wExInd); llsd.Append(nOpenP); llsd.Append(NL); llsd.Append(nTab, wExInd + 1); llsd.Append(nOffset); llsd.Append(aOffsetEnd[j]); llsd.Append(NL); for (int vj = wExInd + 1; vj > 0; --vj) { llsd.Append(nTab, vj - 1); llsd.Append(nCloseP); llsd.Append(NL); } // Once the structure of the Joints starts listing the frames llsd.Append("MOTION" + NL); llsd.Append("Frames: "); llsd.Append((int)mNumFrames); llsd.Append(NL); if (mNumFrames * mFrameTime > 30f) // not more then 30sec animation time { mFrameTime = 30f / mNumFrames; } llsd.Append("Frame Time: "); llsd.Append(NormStr((float)mFrameTime)); llsd.Append(NL); for (i = 0; i < mNumFrames; ++i) { uint ji; for (ji = 0; ji < 19; ++ji) { if (ji == 0) // position values for only the first joint (hip) { llsd.Append(NormStr(myTSBVH.mJoints[0].mPosRotKeys[i].mPos.X)); llsd.Append(" "); llsd.Append(NormStr(myTSBVH.mJoints[0].mPosRotKeys[i].mPos.Y)); llsd.Append(" "); llsd.Append(NormStr(myTSBVH.mJoints[0].mPosRotKeys[i].mPos.Z)); llsd.Append(" "); } // Rotations are arranged by mOrder string s = myTSBVH.mJoints[ji].mOrder; char[] c = s.ToCharArray(); float[] wRot = new float[3]; wRot[0] = myTSBVH.mJoints[ji].mPosRotKeys[i].mRot.X; wRot[1] = myTSBVH.mJoints[ji].mPosRotKeys[i].mRot.Y; wRot[2] = myTSBVH.mJoints[ji].mPosRotKeys[i].mRot.Z; // whim of the programmer 'X' - 'X' = 0, 'Y'- 'X' = 1, 'Z' - 'X' = 2 llsd.Append(NormStr(wRot[c[0] - 'X'])); llsd.Append(" "); llsd.Append(NormStr(wRot[c[1] - 'X'])); llsd.Append(" "); llsd.Append(NormStr(wRot[c[2] - 'X'])); llsd.Append(" "); } llsd.Append(NL); } string outDir = OutputDir.Text; if (!(Directory.Exists(outDir))) { Directory.CreateDirectory(outDir); } string uAnim = outDir + SC + xAnim + ".BVH"; // All done, start writing tha BVH file File.WriteAllText(uAnim, llsd.ToString()); // // We create a second file with .txt ext. // Save the data that help to upload the BVH file StringBuilder llse = new StringBuilder(); llse.Append("\t\t File "); llse.Append(xAnim + ".BVH"); llse.Append(NL); llse.Append(NL); llse.Append("Upload Informations"); llse.Append(NL); llse.Append("-------------------"); llse.Append(NL); llse.Append("Priority\t : "); llse.Append(MyBinBVH.Priority); llse.Append(NL); llse.Append("Loop \t\t : "); llse.Append(MyBinBVH.Loop == true ? "Yes" : "Not"); llse.Append(NL); if (MyBinBVH.Loop == true) { llse.Append("Loop in(%)\t : "); llse.Append((uint)Math.Floor(MyBinBVH.InPoint * 100 / MyBinBVH.Length + 0.5)); llse.Append("\tOut(%)\t : "); llse.Append((uint)Math.Floor(MyBinBVH.OutPoint * 100 / MyBinBVH.Length + 0.5)); llse.Append(NL); } llse.Append("Hand Pose\t : "); llse.Append(HandPose(MyBinBVH.HandPose)); llse.Append(NL); llse.Append("Expression\t : "); llse.Append(MyBinBVH.ExpressionName); llse.Append(NL); llse.Append("Ease in(sec)\t : "); llse.Append(MyBinBVH.EaseInTime); llse.Append("\tOut(sec) : "); llse.Append(MyBinBVH.EaseOutTime); llse.Append(NL); llse.Append(NL); llse.Append("Usefull Information"); llse.Append(NL); llse.Append("-------------------"); llse.Append(NL); llse.Append("Duration(sec)\t : "); llse.Append(NormStr(MyBinBVH.Length)); llse.Append(NL); llse.Append("Frames\t\t : "); llse.Append(NormStr((float)mNumFrames)); llse.Append(NL); if (mNumFrames * mFrameTime > 30f) // not more then 30sec animation time { mFrameTime = 30f / mNumFrames; } llse.Append("Frame Time\t : "); llse.Append(NormStr((float)mFrameTime)); llse.Append(NL); llse.Append(NL); llse.Append("Joint Name Start Frame Values Last Frame Values"); llse.Append(NL); llse.Append("---------- ------------------------------ ------------------------------"); llse.Append(NL); for (i = 0; i < myTSBVH.mJoints.Length; ++i) { if (i == 0) // position values for only the first joint (hip) { llse.Append("hip(Pos) "); llse.Append(NormStr(myTSBVH.mJoints[0].mPosRotKeys[1].mPos.X)); llse.Append(" "); llse.Append(NormStr(myTSBVH.mJoints[0].mPosRotKeys[1].mPos.Y)); llse.Append(" "); llse.Append(NormStr(myTSBVH.mJoints[0].mPosRotKeys[1].mPos.Z)); llse.Append(" "); llse.Append(NormStr(myTSBVH.mJoints[0].mPosRotKeys[mNumFrames - 1].mPos.X)); llse.Append(" "); llse.Append(NormStr(myTSBVH.mJoints[0].mPosRotKeys[mNumFrames - 1].mPos.Y)); llse.Append(" "); llse.Append(NormStr(myTSBVH.mJoints[0].mPosRotKeys[mNumFrames - 1].mPos.Z)); llse.Append(NL); } uAnim = myTSBVH.mJoints[i].mName + " "; llse.Append(uAnim.Substring(0, 12)); string s = myTSBVH.mJoints[i].mOrder; char[] c = s.ToCharArray(); float[] wRot = new float[3]; wRot[0] = myTSBVH.mJoints[i].mPosRotKeys[1].mRot.X; wRot[1] = myTSBVH.mJoints[i].mPosRotKeys[1].mRot.Y; wRot[2] = myTSBVH.mJoints[i].mPosRotKeys[1].mRot.Z; // llse.Append(NormStr(wRot[c[0] - 'X'])); llse.Append(" "); llse.Append(NormStr(wRot[c[1] - 'X'])); llse.Append(" "); llse.Append(NormStr(wRot[c[2] - 'X'])); llse.Append(" "); wRot[0] = myTSBVH.mJoints[i].mPosRotKeys[mNumFrames - 1].mRot.X; wRot[1] = myTSBVH.mJoints[i].mPosRotKeys[mNumFrames - 1].mRot.Y; wRot[2] = myTSBVH.mJoints[i].mPosRotKeys[mNumFrames - 1].mRot.Z; // llse.Append(NormStr(wRot[c[0] - 'X'])); llse.Append(" "); llse.Append(NormStr(wRot[c[1] - 'X'])); llse.Append(" "); llse.Append(NormStr(wRot[c[2] - 'X'])); llse.Append(NL); } File.WriteAllText(outDir + SC + xAnim + ".txt", llse.ToString()); lfilescreated.Text = "BVH files successfully created"; } catch (System.Exception) { // MessageBox.Show("Alcuni file non Convertiti " ); } } }