Logo Search packages:      
Sourcecode: scummvm version File versions

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-0-13-0/engines/cruise/mainDraw.cpp $
 * $Id: mainDraw.cpp 35870 2009-01-16 02:43:41Z fingolfin $
 *
 */

#include "cruise/cruise_main.h"
#include "cruise/polys.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_flipScreen();
      }

      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 = *(dataPtr++);
            flipShort(&offset);

            newX = *(dataPtr++);
            flipShort(&newX);

            newY = *(dataPtr++);
            flipShort(&newY);

            offset += fileId;

            if (offset >= 0) {
                  if (filesDatabase[offset].resType == 0 && 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;

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

// 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 = *(uint16 *)(dataPointer);
                  dataPointer += 2;

                  flipShort(&minimumScale);

                  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 = *(uint16 *)(dataPointer);
                  dataPointer += 2;

                  flipShort(&minimumScale);

                  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;

      var_8 = 0;

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

      int numPasses = 0;

      while (plWork) {
            if (plWork->type == OBJ_TYPE_BGMK && 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_BGMK && 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(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 i;
            int j;
            int x;
            int y;
            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;
            }

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

            y = globalY;
            x = globalX;

            for (i = 0; i < height; i++) {
                  output = initialOuput + 320 * i;

                  for (j = 0; j < pGfxPtr->width; j++) {
                        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 objX1, int var_6, cellStruct *currentObjPtr, char *data1, int objY2, int objX2, char *output, char *data2) {
      int x = 0;
      int y = 0;

      cellStruct* plWork = currentObjPtr;
      int workBufferSize = var_6 * (objX1 / 8);

      unsigned char* workBuf = (unsigned char*)malloc(workBufferSize);
      memcpy(workBuf, data2, workBufferSize);

      int numPasses = 0;

      while (plWork) {
            if (plWork->type == OBJ_TYPE_BGMK && 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_BGMK && filesDatabase[maskFrame].subData.ptrMask) {
                        drawMask(workBuf, objX1 / 8, var_6, filesDatabase[maskFrame].subData.ptrMask, filesDatabase[maskFrame].width / 8, filesDatabase[maskFrame].height, maskX - objX2, maskY - objY2, numPasses++);
                  } else
                        if (filesDatabase[maskFrame].subData.resourceType == OBJ_TYPE_SPRITE && filesDatabase[maskFrame].subData.ptrMask) {
                              drawMask(workBuf, objX1 / 8, var_6, filesDatabase[maskFrame].subData.ptrMask, filesDatabase[maskFrame].width / 8, filesDatabase[maskFrame].height, maskX - objX2, maskY - objY2, numPasses++);
                        }

            }

            plWork = plWork->next;
      }

      for (y = 0; y < var_6; y++) {
            for (x = 0; x < (objX1); x++) {
                  uint8 color = (data1[0]);
                  data1++;

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

      free(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->varC) {
                  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 = backgroundPtrtable[masterScreen];

      if (bgPtr) {
            gfxModuleData_gfxCopyScreen((char *)bgPtr, (char *)gfxModuleData.pPage10);
      }

      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 == 6) {      // sound
                        } else if (filesDatabase[objZ2].resType == 1) { //(num plan == 1)
                        } else if (filesDatabase[objZ2].subData.resourceType == 4) {
                              objX1 = filesDatabase[objZ2].width; // width
                              spriteHeight = filesDatabase[objZ2].height;     // height

                              if (filesDatabase[objZ2].subData.ptr) {
                                    drawSprite(objX1, spriteHeight, currentObjPtr, (char *)filesDatabase[objZ2].subData.ptr, objY2, objX2, (char *)gfxModuleData.pPage10, (char *)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_MSG && 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