Stan0033

Extents Calculations in C# for warcraft 3 models version 800

Oct 16th, 2025 (edited)
340
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 13.65 KB | Source Code | 0 0
  1. public static class ExtentCalculator
  2.  {
  3.      
  4.     public static void Calculate(CModel model)
  5.      {
  6.          //--------------------------------------------------------------
  7.          // null extents in advance, to start fresh
  8.          //--------------------------------------------------------------
  9.          model.Extent = new CExtent();
  10.          foreach (var sequence in model.Sequences) sequence.Extent = new CExtent();
  11.          foreach (var geoset in model.Geosets) { geoset.Extent = new CExtent(); geoset.Extents.Clear(); }
  12.          //--------------------------------------------------------------
  13.          if (model.Geosets.Count == 0) { return; } // nothing to calculate :(
  14.           //--------------------------------------------------------------
  15.          //1. calcualte basic geoset extent
  16.          foreach (var geoset in model.Geosets)  geoset.Extent = GetExtent_fromVectors(geoset.Vertices.Select(x=>x.Position).ToList());
  17.          //2. calculate geoset sequence extents
  18.          foreach (var geoset in model.Geosets)   CalculateGeosetSequenceExtents(geoset, model);
  19.           // no sequences = no geoset sequence extents, sequence extetns and model extents :(
  20.          if (model.Sequences.Count == 0) { return; }
  21.          //3. sum up sequence extents
  22.          for (var i = 0; i < model.Sequences.Count; i++)
  23.          {
  24.              var sequence = model.Sequences[i];
  25.              // the <sequence> extent of each geoset
  26.              List<CExtent> extents = model.Geosets.Select(x => x.Extents[i].Extent).ToList();
  27.              // inflate the geoset to the maximum from all in the list
  28.              sequence.Extent = GetMaxExtent(extents);
  29.          }
  30.          //4. sum up sequence extents and assign to <model> extent
  31.          model.Extent = GetMaxExtent(model.Sequences.Select(x=>x.Extent).ToList());
  32.      }
  33.      private static void CalculateGeosetSequenceExtents(CGeoset whichGeoset, CModel whichModel)
  34.      {
  35.         whichGeoset.Extents.Clear(); // clear before addign new
  36.        
  37.          foreach (var sequence in whichModel.Sequences)
  38.          {
  39.              if (ExtentVisibleInSequence(whichGeoset, sequence, whichModel) == false)
  40.              {
  41.                  whichGeoset.Extents.Add(new CGeosetExtent(whichModel) { Extent = new CExtent() });
  42.                  continue;
  43.              }
  44.                  List<CVector3> ModifiedPositions = new List<CVector3>();
  45.              // get sequence extednt
  46.              int from = sequence.IntervalStart;
  47.              int to = sequence.IntervalEnd;
  48.              foreach (var vertex in whichGeoset.Vertices)
  49.              {
  50.                    HashSet<INode> VisitedNodes = new HashSet<INode>(); // this is for preventing deep-nessted circular faulty node relationships in order to avoid infinite loop
  51.  
  52.                  List<CVector3> All_Reached_Vextex_Posiitons = new List<CVector3>();
  53.                   CVector3 InitialPosition = new CVector3(vertex.Position);
  54.                  CVector3 FinalPosition = new CVector3( vertex.Position);
  55.                     var group = vertex.Group.Object;
  56.                  if (group == null) { ModifiedPositions.Add(new CVector3()); continue; }
  57.                  foreach (var gnode in group.Nodes)
  58.                  {
  59.                      var Loopednode = gnode.Node.Node;
  60.                      if (Loopednode == null) continue;
  61.                      // add a new position for each keyframe that changes it!
  62.                      FinalPosition = CalculateChange(InitialPosition, Loopednode,from, to);
  63.                     // no parent?
  64.                      if (Loopednode.Parent.Node == null) continue;
  65.                      // prevent infinite loop (self-referencing):
  66.                      if (Loopednode.Parent.Node == Loopednode) continue;
  67.                      // prevent infinite loop (mutual-referencing):
  68.                      if (Loopednode.Parent.Node == Loopednode.Parent.Node.Parent.Node) continue;
  69.                      FinalPosition = InheritChangeRecursive(Loopednode.Parent.Node, InitialPosition, from, to, VisitedNodes, ref All_Reached_Vextex_Posiitons);
  70.                      
  71.                  }
  72.                  ModifiedPositions.Add(GetBestOfVertex(InitialPosition, All_Reached_Vextex_Posiitons));
  73.              }
  74.              CExtent max = GetExtent_fromVectors(ModifiedPositions);
  75.              whichGeoset.Extents.Add(new CGeosetExtent(whichModel) { Extent = max });
  76.          }
  77.     }
  78.  
  79.      private static bool ExtentVisibleInSequence(CGeoset whichGeoset, CSequence sequence, CModel model)
  80.      {
  81.          int from = sequence.IntervalStart;
  82.          int to = sequence.IntervalEnd;
  83.          CGeosetAnimation? any = model.GeosetAnimations.FirstOrDefault(x => x.Geoset.Object == whichGeoset);
  84.          if (any != null)
  85.          {
  86.              if (any.Alpha.Static)
  87.              {
  88.                  if (any.Alpha.GetValue() > 0) return true;
  89.                  else return false;
  90.              }
  91.              else
  92.              {
  93.                  // Replace this line:
  94.                  // List<CAnimatorNode<float>> keyframes = any.Alpha.NodeList.Select(x=>x.Time >= from && x.Time <= to).ToList();
  95.  
  96.                  // With this corrected line:
  97.                  List<CAnimatorNode<float>> keyframes = any.Alpha.NodeList
  98.                      .Where(x => x.Time >= from && x.Time <= to)
  99.                      .ToList();
  100.                  if (keyframes.Count > 0)
  101.                  {
  102.                      return keyframes.Any(x => x.Value > 0);
  103.                  }
  104.                  else
  105.                  {
  106.                      return true;
  107.                  }
  108.              }
  109.  
  110.            
  111.          }
  112.          return true; // default
  113.      }
  114.      private static CVector3 GetBestOfVertex(CVector3 position, List<CVector3> all_Reached_Vextex_Posiitons)
  115.      {
  116.          CVector3 best = position;
  117.  
  118.          foreach (var v in all_Reached_Vextex_Posiitons)
  119.          {
  120.              // Check X axis
  121.              if ((position.X >= 0 && v.X > best.X) || (position.X < 0 && v.X < best.X))
  122.                  best.X = v.X;
  123.  
  124.              // Check Y axis
  125.              if ((position.Y >= 0 && v.Y > best.Y) || (position.Y < 0 && v.Y < best.Y))
  126.                  best.Y = v.Y;
  127.  
  128.              // Check Z axis
  129.              if ((position.Z >= 0 && v.Z > best.Z) || (position.Z < 0 && v.Z < best.Z))
  130.                  best.Z = v.Z;
  131.          }
  132.  
  133.          return best;
  134.      }
  135.  
  136.  
  137.      private static CVector3 InheritChangeRecursive(INode inheritFrom, CVector3 position, int from, int to, HashSet<INode> visitedNodes, ref List<CVector3> all_Reached_Vextex_Posiitons, float influence = 100f)
  138.      {
  139.          float InfluencePercent = 0; ;
  140.          if (influence < 0) InfluencePercent = 0;
  141.          else if (influence > 100) InfluencePercent = 1;
  142.          else { InfluencePercent = influence / 100f; }
  143.          // prevent deep circular infinite loop
  144.          if (!visitedNodes.Add(inheritFrom)) return position;
  145.        
  146.          CVector3 workWith =new CVector3(position);
  147.          // 1. scaling
  148.          if (inheritFrom.DontInheritScaling == false)
  149.          {
  150.              
  151.              foreach (var kf in inheritFrom.Scaling)
  152.              {
  153.                  if (kf.Time < from || kf.Time > to) continue;
  154.                  workWith.X *= kf.Value.X / 100f;
  155.                  workWith.Y *= kf.Value.Y / 100f;
  156.                  workWith.Z *= kf.Value.Z / 100f;
  157.              }
  158.          }
  159.          // 2. rotation
  160.          if (inheritFrom.DontInheritRotation == false)
  161.          {
  162.              foreach (var kf in inheritFrom.Rotation)
  163.              {
  164.                  if (kf.Time < from || kf.Time > to) continue;
  165.                  workWith = RotateAround(workWith, inheritFrom.PivotPoint, kf.Value);
  166.              }
  167.          }
  168.          // 3. translation
  169.          if (inheritFrom.DontInheritTranslation == false)
  170.          {
  171.              foreach (var kf in inheritFrom.Translation)
  172.              {
  173.                  if (kf.Time < from || kf.Time > to) continue;
  174.                  workWith.X += kf.Value.X;
  175.                  workWith.Y += kf.Value.Y;
  176.                  workWith.Z += kf.Value.Z;
  177.              }
  178.          }
  179.          // null parent?
  180.          if (inheritFrom.Parent.Node == null) { all_Reached_Vextex_Posiitons.Add(new CVector3(workWith)); return workWith; }
  181.          // prevent infinite loop (self-referencing):
  182.          if (inheritFrom.Parent.Node == inheritFrom) { all_Reached_Vextex_Posiitons.Add(new CVector3(workWith)); return workWith; }
  183.          // prevent infinite loop (mutual-referencing):
  184.          if (inheritFrom.Parent.Node == inheritFrom.Parent.Node.Parent.Node) { all_Reached_Vextex_Posiitons.Add(new CVector3(workWith)); return workWith; }
  185.          // check for more parents to inherit from
  186.          if (inheritFrom.Parent.Node != null)
  187.          {
  188.              workWith = InheritChangeRecursive(inheritFrom.Parent.Node, workWith, from,to, visitedNodes, ref all_Reached_Vextex_Posiitons);
  189.          }
  190.        
  191.          return workWith;
  192.      }
  193.      private static CVector3 CalculateChange(CVector3 position, INode node,int from, int to)
  194.      {
  195.          CVector3 initial = new CVector3(position);
  196.            //1. scaling
  197.          
  198.          foreach (var kf in node.Scaling)
  199.          {
  200.              if (kf.Time < from || kf.Time > to) continue;
  201.              initial.X *= kf.Value.X / 100f;
  202.              initial.Y *= kf.Value.Y / 100f;
  203.              initial.Z *= kf.Value.Z / 100f;
  204.          }
  205.          //2. rotation
  206.          foreach (var kf in node.Rotation)
  207.          {
  208.              if (kf.Time < from || kf.Time > to) continue;
  209.              initial = RotateAround(initial, node.PivotPoint, kf.Value);
  210.          }
  211.          // 3. translation
  212.          foreach (var kf in node.Translation)
  213.          {
  214.              if (kf.Time < from || kf.Time > to) continue;
  215.              initial.X += kf.Value.X;
  216.              initial.Y += kf.Value.Y;
  217.              initial.Z += kf.Value.Z;
  218.          }
  219.         return initial;
  220.      }
  221.      private static CVector3 RotateAround(CVector3 vertexPosition, CVector3 aroundPivotPoint, CVector4 quaternion)
  222.      {
  223.          // Translate the vertex so the pivot is at the origin
  224.          float x = vertexPosition.X - aroundPivotPoint.X;
  225.          float y = vertexPosition.Y - aroundPivotPoint.Y;
  226.          float z = vertexPosition.Z - aroundPivotPoint.Z;
  227.          // Quaternion components
  228.          float qx = quaternion.X;
  229.          float qy = quaternion.Y;
  230.          float qz = quaternion.Z;
  231.          float qw = quaternion.W;
  232.          // Quaternion rotation formula: v' = q * v * q^-1
  233.          // Compute intermediate products
  234.          float ix = qw * x + qy * z - qz * y;
  235.          float iy = qw * y + qz * x - qx * z;
  236.          float iz = qw * z + qx * y - qy * x;
  237.          float iw = -qx * x - qy * y - qz * z;
  238.          // Compute rotated coordinates
  239.          float rx = ix * qw + iw * -qx + iy * -qz - iz * -qy;
  240.          float ry = iy * qw + iw * -qy + iz * -qx - ix * -qz;
  241.          float rz = iz * qw + iw * -qz + ix * -qy - iy * -qx;
  242.          // Translate back
  243.          return new CVector3(rx + aroundPivotPoint.X, ry + aroundPivotPoint.Y, rz + aroundPivotPoint.Z);
  244.      }
  245.      private static CExtent GetExtent_fromVectors(List<CVector3> list)
  246.      {
  247.          if (list == null || list.Count == 0)
  248.              return new CExtent(); // return empty extent if list is empty
  249.          // Initialize min and max with the first point
  250.          float minX = list[0].X;
  251.          float minY = list[0].Y;
  252.          float minZ = list[0].Z;
  253.          float maxX = list[0].X;
  254.          float maxY = list[0].Y;
  255.          float maxZ = list[0].Z;
  256.          foreach (CVector3 point in list)
  257.          {
  258.              if (point.X < minX) minX = point.X;
  259.              if (point.Y < minY) minY = point.Y;
  260.              if (point.Z < minZ) minZ = point.Z;
  261.              if (point.X > maxX) maxX = point.X;
  262.              if (point.Y > maxY) maxY = point.Y;
  263.              if (point.Z > maxZ) maxZ = point.Z;
  264.          }
  265.          CExtent e = new CExtent
  266.          {
  267.              Min = new CVector3(minX, minY, minZ),
  268.              Max = new CVector3(maxX, maxY, maxZ)
  269.          };
  270.          e.Radius = SetRadiusOfExtent(e);
  271.          return e;
  272.      }
  273.      private static CExtent GetMaxExtent(List<CExtent> extents)
  274.      {
  275.          if (extents == null || extents.Count == 0)
  276.              return new CExtent(); // return empty extent if list is empty
  277.          // Initialize min and max with the first extent
  278.          float minX = extents[0].Min.X;
  279.          float minY = extents[0].Min.Y;
  280.          float minZ = extents[0].Min.Z;
  281.          float maxX = extents[0].Max.X;
  282.          float maxY = extents[0].Max.Y;
  283.          float maxZ = extents[0].Max.Z;
  284.          foreach (CExtent extent in extents)
  285.          {
  286.              if (extent.Min.X < minX) minX = extent.Min.X;
  287.              if (extent.Min.Y < minY) minY = extent.Min.Y;
  288.              if (extent.Min.Z < minZ) minZ = extent.Min.Z;
  289.              if (extent.Max.X > maxX) maxX = extent.Max.X;
  290.              if (extent.Max.Y > maxY) maxY = extent.Max.Y;
  291.              if (extent.Max.Z > maxZ) maxZ = extent.Max.Z;
  292.          }
  293.          CExtent result =  new CExtent
  294.          {
  295.              Min = new CVector3(minX, minY, minZ),
  296.              Max = new CVector3(maxX, maxY, maxZ)
  297.          };
  298.          result.Radius = SetRadiusOfExtent(result);
  299.         return result;
  300.      }
  301.      private static float SetRadiusOfExtent(CExtent e)
  302.      {
  303.          var center = new CVector3(
  304.              (e.Min.X + e.Max.X) / 2f,
  305.              (e.Min.Y + e.Max.Y) / 2f,
  306.              (e.Min.Z + e.Max.Z) / 2f
  307.          );
  308.          float dx = e.Max.X - center.X;
  309.          float dy = e.Max.Y - center.Y;
  310.          float dz = e.Max.Z - center.Z;
  311.          return (float)Math.Sqrt(dx * dx + dy * dy + dz * dz);
  312.      }
  313.  
  314.  }
Advertisement
Add Comment
Please, Sign In to add comment