// File: tomfunkhouser[P]gaps/pkgs/R3Surfels/R3SurfelUtils.cpp
// Function: gaps::CreatePlanarGrids(gaps::R3SurfelPointGraph*, double, double, double, double, int, double, double)
RNArray<R3PlanarGrid *> *
CreatePlanarGrids(R3SurfelPointGraph *graph, 
  RNLength max_offplane_distance, RNAngle max_normal_angle,
  RNArea min_area, RNScalar min_density, int min_points,
  RNLength grid_spacing, RNScalar accuracy_factor)
{
  // Get convenient variables
  RNLength offplane_distance_sigma = 0.5 * max_offplane_distance;
  RNLength offplane_distance_sigma_squared = offplane_distance_sigma * offplane_distance_sigma;
  RNScalar offplane_distance_factor = (offplane_distance_sigma_squared != 0) ? 1.0 / (-2.0 * offplane_distance_sigma_squared) : 1;
  RNLength normal_angle_sigma = 0.5 * max_normal_angle;
  RNAngle normal_angle_sigma_squared = normal_angle_sigma * normal_angle_sigma;
  RNScalar normal_angle_factor = (normal_angle_sigma_squared != 0) ? 1.0 / (-2.0 * normal_angle_sigma_squared) : 1;

  // Determine number of samples
  if (min_points <= 1) min_points = 1;
  RNScalar max_grids = graph->NPoints();
  RNScalar bbox_volume = graph->BBox().Volume();
  if ((min_points > 0) && (graph->NPoints() / min_points < max_grids)) max_grids = graph->NPoints() / min_points;
  if ((min_area > 0) && (bbox_volume / min_area < max_grids)) max_grids = bbox_volume / min_area;
  int nsamples = (int) (accuracy_factor * 10.0 * max_grids) + 1;
  if (nsamples > graph->NPoints()) nsamples = graph->NPoints();

  // Create temporary data
  int *point_marks = new int [ graph->NPoints() ];
  R3Vector *point_normals = CreateNormals(graph, FALSE);
  R3Point *point_positions = new R3Point [ graph->NPoints() ];
  RNScalar *point_weights = new RNScalar [ graph->NPoints() ];
  R3PlanarGrid **point_grids = new R3PlanarGrid * [ graph->NPoints() ];
  SurfelPlanarGridData *grid_datas = new SurfelPlanarGridData [ nsamples ];
  for (int i = 0; i < graph->NPoints(); i++) point_marks[i] = 0;
  for (int i = 0; i < graph->NPoints(); i++) point_grids[i] = NULL;

  // Generate grid data
  int grid_data_count = 0;
  for (int iter = 0; iter < nsamples; iter++) {
    // Compute plane 
    int seed_index = (int) (RNRandomScalar() * graph->NPoints());
    if (point_marks[seed_index]) continue;
    if (graph->NNeighbors(seed_index) < 2) continue;
    R3SurfelPoint *seed = graph->Point(seed_index);
    R3Point seed_position = seed->Position();
    const R3Vector& seed_normal = point_normals[seed_index];
    if (R3Contains(seed_normal, R3zero_vector)) continue;
    R3Plane plane(seed_position, seed_normal);

    // Find positions of points near plane
    int point_count = 0;
    RNScalar total_weight = 0;
    for (int i = 0; i < graph->NPoints(); i++) {
      R3SurfelPoint *point = graph->Point(i);
      if (graph->NNeighbors(seed_index) < 2) continue;
      R3Point position = point->Position();
      RNScalar offplane_distance = R3Distance(plane, position);
      if (offplane_distance > max_offplane_distance) continue;
      const R3Vector& normal = point_normals[i];
      if (R3Contains(normal, R3zero_vector)) continue;
      RNScalar dot = fabs(normal.Dot(seed_normal));
      RNAngle normal_angle = (dot < 1) ? acos(dot) : 0;
      if (normal_angle > max_normal_angle) continue;
      RNScalar weight = 1;
      weight *= exp(offplane_distance_factor * offplane_distance * offplane_distance);
      weight *= exp(normal_angle_factor * normal_angle * normal_angle);
      total_weight += weight;
      point_positions[point_count] = position;
      point_weights[point_count] = weight;
      point_count++;
    }

    // Check number of points
    if (total_weight < min_points) continue;

    // Re-compute plane to fit points
    R3Point centroid = R3Centroid(point_count, point_positions, point_weights);
    R3Triad triad = R3PrincipleAxes(centroid, point_count, point_positions, point_weights);
    if (R3Contains(triad[2], R3zero_vector)) continue;
    plane.Reset(centroid, triad[2]);

    // Fill grid data
    SurfelPlanarGridData *grid_data = &grid_datas[grid_data_count];
    grid_data->points.Empty();
    grid_data->plane = plane;
    grid_data->bbox = R3null_box;
    grid_data->weight = 0;
    for (int i = 0; i < graph->NPoints(); i++) {
      R3SurfelPoint *point = graph->Point(i);
      int point_index = graph->PointIndex(point);
      if (graph->NNeighbors(point_index) < 2) continue;
      R3Point position = point->Position();
      RNScalar offplane_distance = R3Distance(plane, position);
      if (offplane_distance > max_offplane_distance) continue;
      const R3Vector& normal = point_normals[i];
      if (R3Contains(normal, R3zero_vector)) continue;
      RNScalar dot = fabs(normal.Dot(plane.Normal()));
      RNAngle normal_angle = (dot < 1) ? acos(dot) : 0;
      if (normal_angle > max_normal_angle) continue;
      RNScalar weight = 1;
      weight *= exp(offplane_distance_factor * offplane_distance * offplane_distance);
      weight *= exp(normal_angle_factor * normal_angle * normal_angle);
      grid_data->points.Insert(point);
      grid_data->bbox.Union(position);
      grid_data->weight += weight;
      point_marks[point_index]++;
    }

    // Check grid
    if (grid_data->weight < min_points) continue;

    // Add grid data
    grid_data_count++;
  }

  ////////////////////

  // Sort grid data
  if (grid_data_count > 0) {
    qsort(grid_datas, grid_data_count, sizeof(SurfelPlanarGridData), CompareSurfelPlanarGridDatas);
  }

  ////////////////////

  // Create array of grids
  RNArray<R3PlanarGrid *> *grids = new RNArray<R3PlanarGrid *>();
  if (!grids) {
    RNFail("Unable to allocate array of grids\n");
    return NULL;
  }

  // Create grids
  for (int i = 0; i < grid_data_count; i++) {
    int point_count = 0;
    SurfelPlanarGridData *grid_data = &grid_datas[i];
    R3PlanarGrid *grid = new R3PlanarGrid(grid_data->plane, grid_data->bbox, grid_spacing);
    for (int j = 0; j < grid_data->points.NEntries(); j++) {
      R3SurfelPoint *point = grid_data->points.Kth(j);
      int point_index = graph->PointIndex(point);
      if (graph->NNeighbors(point_index) < 2) continue;
      if (point_grids[point_index]) continue;
      point_grids[point_index] = grid;
      R3Point position = point->Position();
      RNScalar offplane_distance = R3Distance(grid_data->plane, position);
      if (offplane_distance > max_offplane_distance) continue;
      const R3Vector& normal = point_normals[point_index];
      if (R3Contains(normal, R3zero_vector)) continue;
      RNScalar dot = fabs(normal.Dot(grid_data->plane.Normal()));
      RNAngle normal_angle = (dot < 1) ? acos(dot) : 0;
      if (normal_angle > max_normal_angle) continue;
      RNScalar weight = 1;
      weight *= exp(offplane_distance_factor * offplane_distance * offplane_distance);
      weight *= exp(normal_angle_factor * normal_angle * normal_angle);
      grid->RasterizeWorldPoint(position, weight);
      point_count++;
    }

    // Check grid support
    if ((min_points > 0) && (point_count < min_points)) {
      delete grid;
      continue;
    }

    // Mask low-density areas and small-connected components
    if ((min_density > 0) || (min_area > 0)) {
      RNLength gridcell_per_meter = grid->WorldToGridScaleFactor();
      RNScalar min_grid_density = min_density / (gridcell_per_meter * gridcell_per_meter);
      RNScalar min_grid_area = min_area * gridcell_per_meter * gridcell_per_meter;
      grid->ConnectedComponentFilter(min_grid_density, min_grid_area, 0, 0, 0, R2_GRID_KEEP_VALUE);
      if (grid->Sum() == 0) { delete grid; continue; }
    }

    // Insert grid
    grids->Insert(grid);
  }

  ////////////////////

  // Delete temporary data
  delete [] point_marks;
  delete [] point_normals;
  delete [] point_positions;
  delete [] point_weights;
  delete [] point_grids;
  delete [] grid_datas;

  // Return grids
  return grids;
}

// Assembly:
subq $0x438, %rsp            # imm = 0x438
movq %rdi, 0x428(%rsp)
movsd %xmm0, 0x420(%rsp)
movsd %xmm1, 0x418(%rsp)
movsd %xmm2, 0x410(%rsp)
movsd %xmm3, 0x408(%rsp)
movl %esi, 0x404(%rsp)
movsd %xmm4, 0x3f8(%rsp)
movsd %xmm5, 0x3f0(%rsp)
movsd 0x165fe4(%rip), %xmm0   # 0x1a4158
mulsd 0x420(%rsp), %xmm0
movsd %xmm0, 0x3e8(%rsp)
movsd 0x3e8(%rsp), %xmm0
mulsd 0x3e8(%rsp), %xmm0
movsd %xmm0, 0x3e0(%rsp)
movsd 0x3e0(%rsp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0x3e1b7
jp 0x3e1b7
jmp 0x3e1df
movsd 0x166931(%rip), %xmm1   # 0x1a4af0
mulsd 0x3e0(%rsp), %xmm1
movsd 0x165f98(%rip), %xmm0   # 0x1a4168
divsd %xmm1, %xmm0
movsd %xmm0, 0x150(%rsp)
jmp 0x3e1f2
movsd 0x165f81(%rip), %xmm0   # 0x1a4168
movsd %xmm0, 0x150(%rsp)
jmp 0x3e1f2
movsd 0x150(%rsp), %xmm0
movsd %xmm0, 0x3d8(%rsp)
movsd 0x165f4c(%rip), %xmm0   # 0x1a4158
mulsd 0x418(%rsp), %xmm0
movsd %xmm0, 0x3d0(%rsp)
movsd 0x3d0(%rsp), %xmm0
mulsd 0x3d0(%rsp), %xmm0
movsd %xmm0, 0x3c8(%rsp)
movsd 0x3c8(%rsp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0x3e24f
jp 0x3e24f
jmp 0x3e277
movsd 0x166899(%rip), %xmm1   # 0x1a4af0
mulsd 0x3c8(%rsp), %xmm1
movsd 0x165f00(%rip), %xmm0   # 0x1a4168
divsd %xmm1, %xmm0
movsd %xmm0, 0x148(%rsp)
jmp 0x3e28a
movsd 0x165ee9(%rip), %xmm0   # 0x1a4168
movsd %xmm0, 0x148(%rsp)
jmp 0x3e28a
movsd 0x148(%rsp), %xmm0
movsd %xmm0, 0x3c0(%rsp)
cmpl $0x1, 0x404(%rsp)
jg 0x3e2b1
movl $0x1, 0x404(%rsp)
movq 0x428(%rsp), %rdi
callq 0x43e20
cvtsi2sd %eax, %xmm0
movsd %xmm0, 0x3b8(%rsp)
movq 0x428(%rsp), %rdi
callq 0x44410
movq %rax, %rdi
movq (%rdi), %rax
callq *0x60(%rax)
movsd %xmm0, 0x3b0(%rsp)
cmpl $0x0, 0x404(%rsp)
jle 0x3e33e
movq 0x428(%rsp), %rdi
callq 0x43e20
cltd
idivl 0x404(%rsp)
cvtsi2sd %eax, %xmm1
movsd 0x3b8(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x3e33e
movq 0x428(%rsp), %rdi
callq 0x43e20
cltd
idivl 0x404(%rsp)
cvtsi2sd %eax, %xmm0
movsd %xmm0, 0x3b8(%rsp)
movsd 0x410(%rsp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jbe 0x3e38c
movsd 0x3b0(%rsp), %xmm1
divsd 0x410(%rsp), %xmm1
movsd 0x3b8(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x3e38c
movsd 0x3b0(%rsp), %xmm0
divsd 0x410(%rsp), %xmm0
movsd %xmm0, 0x3b8(%rsp)
movsd 0x166764(%rip), %xmm0   # 0x1a4af8
mulsd 0x3f0(%rsp), %xmm0
mulsd 0x3b8(%rsp), %xmm0
cvttsd2si %xmm0, %eax
addl $0x1, %eax
movl %eax, 0x3ac(%rsp)
movl 0x3ac(%rsp), %eax
movl %eax, 0x144(%rsp)
movq 0x428(%rsp), %rdi
callq 0x43e20
movl %eax, %ecx
movl 0x144(%rsp), %eax
cmpl %ecx, %eax
jle 0x3e3f0
movq 0x428(%rsp), %rdi
callq 0x43e20
movl %eax, 0x3ac(%rsp)
movq 0x428(%rsp), %rdi
callq 0x43e20
cltq
movl $0x4, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x13030
movq %rax, 0x3a0(%rsp)
movq 0x428(%rsp), %rdi
xorl %esi, %esi
callq 0x3c000
movq %rax, 0x398(%rsp)
movq 0x428(%rsp), %rdi
callq 0x43e20
cltq
movq %rax, 0x130(%rsp)
movl $0x18, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
movq %rdi, 0x128(%rsp)
callq 0x13030
movq %rax, %rcx
movq 0x130(%rsp), %rax
movq %rcx, 0x138(%rsp)
cmpq $0x0, %rax
je 0x3e4fa
movq 0x138(%rsp), %rax
movq 0x130(%rsp), %rcx
imulq $0x18, %rcx, %rdx
movq %rax, %rcx
addq %rdx, %rcx
movq %rcx, 0x118(%rsp)
movq %rax, 0x120(%rsp)
movq 0x120(%rsp), %rdi
movq %rdi, 0x110(%rsp)
callq 0xf8340
jmp 0x3e4d9
movq 0x118(%rsp), %rcx
movq 0x110(%rsp), %rax
addq $0x18, %rax
cmpq %rcx, %rax
movq %rax, 0x120(%rsp)
jne 0x3e4c2
movq 0x138(%rsp), %rax
movq %rax, 0x390(%rsp)
movq 0x428(%rsp), %rdi
callq 0x43e20
cltq
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x13030
movq %rax, 0x378(%rsp)
movq 0x428(%rsp), %rdi
callq 0x43e20
cltq
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x13030
movq %rax, 0x370(%rsp)
movslq 0x3ac(%rsp), %rax
movq %rax, 0xf8(%rsp)
movl $0x70, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
addq $0x8, %rdi
setb %al
orb %al, %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
movq %rdi, 0xf0(%rsp)
callq 0x13030
movq %rax, %rcx
movq 0xf8(%rsp), %rax
movq %rcx, 0x100(%rsp)
movq %rax, (%rcx)
addq $0x8, %rcx
movq %rcx, 0x108(%rsp)
cmpq $0x0, %rax
je 0x3e646
movq 0x108(%rsp), %rax
movq 0xf8(%rsp), %rcx
imulq $0x70, %rcx, %rdx
movq %rax, %rcx
addq %rdx, %rcx
movq %rcx, 0xe0(%rsp)
movq %rax, 0xe8(%rsp)
movq 0xe8(%rsp), %rdi
movq %rdi, 0xd8(%rsp)
callq 0x44430
jmp 0x3e625
movq 0xe0(%rsp), %rcx
movq 0xd8(%rsp), %rax
addq $0x70, %rax
cmpq %rcx, %rax
movq %rax, 0xe8(%rsp)
jne 0x3e60e
movq 0x108(%rsp), %rax
movq %rax, 0x368(%rsp)
movl $0x0, 0x364(%rsp)
movl 0x364(%rsp), %eax
movl %eax, 0xd4(%rsp)
movq 0x428(%rsp), %rdi
callq 0x43e20
movl %eax, %ecx
movl 0xd4(%rsp), %eax
cmpl %ecx, %eax
jge 0x3e764
movq 0x3a0(%rsp), %rax
movslq 0x364(%rsp), %rcx
movl $0x0, (%rax,%rcx,4)
movl 0x364(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x364(%rsp)
jmp 0x3e661
movq 0x128(%rsp), %rsi
movq 0x138(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x388(%rsp)
movl %eax, 0x384(%rsp)
callq 0x13a90
jmp 0x3f651
movq 0x108(%rsp), %rcx
movq %rax, %rsi
movq 0xd8(%rsp), %rax
movq %rsi, 0x388(%rsp)
movl %edx, 0x384(%rsp)
cmpq %rax, %rcx
movq %rax, 0xc8(%rsp)
je 0x3e74a
movq 0xc8(%rsp), %rdi
addq $-0x70, %rdi
movq %rdi, 0xc0(%rsp)
callq 0x444a0
movq 0x108(%rsp), %rcx
movq 0xc0(%rsp), %rax
cmpq %rcx, %rax
movq %rax, 0xc8(%rsp)
jne 0x3e714
movq 0xf0(%rsp), %rsi
movq 0x100(%rsp), %rdi
callq 0x13a90
jmp 0x3f651
movl $0x0, 0x360(%rsp)
movl 0x360(%rsp), %eax
movl %eax, 0xbc(%rsp)
movq 0x428(%rsp), %rdi
callq 0x43e20
movl %eax, %ecx
movl 0xbc(%rsp), %eax
cmpl %ecx, %eax
jge 0x3e7c2
movq 0x370(%rsp), %rax
movslq 0x360(%rsp), %rcx
movq $0x0, (%rax,%rcx,8)
movl 0x360(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x360(%rsp)
jmp 0x3e76f
movl $0x0, 0x35c(%rsp)
movl $0x0, 0x358(%rsp)
movl 0x358(%rsp), %eax
cmpl 0x3ac(%rsp), %eax
jge 0x3efa3
callq 0x144f30
movsd %xmm0, 0xb0(%rsp)
movq 0x428(%rsp), %rdi
callq 0x43e20
movsd 0xb0(%rsp), %xmm0
cvtsi2sd %eax, %xmm1
mulsd %xmm1, %xmm0
cvttsd2si %xmm0, %eax
movl %eax, 0x354(%rsp)
movq 0x3a0(%rsp), %rax
movslq 0x354(%rsp), %rcx
cmpl $0x0, (%rax,%rcx,4)
je 0x3e83e
jmp 0x3ef8d
movq 0x428(%rsp), %rdi
movl 0x354(%rsp), %esi
callq 0x43ef0
cmpl $0x2, %eax
jge 0x3e85c
jmp 0x3ef8d
movq 0x428(%rsp), %rdi
movl 0x354(%rsp), %esi
callq 0x43e40
movq %rax, 0x348(%rsp)
movq 0x348(%rsp), %rsi
leaq 0x330(%rsp), %rdi
callq 0x18730
movq 0x398(%rsp), %rax
movslq 0x354(%rsp), %rcx
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movq %rax, 0x328(%rsp)
movq 0x328(%rsp), %rdi
leaq 0x5bf8e5(%rip), %rsi    # 0x5fe1a0
callq 0x89be0
cmpl $0x0, %eax
je 0x3e8ca
jmp 0x3ef8d
movq 0x328(%rsp), %rdx
leaq 0x308(%rsp), %rdi
leaq 0x330(%rsp), %rsi
callq 0xf5ab0
movl $0x0, 0x304(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0x2f8(%rsp)
movl $0x0, 0x2f4(%rsp)
movl 0x2f4(%rsp), %eax
movl %eax, 0xac(%rsp)
movq 0x428(%rsp), %rdi
callq 0x43e20
movl %eax, %ecx
movl 0xac(%rsp), %eax
cmpl %ecx, %eax
jge 0x3eb7f
movq 0x428(%rsp), %rdi
movl 0x2f4(%rsp), %esi
callq 0x43e40
movq %rax, 0x2e8(%rsp)
movq 0x428(%rsp), %rdi
movl 0x354(%rsp), %esi
callq 0x43ef0
cmpl $0x2, %eax
jge 0x3e96f
jmp 0x3eb69
movq 0x2e8(%rsp), %rsi
leaq 0x2d0(%rsp), %rdi
callq 0x18730
leaq 0x308(%rsp), %rdi
leaq 0x2d0(%rsp), %rsi
callq 0x444d0
movsd %xmm0, 0x2c8(%rsp)
movsd 0x2c8(%rsp), %xmm0
ucomisd 0x420(%rsp), %xmm0
jbe 0x3e9bb
jmp 0x3eb69
movq 0x398(%rsp), %rax
movslq 0x2f4(%rsp), %rcx
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movq %rax, 0x2c0(%rsp)
movq 0x2c0(%rsp), %rdi
leaq 0x5bf7b7(%rip), %rsi    # 0x5fe1a0
callq 0x89be0
cmpl $0x0, %eax
je 0x3e9f8
jmp 0x3eb69
movq 0x2c0(%rsp), %rdi
movq 0x328(%rsp), %rsi
callq 0xf9ac0
movaps 0x1659ac(%rip), %xmm1   # 0x1a43c0
pand %xmm1, %xmm0
movsd %xmm0, 0x2b8(%rsp)
movsd 0x16573f(%rip), %xmm0   # 0x1a4168
ucomisd 0x2b8(%rsp), %xmm0
jbe 0x3ea4d
movsd 0x2b8(%rsp), %xmm0
callq 0x13520
movsd %xmm0, 0xa0(%rsp)
jmp 0x3ea5b
xorps %xmm0, %xmm0
movsd %xmm0, 0xa0(%rsp)
jmp 0x3ea5b
movsd 0xa0(%rsp), %xmm0
movsd %xmm0, 0x2b0(%rsp)
movsd 0x2b0(%rsp), %xmm0
ucomisd 0x418(%rsp), %xmm0
jbe 0x3ea86
jmp 0x3eb69
movsd 0x1656da(%rip), %xmm0   # 0x1a4168
movsd %xmm0, 0x2a8(%rsp)
movsd 0x3d8(%rsp), %xmm0
mulsd 0x2c8(%rsp), %xmm0
mulsd 0x2c8(%rsp), %xmm0
callq 0x139a0
mulsd 0x2a8(%rsp), %xmm0
movsd %xmm0, 0x2a8(%rsp)
movsd 0x3c0(%rsp), %xmm0
mulsd 0x2b0(%rsp), %xmm0
mulsd 0x2b0(%rsp), %xmm0
callq 0x139a0
mulsd 0x2a8(%rsp), %xmm0
movsd %xmm0, 0x2a8(%rsp)
movsd 0x2a8(%rsp), %xmm0
addsd 0x2f8(%rsp), %xmm0
movsd %xmm0, 0x2f8(%rsp)
movq 0x390(%rsp), %rdi
movslq 0x304(%rsp), %rax
imulq $0x18, %rax, %rax
addq %rax, %rdi
leaq 0x2d0(%rsp), %rsi
callq 0xf89e0
movsd 0x2a8(%rsp), %xmm0
movq 0x378(%rsp), %rax
movslq 0x304(%rsp), %rcx
movsd %xmm0, (%rax,%rcx,8)
movl 0x304(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x304(%rsp)
movl 0x2f4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x2f4(%rsp)
jmp 0x3e909
movsd 0x2f8(%rsp), %xmm1
cvtsi2sdl 0x404(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x3eb9c
jmp 0x3ef8d
movl 0x304(%rsp), %esi
movq 0x390(%rsp), %rdx
movq 0x378(%rsp), %rcx
leaq 0x290(%rsp), %rdi
callq 0x97b20
movl 0x304(%rsp), %edx
movq 0x390(%rsp), %rcx
movq 0x378(%rsp), %r8
leaq 0x248(%rsp), %rdi
leaq 0x290(%rsp), %rsi
xorl %eax, %eax
movl %eax, %r9d
callq 0x97be0
leaq 0x248(%rsp), %rdi
movl $0x2, %esi
callq 0x44220
movq %rax, %rdi
leaq 0x5bf593(%rip), %rsi    # 0x5fe1a0
callq 0x89be0
cmpl $0x0, %eax
je 0x3ec1c
jmp 0x3ef8d
leaq 0x248(%rsp), %rdi
movl $0x2, %esi
callq 0x44220
movq %rax, %rdx
leaq 0x308(%rsp), %rdi
leaq 0x290(%rsp), %rsi
callq 0xf6b30
movq 0x368(%rsp), %rax
movslq 0x35c(%rsp), %rcx
imulq $0x70, %rcx, %rcx
addq %rcx, %rax
movq %rax, 0x240(%rsp)
movq 0x240(%rsp), %rdi
xorl %esi, %esi
callq 0x142550
movq 0x240(%rsp), %rdi
addq $0x10, %rdi
leaq 0x308(%rsp), %rsi
callq 0x44240
movq 0x240(%rsp), %rdi
addq $0x30, %rdi
leaq 0x1be668(%rip), %rsi    # 0x1fd308
callq 0x1bd40
movq 0x240(%rsp), %rax
xorps %xmm0, %xmm0
movsd %xmm0, 0x68(%rax)
movl $0x0, 0x23c(%rsp)
movl 0x23c(%rsp), %eax
movl %eax, 0x9c(%rsp)
movq 0x428(%rsp), %rdi
callq 0x43e20
movl %eax, %ecx
movl 0x9c(%rsp), %eax
cmpl %ecx, %eax
jge 0x3ef5e
movq 0x428(%rsp), %rdi
movl 0x23c(%rsp), %esi
callq 0x43e40
movq %rax, 0x230(%rsp)
movq 0x428(%rsp), %rdi
movq 0x230(%rsp), %rsi
callq 0x43ec0
movl %eax, 0x22c(%rsp)
movq 0x428(%rsp), %rdi
movl 0x22c(%rsp), %esi
callq 0x43ef0
cmpl $0x2, %eax
jge 0x3ed42
jmp 0x3ef48
movq 0x230(%rsp), %rsi
leaq 0x210(%rsp), %rdi
callq 0x18730
leaq 0x308(%rsp), %rdi
leaq 0x210(%rsp), %rsi
callq 0x444d0
movsd %xmm0, 0x208(%rsp)
movsd 0x208(%rsp), %xmm0
ucomisd 0x420(%rsp), %xmm0
jbe 0x3ed8e
jmp 0x3ef48
movq 0x398(%rsp), %rax
movslq 0x23c(%rsp), %rcx
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movq %rax, 0x200(%rsp)
movq 0x200(%rsp), %rdi
leaq 0x5bf3e4(%rip), %rsi    # 0x5fe1a0
callq 0x89be0
cmpl $0x0, %eax
je 0x3edcb
jmp 0x3ef48
movq 0x200(%rsp), %rax
movq %rax, 0x90(%rsp)
leaq 0x308(%rsp), %rdi
callq 0x44500
movq 0x90(%rsp), %rdi
movq %rax, %rsi
callq 0xf9ac0
movaps 0x1655c1(%rip), %xmm1   # 0x1a43c0
pand %xmm1, %xmm0
movsd %xmm0, 0x1f8(%rsp)
movsd 0x165354(%rip), %xmm0   # 0x1a4168
ucomisd 0x1f8(%rsp), %xmm0
jbe 0x3ee38
movsd 0x1f8(%rsp), %xmm0
callq 0x13520
movsd %xmm0, 0x88(%rsp)
jmp 0x3ee46
xorps %xmm0, %xmm0
movsd %xmm0, 0x88(%rsp)
jmp 0x3ee46
movsd 0x88(%rsp), %xmm0
movsd %xmm0, 0x1f0(%rsp)
movsd 0x1f0(%rsp), %xmm0
ucomisd 0x418(%rsp), %xmm0
jbe 0x3ee71
jmp 0x3ef48
movsd 0x1652ef(%rip), %xmm0   # 0x1a4168
movsd %xmm0, 0x1e8(%rsp)
movsd 0x3d8(%rsp), %xmm0
mulsd 0x208(%rsp), %xmm0
mulsd 0x208(%rsp), %xmm0
callq 0x139a0
mulsd 0x1e8(%rsp), %xmm0
movsd %xmm0, 0x1e8(%rsp)
movsd 0x3c0(%rsp), %xmm0
mulsd 0x1f0(%rsp), %xmm0
mulsd 0x1f0(%rsp), %xmm0
callq 0x139a0
mulsd 0x1e8(%rsp), %xmm0
movsd %xmm0, 0x1e8(%rsp)
movq 0x240(%rsp), %rdi
movq 0x230(%rsp), %rsi
callq 0x43e80
movq 0x240(%rsp), %rdi
addq $0x30, %rdi
leaq 0x210(%rsp), %rsi
callq 0xcb9d0
movsd 0x1e8(%rsp), %xmm0
movq 0x240(%rsp), %rax
addsd 0x68(%rax), %xmm0
movsd %xmm0, 0x68(%rax)
movq 0x3a0(%rsp), %rax
movslq 0x22c(%rsp), %rcx
movl (%rax,%rcx,4), %edx
addl $0x1, %edx
movl %edx, (%rax,%rcx,4)
movl 0x23c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x23c(%rsp)
jmp 0x3ecc0
movq 0x240(%rsp), %rax
movsd 0x68(%rax), %xmm1
cvtsi2sdl 0x404(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x3ef7c
jmp 0x3ef8d
movl 0x35c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x35c(%rsp)
movl 0x358(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x358(%rsp)
jmp 0x3e7d8
cmpl $0x0, 0x35c(%rsp)
jle 0x3efce
movq 0x368(%rsp), %rdi
movslq 0x35c(%rsp), %rsi
movl $0x70, %edx
leaq 0x697(%rip), %rcx       # 0x3f660
callq 0x13a50
movl $0x10, %edi
callq 0x13570
movq %rax, %rdi
movq %rdi, %rax
movq %rax, 0x80(%rsp)
callq 0x44510
jmp 0x3efed
movq 0x80(%rsp), %rax
movq %rax, 0x1e0(%rsp)
cmpq $0x0, 0x1e0(%rsp)
jne 0x3f052
leaq 0x165cff(%rip), %rdi    # 0x1a4d0e
movb $0x0, %al
callq 0x1464b0
movq $0x0, 0x430(%rsp)
jmp 0x3f641
movq 0x80(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x388(%rsp)
movl %eax, 0x384(%rsp)
movl $0x10, %esi
callq 0x13580
jmp 0x3f651
movl $0x0, 0x1dc(%rsp)
movl 0x1dc(%rsp), %eax
cmpl 0x35c(%rsp), %eax
jge 0x3f523
movl $0x0, 0x1d8(%rsp)
movq 0x368(%rsp), %rax
movslq 0x1dc(%rsp), %rcx
imulq $0x70, %rcx, %rcx
addq %rcx, %rax
movq %rax, 0x1d0(%rsp)
movl $0x240, %edi            # imm = 0x240
callq 0x13570
movq %rax, %rdi
movq %rdi, %rax
movq %rax, 0x78(%rsp)
movq 0x1d0(%rsp), %rdx
movq %rdx, %rsi
addq $0x10, %rsi
addq $0x30, %rdx
movsd 0x3f8(%rsp), %xmm0
callq 0xdc6a0
jmp 0x3f0d3
movq 0x78(%rsp), %rax
movq %rax, 0x1c8(%rsp)
movl $0x0, 0x1c4(%rsp)
movl 0x1c4(%rsp), %eax
movl %eax, 0x74(%rsp)
movq 0x1d0(%rsp), %rdi
callq 0x16d50
movl %eax, %ecx
movl 0x74(%rsp), %eax
cmpl %ecx, %eax
jge 0x3f3ab
movq 0x1d0(%rsp), %rdi
movl 0x1c4(%rsp), %esi
callq 0x44520
movq %rax, 0x1b8(%rsp)
movq 0x428(%rsp), %rdi
movq 0x1b8(%rsp), %rsi
callq 0x43ec0
movl %eax, 0x1b4(%rsp)
movq 0x428(%rsp), %rdi
movl 0x1b4(%rsp), %esi
callq 0x43ef0
cmpl $0x2, %eax
jge 0x3f18f
jmp 0x3f395
movq 0x78(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x388(%rsp)
movl %eax, 0x384(%rsp)
movl $0x240, %esi            # imm = 0x240
callq 0x13580
jmp 0x3f651
movq 0x370(%rsp), %rax
movslq 0x1b4(%rsp), %rcx
cmpq $0x0, (%rax,%rcx,8)
je 0x3f1ab
jmp 0x3f395
movq 0x1c8(%rsp), %rdx
movq 0x370(%rsp), %rax
movslq 0x1b4(%rsp), %rcx
movq %rdx, (%rax,%rcx,8)
movq 0x1b8(%rsp), %rsi
leaq 0x198(%rsp), %rdi
callq 0x18730
movq 0x1d0(%rsp), %rdi
addq $0x10, %rdi
leaq 0x198(%rsp), %rsi
callq 0x444d0
movsd %xmm0, 0x190(%rsp)
movsd 0x190(%rsp), %xmm0
ucomisd 0x420(%rsp), %xmm0
jbe 0x3f217
jmp 0x3f395
movq 0x398(%rsp), %rax
movslq 0x1b4(%rsp), %rcx
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movq %rax, 0x188(%rsp)
movq 0x188(%rsp), %rdi
leaq 0x5bef5b(%rip), %rsi    # 0x5fe1a0
callq 0x89be0
cmpl $0x0, %eax
je 0x3f254
jmp 0x3f395
movq 0x188(%rsp), %rax
movq %rax, 0x68(%rsp)
movq 0x1d0(%rsp), %rdi
addq $0x10, %rdi
callq 0x44500
movq 0x68(%rsp), %rdi
movq %rax, %rsi
callq 0xf9ac0
movaps 0x16513a(%rip), %xmm1   # 0x1a43c0
pand %xmm1, %xmm0
movsd %xmm0, 0x180(%rsp)
movsd 0x164ecd(%rip), %xmm0   # 0x1a4168
ucomisd 0x180(%rsp), %xmm0
jbe 0x3f2bc
movsd 0x180(%rsp), %xmm0
callq 0x13520
movsd %xmm0, 0x60(%rsp)
jmp 0x3f2c7
xorps %xmm0, %xmm0
movsd %xmm0, 0x60(%rsp)
jmp 0x3f2c7
movsd 0x60(%rsp), %xmm0
movsd %xmm0, 0x178(%rsp)
movsd 0x178(%rsp), %xmm0
ucomisd 0x418(%rsp), %xmm0
jbe 0x3f2ef
jmp 0x3f395
movsd 0x164e71(%rip), %xmm0   # 0x1a4168
movsd %xmm0, 0x170(%rsp)
movsd 0x3d8(%rsp), %xmm0
mulsd 0x190(%rsp), %xmm0
mulsd 0x190(%rsp), %xmm0
callq 0x139a0
mulsd 0x170(%rsp), %xmm0
movsd %xmm0, 0x170(%rsp)
movsd 0x3c0(%rsp), %xmm0
mulsd 0x178(%rsp), %xmm0
mulsd 0x178(%rsp), %xmm0
callq 0x139a0
mulsd 0x170(%rsp), %xmm0
movsd %xmm0, 0x170(%rsp)
movq 0x1c8(%rsp), %rdi
movsd 0x170(%rsp), %xmm0
leaq 0x198(%rsp), %rsi
xorl %edx, %edx
callq 0x44540
movl 0x1d8(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x1d8(%rsp)
movl 0x1c4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x1c4(%rsp)
jmp 0x3f0eb
cmpl $0x0, 0x404(%rsp)
jle 0x3f3f6
movl 0x1d8(%rsp), %eax
cmpl 0x404(%rsp), %eax
jge 0x3f3f6
movq 0x1c8(%rsp), %rax
movq %rax, 0x58(%rsp)
cmpq $0x0, %rax
je 0x3f3f1
movq 0x58(%rsp), %rdi
callq 0xdde20
movq 0x58(%rsp), %rdi
movl $0x240, %esi            # imm = 0x240
callq 0x13580
jmp 0x3f50d
movsd 0x408(%rsp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
ja 0x3f41e
movsd 0x410(%rsp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jbe 0x3f4f8
movq 0x1c8(%rsp), %rdi
callq 0x445d0
movsd %xmm0, 0x168(%rsp)
movsd 0x408(%rsp), %xmm0
movsd 0x168(%rsp), %xmm1
mulsd 0x168(%rsp), %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, 0x160(%rsp)
movsd 0x410(%rsp), %xmm0
mulsd 0x168(%rsp), %xmm0
mulsd 0x168(%rsp), %xmm0
movsd %xmm0, 0x158(%rsp)
movq 0x1c8(%rsp), %rdi
movsd 0x160(%rsp), %xmm0
movsd 0x158(%rsp), %xmm1
xorps %xmm4, %xmm4
movsd 0x16565b(%rip), %xmm5   # 0x1a4b00
movaps %xmm4, %xmm2
movaps %xmm4, %xmm3
callq 0x44620
movq 0x1c8(%rsp), %rdi
callq 0x44690
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0x3f4f6
jp 0x3f4f6
movq 0x1c8(%rsp), %rax
movq %rax, 0x50(%rsp)
cmpq $0x0, %rax
je 0x3f4f4
movq 0x50(%rsp), %rdi
callq 0xdde20
movq 0x50(%rsp), %rdi
movl $0x240, %esi            # imm = 0x240
callq 0x13580
jmp 0x3f50d
jmp 0x3f4f8
movq 0x1e0(%rsp), %rdi
movq 0x1c8(%rsp), %rsi
callq 0x446b0
movl 0x1dc(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x1dc(%rsp)
jmp 0x3f05d
movq 0x3a0(%rsp), %rax
movq %rax, 0x48(%rsp)
cmpq $0x0, %rax
je 0x3f540
movq 0x48(%rsp), %rdi
callq 0x13750
movq 0x398(%rsp), %rax
movq %rax, 0x40(%rsp)
cmpq $0x0, %rax
je 0x3f55d
movq 0x40(%rsp), %rdi
callq 0x13750
movq 0x390(%rsp), %rax
movq %rax, 0x38(%rsp)
cmpq $0x0, %rax
je 0x3f57a
movq 0x38(%rsp), %rdi
callq 0x13750
movq 0x378(%rsp), %rax
movq %rax, 0x30(%rsp)
cmpq $0x0, %rax
je 0x3f597
movq 0x30(%rsp), %rdi
callq 0x13750
movq 0x370(%rsp), %rax
movq %rax, 0x28(%rsp)
cmpq $0x0, %rax
je 0x3f5b4
movq 0x28(%rsp), %rdi
callq 0x13750
movq 0x368(%rsp), %rax
movq %rax, 0x20(%rsp)
cmpq $0x0, %rax
je 0x3f631
movq 0x20(%rsp), %rcx
movq %rcx, %rax
addq $-0x8, %rax
movq %rax, 0x8(%rsp)
movq -0x8(%rcx), %rax
movq %rax, 0x10(%rsp)
imulq $0x70, %rax, %rdx
movq %rcx, %rax
addq %rdx, %rax
cmpq %rax, %rcx
movq %rax, 0x18(%rsp)
je 0x3f61a
movq 0x18(%rsp), %rdi
addq $-0x70, %rdi
movq %rdi, (%rsp)
callq 0x444a0
movq 0x20(%rsp), %rcx
movq (%rsp), %rax
cmpq %rcx, %rax
movq %rax, 0x18(%rsp)
jne 0x3f5f5
movq 0x8(%rsp), %rdi
movq 0x10(%rsp), %rax
imulq $0x70, %rax, %rsi
addq $0x8, %rsi
callq 0x13a90
movq 0x1e0(%rsp), %rax
movq %rax, 0x430(%rsp)
movq 0x430(%rsp), %rax
addq $0x438, %rsp            # imm = 0x438
retq
movq 0x388(%rsp), %rdi
callq 0x13970
nop