Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

mainDraw.cpp

/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-1-0-0/engines/cruise/mainDraw.cpp $
 * $Id: mainDraw.cpp 44864 2009-10-10 05:33:45Z dreammaster $
 *
 */

#include "cruise/cruise_main.h"
#include "cruise/polys.h"
#include "common/endian.h"
#include "common/util.h"

namespace Cruise {

struct autoCellStruct {
      struct autoCellStruct *next;
      short int ovlIdx;
      short int objIdx;
      short int type;
      short int newValue;
      cellStruct *pCell;
};

autoCellStruct autoCellHead;

void addAutoCell(int overlayIdx, int idx, int type, int newVal, cellStruct *pObject) {
      autoCellStruct *pNewEntry;

      pNewEntry = new autoCellStruct;

      pNewEntry->next = autoCellHead.next;
      autoCellHead.next = pNewEntry;

      pNewEntry->ovlIdx = overlayIdx;
      pNewEntry->objIdx = idx;
      pNewEntry->type = type;
      pNewEntry->newValue = newVal;
      pNewEntry->pCell = pObject;
}

void freeAutoCell(void) {
      autoCellStruct *pCurrent = autoCellHead.next;

      while (pCurrent) {
            autoCellStruct *next = pCurrent->next;

            if (pCurrent->type == 5) {
                  objInit(pCurrent->ovlIdx, pCurrent->objIdx, pCurrent->newValue);
            } else {
                  setObjectPosition(pCurrent->ovlIdx, pCurrent->objIdx, pCurrent->type, pCurrent->newValue);
            }

            if (pCurrent->pCell->animWait < 0) {
                  objectParamsQuery params;

                  getMultipleObjectParam(pCurrent->ovlIdx, pCurrent->objIdx, &params);

                  pCurrent->pCell->animCounter = params.state2 - 1;
            }

            delete pCurrent;

            pCurrent = next;
      }
}

void calcRGB(uint8* pColorSrc, uint8* pColorDst, int* offsetTable) {
      for (unsigned long int i = 0; i < 3; i++) {
            int color = *(pColorSrc++);
            int offset = offsetTable[i];

            color += offset;
            if (color < 0)
                  color = 0;
            if (color > 0xFF)
                  color = 0xFF;

            *(pColorDst++) = (uint8)color;
      }
}

void fadeIn() {
      for (long int i = 256; i >= 0; i -= 32) {
            for (long int j = 0; j < 256; j++) {
                  int offsetTable[3];
                  offsetTable[0] = -i;
                  offsetTable[1] = -i;
                  offsetTable[2] = -i;
                  calcRGB(&palScreen[masterScreen][3*j], &workpal[3*j], offsetTable);
            }
            gfxModuleData_setPal256(workpal);

            gfxModuleData_updatePalette();
            gfxModuleData_updateScreen();
      }

      for (long int j = 0; j < 256; j++) {
            int offsetTable[3];
            offsetTable[0] = 0;
            offsetTable[1] = 0;
            offsetTable[2] = 0;
            calcRGB(&palScreen[masterScreen][3*j], &workpal[3*j], offsetTable);
      }

      gfxModuleData_setPal256(workpal);

      fadeFlag = 0;
      PCFadeFlag = 0;
}

void flipScreen(void) {
      if (switchPal) {
            for (unsigned long int i = 0; i < 256*3; i++) {
                  workpal[i] = palScreen[masterScreen][i];
            }
            switchPal = 0;
            gfxModuleData_setPal256(workpal);
      }

      SWAP(gfxModuleData.pPage00, gfxModuleData.pPage10);

      gfxModuleData_flipScreen();

      if (doFade) {
            fadeIn();
            doFade = 0;
      }
}

int spriteX1;
int spriteX2;
int spriteY1;
int spriteY2;

char *polyOutputBuffer;

void pixel(int x, int y, char color) {
      if (x >= 0 && x < 320 && y >= 0 && y < 200)
            polyOutputBuffer[320 * y + x] = color;
}

// this function checks if the dataPtr is not 0, else it retrives the data for X, Y, scale and DataPtr again (OLD: mainDrawSub1Sub1)
void flipPoly(int fileId, int16 *dataPtr, int scale, char** newFrame, int X, int Y, int *outX, int *outY, int *outScale) {
      if (*dataPtr == 0) {
            int16 offset;
            int16 newX;
            int16 newY;

            dataPtr ++;

            offset = (int16)READ_BE_UINT16(dataPtr);
            dataPtr++;

            newX = (int16)READ_BE_UINT16(dataPtr);
            dataPtr++;

            newY = (int16)READ_BE_UINT16(dataPtr);
            dataPtr++;

            offset += fileId;

            if (offset >= 0) {
                  if (filesDatabase[offset].resType == OBJ_TYPE_LINE && filesDatabase[offset].subData.ptr) {
                        dataPtr = (int16 *)filesDatabase[offset].subData.ptr;
                  }
            }

            scale = -scale;
            X -= newX;
            Y -= newY;
      }

      *newFrame = (char*)dataPtr;
      *outX = X;
      *outY = Y;
      *outScale = scale;
}

int upscaleValue(int value, int scale) {
      return (((value * scale) << 8) / 2);
}

int m_flipLeftRight;
int m_useSmallScale;
int m_lowerX;
int m_lowerY;
int m_coordCount;
int m_first_X;
int m_first_Y;
int m_scaleValue;
int m_color;

/* 
   FIXME: Whether intentional or not, the game often seems to use negative indexing
   of one or more of the arrays below and expects(?) to end up in the preceding one.
   This "worked" on many platforms so far, but on OSX apparently the buffers don't
   occupy contiguous memory, and this causes severe corruption and subsequent crashes.
   Since I'm not really familiar with how the strange drawing code is supposed to work,
   or whether this behaviour is intentional or not, the short-term fix is to allocate a big
   buffer and setup pointers within it.  This fixes the crashes I'm seeing without causing any
   (visual) side-effects.
   If anyone wants to look, this is easily reproduced by starting the game and examining the rug.
   drawPolyMode1() will then (indirectly) negatively index polyBuffer4.   Good luck!
*/

//int16 DIST_3D[512];
//int16 polyBuffer2[512];
//int16 XMIN_XMAX[404];
//int16 polyBuffer4[512];

int16 bigPolyBuf[512 + 512 + 404 + 512];  /* consolidates the 4 separate buffers above */

//set up the replacement index pointers.
int16 *DIST_3D = &bigPolyBuf[0];
int16 *polyBuffer2 = &bigPolyBuf[512];
int16 *XMIN_XMAX = &bigPolyBuf[512 + 512];
int16 *polyBuffer4 = &bigPolyBuf[512 + 512 + 404];




// this function fills the sizeTable for the poly (OLD: mainDrawSub1Sub2)
void getPolySize(int positionX, int positionY, int scale, int sizeTable[4], unsigned char *dataPtr) {
      int upperBorder;
      int lowerBorder;
      m_flipLeftRight = 0;

      if (scale < 0) {        // flip left right
            m_flipLeftRight = 1;
            scale = -scale;
      }
      // X1

      upperBorder = *(dataPtr + 3);

      if (m_flipLeftRight) {
            upperBorder = -upperBorder;
      }

      upperBorder = (upscaleValue(upperBorder, scale) + 0x8000) >> 16;
      upperBorder = -upperBorder;
      lowerBorder = upperBorder;

      // X2

      upperBorder = *(dataPtr + 1);
      upperBorder -= *(dataPtr + 3);

      if (m_flipLeftRight) {
            upperBorder = -upperBorder;
      }

      upperBorder = (upscaleValue(upperBorder, scale) + 0x8000) >> 16;

      if (upperBorder < lowerBorder) {    // exchange borders if lower > upper
            SWAP(upperBorder, lowerBorder);
      }

      sizeTable[0] = lowerBorder + positionX;   // left
      sizeTable[1] = upperBorder + positionX;   // right

      // Y1

      upperBorder = *(dataPtr + 4);
      upperBorder = (upscaleValue(upperBorder, scale) + 0x8000) >> 16;
      upperBorder = -upperBorder;
      lowerBorder = upperBorder;

      // Y2

      upperBorder = *(dataPtr + 2);
      upperBorder -= *(dataPtr + 4);
      upperBorder = (upscaleValue(upperBorder, scale) + 0x8000) >> 16;

      if (upperBorder < lowerBorder) {    // exchange borders if lower > upper
            SWAP(upperBorder, lowerBorder);
      }

      sizeTable[2] = lowerBorder + positionY;   // bottom
      sizeTable[3] = upperBorder + positionY;   // top
}

int nbseg;
int16 nbligne;

void blitPolyMode1(char *dest, char *pMask, int16 * buffer, char color) {
      int Y = XMIN_XMAX[0];

      for (int i = 0; i < nbligne; i++) {
            int currentY = Y + i;
            int XMIN = XMIN_XMAX[1+i*2];
            int XMAX = XMIN_XMAX[1+i*2+1];

            for (int x = XMIN; x <= XMAX; x++) {
                  if (testMask(x, currentY, (unsigned char*)pMask, 40)) {
                        *(dest + currentY * 320 + x) = color;
                  }
            }
            //line(XMIN, currentY, XMAX, currentY, color);
      }
}

void blitPolyMode2(char *dest, int16 * buffer, char color) {
      int Y = XMIN_XMAX[0];

      for (int i = 0; i < nbligne; i++) {
            int currentY = Y + i;
            int XMIN = XMIN_XMAX[1+i*2];
            int XMAX = XMIN_XMAX[1+i*2+1];

            for (int x = XMIN; x <= XMAX; x++) {
                  *(dest + currentY * 320 + x) = color;
            }
      }
}

int polyXMin;
int polyXMax;
int polyYMax;
int polyYMin;

int16 *A2ptr;



void buildSegment(void) {
      int16* pOut = XMIN_XMAX;

      if ((polyXMin >= 320) || (polyXMax < 0) || (polyYMax < 0) || (polyYMin >= 200)) {
            XMIN_XMAX[0] = -1;
            nbligne = -1;
            return;
      }

      if (polyYMin == polyYMax) { // line
            *(pOut++) = polyYMin; // store initial Y

            int cx = nbseg - 1;
            int16* pIn = A2ptr;

            int XLeft;
            int XRight;

            XLeft = XRight = *pIn; // init to first X
            pIn += 2;

            do {
                  int X = *pIn;
                  if (XLeft > X)
                        XLeft = X;
                  if (XRight < X)
                        XRight = X;
                  pIn += 2;
            } while (--cx);

            // now store left and right coordinates in XMIN_XMAX

            int XMin = XLeft;
            int XMax = XRight;

            if (XLeft < 0)
                  XMin = 0;

            if (XRight >= 320)
                  XMax = 319;

            *(pOut++) = XMin;
            *(pOut++) = XMax;
            *(pOut++) = -1;

            nbligne = 1;
            return;
      }

      // true polygon

      int ydep;

      if (polyYMin < 0)
            ydep = 0;
      else
            ydep = polyYMin;

      int yfin;

      if (polyYMax > 199)
            yfin = 199;
      else
            yfin = polyYMax;

      nbligne = yfin - ydep + 1;

      int16* ptrMini = XMIN_XMAX + 1;
      XMIN_XMAX[0] = ydep;

      int16* ptrMax = XMIN_XMAX + ((yfin - ydep) * 2) + 1;
      ptrMax[2] = -1; // mark the end

      // init table with default values
      int16* si = XMIN_XMAX + 1;
      int tempCount = nbligne;
      do {
            si[0] = 5000;
            si[1] = -5000;
            si += 2;
      } while (--tempCount);

      int16* di = A2ptr;
      int segCount = nbseg;

      do {
            int X2 = di[2];
            int X1 = di[0];
            int Y2 = di[3];
            int Y1 = di[1];


            int tempAX = Y1;
            int tempDX = Y2;
            if (tempAX > tempDX) {
                  // swap
                  tempAX = Y2;
                  tempDX = Y1;
            }

            // is segment on screen ?
            if (!((tempAX > 199) || (tempDX < 0))) {
                  int dx = Y1;
                  int cx = X2 - X1;
                  if (cx == 0) {
                        // vertical line
                        int CX = X2;
                        if (CX < 0)
                              CX = 0;

                        int DX = X2;
                        if (DX > 319)
                              DX = 319;

                        int16* BX = XMIN_XMAX + (Y2 - ydep) * 2 + 1;
                        int16* DI = XMIN_XMAX + (Y1 - ydep) * 2 + 1;

                        if (Y2 >= Y1) {
                              SWAP(BX, DI);
                        }

                        do {
                              if ((BX <= ptrMax) && (BX >= ptrMini)) { // are we in screen ?
                                    if (CX < BX[0])
                                          BX[0] = CX;

                                    if (DX > BX[1])
                                          BX[1] = DX;
                              }

                              BX += 2;
                        } while (BX <= DI);
                  } else {
                        if (cx < 0) {
                              cx = -cx;
                              dx = Y2;

                              SWAP(X1, X2);
                              SWAP(Y1, Y2);
                        }
                        // swap again ?
                        SWAP(X1, X2);

                        int patchAdd = 2;

                        int dy = Y2 - Y1;

                        if (dy == 0) {
                              // hline
                              int16* ptr = (Y1 - ydep) * 2 + XMIN_XMAX + 1;

                              if ((ptr <= ptrMax) && (ptr >= ptrMini)) { // are we in screen ?
                                    int CX = X1;
                                    if (CX < 0)
                                          CX = 0;

                                    int SI = X2;
                                    if (SI > 319)
                                          SI = 319;

                                    if (CX < ptr[0])
                                          ptr[0] = CX;

                                    if (SI > ptr[1])
                                          ptr[1] = SI;
                              }
                        } else {
                              if (dy < 0) {
                                    dy = -dy;
                                    patchAdd = -2;
                              }

                              int stepType = 0; // small DY <= DX

                              if (dy > cx) {
                                    stepType = 1; // DX < DY

                                    SWAP(dy, cx);
                              }
                              int patchinc1 = 2 * dy;

                              int d = 2 * dy - cx;
                              int bx = 2 * (dy - cx);

                              int patchinc2 = bx;

                              cx++; // cx is the number of pixels to trace

                              int16* ptr = (Y1 - ydep) * 2 + XMIN_XMAX + 1;

                              if (stepType == 0) {
                                    // small step
                                    int BP = X2;

                                    int SI = BP;
                                    if (SI < 0)
                                          SI = 0;
                                    int DX = BP;
                                    if (DX > 319)
                                          DX = 319;

                                    do {
                                          if ((ptr <= ptrMax) && (ptr >= ptrMini)) { // are we in screen ?
                                                if (SI < ptr[0])
                                                      ptr[0] = SI;

                                                if (DX > ptr[1])
                                                      ptr[1] = DX;
                                          }

                                          BP ++;

                                          // test limits
                                          SI = BP;
                                          if (SI < 0)
                                                SI = 0;
                                          DX = BP;
                                          if (DX > 319)
                                                DX = 319;

                                          if (d < 0) {
                                                d += patchinc1;
                                                if (cx == 1) {   // last ?
                                                      if ((ptr <= ptrMax) && (ptr >= ptrMini)) { // are we in screen ?
                                                            if (SI < ptr[0])
                                                                  ptr[0] = SI;

                                                            if (DX > ptr[1])
                                                                  ptr[1] = DX;
                                                      }
                                                }
                                          } else {
                                                d += patchinc2;
                                                ptr += patchAdd;
                                          }
                                    } while (--cx);
                              } else {
                                    // big step
                                    int BP = X2;

                                    int SI = BP;
                                    if (SI < 0)
                                          SI = 0;
                                    int DX = BP;
                                    if (DX > 319)
                                          DX = 319;

                                    do {
                                          if ((ptr <= ptrMax) && (ptr >= ptrMini)) { // are we in screen ?
                                                if (SI < ptr[0])
                                                      ptr[0] = SI;

                                                if (DX > ptr[1])
                                                      ptr[1] = DX;
                                          }

                                          ptr += patchAdd; // next line

                                          if (d < 0) {
                                                d += patchinc1;
                                          } else {
                                                d += patchinc2;
                                                BP ++;

                                                // test limits
                                                SI = BP;
                                                if (SI < 0)
                                                      SI = 0;
                                                DX = BP;
                                                if (DX > 319)
                                                      DX = 319;
                                          }
                                    } while (--cx);
                              }

                        }
                  }
            }

            di += 2;
      } while (--segCount);
}

unsigned char *drawPolyMode1(unsigned char *dataPointer, int linesToDraw) {
      int index;
      int16 *pBufferDest;

      pBufferDest = polyBuffer4 + nbseg * 2;
      nbseg = linesToDraw;
      A2ptr = polyBuffer4;
      index = *(dataPointer++);

      polyXMin = polyXMax = pBufferDest[-2] = pBufferDest[-2 + linesToDraw * 2] = polyBuffer2[index * 2];
      polyYMin = polyYMax = pBufferDest[-1] = pBufferDest[-1 + linesToDraw * 2] = polyBuffer2[(index * 2) + 1];

      linesToDraw--;

      pBufferDest -= 2;

      A2ptr = pBufferDest;

      do {
            int value;

            index = *(dataPointer++);
            value = pBufferDest[-2] = pBufferDest[-2 + nbseg * 2] = polyBuffer2[index * 2];

            if (value < polyXMin) {
                  polyXMin = value;
            }
            if (value > polyXMax) {
                  polyXMax = value;
            }

            value = pBufferDest[-1] = pBufferDest[-1 + nbseg * 2] = polyBuffer2[(index * 2) + 1];

            if (value < polyYMin) {
                  polyYMin = value;
            }
            if (value > polyYMax) {
                  polyYMax = value;
                  A2ptr = pBufferDest;
            }

            pBufferDest -= 2;

      } while (--linesToDraw);

      buildSegment();

      return dataPointer;
}

unsigned char *drawPolyMode2(unsigned char *dataPointer, int linesToDraw) {
      int index;
      int16 *pBufferDest;

      pBufferDest = polyBuffer4;
      nbseg = linesToDraw;
      A2ptr = polyBuffer4;
      index = *(dataPointer++);

      polyXMin = polyXMax = pBufferDest[0] = pBufferDest[linesToDraw * 2] = polyBuffer2[index * 2];
      polyYMin = polyYMax = pBufferDest[1] = pBufferDest[linesToDraw * 2 + 1] = polyBuffer2[(index * 2) + 1];

      linesToDraw--;

      pBufferDest += 2;

      do {
            int value;

            index = *(dataPointer++);
            value = pBufferDest[0] = pBufferDest[nbseg * 2] = polyBuffer2[index * 2];

            if (value < polyXMin) {
                  polyXMin = value;
            }
            if (value > polyXMax) {
                  polyXMax = value;
            }

            value = pBufferDest[1] = pBufferDest[nbseg * 2 + 1] = polyBuffer2[(index * 2) + 1];

            if (value < polyYMin) {
                  polyYMin = value;
            }
            if (value > polyYMax) {
                  polyYMax = value;
                  A2ptr = pBufferDest;
            }

            pBufferDest += 2;

      } while (--linesToDraw);

      buildSegment();

      return dataPointer;
}

// this function builds the poly model and then calls the draw functions (OLD: mainDrawSub1Sub5)
void buildPolyModel(int positionX, int positionY, int scale, char *pMask, char *destBuffer, char *dataPtr) {
      int counter = 0;  // numbers of coordinates to process
      int startX = 0;         // first X in model
      int startY = 0;         // first Y in model
      int x = 0;        // current X
      int y = 0;        // current Y
      int offsetXinModel = 0; // offset of the X value in the model
      int offsetYinModel = 0; // offset of the Y value in the model
      unsigned char *dataPointer = (unsigned char *)dataPtr;
      int16 *ptrPoly_1_Buf = DIST_3D;
      int16 *ptrPoly_2_Buf;
      polyOutputBuffer = destBuffer;      // global

      m_flipLeftRight = 0;
      m_useSmallScale = 0;
      m_lowerX = *(dataPointer + 3);
      m_lowerY = *(dataPointer + 4);

      if (scale < 0) {
            scale = -scale;   // flip left right
            m_flipLeftRight = 1;
      }

      if (scale < 0x180) {    // If scale is smaller than 384
            m_useSmallScale = 1;
            m_scaleValue = scale << 1;    // double scale
      } else {
            m_scaleValue = scale;
      }

      dataPointer += 5;

      m_coordCount = (*(dataPointer++)) + 1;    // original uses +1 here but its later substracted again, we could skip it
      m_first_X = *(dataPointer);
      dataPointer++;
      m_first_Y = *(dataPointer);
      dataPointer++;
      startX = m_lowerX - m_first_X;
      startY = m_lowerY - m_first_Y;

      if (m_useSmallScale) {
            startX >>= 1;
            startY >>= 1;
      }

      if (m_flipLeftRight) {
            startX = -startX;
      }

      /*
       * NOTE:
       *
       * The original code continues here with using X, Y instead of startX and StartY.
       *
       * Original code:
       * positionX -= (upscaleValue(startX, m_scaleValue) + 0x8000) >> 16;
       * positionY -= (upscaleValue(startX, m_scaleValue) + 0x8000) >> 16;
       */

      // get coordinates from data

      startX = positionX - ((upscaleValue(startX, m_scaleValue) + 0x8000) >> 16);
      startY = positionY - ((upscaleValue(startY, m_scaleValue) + 0x8000) >> 16);

      ptrPoly_1_Buf[0] = 0;
      ptrPoly_1_Buf[1] = 0;
      ptrPoly_1_Buf += 2;
      counter = m_coordCount - 1 - 1;     // skip the first pair, we already have the values

      // dpbcl0
      do {
            x = *(dataPointer) - m_first_X;
            dataPointer++;
            if (m_useSmallScale) {  // shrink all coordinates by factor 2 if a scale smaller than 384 is used
                  x >>= 1;
            }
            ptrPoly_1_Buf[0] = offsetXinModel - x;
            ptrPoly_1_Buf++;
            offsetXinModel = x;

            y = *(dataPointer) - m_first_Y;
            dataPointer++;
            if (m_useSmallScale) {
                  y >>= 1;
            }
            ptrPoly_1_Buf[0] = -(offsetYinModel - y);
            ptrPoly_1_Buf++;
            offsetYinModel = y;

      } while (--counter);

      // scale and adjust coordinates with offset (using two polybuffers by doing that)
      ptrPoly_2_Buf = DIST_3D;
      ptrPoly_1_Buf = polyBuffer2;
      counter = m_coordCount - 1;   // reset counter // process first pair two
      int m_current_X = 0;
      int m_current_Y = 0;

      do {
            x = ptrPoly_2_Buf[0];

            if (m_flipLeftRight == 0) {
                  x = -x;
            }
            //////////////////

            m_current_X += upscaleValue(x, m_scaleValue);
            ptrPoly_1_Buf[0] = ((m_current_X + 0x8000) >> 16) + startX; // adjust X value with start offset

            m_current_Y += upscaleValue(ptrPoly_2_Buf[1], m_scaleValue);
            ptrPoly_1_Buf[1] = ((m_current_Y + 0x8000) >> 16) + startY; // adjust Y value with start offset

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

            ptrPoly_1_Buf += 2;
            ptrPoly_2_Buf += 2;

      } while (--counter);

      // position of the dataPointer is m_coordCount * 2

      int polygonCount = 0;

      do {
            int linesToDraw = *dataPointer++;

            if (linesToDraw > 1) {  // if value not zero
                  uint16 minimumScale;

                  m_color = *dataPointer; // color
                  dataPointer += 2;

                  minimumScale = READ_BE_UINT16(dataPointer);
                  dataPointer += 2;

                  if ((minimumScale <= scale)) {
                        if (m_flipLeftRight) {
                              drawPolyMode1((unsigned char *)dataPointer, linesToDraw);
                        } else {
                              drawPolyMode2((unsigned char *)dataPointer, linesToDraw);
                        }

                        if (destBuffer) {
                              if (pMask) {
                                    blitPolyMode1(destBuffer, pMask, polyBuffer4, m_color & 0xFF);
                              } else {
                                    blitPolyMode2(destBuffer, polyBuffer4, m_color & 0xFF);
                              }
                        }
                  }

                  dataPointer += linesToDraw;
            } else {
                  dataPointer += 4;
            }

            polygonCount ++;
      } while (*dataPointer != 0xFF);
}

bool findPoly(char* dataPtr, int positionX, int positionY, int scale, int mouseX, int mouseY) {
      int counter = 0;  // numbers of coordinates to process
      int startX = 0;         // first X in model
      int startY = 0;         // first Y in model
      int x = 0;        // current X
      int y = 0;        // current Y
      int offsetXinModel = 0; // offset of the X value in the model
      int offsetYinModel = 0; // offset of the Y value in the model
      unsigned char *dataPointer = (unsigned char *)dataPtr;
      int16 *ptrPoly_1_Buf = DIST_3D;
      int16 *ptrPoly_2_Buf;

      m_flipLeftRight = 0;
      m_useSmallScale = 0;
      m_lowerX = *(dataPointer + 3);
      m_lowerY = *(dataPointer + 4);

      if (scale < 0) {
            scale = -scale;   // flip left right
            m_flipLeftRight = 1;
      }

      if (scale < 0x180) {    // If scale is smaller than 384
            m_useSmallScale = 1;
            m_scaleValue = scale << 1;    // double scale
      } else {
            m_scaleValue = scale;
      }

      dataPointer += 5;

      m_coordCount = (*(dataPointer++)) + 1;    // original uses +1 here but its later substracted again, we could skip it
      m_first_X = *(dataPointer);
      dataPointer++;
      m_first_Y = *(dataPointer);
      dataPointer++;
      startX = m_lowerX - m_first_X;
      startY = m_lowerY - m_first_Y;

      if (m_useSmallScale) {
            startX >>= 1;
            startY >>= 1;
      }

      if (m_flipLeftRight) {
            startX = -startX;
      }

      /*
       * NOTE:
       *
       * The original code continues here with using X, Y instead of startX and StartY.
       *
       * Original code:
       * positionX -= (upscaleValue(startX, m_scaleValue) + 0x8000) >> 16;
       * positionY -= (upscaleValue(startX, m_scaleValue) + 0x8000) >> 16;
       */

      // get coordinates from data

      startX = positionX - ((upscaleValue(startX, m_scaleValue) + 0x8000) >> 16);
      startY = positionY - ((upscaleValue(startY, m_scaleValue) + 0x8000) >> 16);

      ptrPoly_1_Buf[0] = 0;
      ptrPoly_1_Buf[1] = 0;
      ptrPoly_1_Buf += 2;
      counter = m_coordCount - 1 - 1;     // skip the first pair, we already have the values

      // dpbcl0
      do {
            x = *(dataPointer) - m_first_X;
            dataPointer++;
            if (m_useSmallScale) {  // shrink all coordinates by factor 2 if a scale smaller than 384 is used
                  x >>= 1;
            }
            ptrPoly_1_Buf[0] = offsetXinModel - x;
            ptrPoly_1_Buf++;
            offsetXinModel = x;

            y = *(dataPointer) - m_first_Y;
            dataPointer++;
            if (m_useSmallScale) {
                  y >>= 1;
            }
            ptrPoly_1_Buf[0] = -(offsetYinModel - y);
            ptrPoly_1_Buf++;
            offsetYinModel = y;

      } while (--counter);

      // scale and adjust coordinates with offset (using two polybuffers by doing that)
      ptrPoly_2_Buf = DIST_3D;
      ptrPoly_1_Buf = polyBuffer2;
      counter = m_coordCount - 1;   // reset counter // process first pair two
      int m_current_X = 0;
      int m_current_Y = 0;

      do {
            x = ptrPoly_2_Buf[0];

            if (m_flipLeftRight == 0) {
                  x = -x;
            }
            //////////////////

            m_current_X += upscaleValue(x, m_scaleValue);
            ptrPoly_1_Buf[0] = ((m_current_X + 0x8000) >> 16) + startX; // adjust X value with start offset

            m_current_Y += upscaleValue(ptrPoly_2_Buf[1], m_scaleValue);
            ptrPoly_1_Buf[1] = ((m_current_Y + 0x8000) >> 16) + startY; // adjust Y value with start offset

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

            ptrPoly_1_Buf += 2;
            ptrPoly_2_Buf += 2;

      } while (--counter);

      // position of the dataPointer is m_coordCount * 2

      int polygonCount = 0;

      do {
            int linesToDraw = *dataPointer++;

            if (linesToDraw > 1) {  // if value not zero
                  uint16 minimumScale;

                  m_color = *dataPointer; // color
                  dataPointer += 2;

                  minimumScale = READ_BE_UINT16(dataPointer);
                  dataPointer += 2;

                  if ((minimumScale <= scale)) {
                        if (m_flipLeftRight) {
                              drawPolyMode1((unsigned char *)dataPointer, linesToDraw);
                        } else {
                              drawPolyMode2((unsigned char *)dataPointer, linesToDraw);
                        }

                        int polygonYMin = XMIN_XMAX[0];
                        int polygonYMax = polygonYMin + nbligne;

                        if ((mouseY >= polygonYMin) && (mouseY < polygonYMax)) {
                              int polygonLineNumber = mouseY - polygonYMin;

                              int XMIN = XMIN_XMAX[1+polygonLineNumber*2];
                              int XMAX = XMIN_XMAX[1+polygonLineNumber*2+1];

                              if ((mouseX >= XMIN) && (mouseX <= XMAX))
                                    return true;
                        }
                  }

                  dataPointer += linesToDraw;
            } else {
                  dataPointer += 4;
            }

            polygonCount ++;
      } while (*dataPointer != 0xFF);

      return false;
}

void clearMaskBit(int x, int y, unsigned char* pData, int stride) {
      unsigned char* ptr = y * stride + x / 8 + pData;

      unsigned char bitToTest = 0x80 >> (x & 7);

      *(ptr) &= ~bitToTest;
}


void drawMask(unsigned char* workBuf, int wbWidth, int wbHeight, unsigned char* pMask, int maskWidth, int maskHeight, int maskX, int maskY, int passIdx) {
      for (int y = 0; y < maskHeight; y++) {
            for (int x = 0; x < maskWidth*8; x++) {
                  if (testMask(x, y, pMask, maskWidth)) {
                        int destX = maskX + x;
                        int destY = maskY + y;

                        if ((destX >= 0) && (destX < wbWidth*8) && (destY >= 0) && (destY < wbHeight))
                              clearMaskBit(destX, destY, workBuf, wbWidth);
                  }
            }
      }
}

unsigned char polygonMask[(320*200)/8];

// draw poly sprite (OLD: mainDrawSub1)
void mainDrawPolygons(int fileIndex, cellStruct *plWork, int X, int scale, int Y, char *destBuffer, char *dataPtr) {
      int newX;
      int newY;
      int newScale;
      char *newFrame;

      int var_8;        // unused

      int sizeTable[4]; // 0 = left, 1 = right, 2 = bottom, 3 = top

      // this function checks if the dataPtr is not 0, else it retrives the data for X, Y, scale and DataPtr again (OLD: mainDrawSub1Sub1)
      flipPoly(fileIndex, (int16*)dataPtr, scale, &newFrame, X, Y, &newX, &newY, &newScale);

      // this function fills the sizeTable for the poly (OLD: mainDrawSub1Sub2)
      getPolySize(newX, newY, newScale, sizeTable, (unsigned char*)newFrame);

      spriteX2 = sizeTable[0] - 2;  // left   border
      spriteX1 = sizeTable[1] + 18; // right  border
      spriteY2 = sizeTable[2] - 2;  // bottom border
      spriteY1 = sizeTable[3] + 2;  // top    border

      if (spriteX2 >= 320)
            return;
      if (spriteX1 < 0)
            return;
      if (spriteY2 >= 200)
            return;
      if (spriteY1 < 0)
            return;

      if (spriteX2 < 0) {
            spriteX2 = 0;
      }
      if (spriteX1 > 320) {
            spriteX1 = 320;
      }
      if (spriteY2 < 0) {
            spriteY2 = 0;
      }
      if (spriteY1 > 200) {
            spriteY1 = 200;
      }

      if (spriteX1 == spriteX2)
            return;
      if (spriteY1 == spriteY2)
            return;

      gfxModuleData_addDirtyRect(Common::Rect(spriteX2, spriteY2, spriteX1, spriteY1));

      var_8 = 0;

      memset(polygonMask, 0xFF, (320*200) / 8);

      int numPasses = 0;

      while (plWork) {
            if (plWork->type == OBJ_TYPE_BGMASK && plWork->freeze == 0) {
                  objectParamsQuery params;

                  getMultipleObjectParam(plWork->overlay, plWork->idx, &params);

                  int maskX = params.X;
                  int maskY = params.Y;
                  int maskFrame = params.fileIdx;

                  if (filesDatabase[maskFrame].subData.resourceType == OBJ_TYPE_BGMASK && filesDatabase[maskFrame].subData.ptrMask) {
                        drawMask(polygonMask, 40, 200, filesDatabase[maskFrame].subData.ptrMask, filesDatabase[maskFrame].width / 8, filesDatabase[maskFrame].height, maskX, maskY, numPasses++);
                  } else
                        if (filesDatabase[maskFrame].subData.resourceType == OBJ_TYPE_SPRITE && filesDatabase[maskFrame].subData.ptrMask) {
                              drawMask(polygonMask, 40, 200, filesDatabase[maskFrame].subData.ptrMask, filesDatabase[maskFrame].width / 8, filesDatabase[maskFrame].height, maskX, maskY, numPasses++);
                        }

            }

            plWork = plWork->next;
      }

      // this function builds the poly model and then calls the draw functions (OLD: mainDrawSub1Sub5)
      buildPolyModel(newX, newY, newScale, (char*)polygonMask, destBuffer, newFrame);
}

void drawMessage(const gfxEntryStruct *pGfxPtr, int globalX, int globalY, int width, int newColor, uint8 *ouputPtr) {
      // this is used for font only

      if (pGfxPtr) {
            uint8 *initialOuput;
            uint8 *output;
            int xp, yp;
            int x, y;
            const uint8 *ptr = pGfxPtr->imagePtr;
            int height = pGfxPtr->height;

            if (width > 310)
                  width = 310;
            if (width + globalX > 319)
                  globalX = 319 - width;
            if (globalY < 0)
                  globalY = 0;
            if (globalX < 0)
                  globalX = 0;

            if (globalY + pGfxPtr->height >= 198) {
                  globalY = 198 - pGfxPtr->height;
            }

            gfxModuleData_addDirtyRect(Common::Rect(globalX, globalY, globalX + width, globalY + height));

            initialOuput = ouputPtr + (globalY * 320) + globalX;

            for (yp = 0; yp < height; yp++) {
                  output = initialOuput + 320 * yp;
                  y = globalY + yp;

                  for (xp = 0; xp < pGfxPtr->width; xp++) {
                        x = globalX + xp;
                        uint8 color = *(ptr++);

                        if (color) {
                              if ((x >= 0) && (x < 320) && (y >= 0) && (y < 200)) {
                                    if (color == 1) {
                                          *output = (uint8) 0;
                                    } else {
                                          *output = (uint8) newColor;
                                    }
                              }
                        }
                        output++;
                  }
            }
      }
}

void drawSprite(int width, int height, cellStruct *currentObjPtr, const uint8 *dataIn, int ys, int xs, uint8 *output, const uint8 *dataBuf) {
      int x = 0;
      int y = 0;

      // Flag the given area as having been changed
      Common::Point ps = Common::Point(MAX(MIN(xs, 320), 0), MAX(MIN(ys, 200), 0));
      Common::Point pe = Common::Point(MAX(MIN(xs + width, 320), 0), MAX(MIN(ys + height, 200), 0));
      if ((ps.x != pe.x) && (ps.y != pe.y))
            // At least part of sprite is on-screen
            gfxModuleData_addDirtyRect(Common::Rect(ps.x, ps.y, pe.x, pe.y));

      cellStruct* plWork = currentObjPtr;
      int workBufferSize = height * (width / 8);

      unsigned char* workBuf = (unsigned char*)MemAlloc(workBufferSize);
      memcpy(workBuf, dataBuf, workBufferSize);

      int numPasses = 0;

      while (plWork) {
            if (plWork->type == OBJ_TYPE_BGMASK && plWork->freeze == 0) {
                  objectParamsQuery params;

                  getMultipleObjectParam(plWork->overlay, plWork->idx, &params);

                  int maskX = params.X;
                  int maskY = params.Y;
                  int maskFrame = params.fileIdx;

                  if (filesDatabase[maskFrame].subData.resourceType == OBJ_TYPE_BGMASK && filesDatabase[maskFrame].subData.ptrMask) {
                        drawMask(workBuf, width / 8, height, filesDatabase[maskFrame].subData.ptrMask, filesDatabase[maskFrame].width / 8, filesDatabase[maskFrame].height, maskX - xs, maskY - ys, numPasses++);
                  } else
                        if (filesDatabase[maskFrame].subData.resourceType == OBJ_TYPE_SPRITE && filesDatabase[maskFrame].subData.ptrMask) {
                              drawMask(workBuf, width / 8, height, filesDatabase[maskFrame].subData.ptrMask, filesDatabase[maskFrame].width / 8, filesDatabase[maskFrame].height, maskX - xs, maskY - ys, numPasses++);
                        }

            }

            plWork = plWork->next;
      }

      for (y = 0; y < height; y++) {
            for (x = 0; x < (width); x++) {
                  uint8 color = *dataIn++;

                  if ((x + xs) >= 0 && (x + xs) < 320 && (y + ys) >= 0 && (y + ys) < 200) {
                        if (testMask(x, y, workBuf, width / 8)) {
                              output[320 * (y + ys) + x + xs] = color;
                        }
                  }
            }
      }

      MemFree(workBuf);
}

#ifdef _DEBUG
void drawCtp(void) {
      /*    int i;

            if (ctp_walkboxTable) {
                  for (i = 0; i < 15; i++) {
                        uint16 *dataPtr = &ctp_walkboxTable[i * 40];
                        int type = walkboxColor[i];   // show different types in different colors

                        if (*dataPtr) {
                              int j;
                              fillpoly((short *)dataPtr + 1, *dataPtr, type);

                              for (j = 0; j < (*dataPtr - 1); j++) {
                                    line(dataPtr[1 + j * 2],
                                        dataPtr[1 + j * 2 + 1],
                                        dataPtr[1 + (j + 1) * 2],
                                        dataPtr[1 + (j + 1) * 2 + 1], 0);
                              }

                              line(dataPtr[1 + j * 2],
                                  dataPtr[1 + j * 2 + 1], dataPtr[1],
                                  dataPtr[2], 0);
                        }
                  }
            }*/
}
#endif

void drawMenu(menuStruct *pMenu) {
      if (pMenu == NULL)
            return;

      if (pMenu->numElements == 0)
            return;

      int hline = pMenu->gfx->height;
      int x = pMenu->x;
      int y = pMenu->y + hline;

      int numItemByLine = (199 - hline * 2) / hline;
      int nbcol = pMenu->numElements / numItemByLine;

      if (!nbcol) {
            nbcol++;

            if (y + pMenu->numElements*hline > 199 - hline) {
                  y = 200 - (pMenu->numElements * hline) - hline;
            }
      } else {
            if (pMenu->numElements % numItemByLine) {
                  nbcol++;
            }

            y = hline;
      }

      if (x > (320 - (nbcol*160)))
            x = 320 - (nbcol * 160);

      if (x < 0)
            x = 0;

      int wx = x + (nbcol - 1) * (160 / 2);

      if (wx <= 320 - 160) {
            drawMessage(pMenu->gfx, wx, y - hline, 160, titleColor, gfxModuleData.pPage10);
      }

      wx = x;
      int wy = y;
      int wc = 0;
      menuElementStruct* p1 = pMenu->ptrNextElement;

      while (p1) {
            gfxEntryStruct *p2 = p1->gfx;

            p1->x = wx;
            p1->y = wy;
            p1->varA = 160;

            int color;

            if (p1->selected) {
                  color = selectColor;
            } else {
                  if (p1->color != 255) {
                        color = p1->color;
                  } else {
                        color = itemColor;
                  }
            }

            if (wx <= (320 - 160)) {
                  drawMessage(p2, wx, wy, 160, color, gfxModuleData.pPage10);
            }

            wy += hline;
            wc ++;

            if (wc == numItemByLine) {
                  wc = 0;
                  wx += 160;
                  wy = y;
            }

            p1 = p1->next;
      }
}

int getValueFromObjectQuerry(objectParamsQuery *params, int idx) {
      switch (idx) {
      case 0:
            return params->X;
      case 1:
            return params->Y;
      case 2:
            return params->baseFileIdx;
      case 3:
            return params->fileIdx;
      case 4:
            return params->scale;
      case 5:
            return params->state;
      case 6:
            return params->state2;
      case 7:
            return params->nbState;
      }

      assert(0);

      return 0;
}

void mainDraw(int16 param) {
      uint8 *bgPtr;
      cellStruct *currentObjPtr;
      int16 currentObjIdx;
      int16 objX1 = 0;
      int16 objY1 = 0;
      int16 objZ1 = 0;
      int16 objX2 = 0;
      int16 objY2 = 0;
      int16 objZ2 = 0;
      int16 spriteHeight;

      /*if (PCFadeFlag) {
            return;
      }*/

      bgPtr = backgroundScreens[masterScreen];

      if (bgPtr) {
            gfxModuleData_gfxCopyScreen(bgPtr, gfxModuleData.pPage10);
            if (backgroundChanged[masterScreen]) {
                  backgroundChanged[masterScreen] = false;
                  switchBackground(bgPtr);
            }
      }

      autoCellHead.next = NULL;

      currentObjPtr = cellHead.next;

#ifdef _DEBUG
      /*    polyOutputBuffer = (char*)bgPtr;
            drawCtp(); */
#endif

      //-------------------------------------------------- PROCESS SPRITES -----------------------------------------//

      while (currentObjPtr) {
            if ((masterScreen == currentObjPtr->backgroundPlane) && (currentObjPtr->freeze == 0) && (currentObjPtr->type == OBJ_TYPE_SPRITE)) {
                  objectParamsQuery params;

                  currentObjIdx = currentObjPtr->idx;

                  if ((currentObjPtr->followObjectOverlayIdx != currentObjPtr->overlay) || (currentObjPtr->followObjectIdx != currentObjPtr->idx)) {
                        // Declaring this twice ?
                        // objectParamsQuery params;

                        getMultipleObjectParam(currentObjPtr->followObjectOverlayIdx, currentObjPtr->followObjectIdx, &params);

                        objX1 = params.X;
                        objY1 = params.Y;
                        objZ1 = params.fileIdx;
                  } else {
                        objX1 = 0;
                        objY1 = 0;
                        objZ1 = 0;
                  }

                  getMultipleObjectParam(currentObjPtr->overlay, currentObjIdx, &params);

                  objX2 = objX1 + params.X;
                  objY2 = objY1 + params.Y;
                  objZ2 = params.fileIdx;

                  if (objZ2 >= 0) {
                        objZ2 += objZ1;
                  }

                  if ((params.state >= 0) && (objZ2 >= 0) && filesDatabase[objZ2].subData.ptr) {
                        if (filesDatabase[objZ2].subData.resourceType == 8) { // Poly
                              mainDrawPolygons(objZ2, currentObjPtr, objX2, params.scale, objY2, (char *)gfxModuleData.pPage10, (char *)filesDatabase[objZ2].subData.ptr);    // poly
                        } else if (filesDatabase[objZ2].subData.resourceType == OBJ_TYPE_SOUND) {
                        } else if (filesDatabase[objZ2].resType == OBJ_TYPE_MASK) {
                        } else if (filesDatabase[objZ2].subData.resourceType == OBJ_TYPE_SPRITE) {
                              objX1 = filesDatabase[objZ2].width; // width
                              spriteHeight = filesDatabase[objZ2].height;     // height

                              if (filesDatabase[objZ2].subData.ptr) {
                                    drawSprite(objX1, spriteHeight, currentObjPtr, filesDatabase[objZ2].subData.ptr, objY2, objX2, gfxModuleData.pPage10, filesDatabase[objZ2].subData.ptrMask);
                              }
                        }
                  }

                  // automatic animation process
                  if (currentObjPtr->animStep && !param) {
                        if (currentObjPtr->animCounter <= 0) {

                              bool change = true;

                              int newVal = getValueFromObjectQuerry(&params, currentObjPtr->animChange) + currentObjPtr->animStep;

                              if (currentObjPtr->animStep > 0) {
                                    if (newVal > currentObjPtr->animEnd) {
                                          if (currentObjPtr->animLoop) {
                                                newVal = currentObjPtr->animStart;
                                                if (currentObjPtr->animLoop > 0)
                                                      currentObjPtr->animLoop--;
                                          } else {
                                                int16 data2;
                                                data2 = currentObjPtr->animStart;

                                                change = false;
                                                currentObjPtr->animStep = 0;

                                                if (currentObjPtr->animType) {      // should we resume the script ?
                                                      if (currentObjPtr->parentType == 20) {
                                                            changeScriptParamInList(currentObjPtr->parentOverlay, currentObjPtr->parent, &procHead, -1, 0);
                                                      } else if (currentObjPtr->parentType == 30) {
                                                            changeScriptParamInList(currentObjPtr->parentOverlay, currentObjPtr->parent, &relHead, -1, 0);
                                                      }
                                                }
                                          }
                                    }
                              } else {
                                    if (newVal < currentObjPtr->animEnd) {
                                          if (currentObjPtr->animLoop) {
                                                newVal = currentObjPtr->animStart;
                                                if (currentObjPtr->animLoop > 0)
                                                      currentObjPtr->animLoop--;
                                          } else {
                                                int16 data2;
                                                data2 = currentObjPtr->animStart;

                                                change = false;
                                                currentObjPtr->animStep = 0;

                                                if (currentObjPtr->animType) {      // should we resume the script ?
                                                      if (currentObjPtr->parentType == 20) {
                                                            changeScriptParamInList(currentObjPtr->parentOverlay, currentObjPtr->parent, &procHead, -1, 0);
                                                      } else if (currentObjPtr->parentType == 30) {
                                                            changeScriptParamInList(currentObjPtr->parentOverlay, currentObjPtr->parent, &relHead, -1, 0);
                                                      }
                                                }
                                          }
                                    }
                              }

                              if (currentObjPtr->animWait >= 0) {
                                    currentObjPtr->animCounter = currentObjPtr->animWait;
                              }

                              if ((currentObjPtr->animSignal >= 0) && (currentObjPtr->animSignal == newVal) && (currentObjPtr->animType != 0)) {
                                    if (currentObjPtr->parentType == 20) {
                                          changeScriptParamInList(currentObjPtr->parentOverlay, currentObjPtr->parent, &procHead, -1, 0);
                                    } else if (currentObjPtr->parentType == 30) {
                                          changeScriptParamInList(currentObjPtr->parentOverlay, currentObjPtr->parent, &relHead, -1, 0);
                                    }

                                    currentObjPtr->animType = 0;
                              }

                              if (change) {
                                    addAutoCell(currentObjPtr->overlay, currentObjPtr->idx, currentObjPtr->animChange, newVal, currentObjPtr);
                              }
                        } else {
                              currentObjPtr->animCounter--;
                        }
                  }
            }

            currentObjPtr = currentObjPtr->next;
      }

      //----------------------------------------------------------------------------------------------------------------//

      freeAutoCell();
      isMessage = 0;

      //-------------------------------------------------- DRAW OBJECTS TYPE 5 (MSG)-----------------------------------------//

      currentObjPtr = cellHead.next;

      while (currentObjPtr) {
            if (currentObjPtr->type == OBJ_TYPE_MESSAGE && currentObjPtr->freeze == 0) {
                  drawMessage(currentObjPtr->gfxPtr, currentObjPtr->x, currentObjPtr->field_C, currentObjPtr->spriteIdx, currentObjPtr->color, gfxModuleData.pPage10);
                  isMessage = 1;
            }
            currentObjPtr = currentObjPtr->next;
      }

      //----------------------------------------------------------------------------------------------------------------//

      if (currentActiveMenu != -1) {
            if (menuTable[currentActiveMenu]) {
                  drawMenu(menuTable[currentActiveMenu]);
                  return;
            }
      } else if ((linkedRelation) && (linkedMsgList)) {
            int16 mouseX;
            int16 mouseY;
            int16 button;
            getMouseStatus(&main10, &mouseX, &button, &mouseY);

            if (mouseY > (linkedMsgList->height)*2)
                  drawMessage(linkedMsgList, 0, 0, 320, findHighColor(), gfxModuleData.pPage10);
            else
                  drawMessage(linkedMsgList, 0, 200, 320, findHighColor(), gfxModuleData.pPage10);
      }
}

} // End of namespace Cruise

Generated by  Doxygen 1.6.0   Back to index