/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
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 3 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, see .
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "plCaptureRender.h"
#ifndef MF_FRONTBUFF_CAPTURE
#include "plGImage/plMipmap.h"
#include "plMessage/plCaptureRenderMsg.h"
#include "plPipeline.h"
#include "plRenderTarget.h"
#include "plScene/plPageTreeMgr.h"
#include "plScene/plPostEffectMod.h"
#include "hsResMgr.h"
#include "pnKeyedObject/plUoid.h"
#include "pfGameGUIMgr/pfGameGUIMgr.h"
// CaptureRenderRequest
//
void plCaptureRenderRequest::Render(plPipeline* pipe, plPageTreeMgr* pageMgr)
{
// If we don't have a render target, something has gone horribly wrong.
if( !GetRenderTarget() )
{
hsAssert(false, "CaptureRenderRequest with no render target");
return;
}
// Set ourselves up like the current pipeline, except with our screen size.
plViewTransform vt = pipe->GetViewTransform();
vt.SetViewPort(0, 0, fRenderTarget->GetWidth(), fRenderTarget->GetHeight());
SetViewTransform(vt);
SetClearColor(pipe->GetClearColor());
SetClearDepth(pipe->GetClearDepth());
// Clear our render target
// Render the scene
pipe->PushRenderRequest(this);
pipe->ClearRenderTarget();
pageMgr->Render(pipe);
pipe->PopRenderRequest(this);
// set up state so we can clear the z-buffer for every gui dialog (and therefore not have it
// be obscured by other geometry)
SetRenderState(GetRenderState() & ~plPipeline::kRenderClearColor);
SetRenderState(GetRenderState() | plPipeline::kRenderClearDepth);
SetClearDepth(1);
// render all GUI items
std::vector guiRenderMods = pfGameGUIMgr::GetInstance()->GetDlgRenderMods();
for (int i = (int)guiRenderMods.size() - 1; i >= 0; i--) // render in reverse, so dialogs on the bottom get rendered first
{
plPageTreeMgr* dlgPageMgr = guiRenderMods[i]->GetPageMgr();
if (dlgPageMgr)
{
SetViewTransform(guiRenderMods[i]->GetViewTransform());
pipe->PushRenderRequest(this);
pipe->ClearRenderTarget();
dlgPageMgr->Render(pipe);
pipe->PopRenderRequest(this);
}
}
// Callback on plCaptureRender to process the render target into a mipmap
// and send it back to the requester.
plCaptureRender::IProcess(pipe, GetAck(), GetRenderTarget());
delete fRenderTarget;
fRenderTarget = nil;
}
hsTArray plCaptureRender::fProcessed;
// plCaptureRender::Capture
hsBool plCaptureRender::Capture(const plKey& ack, UInt16 width, UInt16 height)
{
// Create our render target
const UInt16 flags = plRenderTarget::kIsOffscreen;
const UInt8 bitDepth(32);
const UInt8 zDepth(-1);
const UInt8 stencilDepth(-1);
plRenderTarget* rt = TRACKED_NEW plRenderTarget(flags, width, height, bitDepth, zDepth, stencilDepth);
static int idx=0;
char buff[32];
sprintf(buff, "tRT%d", idx++);
hsgResMgr::ResMgr()->NewKey(buff, rt, ack->GetUoid().GetLocation());
// Create a render request and render request message
plCaptureRenderRequest* req = TRACKED_NEW plCaptureRenderRequest;
const hsScalar pri(-100.f);
req->SetPriority(pri);
req->SetRenderTarget(rt);
const UInt32 renderState
= plPipeline::kRenderNormal
| plPipeline::kRenderClearColor
| plPipeline::kRenderClearDepth;
req->SetRenderState(renderState);
// Set the Ack to be our requestor
req->RequestAck(ack);
// Submit
plRenderRequestMsg* msg = TRACKED_NEW plRenderRequestMsg(ack, req);
hsRefCnt_SafeUnRef(req);
msg->Send();
return true;
}
// plCaptureRender::IProcess
hsBool plCaptureRender::IProcess(plPipeline* pipe, const plKey& ack, plRenderTarget* targ)
{
// We've just had a successful render into our render target
// Copy that into a plMipmap
plMipmap* mipMap = pipe->ExtractMipMap(targ);
if( !mipMap )
return false;
static int currentCapIndex = 0;
// Mipmap isn't created with a key so let's give it one now
char buff[512];
sprintf(buff, "CaptureRender_%d", currentCapIndex++);
hsgResMgr::ResMgr()->NewKey(buff, mipMap, plLocation::kGlobalFixedLoc);
mipMap->Ref();
// Stash it, and send it off during the update phase.
plCaptureRenderMsg* msg = TRACKED_NEW plCaptureRenderMsg(ack, mipMap);
fProcessed.Append(msg);
return true;
}
void plCaptureRender::Update()
{
int i;
for( i = 0; i < fProcessed.GetCount(); i++ )
{
fProcessed[i]->Send();
}
fProcessed.SetCount(0);
}
#else // MF_FRONTBUFF_CAPTURE
#include "plPipeline.h"
#include "plgDispatch.h"
#include "../plMessage/plCaptureRenderMsg.h"
#include "../plGImage/plMipmap.h"
hsTArray plCaptureRender::fCapReqs;
void plCaptureRender::Update(plPipeline* pipe)
{
int i;
for( i = 0; i < fCapReqs.GetCount(); i++ )
{
plMipmap* mipmap = TRACKED_NEW plMipmap(fCapReqs[i].fWidth, fCapReqs[i].fHeight, plMipmap::kARGB32Config, 1);
pipe->CaptureScreen(mipmap, false, fCapReqs[i].fWidth, fCapReqs[i].fHeight);
plCaptureRenderMsg* msg = TRACKED_NEW plCaptureRenderMsg(fCapReqs[i].fAck, mipmap);
msg->Send();
}
fCapReqs.Reset();
}
hsBool plCaptureRender::Capture(const plKey& ack, UInt16 width, UInt16 height)
{
CapInfo capInfo;
capInfo.fAck = ack;
capInfo.fWidth = width;
capInfo.fHeight = height;
fCapReqs.Append(capInfo);
return true;
}
#endif // MF_FRONTBUFF_CAPTURE