// File: tomfunkhouser[P]gaps/apps/grd2grd/grd2grd.cpp
// Function: ApplyOperations(gaps::R3Grid*, Operation*, int)
static int
ApplyOperations(R3Grid *grid, Operation *operations, int noperations)
{
  // Start statistics
  RNTime start_time;
  start_time.Read();

  // Apply operations
  for (int i = 0; i < noperations; i++) {
    Operation *operation = &operations[i];

    // Read grid operand
    R3Grid *grid1 = NULL;
    switch (operation->type) {
    case ADD_GRID_OPERATION: 
    case SUBTRACT_GRID_OPERATION: 
    case MULTIPLY_GRID_OPERATION: 
    case DIVIDE_GRID_OPERATION: 
    case MASK_GRID_OPERATION: 
      grid1 = ReadGrid(operation->operand1);
      if (!grid1) {
        RNFail("Unable to read grid file (%s) for operation %d\n", operation->operand1, i);
        return 0;
      }
    }

    // Print debug message
    if (print_debug) {
      printf("Applying operation: %d %s %s %s\n", operation->type, 
             (operation->operand1) ? operation->operand1 : "-", 
             (operation->operand2) ? operation->operand2 : "-", 
             (operation->operand3) ? operation->operand3 : "-");
    }

    // Apply operation
    switch (operation->type) {
    case NOP_OPERATION: break;
    case ABS_OPERATION: grid->Abs(); break;
    case SQUARE_OPERATION: grid->Square(); break;
    case SQRT_OPERATION: grid->Sqrt(); break;
    case NEGATE_OPERATION: grid->Negate(); break;
    case INVERT_OPERATION: grid->Invert(); break;
    case NORMALIZE_OPERATION: grid->Normalize(); break;
    case GRADIENT_MAGNITUDE_OPERATION: grid->GradientMagnitude(); break;
    case EDGE_DETECT_OPERATION: grid->DetectEdges(); break;
    case SIGNED_DISTANCE_OPERATION: grid->SignedDistanceTransform(); break;
    case SQUARED_DISTANCE_OPERATION: grid->SquaredDistanceTransform(); break;
    case VORONOI_OPERATION: grid->Voronoi(); break;
    case FILL_HOLES_OPERATION: grid->FillHoles(); break;
    case CLEAR_OPERATION: grid->Clear(atof(operation->operand1)); break;
    case ADD_OPERATION: grid->Add(atof(operation->operand1)); break;
    case SUBTRACT_OPERATION: grid->Subtract(atof(operation->operand1)); break;
    case MULTIPLY_OPERATION: grid->Multiply(atof(operation->operand1)); break;
    case DIVIDE_OPERATION: grid->Divide(atof(operation->operand1)); break;
    case POW_OPERATION: grid->Pow(atof(operation->operand1)); break;
    case DILATE_OPERATION: grid->Dilate(atof(operation->operand1)); break;
    case ERODE_OPERATION: grid->Erode(atof(operation->operand1)); break;
    case BLUR_OPERATION: grid->Blur(atof(operation->operand1)); break;
    case RESAMPLE_OPERATION: grid->Resample(atoi(operation->operand1), atoi(operation->operand2), atoi(operation->operand3)); break;
    case ADD_GRID_OPERATION: grid->Add(*grid1); break;
    case SUBTRACT_GRID_OPERATION: grid->Subtract(*grid1); break;
    case MULTIPLY_GRID_OPERATION: grid->Multiply(*grid1); break;
    case DIVIDE_GRID_OPERATION: grid->Divide(*grid1); break;
    case MASK_GRID_OPERATION: grid->Divide(*grid1); break;
    case THRESHOLD_OPERATION: {
      RNScalar value1 = (strcmp(operation->operand2, "keep")) ? atof(operation->operand2) : R3_GRID_KEEP_VALUE;
      RNScalar value2 = (strcmp(operation->operand3, "keep")) ? atof(operation->operand3) : R3_GRID_KEEP_VALUE;
      grid->Threshold(atof(operation->operand1), value1, value2); 
      break; }
    default: 
      RNFail("Unknown operation type (%d) in operation %d\n", operation->type, i); 
      return 0; 
    }
  }

  // Print statistics
  if (print_verbose) {
    printf("Applied operations ...\n");
    printf("  Time = %.2f seconds\n", start_time.Elapsed());
    printf("  # Operations = %d\n", noperations);
    printf("  Resolution = %d %d %d\n", grid->XResolution(), grid->YResolution(), grid->ZResolution());
    printf("  Spacing = %g\n", grid->GridToWorldScaleFactor());
    printf("  Cardinality = %d\n", grid->Cardinality());
    printf("  Volume = %g\n", grid->Volume());
    RNInterval grid_range = grid->Range();
    printf("  Minimum = %g\n", grid_range.Min());
    printf("  Maximum = %g\n", grid_range.Max());
    printf("  L1Norm = %g\n", grid->L1Norm());
    printf("  L2Norm = %g\n", grid->L2Norm());
    fflush(stdout);
  }

  // Return success
  return 1;
}

// Assembly:
subq $0x118, %rsp            # imm = 0x118
movq %rdi, 0x108(%rsp)
movq %rsi, 0x100(%rsp)
movl %edx, 0xfc(%rsp)
leaq 0xe8(%rsp), %rdi
callq 0xd1630
leaq 0xe8(%rsp), %rdi
callq 0x140a0
movl $0x0, 0xe4(%rsp)
movl 0xe4(%rsp), %eax
cmpl 0xfc(%rsp), %eax
jge 0x13e6d
movq 0x100(%rsp), %rax
movslq 0xe4(%rsp), %rcx
shlq $0x5, %rcx
addq %rcx, %rax
movq %rax, 0xd8(%rsp)
movq $0x0, 0xd0(%rsp)
movq 0xd8(%rsp), %rax
movl (%rax), %eax
addl $-0x18, %eax
subl $0x4, %eax
ja 0x1389d
jmp 0x13846
movq 0xd8(%rsp), %rax
movq 0x8(%rax), %rdi
callq 0x13580
movq %rax, 0xd0(%rsp)
cmpq $0x0, 0xd0(%rsp)
jne 0x1389b
movq 0xd8(%rsp), %rax
movq 0x8(%rax), %rsi
movl 0xe4(%rsp), %edx
leaq 0x120a90(%rip), %rdi    # 0x134314
movb $0x0, %al
callq 0xd5850
movl $0x0, 0x114(%rsp)
jmp 0x13feb
jmp 0x1389d
cmpl $0x0, 0x166950(%rip)    # 0x17a1f4
je 0x139aa
movq 0xd8(%rsp), %rax
movl (%rax), %eax
movl %eax, 0xac(%rsp)
movq 0xd8(%rsp), %rax
cmpq $0x0, 0x8(%rax)
je 0x138e0
movq 0xd8(%rsp), %rax
movq 0x8(%rax), %rax
movq %rax, 0xa0(%rsp)
jmp 0x138f1
leaq 0x120a7e(%rip), %rax    # 0x134365
movq %rax, 0xa0(%rsp)
jmp 0x138f1
movq 0xa0(%rsp), %rax
movq %rax, 0x98(%rsp)
movq 0xd8(%rsp), %rax
cmpq $0x0, 0x10(%rax)
je 0x13926
movq 0xd8(%rsp), %rax
movq 0x10(%rax), %rax
movq %rax, 0x90(%rsp)
jmp 0x13937
leaq 0x120a38(%rip), %rax    # 0x134365
movq %rax, 0x90(%rsp)
jmp 0x13937
movq 0x90(%rsp), %rax
movq %rax, 0x88(%rsp)
movq 0xd8(%rsp), %rax
cmpq $0x0, 0x18(%rax)
je 0x1396c
movq 0xd8(%rsp), %rax
movq 0x18(%rax), %rax
movq %rax, 0x80(%rsp)
jmp 0x1397d
leaq 0x1209f2(%rip), %rax    # 0x134365
movq %rax, 0x80(%rsp)
jmp 0x1397d
movq 0x88(%rsp), %rcx
movq 0x98(%rsp), %rdx
movl 0xac(%rsp), %esi
movq 0x80(%rsp), %r8
leaq 0x1209a1(%rip), %rdi    # 0x134344
movb $0x0, %al
callq 0xf070
movq 0xd8(%rsp), %rax
movl (%rax), %eax
movq %rax, 0x78(%rsp)
subq $0x1c, %rax
ja 0x13e26
movq 0x78(%rsp), %rax
leaq 0x120635(%rip), %rcx    # 0x134004
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
jmp 0x13e55
movq 0x108(%rsp), %rdi
callq 0x173d0
jmp 0x13e55
movq 0x108(%rsp), %rdi
callq 0x174b0
jmp 0x13e55
movq 0x108(%rsp), %rdi
callq 0x17440
jmp 0x13e55
movq 0x108(%rsp), %rdi
callq 0x17520
jmp 0x13e55
movq 0x108(%rsp), %rdi
callq 0x175a0
jmp 0x13e55
movq 0x108(%rsp), %rdi
callq 0x177b0
jmp 0x13e55
movq 0x108(%rsp), %rdi
callq 0x1a020
jmp 0x13e55
movq 0x108(%rsp), %rdi
callq 0x1a230
jmp 0x13e55
movq 0x108(%rsp), %rdi
callq 0x1d0a0
jmp 0x13e55
movq 0x108(%rsp), %rdi
callq 0x17880
jmp 0x13e55
movq 0x108(%rsp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x1beb0
jmp 0x13e55
movq 0x108(%rsp), %rdi
movl $0x7fffffff, %esi       # imm = 0x7FFFFFFF
callq 0x1aa50
jmp 0x13e55
movq 0x108(%rsp), %rax
movq %rax, 0x70(%rsp)
movq 0xd8(%rsp), %rax
movq 0x8(%rax), %rdi
callq 0xf640
movq 0x70(%rsp), %rdi
callq 0x1b1d0
jmp 0x13e55
movq 0x108(%rsp), %rax
movq %rax, 0x68(%rsp)
movq 0xd8(%rsp), %rax
movq 0x8(%rax), %rdi
callq 0xf640
movq 0x68(%rsp), %rdi
callq 0x1b2c0
jmp 0x13e55
movq 0x108(%rsp), %rax
movq %rax, 0x60(%rsp)
movq 0xd8(%rsp), %rax
movq 0x8(%rax), %rdi
callq 0xf640
movq 0x60(%rsp), %rdi
callq 0x1b9e0
jmp 0x13e55
movq 0x108(%rsp), %rax
movq %rax, 0x58(%rsp)
movq 0xd8(%rsp), %rax
movq 0x8(%rax), %rdi
callq 0xf640
movq 0x58(%rsp), %rdi
callq 0x1ba90
jmp 0x13e55
movq 0x108(%rsp), %rax
movq %rax, 0x50(%rsp)
movq 0xd8(%rsp), %rax
movq 0x8(%rax), %rdi
callq 0xf640
movq 0x50(%rsp), %rdi
callq 0x177e0
jmp 0x13e55
movq 0x108(%rsp), %rax
movq %rax, 0x48(%rsp)
movq 0xd8(%rsp), %rax
movq 0x8(%rax), %rdi
callq 0xf640
movq 0x48(%rsp), %rdi
callq 0x1bd70
jmp 0x13e55
movq 0x108(%rsp), %rax
movq %rax, 0x40(%rsp)
movq 0xd8(%rsp), %rax
movq 0x8(%rax), %rdi
callq 0xf640
movq 0x40(%rsp), %rdi
callq 0x17830
jmp 0x13e55
movq 0x108(%rsp), %rax
movq %rax, 0x38(%rsp)
movq 0xd8(%rsp), %rax
movq 0x8(%rax), %rdi
callq 0xf640
movq 0x38(%rsp), %rdi
callq 0x18580
jmp 0x13e55
movq 0x108(%rsp), %rax
movq %rax, 0x30(%rsp)
movq 0xd8(%rsp), %rax
movq 0x8(%rax), %rdi
callq 0xf640
movq 0x30(%rsp), %rdi
callq 0x185e0
jmp 0x13e55
movq 0x108(%rsp), %rax
movq %rax, 0x20(%rsp)
movq 0xd8(%rsp), %rax
movq 0x8(%rax), %rdi
callq 0xf7b0
movl %eax, 0x28(%rsp)
movq 0xd8(%rsp), %rax
movq 0x10(%rax), %rdi
callq 0xf7b0
movl %eax, 0x2c(%rsp)
movq 0xd8(%rsp), %rax
movq 0x18(%rax), %rdi
callq 0xf7b0
movq 0x20(%rsp), %rdi
movl 0x28(%rsp), %esi
movl 0x2c(%rsp), %edx
movl %eax, %ecx
callq 0x1d2d0
jmp 0x13e55
movq 0x108(%rsp), %rdi
movq 0xd0(%rsp), %rsi
callq 0x1b3a0
jmp 0x13e55
movq 0x108(%rsp), %rdi
movq 0xd0(%rsp), %rsi
callq 0x1ba20
jmp 0x13e55
movq 0x108(%rsp), %rdi
movq 0xd0(%rsp), %rsi
callq 0x1bb00
jmp 0x13e55
movq 0x108(%rsp), %rdi
movq 0xd0(%rsp), %rsi
callq 0x1bb70
jmp 0x13e55
movq 0x108(%rsp), %rdi
movq 0xd0(%rsp), %rsi
callq 0x1bb70
jmp 0x13e55
movq 0xd8(%rsp), %rax
movq 0x10(%rax), %rdi
leaq 0x12061e(%rip), %rsi    # 0x134367
callq 0xf700
cmpl $0x0, %eax
je 0x13d6c
movq 0xd8(%rsp), %rax
movq 0x10(%rax), %rdi
callq 0xf640
movsd %xmm0, 0x18(%rsp)
jmp 0x13d81
leaq 0x12073d(%rip), %rax    # 0x1344b0
movss (%rax), %xmm0
cvtss2sd %xmm0, %xmm0
movsd %xmm0, 0x18(%rsp)
movsd 0x18(%rsp), %xmm0
movsd %xmm0, 0xc8(%rsp)
movq 0xd8(%rsp), %rax
movq 0x18(%rax), %rdi
leaq 0x1205c4(%rip), %rsi    # 0x134367
callq 0xf700
cmpl $0x0, %eax
je 0x13dc6
movq 0xd8(%rsp), %rax
movq 0x18(%rax), %rdi
callq 0xf640
movsd %xmm0, 0x10(%rsp)
jmp 0x13ddb
leaq 0x1206e3(%rip), %rax    # 0x1344b0
movss (%rax), %xmm0
cvtss2sd %xmm0, %xmm0
movsd %xmm0, 0x10(%rsp)
movsd 0x10(%rsp), %xmm0
movsd %xmm0, 0xc0(%rsp)
movq 0x108(%rsp), %rax
movq %rax, 0x8(%rsp)
movq 0xd8(%rsp), %rax
movq 0x8(%rax), %rdi
callq 0xf640
movq 0x8(%rsp), %rdi
movsd 0xc8(%rsp), %xmm1
movsd 0xc0(%rsp), %xmm2
callq 0x184b0
jmp 0x13e55
movq 0xd8(%rsp), %rax
movl (%rax), %esi
movl 0xe4(%rsp), %edx
leaq 0x12052e(%rip), %rdi    # 0x13436c
movb $0x0, %al
callq 0xd5850
movl $0x0, 0x114(%rsp)
jmp 0x13feb
jmp 0x13e57
movl 0xe4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xe4(%rsp)
jmp 0x137f3
cmpl $0x0, 0x16637c(%rip)    # 0x17a1f0
je 0x13fe0
leaq 0x120518(%rip), %rdi    # 0x134399
movb $0x0, %al
callq 0xf070
leaq 0xe8(%rsp), %rdi
callq 0xd16f0
leaq 0x1203d7(%rip), %rdi    # 0x134273
movb $0x1, %al
callq 0xf070
movl 0xfc(%rsp), %esi
leaq 0x120500(%rip), %rdi    # 0x1343b1
movb $0x0, %al
callq 0xf070
movq 0x108(%rsp), %rdi
callq 0x140c0
movl %eax, (%rsp)
movq 0x108(%rsp), %rdi
callq 0x140e0
movl %eax, 0x4(%rsp)
movq 0x108(%rsp), %rdi
callq 0x14100
movl (%rsp), %esi
movl 0x4(%rsp), %edx
movl %eax, %ecx
leaq 0x120394(%rip), %rdi    # 0x13428a
movb $0x0, %al
callq 0xf070
movq 0x108(%rsp), %rdi
callq 0x14120
leaq 0x120392(%rip), %rdi    # 0x1342a3
movb $0x1, %al
callq 0xf070
movq 0x108(%rsp), %rdi
callq 0x15920
movl %eax, %esi
leaq 0x120385(%rip), %rdi    # 0x1342b3
movb $0x0, %al
callq 0xf070
movq 0x108(%rsp), %rdi
callq 0x14140
leaq 0x12037e(%rip), %rdi    # 0x1342c7
movb $0x1, %al
callq 0xf070
movq 0x108(%rsp), %rsi
leaq 0xb0(%rsp), %rdi
callq 0x15720
leaq 0xb0(%rsp), %rdi
callq 0x14180
leaq 0x12035d(%rip), %rdi    # 0x1342d6
movb $0x1, %al
callq 0xf070
leaq 0xb0(%rsp), %rdi
callq 0x14190
leaq 0x120352(%rip), %rdi    # 0x1342e6
movb $0x1, %al
callq 0xf070
movq 0x108(%rsp), %rdi
callq 0x15810
leaq 0x120347(%rip), %rdi    # 0x1342f6
movb $0x1, %al
callq 0xf070
movq 0x108(%rsp), %rdi
callq 0x141a0
leaq 0x12033b(%rip), %rdi    # 0x134305
movb $0x1, %al
callq 0xf070
movq 0x15bfb8(%rip), %rax    # 0x16ff90
movq (%rax), %rdi
callq 0xf5d0
movl $0x1, 0x114(%rsp)
movl 0x114(%rsp), %eax
addq $0x118, %rsp            # imm = 0x118
retq
nopw (%rax,%rax)