Ejemplo n.º 1
0
void C4GraphicsOverlay::Draw(C4TargetFacet &cgo, C4Object *pForObj, int32_t iByPlayer)
{
	assert(!IsPicture());
	assert(pForObj);
	// get target pos
	float offX, offY;
	float newzoom;
	pForObj->GetDrawPosition(cgo, offX, offY, newzoom);
	ZoomDataStackItem zdsi(newzoom);

	// special blit mode
	if (dwBlitMode == C4GFXBLIT_PARENT)
		(OverlayObj ? static_cast<C4Object*>(OverlayObj) : pForObj)->PrepareDrawing();
	else
	{
		pDraw->SetBlitMode(dwBlitMode);
		if (dwClrModulation != 0xffffff) pDraw->ActivateBlitModulation(dwClrModulation);

		if (pMeshInstance)
			pMeshInstance->SetFaceOrderingForClrModulation(dwClrModulation);
	}
	if (eMode == MODE_Rank)
	{
		C4TargetFacet ccgo;
		ccgo.Set(cgo.Surface, offX+pForObj->Shape.x,offY+pForObj->Shape.y,pForObj->Shape.Wdt,pForObj->Shape.Hgt, cgo.TargetX, cgo.TargetY);
		DrawRankSymbol(ccgo, OverlayObj);
	}
	// drawing specific object?
	else if (OverlayObj)
	{
		// TODO: Shouldn't have called PrepareDrawing/set ClrModulation here, since 
		// OverlayObj drawing will do it on its own.
		if (eMode == MODE_ObjectPicture)
		{
			C4Facet fctTarget;
			fctTarget.Set(cgo.Surface, offX+pForObj->Shape.x, offY+pForObj->Shape.y, pForObj->Shape.Wdt, pForObj->Shape.Hgt);

			OverlayObj->DrawPicture(fctTarget, false, &C4DrawTransform(Transform, fctTarget.X+float(fctTarget.Wdt)/2, fctTarget.Y+float(fctTarget.Hgt)/2));
		}
		else
		{
			// Draw specified object at target pos of this object; offset by transform.
			OverlayObj->Draw(cgo, iByPlayer, C4Object::ODM_Overlay, offX + Transform.GetXOffset(), offY + Transform.GetYOffset());
			OverlayObj->DrawTopFace(cgo, iByPlayer, C4Object::ODM_Overlay, offX + Transform.GetXOffset(), offY + Transform.GetYOffset());
		}
	}
	else if (eMode == MODE_ExtraGraphics)
	{
		// draw self with specified gfx
		if (pSourceGfx)
		{
			C4DefGraphics *pPrevGfx = pForObj->GetGraphics();
			C4DrawTransform *pPrevTrf = pForObj->pDrawTransform;
			C4DrawTransform trf;
			if (pPrevTrf)
			{
				trf = *pPrevTrf;
				trf *= Transform;
			}
			else
			{
				trf = Transform;
			}
			pForObj->SetGraphics(pSourceGfx, true);
			pForObj->pDrawTransform = &trf;
			pForObj->Draw(cgo, iByPlayer, C4Object::ODM_BaseOnly);
			pForObj->DrawTopFace(cgo, iByPlayer, C4Object::ODM_BaseOnly);
			pForObj->SetGraphics(pPrevGfx, true);
			pForObj->pDrawTransform = pPrevTrf;
		}
	}
	else if(eMode == MODE_Picture || eMode == MODE_IngamePicture)
	{
		float twdt, thgt;
		if (fZoomToShape)
		{
			twdt = pForObj->Shape.Wdt;
			thgt = pForObj->Shape.Hgt;
		}
		else
		{
			twdt = pSourceGfx->pDef->Shape.Wdt;
			thgt = pSourceGfx->pDef->Shape.Hgt;
		}

		C4TargetFacet ccgo;
		ccgo.Set(cgo.Surface, offX-twdt/2, offY-thgt/2, twdt, thgt, cgo.TargetX, cgo.TargetY);
		C4DrawTransform trf(Transform, offX, offY);

		// Don't set pForObj because we don't draw the picture of pForObj, but the picture of another definition on top of pForObj:
		pSourceGfx->Draw(ccgo, pForObj->Color, NULL, iPhase, 0, &trf);
	}
	else
	{
		// no object specified: Draw from fctBlit
		// update by object color
		if (fctBlit.Surface) fctBlit.Surface->SetClr(pForObj->Color);

		if (!pMeshInstance)
		{
			// draw there
			C4DrawTransform trf(Transform, offX, offY);
			if (fZoomToShape)
			{
				float fZoom = std::min(pForObj->Shape.Wdt / std::max(fctBlit.Wdt, 1.0f), pForObj->Shape.Hgt / std::max(fctBlit.Hgt, 1.0f));
				trf.ScaleAt(fZoom, fZoom, offX, offY);
			}

			fctBlit.DrawT(cgo.Surface, offX - fctBlit.Wdt/2 + fctBlit.TargetX, offY - fctBlit.Hgt/2 + fctBlit.TargetY, iPhase, 0, &trf);
		}
		else
		{
			C4Def *pDef = pSourceGfx->pDef;

			// draw there
			C4DrawTransform trf(Transform, offX, offY);
			if (fZoomToShape)
			{
				float fZoom = std::min((float)pForObj->Shape.Wdt / std::max(pDef->Shape.Wdt, 1), (float)pForObj->Shape.Hgt / std::max(pDef->Shape.Hgt, 1));
				trf.ScaleAt(fZoom, fZoom,  offX, offY);
			}

			C4Value value;
			pDef->GetProperty(P_MeshTransformation, &value);
			StdMeshMatrix matrix;
			if (C4ValueToMatrix(value, &matrix))
				pDraw->SetMeshTransform(&matrix);

			pDraw->RenderMesh(*pMeshInstance, cgo.Surface, offX - pDef->Shape.Wdt/2.0, offY - pDef->Shape.Hgt/2.0, pDef->Shape.Wdt, pDef->Shape.Hgt, pForObj->Color, &trf);
			pDraw->SetMeshTransform(NULL);
		}
	}

	// cleanup
	if (dwBlitMode == C4GFXBLIT_PARENT)
		(OverlayObj ? static_cast<C4Object*>(OverlayObj) : pForObj)->FinishedDrawing();
	else
	{
		pDraw->ResetBlitMode();
		pDraw->DeactivateBlitModulation();
	}
}
Ejemplo n.º 2
0
bool C4GraphicsSystem::DoSaveScreenshot(bool fSaveAll, const char *szFilename, float fSaveAllZoom)
{
	// Fullscreen only
	if (Application.isEditor) return false;
	// back surface must be present
	if (!FullScreen.pSurface) return false;

	// save landscape
	if (fSaveAll)
	{
		// Create full map screenshots at zoom 2x. Fractional zooms (like 1.7x) should work but might cause some trouble at screen borders.
		float zoom = fSaveAllZoom;
		// get viewport to draw in
		C4Viewport *pVP=::Viewports.GetFirstViewport(); if (!pVP) return false;
		// create image large enough to hold the landscape
		std::unique_ptr<CPNGFile> png(new CPNGFile());
		int32_t lWdt = GBackWdt * zoom, lHgt = GBackHgt * zoom;
		if (!png->Create(lWdt, lHgt, false)) return false;
		// get backbuffer size
		int32_t bkWdt=C4GUI::GetScreenWdt(), bkHgt=C4GUI::GetScreenHgt();
		if (!bkWdt || !bkHgt) return false;
		// facet for blitting
		C4TargetFacet bkFct;
		// mark background to be redrawn
		InvalidateBg();
		// draw on one big viewport
		pVP->SetOutputSize(0,0,0,0, bkWdt, bkHgt);
		// backup and clear sky parallaxity
		int32_t iParX=::Landscape.Sky.ParX; ::Landscape.Sky.ParX=10;
		int32_t iParY=::Landscape.Sky.ParY; ::Landscape.Sky.ParY=10;
		// backup and clear viewport borders
		FLOAT_RECT vp_borders = { pVP->BorderLeft, pVP->BorderRight, pVP->BorderTop, pVP->BorderBottom };
		pVP->BorderLeft = pVP->BorderRight = pVP->BorderTop = pVP->BorderBottom = 0.0f;
		// temporarily change viewport player
		int32_t iVpPlr=pVP->Player; pVP->Player=NO_OWNER;
		// blit all tiles needed
		for (int32_t iY=0; iY<lHgt; iY+=bkHgt) for (int32_t iX=0; iX<lWdt; iX+=bkWdt)
			{
				// get max width/height
				int32_t bkWdt2=bkWdt,bkHgt2=bkHgt;
				if (iX+bkWdt2>lWdt) bkWdt2-=iX+bkWdt2-lWdt;
				if (iY+bkHgt2>lHgt) bkHgt2-=iY+bkHgt2-lHgt;
				// update facet
				bkFct.Set(FullScreen.pSurface, 0, 0, ceil(float(bkWdt2)/zoom), ceil(float(bkHgt2)/zoom), iX/zoom, iY/zoom, zoom, 0, 0);
				// draw there
				pVP->Draw(bkFct, true, false);
				// render
				FullScreen.pSurface->PageFlip(); FullScreen.pSurface->PageFlip();
				// get output (locking primary!)
				if (FullScreen.pSurface->Lock())
				{
					// transfer each pixel - slooow...
					for (int32_t iY2 = 0; iY2 < bkHgt2; ++iY2)
#ifndef USE_CONSOLE
						glReadPixels(0, FullScreen.pSurface->Hgt - iY2 - 1, bkWdt2, 1, GL_BGR, GL_UNSIGNED_BYTE, reinterpret_cast<BYTE *>(png->GetRow(iY + iY2)) + iX * 3);
#else
						for (int32_t iX2=0; iX2<bkWdt2; ++iX2)
							png->SetPix(iX+iX2, iY+iY2, FullScreen.pSurface->GetPixDw(iX2, iY2, false));
#endif
					// done; unlock
					FullScreen.pSurface->Unlock();
					// This can take a long time and we would like to pump messages
					// However, we're currently hogging the primary surface and horrible things might happen if we do that, including initiation of another screenshot
					// The only thing that can be safely run is music (sound could play but that would just make them out of sync of the game)
					::Application.MusicSystem.Execute(true);
				}
			}
		// restore viewport player
		pVP->Player=iVpPlr;
		// restore viewport borders
		pVP->BorderLeft = vp_borders.left;
		pVP->BorderTop = vp_borders.top;
		pVP->BorderRight = vp_borders.right;
		pVP->BorderBottom = vp_borders.bottom;
		// restore parallaxity
		::Landscape.Sky.ParX=iParX;
		::Landscape.Sky.ParY=iParY;
		// restore viewport size
		::Viewports.RecalculateViewports();
		// save!
		CPNGFile::ScheduleSaving(png.release(), szFilename);
		return true;
	}
	// Save primary surface in background thread
	return FullScreen.pSurface->SavePNG(szFilename, false, false, true);
}