Scene Overlay



  • On 30/04/2013 at 03:57, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   V14+ 
    Platform:   Windows  ;   Mac OSX  ; 
    Language(s) :     C++  ;

    ---------
    Hi,

    What is the best way of overlaying a bitmap with an alpha channel on the scene at a certain position?

    This "overlay" is not associated with an active tool. But should be moved with the scene as if it is part of the scene, but not be part of the scene. Currently I think this requires a SceneHook. Are there any samples that use one?

    Markus



  • On 30/04/2013 at 07:38, xxxxxxxx wrote:

    Hi Markus,

    you could use BaseDraw.DrawTexture() to place a Bitmap with an alpha channel in a 
    BaseDraw. Or you use simply an ObjectData plugin and return a  textured plane with 
    a DisplayTag attached to it, to ensure it is displayed shaded.

    I think i am misunderstanding your problem or what you are after.



  • On 01/05/2013 at 01:33, xxxxxxxx wrote:

    If you want to display an overlayed image in the viewport without having a corresponding object or tag in the document hierarchy, a SceneHook is in deed the right choice.



  • On 01/05/2013 at 03:38, xxxxxxxx wrote:

    As c4dJack says. :)



  • On 01/05/2013 at 07:50, xxxxxxxx wrote:

    He asked for an example. And there is one that's been floating around the forum:
    https://plugincafe.maxon.net/topic/6062/6237_scenehook-plugin-problem&KW=SceneHook&PID=26152#26152

    But I have two questions about that:

    1- In the Message() code where it listens if a new document is opened. If I add some task there. For example create a polygon. It works fine if C4D is already open.
    But this causes C4D to crash when it launches.
    How do we use MSG_DOCUMENTINFO_TYPE_LOAD in a SH to execute something when a new document is opened. But not execute when C4D is launching for the first time?

    *Edit:
    I guess I should also say that to even be able to test and play around with the SH code and not have it crash on start up. This is the hack I'm using in the main.cpp file.
    But this is obviously wrong:

    Bool PluginMessage(LONG id, void *data)  
    {  
      //use the following lines to set a plugin priority  
      switch (id)  
      {  
          case C4DPL_INIT_SYS:  
          if (!resource.Init()) return FALSE; // don't start plugin without resource  
      
      return TRUE;  
      
          case C4DPL_PROGRAM_STARTED:  
              if (!RegisterMyNode()) return FALSE;          <------ My hack to prevent C4D from crashing!!!  
              if (!RegisterMySceneHook()) return FALSE;  
      
          etc....
    

    2- In the SH example provided by Matthias.
    If I add an Init() to the Node class. And do something like for example create a sphere. It does work.
    But when I open a document. The SH creates a whole new (second) document and puts the sphere in there. And that's not good.
    How would I make the SH put the sphere into the document I'm opening instead?

    -ScottA



  • On 01/05/2013 at 09:24, xxxxxxxx wrote:

    1. No hacks are necessary. A SceneHook does not crash if written right.
    2. What does RegisterMyNode() even do, anyway?
    3. Since a SceneHook is part of the document itself, I don't think it would create an additional document. You are doing something wrong there.
    4. To answer your original question: ScenHooks provide an execution hook inside your document. It does not make any sence to have them execute or not execute based on if Cinema has just started or not.

    You might have to rethink your approach.



  • On 01/05/2013 at 11:41, xxxxxxxx wrote:

    I know I'm not doing it right.
    The example from Matthias is a nice starting point. But it leaves me with too many unanswered questions on how to use it.
    The guy is looking for an example. And so am I.

    -ScottA



  • On 01/05/2013 at 14:08, xxxxxxxx wrote:

    Oh Duh. 😊
    I just realized that you posted an example of this on your blog Frank.
    http://c4dprogramming.wordpress.com/2012/11/15/2d-drawing-using-a-scenehook/

    I'm so used to using my own special drawing trick to draw things. That I forgot all about it.
    The example Matthias posted is for combining a NodeData plugin with a SceneHook. And that approach is different than just drawing things on the screen.

    -ScottA



  • On 01/05/2013 at 14:11, xxxxxxxx wrote:

    Hi,

    here's a quick example of drawing an image over the editor window:

    /**
     * Copyright (C) 2013, Niklas Rosenstein
     * All rights reserved.
     *
     * This program is free software: you can redistribute it and/or modify
     * it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
     * 
     * You should have received a copy of the Lesser GNU General Public License
     * along with this program. If not, see <http://www.gnu.org/licenses/>.
     */
      
    #include <c4d.h>
    #include <lib_clipmap.h>
      
    typedef struct Rect {
        LONG x1, y1, x2, y2;
    } Rect_t;
      
    class OverlayHook : public SceneHookData {
      
        AutoAlloc<GeClipMap> image;
        BaseTime last_time;
        Bool drawn;
      
    public:
      
        static NodeData* Alloc() { return gNew OverlayHook; }
      
        OverlayHook();
      
        void FillOverlay(const Rect_t& rect, LONG frame, Bool update_fill);
      
        //////// SceneHookData Overrides
      
        Bool Draw(BaseSceneHook* host, BaseDocument* doc, BaseDraw* bd, BaseDrawHelp* bh,
                  BaseThread* bt, SCENEHOOKDRAW flags);
      
    };
      
      
    OverlayHook::OverlayHook() : drawn(FALSE) {
    }
      
    void OverlayHook::FillOverlay(const Rect_t& rect, LONG frame, Bool update_fill) {
        LONG width = rect.x2 - rect.x1;
        LONG height = rect.y2 - rect.y1;
      
        // Ensure that the image is large enough, reallocate if
        // necessary!
        if (image->GetBw() < width || image->GetBh() < height) {
            GeDebugOut("  Reallocating image...");
            image->Destroy();
            if (image->Init(width, height, 32) != IMAGERESULT_OK) {
                return;
            }
            update_fill = TRUE;
        }
      
        if (!update_fill) return;
      
        GeDebugOut("  Updating fill..");
      
        image->BeginDraw();
        for (LONG x=0; x < width; x++) {
            for (LONG y=0; y < height; y++) {
                Real v = (SNoise(Vector(x / 50.0, y / 50.0, frame)) + 1) / 2;
                v *= (Real) x / width;
                LONG g = (LONG) (v * 255);
      
                image->SetPixelRGBA(x, y, 255, 255, 255, g);
            }
        }
        image->EndDraw();
      
        drawn = TRUE;
    }
      
    Bool OverlayHook::Draw(BaseSceneHook* host, BaseDocument* doc, BaseDraw* bd, BaseDrawHelp* bh,
                           BaseThread* bt, SCENEHOOKDRAW flags) {
        if (!host || !doc || !bd || !bh || !bt) return FALSE;
        if (flags != SCENEHOOKDRAW_DRAW_PASS) return TRUE;
      
        Rect_t rect;
        bd->GetSafeFrame(&rect.x1, &rect.y1, &rect.x2, &rect.y2);
      
        // Draw something on the overlay image.
        BaseTime time = doc->GetTime();
        Bool update_fill = time != last_time || !drawn;
      
        last_time = time;
        FillOverlay(rect, time.GetFrame(doc->GetFps()), update_fill);
      
        // Draw the overlay image on the screen.
        BaseBitmap* bmp = image->GetBitmap();
        if (!bmp) return TRUE;
      
        bd->SetMatrix_Screen();
      
        Vector padr4[4];
        padr4[0] = Vector(rect.x1, rect.y1, 0);
        padr4[1] = Vector(rect.x2, rect.y1, 0);
        padr4[2] = Vector(rect.x2, rect.y2, 0);
        padr4[3] = Vector(rect.x1, rect.y2, 0);
      
        Vector uvadr[4];
        uvadr[0] = Vector(0, 0, 0);
        uvadr[1] = Vector(1, 0, 0);
        uvadr[2] = Vector(1, 1, 0);
        uvadr[3] = Vector(0, 1, 0);
      
        bd->DrawTexture(bmp, padr4, NULL, NULL, uvadr, 4,
                        DRAW_ALPHA_FROM_IMAGE, DRAW_TEXTUREFLAGS_0);
      
        return TRUE;
    }
      
      
    Bool RegisterOverlayHook() {
        LONG flags = PLUGINFLAG_SCENEHOOK_NOTDRAGGABLE;
        DataAllocator* alloc = OverlayHook::Alloc;
        return RegisterSceneHookPlugin(1000001, "Overlay Hook", flags, alloc, 0, 0);
    }
      
    Bool PluginStart() {
        return RegisterOverlayHook();
    }
      
    Bool PluginMessage(LONG type, void* pData) {
        return TRUE;
    }
      
    void PluginEnd() {
    }
    

    I had immense problems figuring out how to actually apply the DrawTexture() method, so that
    took most of the time, the rest was really easy. It's not working 100% satisfieng (see this thread)
    but actually does it's job.

    What also still needs to be added, is that the pixels are actually drawn 1 by 1 on the screen. Atm,
    the whole bitmap is drawn into the editor window. The bitmap might actually exceed the window
    resolution because I reallocate it when it was to small to fit in it, but do not reallocate it when it
    would exceed (which would eat lots of power).

    Best,
    -Niklas

    EDIT: Added missing line (orange).



  • On 01/05/2013 at 14:24, xxxxxxxx wrote:

    Thanks Nik,

    I got it all figured out from the code on that blog.
    But your is helpful too.

    -ScottA



  • On 06/05/2013 at 03:38, xxxxxxxx wrote:

    Hi All,

    Sorry I couldn't respond earlier. Thank you all for the wealth of information. I haven't managed to digest it all, yet, though.

    Markus


Log in to reply