📄 macroot.cpp
字号:
// Forcing the source rect to equal the destination rect; all the
// complicated math actually takes place elsewhere so this is an
// OK thing to do.
Rect srcR = dstR;
if (CHXMacSite::zm_bFullScreenActive)
{
CHXMacSite* pMacSite = (CHXMacSite*)m_pSite;
if (!pMacSite->m_bInternalResizeOnFullscreen)
{
dstR.right = dstR.left + (long)(((double)dstR.right - (double)dstR.left)*pMacSite->m_fStretchMultiple);
dstR.bottom = dstR.top + (long)(((double)dstR.bottom - (double)dstR.top)*pMacSite->m_fStretchMultiple);
}
}
if (m_nBlitDepthEnum >= 0)
{
RGBColor blackRGB = {0x0000, 0x0000, 0x0000};
RGBColor whiteRGB = {0xffff, 0xffff, 0xffff};
ColorSpec prevFore;
ColorSpec prevBack;
::SaveFore(&prevFore);
::SaveBack(&prevBack);
::RGBForeColor(&blackRGB);
::RGBBackColor(&whiteRGB);
::CopyBits( (BitMap*)*m_RootGWorldPixMap[m_nBlitDepthEnum],
GetPortBitMapForCopyBits(GetWindowPort(macWindow)),
&srcR, &dstR, srcCopy, nil );
::QDFlushPortBuffer( ::GetWindowPort(macWindow), NULL );
::RestoreFore(&prevFore);
::RestoreBack(&prevBack);
}
SetOriginAndMaintainClipRgn(oldOrigin.h, oldOrigin.v);
::SetPort(savePort);
}
}
unsigned long
CMacRootSurface::_GetScreenPixelValue(long globX, long globY)
{
unsigned long retVal = 0;
int whichDevice;
for (whichDevice = 0; whichDevice < zm_uNumberOfAttachedDevices; whichDevice++)
{
HX_ASSERT(zm_AttachedDevice[whichDevice]);
PixMapHandle thePMH = (**zm_AttachedDevice[whichDevice]).gdPMap;
unsigned long dstPtr = (unsigned long)::GetPixBaseAddr(thePMH);
int pixelSize = (**thePMH).pixelSize;
Rect deviceRect = (**zm_AttachedDevice[whichDevice]).gdRect;
if (globX >= deviceRect.left && globX <= deviceRect.right
&& globY >= deviceRect.top && globY <= deviceRect.bottom)
{
int rowOffset = (globY - deviceRect.top) * ((**thePMH).rowBytes & 0x3fff);
int columnOffset = (globX - deviceRect.left) * pixelSize / 8;
dstPtr += rowOffset + columnOffset;
switch (pixelSize)
{
case 32:
retVal = *(unsigned long*)dstPtr;
break;
case 16:
retVal = *(unsigned short*)dstPtr;
break;
case 8:
retVal = *(unsigned char*)dstPtr;
break;
}
}
}
return retVal;
}
unsigned long
CMacRootSurface::_GetGWorldPixelValue(int whichDepth, long x, long y)
{
unsigned long retVal = 0;
unsigned long offscreenPtr = (unsigned long)GetPixBaseAddr(m_RootGWorldPixMap[whichDepth]);
offscreenPtr += y * ((**m_RootGWorldPixMap[whichDepth]).rowBytes & 0x3fff);
switch (whichDepth)
{
case kEightBitDepth:
offscreenPtr += x;
retVal = *(unsigned char*)offscreenPtr;
break;
case kSixteenBitDepth:
offscreenPtr += 2*x;
retVal = *(unsigned short*)offscreenPtr;
break;
case kThirtyTwoBitDepth:
offscreenPtr += 4*x;
retVal = *(unsigned long*)offscreenPtr;
break;
}
return retVal;
}
/************************************************************************
* Method:
* CMacRootSurface::InternalReflectRect
*
* Note that theRectToBlit needs to be in global coords!
*
* This is the function that slams it home. All obscuring menus have
* been taken care of. Any vis region holes have been taken care of.
* The rectangles that arrive at this rectangle are honest-to-God
* blittable rectangles.
*
*/
void
CMacRootSurface::InternalReflectRect(Rect theRectToBlit)
{
int whichDevice;
for (whichDevice = 0; whichDevice < zm_uNumberOfAttachedDevices; whichDevice++)
{
HX_ASSERT(zm_AttachedDevice[whichDevice]);
PixMapHandle thePMH = (**zm_AttachedDevice[whichDevice]).gdPMap;
unsigned char* dstPtr = (unsigned char*)::GetPixBaseAddr(thePMH);
int pixelSize = (**thePMH).pixelSize;
INT32 whichDepth = DepthToDepthEnum(pixelSize);
if ( 1 /* m_RootSurfaceGWorld[whichDepth] */ ) // <== this may be useful later but for now I want the assert to be executed that's maybe a dozen lines down.
{
Rect deviceRect = (**zm_AttachedDevice[whichDevice]).gdRect;
Rect intersectionRect; // <== should always be equal to theRectToBlit I think XXXbobclark
if (::SectRect(&theRectToBlit, &deviceRect, &intersectionRect))
{
// XXXbobclark
// in the old site code we manually trimmed theRectToBlit to the limits of
// intersectionRect; but since nowadays we're supposedly ensuring that we're
// only getting rects wholly enclosed by their monitors we shouldn't need
// to do that. Theoretically the only reason to do SectRect is to see if
// this is actually the monitor that we need to blit to right now.
HX_ASSERT(m_RootSurfaceGWorld[whichDepth]);
if (!m_RootSurfaceGWorld[whichDepth]) return;
unsigned char* offscreenPtr = (unsigned char*)GetPixBaseAddr(m_RootGWorldPixMap[whichDepth]);
int localLeft = intersectionRect.left - m_LocalToGlobalCoords.h;
int localTop = intersectionRect.top - m_LocalToGlobalCoords.v;
int localRight = intersectionRect.right - m_LocalToGlobalCoords.h;
int localBottom = intersectionRect.bottom - m_LocalToGlobalCoords.v;
int localScreenLeft = intersectionRect.left - (**zm_AttachedDevice[whichDevice]).gdRect.left;
int localScreenRight = intersectionRect.right - (**zm_AttachedDevice[whichDevice]).gdRect.left;
int localScreenTop = intersectionRect.top - (**zm_AttachedDevice[whichDevice]).gdRect.top;
int localScreenBottom = intersectionRect.bottom - (**zm_AttachedDevice[whichDevice]).gdRect.top;
for (int localScreenRow = localScreenTop; localScreenRow < localScreenBottom; localScreenRow++)
{
int bytesPerPixel = pixelSize / 8;
if (bytesPerPixel >= 1) // only ITB if at least 8-bit monitor
{
int localRow = (localScreenRow-localScreenTop) + localTop;
long offscreenOffset = ((**m_RootGWorldPixMap[whichDepth]).rowBytes & 0x3fff) * localRow + localLeft * bytesPerPixel;
long localScreenOffset = ((**thePMH).rowBytes & 0x3fff) * localScreenRow + localScreenLeft * bytesPerPixel;
long srcP = (long)offscreenPtr + offscreenOffset;
long dstP = (long)dstPtr + localScreenOffset;
switch (bytesPerPixel)
{
case 4:
// XXXbobclark
// now we'll trash srcP and dstP...
// it turns out that poking longs by hand is a lot faster
// than going through BlockMoveData for some reason. In a
// simplified test case, it was using 7-8 microseconds for
// poking by hand, compared to 17-18 microseconds for using
// BlockMoveData.
{
long maxP = dstP + (localRight-localLeft) * bytesPerPixel;
for ( ; dstP < maxP; )
{
// if the pixel is lined up on an eight-byte boundary
// and won't overwrite the right edge of the rectangle
// then copy eight bytes at once.
if ( (dstP % 8 == 0) && (maxP - dstP >= 8) )
{
*(double*)dstP = *(double*)srcP;
srcP += 8;
dstP += 8;
}
else
{
*(long*)dstP = *(long*)srcP;
srcP += 4;
dstP += 4;
}
}
}
break;
default:
// XXXbobclark
// I could do something similar to the 32-bit case here,
// where I attempt to outdo BlockMoveData()... but for
// one thing, it would be even clunkier, since I'd need
// more cases when it doesn't happen to line up on eight-
// byte boundaries for super-fast copies, plus non-32-bit
// cases are rarer than 32-bit cases.
::BlockMoveData( (void*)srcP, (void*)dstP, (localRight-localLeft)*bytesPerPixel );
break;
}
}
}
}
}
}
}
/************************************************************************
* Method:
* CMacRootSurface::InternalReflectRectInVisRegion
*
* Note that theRectToBlit needs to be in global coords!
*
*/
void
CMacRootSurface::InternalReflectRectInVisRegion(Rect theRectToBlit)
{
CHXSimpleList::Iterator ndx = m_pVisRgnRects->Begin();
for (; ndx != m_pVisRgnRects->End(); ++ndx)
{
Rect* r = (Rect*)(*ndx);
Rect blittableRect = theRectToBlit;
if (blittableRect.left < r->left) blittableRect.left = r->left;
if (blittableRect.top < r->top) blittableRect.top = r->top;
if (blittableRect.right > r->right) blittableRect.right = r->right;
if (blittableRect.bottom > r->bottom) blittableRect.bottom = r->bottom;
if (blittableRect.left < blittableRect.right && blittableRect.top < blittableRect.bottom)
{
InternalReflectRect(blittableRect);
}
}
}
/************************************************************************
* Method:
* CMacRootSurface::PotentiallyAddRect
*
* Useful shortcut for constructing lists of rectangles for
* menu-down blitting.
*
*/
void
CMacRootSurface::PotentiallyAddRect( CHXSimpleList* theList, Rect originalVisRect, short left, short top, short right, short bottom )
{
if ( left < originalVisRect.left ) left = originalVisRect.left;
if ( top < originalVisRect.top ) top = originalVisRect.top;
if ( right > originalVisRect.right ) right = originalVisRect.right;
if ( bottom > originalVisRect.bottom ) bottom = originalVisRect.bottom;
if ( left < right && top < bottom )
{
// OK, it's a legal rect so let's add it.
Rect* r = new Rect;
r->left = left;
r->top = top;
r->right = right;
r->bottom = bottom;
theList->AddTail( r );
}
}
/************************************************************************
* Method:
* CMacRootSurface::ReflectRectToFullScreen
*
* Note that theOriginalRectToBlit needs to be in global coords!
*
*/
void
CMacRootSurface::ReflectRectToFullScreen(Rect theOriginalRectToBlit)
{
// xxxbobclark assumptions include that this rectangle
// is smaller than the main screen (which is where it
// assumes the full-screen is playing).
// See InternalReflectRect for details of what up
HX_ASSERT(CHXMacSite::zm_bFullScreenActive);
int whichDevice;
for (whichDevice = 0; whichDevice < zm_uNumberOfAttachedDevices; whichDevice++)
{
PixMapHandle thePMH = (**zm_AttachedDevice[whichDevice]).gdPMap;
unsigned char* dstPtr = (unsigned char*)::GetPixBaseAddr(thePMH);
int honestScreenRowBytes = (**thePMH).rowBytes & 0x3fff;
int pixelSize = (**thePMH).pixelSize;
INT32 whichDepth = DepthToDepthEnum(pixelSize);
if (m_RootSurfaceGWorld[whichDepth])
{
Rect adjustedRect;
CHXMacSite* pMacSite = (CHXMacSite*)m_pSite;
double stretch = pMacSite->m_fStretchMultiple;
adjustedRect.left = theOriginalRectToBlit.left + stretch * (theOriginalRectToBlit.left - m_LocalToGlobalCoords.h);
adjustedRect.top = theOriginalRectToBlit.top + stretch * (theOriginalRectToBlit.top - m_LocalToGlobalCoords.v);
adjustedRect.right = theOriginalRectToBlit.left + stretch * (theOriginalRectToBlit.right - m_LocalToGlobalCoords.h);
adjustedRect.bottom = theOriginalRectToBlit.top + stretch * (theOriginalRectToBlit.bottom - m_LocalToGlobalCoords.v);
Rect deviceRect = (**zm_AttachedDevice[whichDevice]).gdRect;
if (adjustedRect.left >= deviceRect.left
&& adjustedRect.top >= deviceRect.top
&& adjustedRect.right <= deviceRect.right
&& adjustedRect.bottom <= deviceRect.bottom)
{
// xxxbobclark whew, we can blit here since it's full
// screen and wholly enclosed.
int bytesPerPixel = pixelSize / 8;
if (bytesPerPixel < 1) return; // ack, can't handle less than 8-bit!
unsigned char* offscreenPtr = (unsigned char*)GetPixBaseAddr(m_RootGWorldPixMap[whichDepth]);
int honestOffscreenRowBytes = (**m_RootGWorldPixMap[whichDepth]).rowBytes & 0x3fff;
int fromLeft = theOriginalRectToBlit.left - m_LocalToGlobalCoords.h;
int fromTop = theOriginalRectToBlit.top - m_LocalToGlobalCoords.v;
int fromRight = theOriginalRectToBlit.right - m_LocalToGlobalCoords.h;
int fromBottom = theOriginalRectToBlit.bottom - m_LocalToGlobalCoords.v;
for (int fromRow = fromTop; fromRow < fromBottom; fromRow++)
{
for (int fromColumn = fromLeft; fromColumn < fromRight; fromColumn++)
{
// xxxbobclark OK now here we have one pixel
// in the offscreen. This could grow to
// multiple pixels on screen so we'll have to
// blit all of them.
long* pixelPtr = (long*)((long)offscreenPtr + fromRow*(long)honestOffscreenRowBytes);
pixelPtr = (long*)((long)pixelPtr + bytesPerPixel * fromColumn);
long pixelValue = *pixelPtr;
// ok, got the pixel value, now figure out where all we
// need to poke it.
int destLeft = (int)((double)(fromColumn - fromLeft) * stretch + (double)adjustedRect.left);
int destTop = (int)((double)(fromRow - fromTop) * stretch + (double)adjustedRect.top);
int destRight = (int)((double)(fromColumn - fromLeft + 1) * stretch + (double)adjustedRect.left);
int destBottom = (int)((double)(fromRow - fromTop + 1) * stretch + (double)adjustedRect.top);
pixelPtr = (long*)((long)dstPtr + destTop * honestScreenRowBytes);
pixelPtr = (long*)((long)pixelPtr + bytesPerPixel * destLeft);
for (int destRow = destTop; destRow < destBottom; destRow++)
{
for (int destColumn = destLeft; destColumn < destRight; destColumn++)
{
*pixelPtr = pixelValue;
pixelPtr = (long*)((long)pixelPtr + bytesPerPixel);
}
pixelPtr = (long*)((long)pixelPtr + honestScreenRowBytes - (bytesPerPixel * (destRight-destLeft)));
}
}
}
}
}
}
}
/************************************************************************
* Method:
* CMacRootSurface::DepthToDepthEnum
*/
int
CMacRootSurface::DepthToDepthEnum( short depth )
{
int result = kEightBitDepth;
switch ( depth )
{
case 32:
result = kThirtyTwoBitDepth;
break;
case 16:
result = kSixteenBitDepth;
break;
}
return result;
}
/************************************************************************
* Method:
* CMacRootSurface::VisRgnChangedCallback
*
* This is called from several trap patches which can
* change the vis region. This prevents subsequent blits
* until the vis region we know about can be updated.
*/
/* static */
pascal void
CMacRootSurface::VisRgnChangedCallback(void)
{
#ifndef _MAC_UNIX
HXMM_INTERRUPTON();
#endif
// since the visRgn probably changed in the patched trap, let's wait until
// we can update our version of the visRgn before doing any more interrupt-
// time blits.
CHXSimpleList::Iterator ndxSite = zm_RootSurfaceList.Begin();
for (; ndxSite != zm_RootSurfaceList.End(); ++ndxSite)
{
CMacRootSurface* pRootSurface = (CMacRootSurface*)(*ndxSite);
if ( pRootSurface )
{
pRootSurface->m_bItsOKToDoAnInterruptBlit = FALSE;
}
}
if (CMacSurface::zm_pOverlaySurface)
{
CMacSurface::zm_bSafeToOverlayBlit = FALSE;
}
#ifndef _MAC_UNIX
HXMM_INTERRUPTOFF();
#endif
}
#define kSizeOfSimpleRectangleRegion 10
/************************************************************************
* Method:
* CMacRootSurface::CheckRectRgn
*
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -