Beispiel #1
0
void PadPict(char poff)
{
    SimpleHdr table;
    FILE *in;
    display::AutoPal p(display::graphics.legacyScreen());

    in = sOpen("LFACIL.BUT", "rb", 0);
    fread_SimpleHdr(&table, 1, in);
    fseek(in, 6 * sizeof_SimpleHdr, SEEK_SET);
    fread(p.pal, 768, 1, in);
    fseek(in, table.offset, SEEK_SET);
    fread(buffer, table.size, 1, in);

    display::LegacySurface local(148, 148);
    display::LegacySurface local2(148, 148);

    RLED_img(buffer, local.pixels(), table.size, local.width(), local.height());
    fseek(in, (poff)*sizeof_SimpleHdr, SEEK_SET);
    fread_SimpleHdr(&table, 1, in);
    fseek(in, table.offset, SEEK_SET);
    fread(buffer, table.size, 1, in);
    RLED_img(buffer, local2.pixels(), table.size, local2.width(), local2.height());

    local2.copyTo(display::graphics.legacyScreen(), 168, 28);

    fclose(in);
}
Beispiel #2
0
void Display_ARROW(char num, int x, int y)
{
    /* Look for explanations in place.c:PatchMe() */
    PatchHdrSmall P;
    FILE *in;
    in = sOpen("ARROWS.BUT", "rb", 0);
    fseek(in, (num) * (sizeof P), SEEK_CUR);
    fread(&P, sizeof P, 1, in);
    SwapPatchHdrSmall(&P);
    fseek(in, P.offset, SEEK_SET);

    if (P.w * P.h != P.size) {
        /* fprintf(stderr,
                "Display_ARROW(): w*h != size (%hhd*%hhd == %d != %hd)\n",
                P.w, P.h, P.w*P.h, P.size); */
        if ((P.w + 1) * P.h == P.size) {
            /* fprintf(stderr, "Display_ARROW(): P.w++ saves the day!\n"); */
            P.w++;
        }

        P.size = P.w * P.h;
    }

    display::Surface local(P.w, P.h);
    display::Surface local2(P.w, P.h);
    local2.copyFrom(display::graphics.screen(), x, y, x + P.w - 1, y + P.h - 1);
    fread(local.pixels(), P.size, 1, in);
    fclose(in);
// for (j=0;j<P.size;j++)
//   if(local.vptr[j]!=0) local2.vptr[j]=local.vptr[j];
    local.copyTo(display::graphics.screen(), x, y);
}
Beispiel #3
0
clsparseStatus
reduce_by_key(
    int keys_first,
    int keys_last,
    int values_first,
    cl_mem keys_input,
    cl_mem values_input,
    cl_mem keys_output,
    cl_mem values_output,
    int *count,
    clsparseControl control
)
{

    cl_int l_Error;

    /**********************************************************************************
     * Compile Options
     *********************************************************************************/
    const int kernel0_WgSize = WAVESIZE*KERNEL02WAVES;
    const int kernel1_WgSize = WAVESIZE*KERNEL1WAVES;
    const int kernel2_WgSize = WAVESIZE*KERNEL02WAVES;

    //const std::string params = std::string() +
    //          " -DKERNEL0WORKGROUPSIZE=" + std::to_string(kernel0_WgSize)
    //        + " -DKERNEL1WORKGROUPSIZE=" + std::to_string(kernel1_WgSize)
    //        + " -DKERNEL2WORKGROUPSIZE=" + std::to_string(kernel2_WgSize);
    const std::string params;

    cl::Context context = control->getContext();
    std::vector<cl::Device> dev = context.getInfo<CL_CONTEXT_DEVICES>();
    int computeUnits  = dev[0].getInfo< CL_DEVICE_MAX_COMPUTE_UNITS >( );
    int wgPerComputeUnit = dev[0].getInfo< CL_DEVICE_MAX_WORK_GROUP_SIZE >( );


    int resultCnt = computeUnits * wgPerComputeUnit;
    cl_uint numElements = keys_last - keys_first + 1;

    size_t sizeInputBuff = numElements;
    int modWgSize = (sizeInputBuff & (kernel0_WgSize-1));
    if( modWgSize )
    {
        sizeInputBuff &= ~modWgSize;
        sizeInputBuff += kernel0_WgSize;
    }
    cl_uint numWorkGroupsK0 = static_cast< cl_uint >( sizeInputBuff / kernel0_WgSize );

    size_t sizeScanBuff = numWorkGroupsK0;
    modWgSize = (sizeScanBuff & (kernel0_WgSize-1));
    if( modWgSize )
    {
        sizeScanBuff &= ~modWgSize;
        sizeScanBuff += kernel0_WgSize;
    }

    cl_mem tempArrayVec = clCreateBuffer(context(),CL_MEM_READ_WRITE, (numElements)*sizeof(int), NULL, NULL );

    /**********************************************************************************
     *  Kernel 0
     *********************************************************************************/

    cl::Kernel kernel0 = KernelCache::get(control->queue,"reduce_by_key", "OffsetCalculation", params);

    KernelWrap kWrapper0(kernel0);

    kWrapper0 << keys_input << tempArrayVec
              << numElements;

    cl::NDRange local0(kernel0_WgSize);
    cl::NDRange global0(sizeInputBuff);

    cl_int status = kWrapper0.run(control, global0, local0);

    if (status != CL_SUCCESS)
    {
        return clsparseInvalidKernelExecution;
    }

    int init = 0;

    scan(0,
	 numElements - 1,
         tempArrayVec,
         tempArrayVec,
         0,
         0,
         control
         );

    int pattern = 0;
    cl_mem keySumArray = clCreateBuffer(context(),CL_MEM_READ_WRITE, (sizeScanBuff)*sizeof(int), NULL, NULL );
    cl_mem preSumArray = clCreateBuffer(context(),CL_MEM_READ_WRITE, (sizeScanBuff)*sizeof(int), NULL, NULL );
    cl_mem postSumArray = clCreateBuffer(context(),CL_MEM_READ_WRITE,(sizeScanBuff)*sizeof(int), NULL, NULL );
    clEnqueueFillBuffer(control->queue(), keySumArray, &pattern, sizeof(int), 0,
                        (sizeScanBuff)*sizeof(int), 0, NULL, NULL);
    clEnqueueFillBuffer(control->queue(), preSumArray, &pattern, sizeof(int), 0,
                        (sizeScanBuff)*sizeof(int), 0, NULL, NULL);
    clEnqueueFillBuffer(control->queue(), postSumArray, &pattern, sizeof(int), 0,
                        (sizeScanBuff)*sizeof(int), 0, NULL, NULL);


    /**********************************************************************************
     *  Kernel 1
     *********************************************************************************/

    cl::Kernel kernel1 = KernelCache::get(control->queue,"reduce_by_key", "perBlockScanByKey", params);

    KernelWrap kWrapper1(kernel1);

    kWrapper1 << tempArrayVec
	      << values_input
              << numElements
	      << keySumArray
	      << preSumArray;

    cl::NDRange local1(kernel0_WgSize);
    cl::NDRange global1(sizeInputBuff);

    status = kWrapper1.run(control, global1, local1);

    if (status != CL_SUCCESS)
    {
        return clsparseInvalidKernelExecution;
    }

    /**********************************************************************************
     *  Kernel 2
     *********************************************************************************/
    cl_uint workPerThread = static_cast< cl_uint >( sizeScanBuff / kernel1_WgSize );

    cl::Kernel kernel2 = KernelCache::get(control->queue,"reduce_by_key", "intraBlockInclusiveScanByKey", params);

    KernelWrap kWrapper2(kernel2);

    kWrapper2 << keySumArray << preSumArray
              << postSumArray << numWorkGroupsK0 << workPerThread;

    cl::NDRange local2(kernel1_WgSize);
    cl::NDRange global2(kernel1_WgSize);

    status = kWrapper2.run(control, global2, local2);

    if (status != CL_SUCCESS)
    {
        return clsparseInvalidKernelExecution;
    }

    /**********************************************************************************
     *  Kernel 3
     *********************************************************************************/

    cl::Kernel kernel3 = KernelCache::get(control->queue,"reduce_by_key", "keyValueMapping", params);

    KernelWrap kWrapper3(kernel3);

    kWrapper3 << keys_input << keys_output
              << values_input << values_output << tempArrayVec
              << keySumArray << postSumArray << numElements;

    cl::NDRange local3(kernel0_WgSize);
    cl::NDRange global3(sizeInputBuff);

    status = kWrapper3.run(control, global3, local3);

    if (status != CL_SUCCESS)
    {
        return clsparseInvalidKernelExecution;
    }

    int *h_result = (int *) malloc (sizeof(int));

    clEnqueueReadBuffer(control->queue(),
                        tempArrayVec,
                        1,
                       (numElements-1)*sizeof(int),
                        sizeof(int),
                        h_result,
                        0,
                        0,
                        0);

    *count = *(h_result);
    //printf("h_result = %d\n", *count );

    //release buffers
    clReleaseMemObject(tempArrayVec);
    clReleaseMemObject(preSumArray);
    clReleaseMemObject(postSumArray);
    clReleaseMemObject(keySumArray);

    return clsparseSuccess;
}   //end of reduce_by_key
int main(int argc, char *argv[])
{
  Pooma::initialize(argc, argv);
  Pooma::Tester tester(argc, argv);

  // To declare a field, you first need to set up a layout. This requires
  // knowing the physical vertex-domain and the number of external guard
  // cell layers. Vertex domains contain enough points to hold all of the
  // rectilinear centerings that POOMA is likely to support for quite
  // awhile. Also, it means that the same layout can be used for all
  // fields, regardless of centering.
  
  Interval<2> physicalVertexDomain(14, 14);
  Loc<2> blocks(3, 3);
  GridLayout<2> layout1(physicalVertexDomain, blocks, GuardLayers<2>(1),
                        LayoutTag_t());
  GridLayout<2> layout0(physicalVertexDomain, blocks, GuardLayers<2>(0),
                        LayoutTag_t());

  Centering<2> cell = canonicalCentering<2>(CellType, Continuous, AllDim);
  Centering<2> vert = canonicalCentering<2>(VertexType, Continuous, AllDim);
  Centering<2> yedge = canonicalCentering<2>(EdgeType, Continuous, YDim);

  Vector<2> origin(0.0);
  Vector<2> spacings(1.0, 2.0);

  // First basic test verifies that we're assigning to the correct areas
  // on a brick.

  typedef
    Field<UniformRectilinearMesh<2>, double,
    MultiPatch<GridTag, BrickTag_t> > Field_t;
  Field_t b0(cell, layout1, origin, spacings);
  Field_t b1(vert, layout1, origin, spacings);
  Field_t b2(yedge, layout1, origin, spacings);
  Field_t b3(yedge, layout1, origin, spacings);
  Field_t bb0(cell, layout0, origin, spacings);
  Field_t bb1(vert, layout0, origin, spacings);
  Field_t bb2(yedge, layout0, origin, spacings);

  b0.all() = 0.0;
  b1.all() = 0.0;
  b2.all() = 0.0;

  b0 = 1.0;
  b1 = 1.0;
  b2 = 1.0;

  bb0.all() = 0.0;
  bb1.all() = 0.0;
  bb2.all() = 0.0;

  bb0 = 1.0;
  bb1 = 1.0;
  bb2 = 1.0;

  // SPMD code follows.
  // Note, SPMD code will work with the evaluator if you are careful
  // to perform assignment on all the relevant contexts.  The patchLocal
  // function creates a brick on the local context, so you can just perform
  // the assignment on that context.

  int i;

  for (i = 0; i < b0.numPatchesLocal(); ++i)
  {
    Patch<Field_t>::Type_t patch = b0.patchLocal(i);
    //    tester.out() << "context " << Pooma::context() << ":  assigning to patch " << i
    //              << " with domain " << patch.domain() << std::endl;
    patch += 1.5;
  }

  // This is safe to do since b1 and b2 are built with the same layout.
  for (i = 0; i < b1.numPatchesLocal(); ++i)
  {
    b1.patchLocal(i) += 1.5;
    b2.patchLocal(i) += 1.5;
  }

  for (i = 0; i < bb0.numPatchesLocal(); ++i)
  {
    Patch<Field_t>::Type_t patch = bb0.patchLocal(i);
    //    tester.out() << "context " << Pooma::context() << ":  assigning to patch on bb0 " << i
    //              << " with domain " << patch.domain() << std::endl;
    patch += 1.5;
  }

  // This is safe to do since bb1 and bb2 are built with the same layout.
  for (i = 0; i < bb1.numPatchesLocal(); ++i)
  {
    bb1.patchLocal(i) += 1.5;
    bb2.patchLocal(i) += 1.5;
  }

  tester.check("cell centered field is 2.5", all(b0 == 2.5));
  tester.check("vert centered field is 2.5", all(b1 == 2.5));
  tester.check("edge centered field is 2.5", all(b2 == 2.5));

  tester.out() << "b0.all():" << std::endl << b0.all() << std::endl;
  tester.out() << "b1.all():" << std::endl << b1.all() << std::endl;
  tester.out() << "b2.all():" << std::endl << b2.all() << std::endl;

  tester.check("didn't write into b0 boundary",
               sum(b0.all()) == 2.5 * b0.physicalDomain().size());
  tester.check("didn't write into b1 boundary",
               sum(b1.all()) == 2.5 * b1.physicalDomain().size());
  tester.check("didn't write into b2 boundary",
               sum(b2.all()) == 2.5 * b2.physicalDomain().size());

  tester.check("cell centered field is 2.5", all(bb0 == 2.5));
  tester.check("vert centered field is 2.5", all(bb1 == 2.5));
  tester.check("edge centered field is 2.5", all(bb2 == 2.5));

  tester.out() << "bb0:" << std::endl << bb0 << std::endl;
  tester.out() << "bb1:" << std::endl << bb1 << std::endl;
  tester.out() << "bb2:" << std::endl << bb2 << std::endl;

  typedef
    Field<UniformRectilinearMesh<2>, double,
    MultiPatch<GridTag, CompressibleBrickTag_t> > CField_t;
  CField_t c0(cell, layout1, origin, spacings);
  CField_t c1(vert, layout1, origin, spacings);
  CField_t c2(yedge, layout1, origin, spacings);
  CField_t cb0(cell, layout0, origin, spacings);
  CField_t cb1(vert, layout0, origin, spacings);
  CField_t cb2(yedge, layout0, origin, spacings);

  c0.all() = 0.0;
  c1.all() = 0.0;
  c2.all() = 0.0;

  c0 = 1.0;
  c1 = 1.0;
  c2 = 1.0;

  cb0.all() = 0.0;
  cb1.all() = 0.0;
  cb2.all() = 0.0;

  cb0 = 1.0;
  cb1 = 1.0;
  cb2 = 1.0;

  // SPMD code follows.
  // Note, SPMD code will work with the evaluator if you are careful
  // to perform assignment on all the relevant contexts.  The patchLocal
  // function creates a brick on the local context, so you can just perform
  // the assignment on that context.

  for (i = 0; i < c0.numPatchesLocal(); ++i)
  {
    Patch<CField_t>::Type_t patch = c0.patchLocal(i);
    tester.out() << "context " << Pooma::context() << ":  assigning to patch " << i
                 << " with domain " << patch.domain() << std::endl;
    patch += 1.5;
  }

  // This is safe to do since c1 and c2 are built with the same layout.
  for (i = 0; i < c1.numPatchesLocal(); ++i)
  {
    c1.patchLocal(i) += 1.5;
    c2.patchLocal(i) += 1.5;
  }

  for (i = 0; i < cb0.numPatchesLocal(); ++i)
  {
    Patch<CField_t>::Type_t patch = cb0.patchLocal(i);
    tester.out() << "context " << Pooma::context() << ":  assigning to patch on cb0 " << i
                 << " with domain " << patch.domain() << std::endl;
    patch += 1.5;
  }

  // This is safe to do since cb1 and cb2 are cuilt with the same layout.
  for (i = 0; i < cb1.numPatchesLocal(); ++i)
  {
    cb1.patchLocal(i) += 1.5;
    cb2.patchLocal(i) += 1.5;
  }

  tester.check("cell centered field is 2.5", all(c0 == 2.5));
  tester.check("vert centered field is 2.5", all(c1 == 2.5));
  tester.check("edge centered field is 2.5", all(c2 == 2.5));

  tester.out() << "c0.all():" << std::endl << c0.all() << std::endl;
  tester.out() << "c1.all():" << std::endl << c1.all() << std::endl;
  tester.out() << "c2.all():" << std::endl << c2.all() << std::endl;

  tester.check("didn't write into c0 boundary",
               sum(c0.all()) == 2.5 * c0.physicalDomain().size());
  tester.check("didn't write into c1 boundary",
               sum(c1.all()) == 2.5 * c1.physicalDomain().size());
  tester.check("didn't write into c2 boundary",
               sum(c2.all()) == 2.5 * c2.physicalDomain().size());

  tester.check("cell centered field is 2.5", all(cb0 == 2.5));
  tester.check("vert centered field is 2.5", all(cb1 == 2.5));
  tester.check("edge centered field is 2.5", all(cb2 == 2.5));

  tester.out() << "cb0:" << std::endl << cb0 << std::endl;
  tester.out() << "cb1:" << std::endl << cb1 << std::endl;
  tester.out() << "cb2:" << std::endl << cb2 << std::endl;

  //------------------------------------------------------------------
  // Scalar code example:
  //

  c0 = iota(c0.domain()).comp(0);
  c1 = iota(c1.domain()).comp(1);

  // Make sure all the data-parallel are done:

  Pooma::blockAndEvaluate();

  for (i = 0; i < c0.numPatchesLocal(); ++i)
  {
    Patch<CField_t>::Type_t local0 = c0.patchLocal(i);
    Patch<CField_t>::Type_t local1 = c1.patchLocal(i);
    Patch<CField_t>::Type_t local2 = c2.patchLocal(i);

    Interval<2> domain = local2.domain();  // physical domain of local y-edges

    // --------------------------------------------------------------
    // I believe the following is probably the most efficient approach
    // for sparse computations.  For data-parallel computations, the
    // evaluator will uncompress the patches and take brick views, which
    // provide the most efficient access.  If you are only performing
    // the computation on a small portion of cells, then the gains would
    // be outweighed by the act of copying the compressed value to all the
    // cells.
    //
    // The read function is used on the right hand side, because
    // operator() is forced to uncompress the patch just in case you want
    // to write to it.

    for(Interval<2>::iterator pos = domain.begin(); pos != domain.end(); ++pos)
    {
      Loc<2> edge = *pos;
      Loc<2> rightCell = edge;  // cell to right is same cell
      Loc<2> leftCell = edge - Loc<2>(1,0);
      Loc<2> topVert = edge + Loc<2>(0, 1);
      Loc<2> bottomVert = edge;

      local2(edge) =
        local0.read(rightCell) + local0.read(leftCell) +
        local1.read(topVert) + local1.read(bottomVert);
    }

    // This statement is optional, it tries to compress the patch after
    // we're done computing on it.  Since I used .read() for the local0 and 1
    // they remained in their original state. compress() can be expensive, so
    // it may not be worth trying unless space is really important.

    compress(local2);
  }

  tester.out() << "c0" << std::endl << c0 << std::endl;
  tester.out() << "c1" << std::endl << c1 << std::endl;
  tester.out() << "c2" << std::endl << c2 << std::endl;

  //------------------------------------------------------------------
  // Interfacing with a c-function:
  //
  // This example handles the corner cases, where the patches from a
  // cell centered field with no guard layers actually contain some
  // extra data.

  Pooma::blockAndEvaluate();

  for (i = 0; i < cb0.numPatchesLocal(); ++i)
  {
    Patch<CField_t>::Type_t local0 = cb0.patchLocal(i);
    Interval<2> physicalDomain = local0.physicalDomain();
    double *data;
    int size = physicalDomain.size();

    if (physicalDomain == local0.totalDomain())
    {
      uncompress(local0);
      data = &local0(physicalDomain.firsts());
      nonsense(data, size);
    }
    else
    {
      // In this case, the engine has extra storage even though the
      // field has the right domain. We copy it to a brick engine,
      // call the function and copy it back.  No uncompress is required,
      // since the assignment will copy the compressed value into the
      // brick.

      // arrayView is a work-around.  Array = Field doesn't work at
      // the moment.

      Array<2, double, Brick> brick(physicalDomain);
      Array<2, double, CompressibleBrick> arrayView(local0.engine());
      brick = arrayView(physicalDomain);
      Pooma::blockAndEvaluate();
      data = &brick(Loc<2>(0));
      nonsense(data, size);
      arrayView(physicalDomain) = brick;

      // Note that we don't need a blockAndEvaluate here, since an iterate has
      // been spawned to perform the copy.
    }

    // If you want to try compress(local0) here, you should do blockAndEvaluate
    // first in case the local0 = brick hasn't been executed yet.
  }
      
  tester.out() << "cb0.all()" << std::endl << cb0 << std::endl;

  b2 = positions(b2).comp(0);

  RefCountedBlockPtr<double> block = pack(b2);

  // The following functions give you access to the raw data from pack.
  // Note that the lifetime of the data is managed by the RefCountedBlockPtr,
  // so when "block" goes out of scope, the data goes away.  (i.e. Don't write
  // a function where you return block.beginPointer().)

  double *start = block.beginPointer();  // start of the data
  double *end = block.endPointer();      // one past the end
  int size = block.size();               // size of the data

  tester.out() << Pooma::context() << ":" << block.size() << std::endl;

  unpack(b3, block);

  tester.out() << "b2" << std::endl << b2 << std::endl;
  tester.out() << "b3" << std::endl << b3 << std::endl;

  tester.check("pack, unpack", all(b2 == b3));

  int ret = tester.results("LocalPatch");
  Pooma::finalize();
  return ret;
}
Beispiel #5
0
/* The main control loop for the Future Missions feature.
 */
void Future(char plr)
{
    /** \todo the whole Future()-function is 500 >lines and unreadable */
    TRACE1("->Future(plr)");
    int MisNum = 0, DuraType = 0, MaxDur = 6;
    int setting = -1, prev_setting = -1;

    display::LegacySurface local(166, 9);
    display::LegacySurface local2(177, 197);
    vh = new display::LegacySurface(240, 90);

    unsigned int year = Data->Year;
    unsigned int season = Data->Season;
    TRACE3("--- Setting year=Year (%d), season=Season (%d)", year, season);

    SetParameters();
    MarsFlag = MarsInRange(year, season);
    JupiterFlag = JupiterInRange(year, season);
    SaturnFlag = SaturnInRange(year, season);

    while ((MisNum = FutureCheck(plr, 0)) != 5) {
        F1 = F2 = F3 = F4 = F5 = 0;

        for (int i = 0; i < 5; i++) {
            lock[i] = false;
            status[i] = 0;
        }

        keyHelpText = "k011";
        helpText = "i011";
        Pad = MisNum;
        DuraType = 0;
        MisType = 0;
        ClrFut(plr, MisNum);

        JointFlag = JointMissionOK(plr, MisNum); // initialize joint flag

        if (JointFlag == false) {
            F4 = 2;
            lock[4] = true;
            status[4] = 0;
        }

        DrawFuture(plr, MisType, MisNum);

        while (1) {
            key = 0;
            GetMouse();

            prev_setting = setting;
            setting = -1;

            // SEG determines the number of control points used in creating
            // the B-splines for drawing the mission flight path.
            // The more control points, the smoother the path should
            // appear.
            if (key == '-' && SEG > 1) {
                SEG--;
            } else if (key == '+' && SEG < 500) {
                SEG++;
            } else if (key >= 65 && key < Bub_Count + 65) {
                setting = key - 65;
            }

            // If the mouse is over one of the Mission Step bubbles,
            // display the step information.
            for (int i = 0; i < Bub_Count; i++) {
                if (x >= StepBub[i].x_cor && x <= StepBub[i].x_cor + 7 &&
                    y >= StepBub[i].y_cor && y <= StepBub[i].y_cor + 7) {
                    setting = i;
                    break;
                }
            }

            if (setting >= 0) {
                if (prev_setting < 0) {
                    local.copyFrom(display::graphics.legacyScreen(), 18, 186, 183, 194);
                }

                if (prev_setting != setting) {
                    ShBox(18, 186, 183, 194);
                    display::graphics.setForegroundColor(1);
                    MisStep(21, 192, Mev[setting].loc);
                }
            } else if (setting < 0 && prev_setting >= 0) {
                local.copyTo(display::graphics.legacyScreen(), 18, 186);
            }

            if (Mis.Dur <= V[MisType].E &&
                ((x >= 244 && y >= 5 && x <= 313 && y <= 17 && mousebuttons > 0) ||
                 key == K_ENTER)) {
                InBox(244, 5, 313, 17);
                WaitForMouseUp();

                if (key > 0) {
                    delay(300);
                }

                key = 0;
                OutBox(244, 5, 313, 17);

                // Copy the screen contents to a buffer. If the mission
                // requires a capsule to be assigned, a pop-up will be
                // created listing the options. Once the pop-up is
                // dismissed the screen may be redrawn from the buffer.
                local2.copyFrom(display::graphics.legacyScreen(), 74, 3, 250, 199);
                int NewType = V[MisType].X;
                Data->P[plr].Future[MisNum].Duration = DuraType;

                int Ok = HardCrewAssign(plr, MisNum, MisType, NewType);

                local2.copyTo(display::graphics.legacyScreen(), 74, 3);

                if (Ok == 1) {
                    Data->P[plr].Future[MisNum].Duration = DuraType;
                    break;        // return to launchpad loop
                } else {
                    ClrFut(plr, MisNum);
                    continue;
                }
            } else if ((x >= 43 && y >= 74 && x <= 53 && y <= 82 && mousebuttons > 0) ||
                       key == '!') { // Duration restriction lock
                lock[0] = (! lock[0]);

                if (lock[0] == true) {
                    InBox(43, 74, 53, 82);
                    PlaceRX(1);
                    F5 = (status[0] == 0) ? -1 : status[0];
                } else {
                    OutBox(43, 74, 53, 82);
                    ClearRX(1);
                    F5 = status[0] = 0;
                }

                WaitForMouseUp();

            } else if (lock[0] != true &&
                       ((x >= 5 && y >= 49 && x <= 53 && y <= 72 && mousebuttons > 0) ||
                        key == '1')) { // Duration toggle
                InBox(5, 49, 53, 72);

                if (DuraType == MaxDur) {
                    DuraType = 0;
                } else {
                    DuraType++;
                }

                Data->P[plr].Future[MisNum].Duration = DuraType;

                if (DuraType == 0) {
                    Toggle(5, 0);
                } else if (DuraType == 1) {
                    Toggle(5, 1);
                }

                if (DuraType != 0) {
                    draw_Pie(DuraType);
                }

                status[0] = DuraType;

                WaitForMouseUp();

                display::graphics.setForegroundColor(34);
                OutBox(5, 49, 53, 72);
            } else if ((x >= 5 && y >= 74 && x <= 41 && y <= 82 && mousebuttons > 0) ||
                       (key == K_ESCAPE)) { // Reset mission selection
                InBox(5, 74, 41, 82);

                WaitForMouseUp();

                MisType = 0;

                DuraType = F1 = F2 = F3 = F4 = F5 = 0;

                for (int i = 0; i < 5; i++) {
                    lock[i] = false;
                    status[i] = 0;
                }

                if (JointFlag == false) {
                    F4 = 2;
                    lock[4] = true;
                    InBox(191, 74, 201, 82);
                    TogBox(166, 49, 1);
                } else {
                    OutBox(191, 74, 201, 82);
                }

                OutBox(5, 49, 53, 72);
                OutBox(43, 74, 53, 82);
                OutBox(80, 74, 90, 82);
                OutBox(117, 74, 127, 82);
                OutBox(154, 74, 164, 82);

                ClrFut(plr, MisNum);
                Missions(plr, 8, 37, MisType, 1);
                GetMinus(plr);
                OutBox(5, 74, 41, 82);

            } else if ((x >= 80 && y >= 74 && x <= 90 && y <= 82 && mousebuttons > 0) ||
                       key == '@') { // Docking restriction lock
                lock[1] = (! lock[1]);

                if (lock[1] == true) {
                    InBox(80, 74, 90, 82);
                    PlaceRX(2);
                } else {
                    OutBox(80, 74, 90, 82);
                    ClearRX(2);
                }

                if ((status[1] == 0) && (lock[1] == true)) {
                    F1 = 2;
                } else if ((status[1] == 1) && (lock[1] == true)) {
                    F1 = 1;
                } else {
                    F1 = 0;
                }

                WaitForMouseUp();

            } else if (lock[1] == false &&
                       (((x >= 55 && y >= 49 && x <= 90 && y <= 82) && mousebuttons > 0) ||
                        key == '2')) { // Docking toggle
                TogBox(55, 49, 1);

                if (status[1] == 0) {
                    Toggle(1, 1);
                } else {
                    Toggle(1, 0);
                }

                status[1] = abs(status[1] - 1);
                WaitForMouseUp();
                TogBox(55, 49, 0);

            } else if ((x >= 117 && y >= 74 && x <= 127 && y <= 82 && mousebuttons > 0) ||
                       key == '#') { // EVA Restriction button
                lock[2] = (! lock[2]);

                if (lock[2] == true) {
                    InBox(117, 74, 127, 82);
                    PlaceRX(3);
                } else {
                    OutBox(117, 74, 127, 82);
                    ClearRX(3);
                }

                if ((status[2] == 0) && (lock[2] == true)) {
                    F2 = 2;
                } else if ((status[2] == 1) && (lock[2] == true)) {
                    F2 = 1;
                } else {
                    F2 = 0;
                }

                WaitForMouseUp();

            } else if (lock[2] == false &&
                       ((x >= 92 && y >= 49 && x <= 127 && y <= 82 && mousebuttons > 0) ||
                        key == '3')) { // EVA toggle
                TogBox(92, 49, 1);

                if (status[2] == 0) {
                    Toggle(2, 1);
                } else {
                    Toggle(2, 0);
                }

                status[2] = abs(status[2] - 1);
                WaitForMouseUp();
                TogBox(92, 49, 0);

            } else if ((x >= 154 && y >= 74 && x <= 164 && y <= 82 && mousebuttons > 0) ||
                       key == '$') { // Lunar Module Restriction button
                lock[3] = (! lock[3]);

                if (lock[3] == true) {
                    InBox(154, 74, 164, 82);
                    PlaceRX(4);
                } else {
                    OutBox(154, 74, 164, 82);
                    ClearRX(4);
                }

                if ((status[3] == 0) && (lock[3] == true)) {
                    F3 = 2;
                } else if ((status[3] == 1) && (lock[3] == true)) {
                    F3 = 1;
                } else {
                    F3 = 0;
                }

                WaitForMouseUp();

            } else if (lock[3] == false &&
                       ((x >= 129 && y >= 49 && x <= 164 && y <= 82 && mousebuttons > 0) ||
                        key == '4')) { // LEM toggle
                TogBox(129, 49, 1);

                if (status[3] == 0) {
                    Toggle(3, 1);
                } else {
                    Toggle(3, 0);
                }

                status[3] = abs(status[3] - 1);
                WaitForMouseUp();
                TogBox(129, 49, 0);

            } else if (JointFlag == true &&
                       ((x > 191 && y >= 74 && x <= 201 && y <= 82 && mousebuttons > 0) ||
                        key == '%')) { // Joint Mission Restriction button
                lock[4] = (! lock[4]);

                if (lock[4] == true) {
                    InBox(191, 74, 201, 82);
                    PlaceRX(5);
                } else {
                    OutBox(191, 74, 201, 82);
                    ClearRX(5);
                }

                if ((status[4] == 0) && (lock[4] == true)) {
                    F4 = 2;
                } else if ((status[4] == 1) && (lock[4] == true)) {
                    F4 = 1;
                } else {
                    F4 = 0;
                }

                WaitForMouseUp();

            } else if (lock[4] == false && JointFlag == true &&
                       ((x >= 166 && y >= 49 && x <= 201 && y <= 82 && mousebuttons > 0) ||
                        key == '5')) { // Joint Mission
                TogBox(166, 49, 1);
                status[4] = abs(status[4] - 1);

                if (status[4] == 0) {
                    Toggle(4, 1);
                } else {
                    Toggle(4, 0);
                }

                WaitForMouseUp();
                TogBox(166, 49, 0);

            } else if ((x >= 5 && y >= 84 && x <= 16 && y <= 130 && mousebuttons > 0) ||
                       (key == UP_ARROW)) {
                // Scroll up among Mission Types
                InBox(5, 84, 16, 130);

                for (int i = 0; i < 50; i++) {
                    key = 0;
                    GetMouse();
                    delay(10);

                    if (mousebuttons == 0) {
                        MisType = UpSearchRout(MisType, plr);
                        Data->P[plr].Future[MisNum].MissionCode = MisType;
                        i = 51;
                    }
                }

                // Keep scrolling while mouse/key is held down.
                while (mousebuttons == 1 || key == UP_ARROW) {
                    MisType = UpSearchRout(MisType, plr);
                    Data->P[plr].Future[MisNum].MissionCode = MisType;
                    Missions(plr, 8, 37, MisType, 3);
                    delay(100);
                    key = 0;
                    GetMouse();
                }

                Missions(plr, 8, 37, MisType, 3);
                DuraType = status[0];
                OutBox(5, 84, 16, 130);
            } else if ((x >= 5 && y >= 132 && x < 16 && y <= 146 && mousebuttons > 0) ||
                       (key == K_SPACE)) {
                // Turn on Mission Steps display
                InBox(5, 132, 16, 146);
                WaitForMouseUp();
                delay(50);
                MisType = Data->P[plr].Future[MisNum].MissionCode;
                assert(0 <= MisType);

                if (MisType != 0) {
                    Missions(plr, 8, 37, MisType, 1);
                } else {
                    Missions(plr, 8, 37, MisType, 3);
                }

                OutBox(5, 132, 16, 146);
            } else if ((x >= 5 && y >= 148 && x <= 16 && y <= 194 && mousebuttons > 0) ||
                       (key == DN_ARROW)) {
                // Scroll down among Mission Types
                InBox(5, 148, 16, 194);

                for (int i = 0; i < 50; i++) {
                    key = 0;
                    GetMouse();
                    delay(10);

                    if (mousebuttons == 0) {
                        MisType = DownSearchRout(MisType, plr);
                        Data->P[plr].Future[MisNum].MissionCode = MisType;
                        i = 51;
                    }

                }

                // Keep scrolling while mouse/key is held down.
                while (mousebuttons == 1 || key == DN_ARROW) {
                    MisType = DownSearchRout(MisType, plr);
                    Data->P[plr].Future[MisNum].MissionCode = MisType;
                    Missions(plr, 8, 37, MisType, 3);
                    delay(100);
                    key = 0;
                    GetMouse();
                }

                Missions(plr, 8, 37, MisType, 3);
                DuraType = status[0];
                OutBox(5, 148, 16, 194);
            }
        }                              // Input while loop
    }                              // Launch pad selection loop

    delete vh;
    vh = NULL;
    TRACE1("<-Future()");
}