#include "sol.h" VSZASSERT /* flags for _lseek */ #define SEEK_CUR 1 #define SEEK_END 2 #define SEEK_SET 0 #define cbBand 8192 BGND bgnd; BOOL _FValidBm(BMP *pbm) { return((pbm->biBitCount == 1 || pbm->biBitCount == 4) && pbm->biPlanes == 1 && pbm->biSize == sizeof(BMP)); } BOOL FInitBgnd(TCHAR *szFile) { INT fh; BOOL fResult; LONG lcbBm; LONG dwBmSize; fResult = fFalse; bgnd.fUseBitmap = fFalse; if((fh = OpenFile(szFile, &bgnd.of, OF_CANCEL|OF_READ)) == -1) return fFalse; if(!FReadDibBitmapInfo(fh, &bgnd.bm)) goto ReturnClose; bgnd.dwOfsBits = M_llseek( fh, 0L, SEEK_CUR); if(!_FValidBm(&bgnd.bm)) goto ReturnClose; /* BUG: check if bitmap is ok */ bgnd.cbLine = (((INT) bgnd.bm.biWidth * bgnd.bm.biBitCount+31)/32)*4; lcbBm = (LONG) bgnd.cbLine * DyBmp(bgnd.bm); bgnd.ibndMac = (INT) ((lcbBm+cbBand-1) / cbBand); if((bgnd.rghbnd = PAlloc(bgnd.ibndMac*sizeof(HANDLE))) == NULL) goto ReturnClose; bgnd.dyBand = (INT) ((LONG) DyBmp(bgnd.bm) * cbBand / lcbBm); bgnd.fUseBitmap = fTrue; SetBgndOrg(); fResult = fTrue; ReturnClose: M_lclose(fh); return fResult; } BOOL FDestroyBgnd() { INT ibnd; HANDLE *phbnd; if(bgnd.fUseBitmap) { for(ibnd = 0; ibnd < bgnd.ibndMac; ibnd++) { if(*(phbnd = &bgnd.rghbnd[ibnd]) != NULL) { GlobalFree(*phbnd); *phbnd = NULL; } } FreeP(bgnd.rghbnd); } return fTrue; } BOOL FGetBgndFile(TCHAR *sz) { if(bgnd.fUseBitmap) PszCopy(bgnd.of.szPathName, sz); else sz[0] = TEXT('\000'); return fTrue; } BOOL _FLoadBand(INT ibnd, Y y) { HANDLE hbnd; BYTE[ ]*FAR[ ]**lpb; INT ipln; INT fh; LONG lcbpln; HANDLE *phbnd; DY dy; phbnd = &bgnd.rghbnd[ibnd]; if(*phbnd != NULL) GlobalFree(*phbnd); hbnd = GlobalAlloc(GMEM_MOVEABLE|GMEM_DISCARDABLE, (LONG) cbBand); lpb = GlobalLock(hbnd); if(lpb == NULL) return fFalse; fh = OpenFile("", &bgnd.of, OF_REOPEN|OF_READ ); lcbpln = 0L; dy = WMin(bgnd.dyBand, DyBmp(bgnd.bm)-y); for(ipln = 0; ipln < CplnBmp(bgnd.bm); ipln++) { M_llseek( fh, (LONG)OfsBits(bgnd)+ipln*lcbpln+(y)*CbLine(bgnd), 0); M_lread( fh, (LPSTR) lpb+ipln*CbLine(bgnd)*bgnd.dyBand, dy * CbLine(bgnd)); } GlobalUnlock(hbnd); *phbnd = hbnd; M_lclose(fh); return fTrue; } Y _YDrawBand(HDC hdcMem, HBITMAP hbm, X xLeft, Y yTop, X xRight, Y yBot) { HBITMAP hbmSav; HANDLE hbnd; BYTE[ ]*FAR[ ]**lpb; Y y; INT ibnd; /* round yTop to nearest band */ y = ((yTop-bgnd.ptOrg.y)/bgnd.dyBand)*bgnd.dyBand; ibnd = y/bgnd.dyBand; if(ibnd < 0) return bgnd.ptOrg.y; if(ibnd >= bgnd.ibndMac) return yBot+1; ibnd = bgnd.ibndMac-ibnd-1; Assert(ibnd >= 0); Assert(ibnd < bgnd.ibndMac); while((hbnd = bgnd.rghbnd[ibnd]) == NULL || (lpb = (BYTE[ ]*FAR[ ]**) GlobalLock(hbnd)) == NULL) { if(!_FLoadBand(ibnd, y)) /* KLUDGE:, should back out gracefully */ return yBot; } Assert(lpb != NULL); SetDIBitsToDevice(hdcCur, xLeft-xOrgCur, yTop-yOrgCur, WMin(xRight-xLeft, DyBmp(bgnd.bm)-xLeft+bgnd.ptOrg.x), WMin(WMin(bgnd.dyBand, yBot-yTop), DyBmp(bgnd.bm)-yTop+bgnd.ptOrg.y), 0, 0, y-bgnd.ptOrg.y, bgnd.dyBand, // xLeft-bgnd.ptOrg.x, yTop-y-bgnd.ptOrg.y, // 0, // WMin(WMin(bgnd.dyBand, yBot-yTop), DyBmp(bgnd.bm)-yTop+bgnd.ptOrg.y), lpb, (BITMAPINFO FAR *)&bgnd.bm, DIB_RGB_COLORS); GlobalUnlock(hbnd); return y+bgnd.dyBand+bgnd.ptOrg.y; } VOID DrawBgnd(X xLeft, Y yTop, X xRight, Y yBot) { INT dy; Y y; HDC hdcMem; HBITMAP hbm; HBRUSH hbr; if(bgnd.fUseBitmap) { for(y = yTop; y <= yBot; ) { y = _YDrawBand(hdcMem, hbm, xLeft, y, xRight, yBot); } ExcludeClipRect(hdcCur, bgnd.ptOrg.x-xOrgCur, bgnd.ptOrg.y-yOrgCur, bgnd.ptOrg.x+DxBmp(bgnd.bm)-xOrgCur, bgnd.ptOrg.y+DyBmp(bgnd.bm)-yOrgCur); } MSetBrushOrg(hdcCur, xOrgCur, yOrgCur); MUnrealizeObject( hbrTable ); hbr = SelectObject(hdcCur, hbrTable); Assert(xRight >= xLeft); Assert(yBot >= yTop); PatBlt(hdcCur, xLeft-xOrgCur, yTop-yOrgCur, xRight-xLeft, yBot-yTop, PATCOPY); SelectObject(hdcCur, hbr); if(bgnd.fUseBitmap) SelectClipRgn(hdcCur, NULL); } VOID SetBgndOrg() { bgnd.ptOrg.x = (rcClient.xRight - DxBmp(bgnd.bm))/2; bgnd.ptOrg.y = (rcClient.yBot - DyBmp(bgnd.bm))/2; } /* * ReadDibBitmapInfo() * * Will read a file in DIB format and return a global HANDLE to it's * BITMAPINFO. This function will work with both "old" and "new" * bitmap formats, but will allways return a "new" BITMAPINFO * */ BOOL FReadDibBitmapInfo(INT fh, BITMAPINFO *pbi) { DWORD off; HANDLE hbi = NULL; INT size; INT i; WORD nNumColors; RGBQUAD FAR *pRgb; BITMAPINFOHEADER bi; BITMAPCOREHEADER bc; LPBITMAPINFOHEADER lpbi; BITMAPFILEHEADER bf; if (fh == -1) return NULL; off = M_llseek( fh, 0L, SEEK_CUR); if (sizeof(bf) != M_lread( fh, (LPSTR)&bf, sizeof(bf)) ) return fFalse; /* * do we have a RC HEADER? */ if (!ISDIB(bf.bfType)) { bf.bfOffBits = 0L; M_llseek( fh, off, SEEK_SET ); } if (sizeof(bi) != M_lread( fh, (LPSTR)&bi, sizeof(bi)) ) return fFalse; nNumColors = DibNumColors(&bi); /* * what type of bitmap info is this? */ switch (size = (INT)bi.biSize) { case sizeof(BITMAPINFOHEADER): break; case sizeof(BITMAPCOREHEADER): bc = *(BITMAPCOREHEADER*)&bi; bi.biSize = sizeof(BITMAPINFOHEADER); bi.biWidth = (DWORD)bc.bcWidth; bi.biHeight = (DWORD)bc.bcHeight; bi.biPlanes = (WORD)bc.bcPlanes; bi.biBitCount = (WORD)bc.bcBitCount; bi.biStyle = 0; bi.biSizeImage = 0; bi.biXPelsPerMeter = 0; bi.biYPelsPerMeter = 0; bi.biClrUsed = nNumColors; bi.biClrImportant = nNumColors; M_llseek(fh, (LONG)sizeof(BITMAPCOREHEADER)-sizeof(BITMAPINFOHEADER), SEEK_CUR); break; default: return fFalse; /* not a DIB */ } /* * fill in some default values! */ if (bi.biSizeImage == 0) { bi.biSizeImage = WIDTHBYTES((DWORD)bi.biWidth * bi.biBitCount) * bi.biHeight; } if (bi.biXPelsPerMeter == 0) { bi.biXPelsPerMeter = 0; // ?????????????? } if (bi.biYPelsPerMeter == 0) { bi.biYPelsPerMeter = 0; // ?????????????? } if (bi.biClrUsed == 0) { bi.biClrUsed = DibNumColors(&bi); } lpbi = (VOID FAR *)pbi; *lpbi = bi; pRgb = (RGBQUAD FAR *)((LPSTR)lpbi + bi.biSize); if (nNumColors) { if (size == sizeof(BITMAPCOREHEADER)) { /* * convert a old color table (3 byte entries) to a new * color table (4 byte entries) */ M_lread( fh, (LPSTR)pRgb, nNumColors * sizeof(RGBTRIPLE) ); for (i=nNumColors-1; i>=0; i--) { RGBQUAD rgb; rgb.rgbRed = ((RGBTRIPLE FAR *)pRgb)[i].rgbtRed; rgb.rgbBlue = ((RGBTRIPLE FAR *)pRgb)[i].rgbtBlue; rgb.rgbGreen = ((RGBTRIPLE FAR *)pRgb)[i].rgbtGreen; rgb.rgbReserved = (BYTE)0; pRgb[i] = rgb; // BUG, this is wrong!!!! } } else { M_lread(fh, (LPSTR)pRgb, nNumColors * sizeof(RGBQUAD)); } } if (bf.bfOffBits != 0L) M_llseek( fh, off + bf.bfOffBits, SEEK_SET ); return fTrue; } /* How Many colors does this DIB have? * this will work on both PM and Windows bitmap info structures. */ WORD DibNumColors(VOID FAR * pv) { INT bits; /* * with the new format headers, the size of the palette is in biClrUsed * else is dependent on bits per pixel */ if (((LPBITMAPINFOHEADER)pv)->biSize != sizeof(BITMAPCOREHEADER)) { if (((LPBITMAPINFOHEADER)pv)->biClrUsed != 0) return (WORD)((LPBITMAPINFOHEADER)pv)->biClrUsed; bits = ((LPBITMAPINFOHEADER)pv)->biBitCount; } else { bits = ((LPBITMAPCOREHEADER)pv)->bcBitCount; } switch (bits) { case 1: return 2; case 4: return 16; case 8: Assert(fFalse); // NYI return 256; default: return 0; } } #ifdef LATER HDC HdcCreateImage(HDC hdcApp, INT idbMask, INT idbImage, LONG rgb, DX *pdx, DY *pdy) { HDC hdcMem, hdcMem1; HBITMAP hbmT, hbmTT, hbmMask; HBRUSH hbr; BITMAP bm; hdcMem = CreateCompatibleDC(hdcApp); hbmMask = LoadBitmap(hinstApp, MAKEINTRESOURCE(idbMask)); GetObject(hbmMask, sizeof(BITMAP), (LPSTR) &bm); /* enlarge the size of hdc */ hbmT = SelectObject(hdcMem, CreateCompatibleBitmap(hdcApp, bm.bmWidth, bm.bmHeight)); hbr = SelectObject(hdcMem, hbrTable); PatBlt(hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, PATCOPY); SelectObject(hdcMem, hbr); hdcMem1 = CreateCompatibleDC(hdcApp); hbmTT = SelectObject(hdcMem1, hbmMask); BitBlt(hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem1, 0, 0, SRCAND); /* load image and delete hbmMask */ DeleteObject(SelectObject(hdcMem1, LoadBitmap(hinstApp, MAKEINTRESOURCE(idbImage)))); /* load brush to color image */ hbr = SelectObject(hdcMem, CreateSolidBrush(rgb)); #define ropDPSao 0x00EA02E9 /* (Source & Pattern) | Dest */ BitBlt(hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem1, 0, 0, ropDPSao); DeleteObject(SelectObject(hdcMem, hbr)); DeleteObject(SelectObject(hdcMem1, hbmTT)); DeleteDC(hdcMem1); *pdx = bm.bmWidth; *pdy = bm.bmHeight; return hdcMem; } Marquee(RC *prc) { HDC hdc; HDC hdcObj; X x; Y y; DX dxObj; DY dyObj; DX dx; DY dy; INT dobjX, dobjY; /* # of objects per dir */ INT iobj; INT iSlice, iSlice1; hdc = GetDC(hwndApp); hdcObj = HdcCreateImage(hdc, idbBlackBear, idbWhiteBear, RGB(255, 0, 0), &dxObj, &dyObj); dobjX = (prc->xRight-prc->xLeft)/dxObj; dobjY = (prc->yBot-prc->yTop)/dyObj; dx = dxObj*2; dy = 0; y = prc->yTop-dyObj; x = prc->xLeft-dxObj+iSlice%dxObj; for(iobj = 0; iobj < 2*dobjX+2*dobjY; iobj++) { BitBlt(hdc, x, y, dxObj, dyObj, hdcObj, 0, 0, SRCCOPY); if(dy == 0) { if(x > prc->xRight+dxObj) { dy = dyObj*2; dx = 0; } else if(x < prc->xLeft-dxObj) { dy = -dyObj*2; dx = 0; } } else if(dx == 0) { if(y > prc->yBot+dyObj) { dx = -dxObj*2; dy = 0; } } x+=dx; y+=dy; } for(iSlice = 0; iSlice < 5; iSlice++) { for(iSlice1 = 0; iSlice1 < dxObj; iSlice1++) { BitBlt(hdc, prc->xLeft-dxObj+iSlice1+1, prc->yTop-dyObj, prc->xRight-prc->xLeft+dxObj, dyObj, hdc, prc->xLeft-dxObj+iSlice1, prc->yTop-dyObj, SRCCOPY); BitBlt(hdc, prc->xRight+dxObj, prc->yTop-dyObj+iSlice1+1, dxObj, prc->yBot-prc->yTop+dyObj, hdc, prc->xRight+dxObj, prc->yTop-dyObj+iSlice1, SRCCOPY); } } DeleteDC(hdcObj); ReleaseDC(hwndApp, hdc); return fTrue; } Animation() { INT iX, iY, ihdc; DX dx; DY dy; HDC hdc; HDC rghdc[3]; RC rc; rc.xLeft = 100; rc.xRight = 300; rc.yTop = 100; rc.yBot = 200; Marquee(&rc); return fTrue; } #endif /* LATER */