Watermark doesn't work with TR & 3rd Party Render
-
On 15/03/2016 at 05:48, xxxxxxxx wrote:
User Information:
Cinema 4D Version: R16
Platform:
Language(s) : C++ ;---------
Hi!The built-in Watermark videopost has the same problem. I have a videopost that adds a watermark
in VIDEOPOSTCALL_FRAME with !vps->open. This works fine in normal renders, but it does not when
rendering a single frame via Team Render.This is the code from VideoPostData::Execute()
RENDERRESULT Execute(BaseVideoPost* node, VideoPostStruct* vps) override { GePrint("Execute() " + String::IntToString(vps->vp)); // DEBUG if (vps->vp == VIDEOPOSTCALL_FRAME && vps->open) { _executeLineCalled = false; _applyWatermark = HasFixtureContainer(vps->doc) && !StageHook_TestLicense(vps->doc); } else if (vps->vp == VIDEOPOSTCALL_FRAME && !vps->open && _applyWatermark && !_executeLineCalled) { // If ExecuteLine() should have been called but was not, we are // dealing with a third-party renderer that doesn't support it. VPBuffer* rgba = vps->render->GetBuffer(VPBUFFER_RGBA, 0); Int32 const size = (rgba ? rgba->GetBw() * rgba->GetCpp() : 0); AutoGeFree<Float32> line(NewMemClear(Float32, size)); if (!rgba) GePrint("No RGBA Buffer!"); // DEBUG if (rgba && line) { Int32 const width = rgba->GetBw(); for (Int32 y = 0; y < rgba->GetBh(); ++y) { rgba->GetLine(0, y, width, line, 32, true); PixelPost pp; pp.frag = nullptr; pp.frag_nx = nullptr; pp.vd = vps->vd; pp.col = line; pp.mp = nullptr; pp.aa = false; pp.valid_line = true; pp.comp = rgba->GetCpp(); pp.cpu_num = 0; pp.xmin = 0; pp.xmax = width - 1; pp.line = y; this->ExecuteLine(node, &pp); rgba->SetLine(0, y, width, line, 32, true); } } } return RENDERRESULT_OK; }
Is it a limition of Team Render?
-
On 16/03/2016 at 04:57, xxxxxxxx wrote:
Hello,
I'm testing this with 17.048. It seems that "Watermark" works fine with Team Render single frame rendering. Please notice that if "Multi-Pass" is enabled, the post effect will not render it's result into the RGBA buffer but into separate passes.
It looks like that if a post effect should be executed on !vps->open this has to be done not on a single client but on the server. To make sure your post effect is executed on the server you must return VIDEOPOSTINFO_NETRUNONSERVER in your GetRenderInfo().
Best wishes,
Sebastian -
On 16/03/2016 at 05:34, xxxxxxxx wrote:
Hi Sebastian, thanks a lot for your reply.
Unfortunately I can't confirm the "Watermark" video post working with Team Render single frame rendering,
neither in R16.050 nor R17.048. ** It does not work with third-party renderers , just to be clear.I use the sdk_teamrender.cpp example to test it. I've added a GIF that shows rendering using that
Team Render Example renderer locally, then using Team Render single frame.Note that it does work rendering an animation. I guess this is due to the fact that Team Render
assigns a full frame per node, thus its the same as doing a single frame render without TR.Thanks!
NiklasPS: Attached is the source of that teamrender example, just in case.
#include "c4d.h" // #include "main.h" #include "lib_clipmap.h" #include "lib_net.h" /**A unique plugin ID. You must obtain this from http://www.plugincafe.com. Use this ID to create new instances of this material.*/ #define ID_SDK_TEAMRENDER_EXAMPLE 1033999 // NOT A REAL PLUGIN ID !! #define BUCKET_SIZE 64 // hardcoded bucket size //---------------------------------------------------------------------------------------- /// Data structure relevant for the Team Render Client //---------------------------------------------------------------------------------------- struct TeamRenderClientData { VideoPostStruct* _vps; Int32 _bucketSize; Int32 _currentBucket; Int32 _x1; Int32 _x2; Int32 _y1; Int32 _y2; }; //---------------------------------------------------------------------------------------- /// Data structure relevant for the Team Render Server //---------------------------------------------------------------------------------------- struct TeamRenderServerData { RenderJob* _renderJob; MultipassBitmap* _targetBitmap; Int32 _lastBucketIndex; Int32 _totalBucketCount; Int32 _finishedBucketCount; Int32 _startTime; }; //---------------------------------------------------------------------------------------- /// Simple VideoPostData renderer using Team Render funtionality //---------------------------------------------------------------------------------------- class TeamRenderVideoPost : public VideoPostData { INSTANCEOF(TeamRenderVideoPost, VideoPostData) public: static NodeData* Alloc() { return NewObjClear(TeamRenderVideoPost);} virtual VIDEOPOSTINFO GetRenderInfo(BaseVideoPost* node); virtual RENDERRESULT Execute(BaseVideoPost* node, VideoPostStruct* vps); virtual Bool RenderEngineCheck(BaseVideoPost* node, Int32 id); virtual Bool NetFrameInit(BaseVideoPost *node, BaseDocument* doc, RenderJob* job, Int32 initialclients, const NetRenderData* renderinfo, MultipassBitmap* frameBmp, BaseThread* bt, Int32 &realdepth); virtual void NetFrameFree(BaseVideoPost* node); virtual Bool NetFrameMessage(BaseVideoPost *node, const C4DUuid& remoteUuid, const NetRenderBuffer& data, NetRenderBuffer *result); private: void FillBuffer(VideoPostStruct* vps, String text, Vector color); private: // client methods void HandleTeamRenderBucket(VideoPostStruct* vps); Bool GetBucketSize(TeamRenderClientData* data); Bool GetBucketIndex(TeamRenderClientData* data); void GetBucketDimensions(TeamRenderClientData* data); void SendResult(TeamRenderClientData* data); private: // server data TeamRenderServerData _serverData; private: // server methods void FillRegion(Int32 x1, Int32 x2, Int32 y1, Int32 y2); void FillRegion(NetRenderMsgBucketFinished* result); }; VIDEOPOSTINFO TeamRenderVideoPost::GetRenderInfo(BaseVideoPost* node) { return VIDEOPOSTINFO_NETFRAME; //return VIDEOPOSTINFO_0; } RENDERRESULT TeamRenderVideoPost::Execute(BaseVideoPost* node, VideoPostStruct* vps) { // check if break if(vps->thread && vps->thread->TestBreak()) { return RENDERRESULT_OK; } if (vps->open) { switch (vps->vp) { case(VIDEOPOSTCALL_RENDER) : { // skip default Cinema Render process if(vps->vd) vps->vd->SkipRenderProcess(); break; } case(VIDEOPOSTCALL_INNER) : { // check if Team Render situation if(vps->net && vps->net_server == false) { if(vps->net->_singleImageDistribution) { // distrubuted rendering (single frame render buckets) this->HandleTeamRenderBucket(vps); } else { // animation rendering (render a whole frame) this->FillBuffer(vps,"Render with Team Render",Vector(1,1,1)); } } else { // no Team Render situation this->FillBuffer(vps,"Render locally",Vector(1,1,1)); } break; } } } return RENDERRESULT_OK; } Bool TeamRenderVideoPost::RenderEngineCheck(BaseVideoPost* node, Int32 id) { switch (id) { case RENDERSETTING_STATICTAB_ANTIALIASING: case RENDERSETTING_STATICTAB_OPTIONS: case RENDERSETTING_STATICTAB_STEREO: return false; } return true; } //---------------------------------------------------------------------------------------- /// Function is called when the Team Render server process starts. Access and save all relevant information. //---------------------------------------------------------------------------------------- Bool TeamRenderVideoPost::NetFrameInit(BaseVideoPost *node, BaseDocument* doc, RenderJob* job, Int32 initialclients, const NetRenderData* renderinfo, MultipassBitmap* frameBmp, BaseThread* bt, Int32 &realdepth) { GePrint("TeamRenderVideoPost::NetFrameInit"); // calculating the total number of render buckets VPBuffer* rgba = (VPBuffer* )frameBmp; if(!rgba) return false; const Int32 w = rgba->GetBw(); const Int32 h = rgba->GetBh(); const Int32 subdivisionX = (Int32)maxon::Ceil((Float)w / (Float)BUCKET_SIZE); const Int32 subdivisionY = (Int32)maxon::Ceil((Float)h / (Float)BUCKET_SIZE); _serverData._totalBucketCount = subdivisionX * subdivisionY; // number of finished buckets _serverData._finishedBucketCount = 0; // default first bucket index _serverData._lastBucketIndex = 0; // save target framebuffer _serverData._targetBitmap = frameBmp; // save RenderJob _serverData._renderJob = job; // save start time _serverData._startTime = GeGetMilliSeconds(); frameBmp->SetData(BASEBITMAP_DATA_PROGRESS_PHASE, GeData(RENDERPROGRESSTYPE_DURINGRENDERING)); frameBmp->SetData(BASEBITMAP_DATA_PROGRESS_FRAME, GeData(0.0)); frameBmp->SetData(BASEBITMAP_DATA_STARTTIME, GeData(GeGetTimer())); frameBmp->SetSave(true); // add passes MultipassBitmap* layer = frameBmp->AddLayer(nullptr ,COLORMODE_RGB,false); if(layer) { layer->SetUserID(2000); layer->SetName("Multipass A"); layer->SetSave(true); } layer = frameBmp->AddLayer(nullptr ,COLORMODE_RGB,false); if(layer) { layer->SetUserID(2001); layer->SetName("Multipass B"); layer->SetSave(true); } return true; } //---------------------------------------------------------------------------------------- /// Function is called when the Team Render server process ends. //---------------------------------------------------------------------------------------- void TeamRenderVideoPost::NetFrameFree(BaseVideoPost* node) { GePrint("RendererVideoPost::NetFrameFree"); if(!node) return; BaseDocument* doc = node->GetDocument(); if(!doc) return; const RenderData* const renderData = doc->GetActiveRenderData(); if(_serverData._targetBitmap == nullptr) return; _serverData._targetBitmap->SetData(BASEBITMAP_DATA_PROGRESS_PHASE, GeData(RENDERPROGRESSTYPE_AFTERRENDERING)); // set Picture Viewer status bar text const Int32 diff = GeGetMilliSeconds() - _serverData._startTime; const Float32 seconds = Float32(diff) / 1000.0f; const String text = "Render Time: "+String::FloatToString(seconds,-1,1)+ " s."; _serverData._targetBitmap->SetData(BASEBITMAP_DATA_PROGRESS_TIME, GeData(text)); // // make saving the multipasses depend on whatever your multipasses depend on // // save image data const Int32 layerCount = _serverData._targetBitmap->GetLayerCount(); for(Int32 i = 0; i < layerCount; ++i) { MultipassBitmap* bmp = _serverData._targetBitmap->GetLayerNum(i); if(bmp) { GeData name = bmp->GetParameter(MPBTYPE_NAME); GeData userID = bmp->GetParameter(MPBTYPE_USERID); GeData save = bmp->GetParameter(MPBTYPE_SAVE); if(save.GetBool()) { Filename imagePath = renderData->GetDataInstance()->GetFilename(RDATA_PATH); String suffix = imagePath.GetSuffix(); imagePath.SetFile("mp_"+String::IntToString(i)+"."+suffix); GePrint("write file :"+imagePath.GetString()); bmp->Save(imagePath,FILTER_TIF,nullptr,SAVEBIT_0); } } } // saving the rgba image if(renderData->GetDataInstance()->GetBool(RDATA_SAVEIMAGE)) { Int32 format = renderData->GetDataInstance()->GetInt32(RDATA_FORMAT); Filename imagePath = renderData->GetDataInstance()->GetFilename(RDATA_PATH); GePrint("write file :"+imagePath.GetString()); _serverData._targetBitmap->Save(imagePath,format,nullptr,SAVEBIT_0); } } //---------------------------------------------------------------------------------------- /// Function is called when the Team Render server receives a message from a client. //---------------------------------------------------------------------------------------- Bool TeamRenderVideoPost::NetFrameMessage(BaseVideoPost* node, const C4DUuid& remoteUuid, const NetRenderBuffer& data, NetRenderBuffer* result) { GePrint("RendererVideoPost::NetFrameMessage"); switch(data.id) { // Client requests the bucket size case(MSG_NETRENDER_BUCKET_INFO) : { GePrint("- MSG_NETRENDER_BUCKET_INFO"); // prepare answer NetRenderMsgBucketInfo* answer = NewMemClear(NetRenderMsgBucketInfo, 1); if ((answer == nullptr) || (result == nullptr)) return false; // set data answer->bucketSize = BUCKET_SIZE; // set result result->size = sizeof(NetRenderMsgBucketInfo); result->data = answer; break; } // client requests the index of a bucket to render case MSG_NETRENDER_BUCKET_INDEX: { GePrint("- MSG_NETRENDER_BUCKET_INDEX"); // return -1 if the client should no longer do anything Int32 bucketIndex = -1; // only send a new bucket index if there are still bucket to distribute if(_serverData._lastBucketIndex < _serverData._totalBucketCount) bucketIndex = _serverData._lastBucketIndex; // prepare answer NetRenderMsgBucketIndex* answer = NewMemClear(NetRenderMsgBucketIndex, 1); if ((answer == nullptr) || (result == nullptr)) return false; // set data answer->bucketID = bucketIndex; result->size = sizeof(NetRenderMsgBucketIndex); result->data = answer; // increment _serverData._lastBucketIndex++; break; } // client sends the dimensions of the bucket he is about to render // this is used to highlight the bucket in the framebuffer case MSG_NETRENDER_BUCKET_REQUEST: { GePrint("- MSG_NETRENDER_BUCKET_REQUEST"); NetRenderMsgBucketStarted* message = (NetRenderMsgBucketStarted* )data.data; this->FillRegion( message->regionX1, message->regionX2, message->regionY1, message->regionY2); break; } // client sends the results of the rendering process case MSG_NETRENDER_BUCKET_FINISHED: { GePrint("- MSG_NETRENDER_BUCKET_FINISHED"); NetRenderMsgBucketFinished* message = (NetRenderMsgBucketFinished* )data.data; message->buffer = (Float32* )(((UChar* )message) + sizeof(NetRenderMsgBucketFinished)); // write the data to the framebuffer this->FillRegion(message); // increment finished buckets _serverData._finishedBucketCount++; if(_serverData._finishedBucketCount == _serverData._totalBucketCount) { // end the render process _serverData._renderJob->UpdateProgress(1.0, true); } else { const Float progress = (Float)_serverData._finishedBucketCount / (Float)_serverData._totalBucketCount; _serverData._renderJob->UpdateProgress(progress, false); // define progress bar in picture viewer String showProgress = String::FloatToString(progress*100.0); showProgress += " %"; _serverData._targetBitmap->SetData(BASEBITMAP_DATA_PROGRESS_FRAME,GeData(progress)); _serverData._targetBitmap->SetData(BASEBITMAP_DATA_PROGRESS_ACTION, GeData(showProgress)); } break; } } return true; } //---------------------------------------------------------------------------------------- /// Function will fill the framebuffer with the given color and will write the given text. //---------------------------------------------------------------------------------------- void TeamRenderVideoPost::FillBuffer(VideoPostStruct* vps, String text, Vector color) { if(!vps || !vps->render) return; VPBuffer* rgba = vps->render->GetBuffer(VPBUFFER_RGBA, NOTOK); if(!rgba) return; AutoAlloc<GeClipMap> clipMap; if(clipMap->Init(rgba->GetBw(),rgba->GetBh(),32) != IMAGERESULT_OK) return; clipMap->BeginDraw(); const Int32 col_r = SAFEINT32(color.x * 255.0); const Int32 col_g = SAFEINT32(color.y * 255.0); const Int32 col_b = SAFEINT32(color.z * 255.0); clipMap->SetColor(col_r,col_g,col_b); clipMap->FillRect(0,0,clipMap->GetBw()-1,clipMap->GetBh()-1); clipMap->SetColor(0,0,0); String output = "Frame: "; output += String::IntToString(vps->time.GetFrame(vps->fps)); output += ": " + text; clipMap->TextAt(10, 10,output); clipMap->EndDraw(); BaseBitmap* res = clipMap->GetBitmap(); // copy Int32 x1, y1, x2, y2, x, y, cnt; // example functions Int32 cpp = rgba->GetInfo(VPGETINFO_CPP); x1 = 0; y1 = 0; x2 = rgba->GetBw(); y2 = rgba->GetBh(); cnt = rgba->GetBw(); Int bufferSize = cpp * cnt; Float32* b, *buffer = nullptr; if (bufferSize > 0) buffer = NewMemClear(Float32, bufferSize); if (!buffer) return; for (y = 0; y < y2; y++) { rgba->GetLine(x1, y, cnt, buffer, 32, true); for (b = buffer, x = 0; x < x2; x++, b += cpp) { UInt16 pr,pg,pb; res->GetPixel(x, y, &pr, &pg, &pb); b[0] = (Float32)pr / 255.0f; b[1] = (Float32)pg / 255.0f; b[2] = (Float32)pb / 255.0f; } rgba->SetLine(x1, y, cnt, buffer, 32, true); } DeleteMem(buffer); } //---------------------------------------------------------------------------------------- /// The client requests buckets and will send render results to the server. //---------------------------------------------------------------------------------------- void TeamRenderVideoPost::HandleTeamRenderBucket(VideoPostStruct* vps) { // prepare data TeamRenderClientData data; data._vps = vps; data._currentBucket = -1; Bool res = false; // request bucket size res = this->GetBucketSize(&data); if(res == false) return; // loop until there are no more buckets to render while(true) { // request bucket index res = this->GetBucketIndex(&data); if(res == false) return; // simulate activity GeSleep(50); // send results to the server this->SendResult(&data); if(vps->thread->TestBreak()) return; } } //---------------------------------------------------------------------------------------- /// The client requests the bucket size. //---------------------------------------------------------------------------------------- Bool TeamRenderVideoPost::GetBucketSize(TeamRenderClientData* data) { // setup message NetRenderBuffer requestMessage; NetRenderMsgBucketInfo* messageData = NewObjClear(NetRenderMsgBucketInfo); requestMessage.id = MSG_NETRENDER_BUCKET_INFO; requestMessage.job = data->_vps->net->_renderJob->GetUuid(); requestMessage.size = sizeof(NetRenderMsgBucketInfo); requestMessage.data = messageData; // setup Result NetRenderBuffer requestResult; requestResult.id = MSG_NETRENDER_BUCKET_INFO; requestResult.job = data->_vps->net->_renderJob->GetUuid(); requestResult.size = 0; requestResult.data = nullptr; // send GePrint("Send MSG_NETRENDER_BUCKET_INFO"); MESSAGERESULT res = NetSendData(data->_vps->net->_service, data->_vps->net->_renderJob->GetServerUuid(), &requestMessage, &requestResult); if(res != MESSAGERESULT_OK) return false; if (requestResult.data == nullptr) return false; // get data NetRenderMsgBucketInfo* bucketInfo = (NetRenderMsgBucketInfo* )requestResult.data; data->_bucketSize = bucketInfo->bucketSize; return true; } //---------------------------------------------------------------------------------------- /// The client requests the bucket index and will send the bucket dimensions to the server. //---------------------------------------------------------------------------------------- Bool TeamRenderVideoPost::GetBucketIndex(TeamRenderClientData* data) { data->_currentBucket = -1; NetRenderMsgBucketInfo* pNetMsgInfo = NewMemClear(NetRenderMsgBucketInfo, 1); if (pNetMsgInfo == nullptr) return false; // prepare message NetRenderBuffer requestMessage; requestMessage.id = MSG_NETRENDER_BUCKET_INDEX; requestMessage.job = data->_vps->net->_renderJob->GetUuid(); requestMessage.size = sizeof(NetRenderMsgBucketIndex); requestMessage.data = pNetMsgInfo; NetRenderBuffer requestResult; requestResult.id = MSG_NETRENDER_BUCKET_INDEX; requestResult.job = data->_vps->net->_renderJob->GetUuid(); requestResult.size = 0; requestResult.data = nullptr; GePrint("Send MSG_NETRENDER_BUCKET_INDEX"); NetSendData(data->_vps->net->_service,data->_vps->net->_renderJob->GetServerUuid(), &requestMessage, &requestResult); if(requestResult.data == nullptr) return false; data->_currentBucket = ((NetRenderMsgBucketIndex* )requestResult.data)->bucketID; if(data->_currentBucket == -1) return false; // get dimensions this->GetBucketDimensions(data); //---------------------- // answer server //---------------------- // setup answer data NetRenderMsgBucketStarted* answerData = NewMemClear(NetRenderMsgBucketStarted, 1); answerData->bucketID = data->_currentBucket; answerData->regionX1 = data->_x1; answerData->regionX2 = data->_x2; answerData->regionY1 = data->_y1; answerData->regionY2 = data->_y2; // setup answer message NetRenderBuffer* answerMessage = NewObj(NetRenderBuffer); answerMessage->id = MSG_NETRENDER_BUCKET_REQUEST; answerMessage->job = data->_vps->net->_renderJob->GetUuid(); answerMessage->size = sizeof(NetRenderMsgBucketStarted); answerMessage->data = answerData; GePrint("Send MSG_NETRENDER_BUCKET_REQUEST"); NetSendData(data->_vps->net->_service, data->_vps->net->_renderJob->GetServerUuid(), answerMessage, nullptr); return true; } //---------------------------------------------------------------------------------------- /// Used to calculate the position and the dimensions of the bucked defined by the current bucket index. //---------------------------------------------------------------------------------------- void TeamRenderVideoPost::GetBucketDimensions(TeamRenderClientData* data) { VPBuffer* rgba = data->_vps->render->GetBuffer(VPBUFFER_RGBA, NOTOK); if(!rgba) return; const Int32 w = rgba->GetBw(); const Int32 h = rgba->GetBh(); const Int32 subdivisionX = (Int32)maxon::Ceil((Float)w / (Float)data->_bucketSize); const Int32 xBucket = data->_currentBucket % subdivisionX; const Int32 yBucket = (Int32)maxon::Floor((Float)data->_currentBucket / (Float)subdivisionX); data->_x1 = xBucket * data->_bucketSize; data->_x2 = data->_x1 + data->_bucketSize; data->_y1 = yBucket * data->_bucketSize; data->_y2 = data->_y1 + data->_bucketSize; if(data->_x2 > w) data->_x2 = w; if(data->_y2 > h) data->_y2 = h; } //---------------------------------------------------------------------------------------- /// The client sends the final image data to the server. //---------------------------------------------------------------------------------------- void TeamRenderVideoPost::SendResult(TeamRenderClientData* data) { //---------------- // First I fill some memory with a random color to simulate "rendering" //---------------- const Int32 width = data->_x2 - data->_x1; const Int32 height = data->_y2 - data->_y1; const Int32 payloadPixels = width * height * 4; //RGBA const Int32 payloadSize = payloadPixels * sizeof(Float32); Float32* payload = NewMemClear(Float32,payloadPixels); // fill payload with random color Random random; random.Init(GeGetTimer()); Float32 r = (Float32)random.Get01(); Float32 g = (Float32)random.Get01(); Float32 b = (Float32)random.Get01(); for(Int32 i = 0; i < (width * height); ++i) { const Int32 offset = i*4; payload[offset] = r; payload[offset+1] = g; payload[offset+2] = b; payload[offset+3] = 1.0f; } //--------- // Now I prepare the message to the server //--------- // setup message // I need to allocate enough memory for both the message and the payload UChar* messageRoughData = NewMemClear(UChar, sizeof(NetRenderMsgBucketFinished) + payloadSize); NetRenderMsgBucketFinished* messageData = (NetRenderMsgBucketFinished* )messageRoughData; messageData->bucketID = data->_currentBucket; messageData->offsetX = data->_x1; messageData->offsetY = data->_y1; messageData->sizeX = data->_x2 - data->_x1; messageData->sizeY = data->_y2 - data->_y1; messageData->bufferSize = payloadSize; // the payload bufer can be found at the "end" of the NetRenderMsgBucketFinished object memory messageData->buffer = (Float32* )(messageRoughData + sizeof(NetRenderMsgBucketFinished)); // copy the image data into the payload memory ClearMem(messageData->buffer, payloadSize); CopyMem(payload, messageData->buffer, payloadSize); // setup message NetRenderBuffer* message = NewObj(NetRenderBuffer); message->id = MSG_NETRENDER_BUCKET_FINISHED; message->job = data->_vps->net->_renderJob->GetUuid(); message->size = sizeof(NetRenderMsgBucketFinished) + payloadSize; message->data = messageData; // send message GePrint("Send MSG_NETRENDER_BUCKET_FINISHED"); NetSendData(data->_vps->net->_service, data->_vps->net->_renderJob->GetServerUuid(), message, nullptr, data->_vps->thread); DeleteMem(payload); } //---------------------------------------------------------------------------------------- /// The defined region of the frame buffer is filled to indicate the start of the rendering of this bucket. //---------------------------------------------------------------------------------------- void TeamRenderVideoPost::FillRegion(Int32 x1, Int32 x2, Int32 y1, Int32 y2) { if(_serverData._targetBitmap == nullptr) return; VPBuffer* rgba = (VPBuffer* )_serverData._targetBitmap; Int32 x, y, cnt; cnt = x2 - x1; Int32 cpp = rgba->GetInfo(VPGETINFO_CPP); Int bufferSize = cpp * cnt; Float32* b, *buffer = nullptr; if (bufferSize > 0) buffer = NewMemClear(Float32, bufferSize); if (!buffer) return; for (y = y1; y < y2; y++) { rgba->GetLine(x1, y, cnt, buffer, 32, true); for (b = buffer, x = x1; x < x2; x++, b += cpp) { b[0] = 1.0; b[1] = 0.0; b[2] = 0.0; if(cpp == 4) b[3] = 1.0f; } rgba->SetLine(x1, y, cnt, buffer, 32, true); } DeleteMem(buffer); } //---------------------------------------------------------------------------------------- /// The region defined in the message is filled with the data of that message. //---------------------------------------------------------------------------------------- void TeamRenderVideoPost::FillRegion(NetRenderMsgBucketFinished* result) { if(_serverData._targetBitmap == nullptr) return; if(result == nullptr) return; VPBuffer* rgba = (VPBuffer* )_serverData._targetBitmap; VPBuffer* multipass = nullptr; // multipasses Int32 layerCount = _serverData._targetBitmap->GetLayerCount(); for(Int32 i = 0; i < layerCount; ++i) { MultipassBitmap* bmp = _serverData._targetBitmap->GetLayerNum(i); if(bmp) { GeData userID = bmp->GetParameter(MPBTYPE_USERID); if(userID == 2000) multipass = (VPBuffer* )bmp; } } const Int32 x1 = result->offsetX; const Int32 x2 = result->offsetX + result->sizeX; const Int32 y1 = result->offsetY; const Int32 y2 = result->offsetY + result->sizeY; Int32 x, y, cnt; cnt = result->sizeX; Int32 cpp = rgba->GetInfo(VPGETINFO_CPP); Int bufferSize = cpp * cnt; Float32* b, *buffer = nullptr; if (bufferSize > 0) buffer = NewMemClear(Float32, bufferSize); if (!buffer) return; Int bufferOffset = 0; for (y = y1; y < y2; y++) { rgba->GetLine(x1, y, cnt, buffer, 32, true); for (b = buffer, x = x1; x < x2; x++, b += cpp) { b[0] = result->buffer[bufferOffset]; b[1] = result->buffer[bufferOffset+1]; b[2] = result->buffer[bufferOffset+2]; if(cpp == 4) b[3] = 1.0f; bufferOffset += 4; } rgba->SetLine(x1, y, cnt, buffer, 32, true); } DeleteMem(buffer); // fill a layer if(multipass) { buffer = NewMemClear(Float32, bufferSize); cpp = 3; for (y = y1; y < y2; y++) { multipass->GetLine(x1, y, cnt, buffer, 32, true); for (b = buffer, x = x1; x < x2; x++, b += cpp) { b[0] = 1.0f; b[1] = 0.0f; b[2] = 0.0f; } multipass->SetLine(x1, y, cnt, buffer, 32, true); } DeleteMem(buffer); } } Bool RegisterSDKTeamRenderExample() { return RegisterVideoPostPlugin(ID_SDK_TEAMRENDER_EXAMPLE, "Team Render Example", PLUGINFLAG_VIDEOPOST_ISRENDERER|PLUGINFLAG_VIDEOPOST_ISRENDERER_NET, TeamRenderVideoPost::Alloc, "vptr", 0, 0); };
-
On 17/03/2016 at 10:26, xxxxxxxx wrote:
Hello,
a custom renderer that handles single frame rendering is responsible for pretty much everything. This means that Cinema won't execute the video post effects after the single frame finished. One would have to execute the video posts in NetFrameFree(). But since BaseVideoPost offers no way to execute the video post I'm afraid that there is no solution for this scenario.
Best wishes,
Sebastian -
On 18/03/2016 at 06:21, xxxxxxxx wrote:
Hi Sebastian,
thanks for the information. IMHO this is something that TR should be doing automatically and nothing
that would need to be done manually. Maybe R18 will feature this.Anyway, that's bad for my client since the only "reliable" protection of his plugin is the watermark.
With the watermark being circumvented using third party renderers and V-Ray, well you get the point.Best,
Niklas