Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Draw HUD-like text to viewport

    Cinema 4D SDK
    r21 classic api
    4
    12
    1.8k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • fwilleke80F
      fwilleke80
      last edited by

      Hi & thank you for the reply!

      That is, I guess pretty much what I do. Only you are copying alpha values from another BaseBitmap, and I need to make up alpha values based on the color of pixels in the BaseBitmap I got from the GeClipMap. As long as my alpha values are in the range of 0 ... 255 (which they are), I should see at least some kind of semi transparency, right?

      So, my question remains 😄 Maybe the SDK team knows some details?

      Thanks & greetings,
      Frank

      www.frankwilleke.de
      Only asking personal code questions here.

      1 Reply Last reply Reply Quote 0
      • ferdinandF
        ferdinand
        last edited by ferdinand

        Hi,

        Maybe I am misunderstanding something, but you were talking about BaseBitmap::AddChannel, which will add an additional alpha channel as supported by the psd or tif format for example. BaseBitmap::SetAlphaPixel will write to the primary alpha channel as supported by many image formats. So there is a major difference between @C4DS's and your code.

        Cheers,
        zipit

        MAXON SDK Specialist
        developers.maxon.net

        1 Reply Last reply Reply Quote 0
        • fwilleke80F
          fwilleke80
          last edited by fwilleke80

          Oh, ok. As far as I understood the docs, BaseBitmap::AddChannel() would add an alpha channel, and passing true as the first argument would make this the "internal" alpha channel. After all, before I can set any alpha value with BaseBitmap::SetAlphaPixel() I would need an alpha channel to set the data to, right? BaseBitmap::GetInternalChannel() gives me nullptr if I don't call BaseBitmap::AddChannel() first.

          And no, as I see it, BaseBitmap::SetAlphaPixel() does not always write to the primary alpha channel, but to the channel I pass to the function. If I pass nullptr, no alpha value seems to be written.

          www.frankwilleke.de
          Only asking personal code questions here.

          ferdinandF 1 Reply Last reply Reply Quote 0
          • ferdinandF
            ferdinand @fwilleke80
            last edited by

            @fwilleke80 said in Draw HUD-like text to viewport:

            As far as I understood the docs, BaseBitmap::AddChannel() would add an alpha channel, and passing true as the first argument would make this the "internal" alpha channel.

            You are absolutely right, sorry, I did not read your posting carefully enough. But I also have drawn a bitmap to viewport with the approach shown by @C4DS, so it still might be worth a try.

            Cheerss,
            zipit

            MAXON SDK Specialist
            developers.maxon.net

            1 Reply Last reply Reply Quote 0
            • fwilleke80F
              fwilleke80
              last edited by

              But that is how I am doing it, too. Using BaseBitmap::SetAlphaPixel() to set alpha values into the bitmap's internal alpha channel. I am getting my values from another source (because I'm not copying a bitmap, but creating a new one), but they are still in the correct value range. I have even tried setting all pixels to the same alpha value (e.g. 128) and still did not get a semi transparent result in the viewport.

              www.frankwilleke.de
              Only asking personal code questions here.

              1 Reply Last reply Reply Quote 0
              • fwilleke80F
                fwilleke80
                last edited by

                Hm... interesting. I am getting a promising result now with this code:

                BaseBitmap* MyClass::CreateTextBitmap(const String &text, const Vector &textColor, const Vector &bgColor, Float bgOpacity, Int32 margin)
                {
                	if (!_clipmap)
                	{
                		_clipmap.Assign(GeClipMap::Alloc());
                		if (!_clipmap)
                			return nullptr;
                	}
                
                	// Dummy draw, just to get the text dimensions
                	if (_clipmap->Init(0, 0, 32) != IMAGERESULT::OK)
                		return nullptr;
                	_clipmap->BeginDraw();
                	Int32 width = _clipmap->GetTextWidth(text) + margin * 2;
                	Int32 height = _clipmap->GetTextHeight() + margin * 2;
                	_clipmap->EndDraw();
                	_clipmap->Destroy();
                
                	// Begin actual drawing
                	if (_clipmap->Init(width, height, 32) != IMAGERESULT::OK)
                		return nullptr;
                	_clipmap->BeginDraw();
                	_clipmap->EndDraw();
                	
                	width = _clipmap->GetBw();
                	height = _clipmap->GetBh();
                	_clipmap->BeginDraw();
                
                	// Background. Fill clipmap with a rectangle, overpainting possibly existing text
                	// Drawn with alpha = 255, because this alpha value just defines the transparency of the drawn color over the background.
                	// The actual background alpha is set later.
                	const Int32 backgroundColorR = (Int32)(bgColor.x * 255.0);
                	const Int32 backgroundColorG = (Int32)(bgColor.y * 255.0);
                	const Int32 backgroundColorB = (Int32)(bgColor.z * 255.0);
                	_clipmap->SetColor(backgroundColorR, backgroundColorG, backgroundColorB, 255);
                	_clipmap->FillRect(0, 0, width - 1, height - 1);
                
                	const Int32 backgroundOpacity = (Int32)(bgOpacity * 255.0);
                
                	// Text
                	// Drawn with alpha = 255, because this alpha value just defines the transparency of the drawn color over the background.
                	_clipmap->SetColor((Int32)(textColor.x * 255.0), (Int32)(textColor.y * 255.0), (Int32)(textColor.z * 255.0), 255);
                	_clipmap->TextAt(margin, margin, text);
                
                	_clipmap->EndDraw();
                
                	BaseBitmap *bitmap = _clipmap->GetBitmap()->GetClone();
                	if (!bitmap)
                		return nullptr;
                
                	BaseBitmap *alphaBitmap = bitmap->AddChannel(true, true);
                	if (!alphaBitmap)
                		return nullptr;
                	alphaBitmap = bitmap->GetInternalChannel();
                	if (!alphaBitmap)
                		return nullptr;
                
                	for (Int32 y = 0; y < bitmap->GetBh(); ++y)
                	{
                		for (Int32 x = 0; x < bitmap->GetBw(); ++x)
                		{
                			// 100% transparent corners
                			if ((x == 0 && y == 0) || (x == width - 1 && y == height - 1) ||
                				(x == 0 && y == height - 1) || (x == width - 1 && y == 0))
                			{
                				bitmap->SetAlphaPixel(alphaBitmap, x, y, 0);
                			}
                			else // All other pixels: semi transparent
                			{
                				bitmap->SetAlphaPixel(alphaBitmap, x, y, backgroundOpacity);
                			}
                		}
                	}
                	
                	return bitmap;
                }
                

                I wonder why this looks so different... I still didn't set opaque pixels for the text, but it seems to be a good start...

                www.frankwilleke.de
                Only asking personal code questions here.

                1 Reply Last reply Reply Quote 0
                • fwilleke80F
                  fwilleke80
                  last edited by

                  What I also find weird is, that even if I use the DrawMultipleHUDText() function, the stuff that appears in the viewport still looks different from the standard HUD elements like "Projection" or "FPS". It's a bit darker and the margin around the text looks different.

                  www.frankwilleke.de
                  Only asking personal code questions here.

                  1 Reply Last reply Reply Quote 0
                  • r_giganteR
                    r_gigante
                    last edited by

                    Hi Frank, thanks for reaching out us.

                    I've played a bit with and I came to this other solution which make no use of BaseBitmap and should provide more coherent results UI-wise.

                    Looking forward checking how it compares with regard to performances.

                    maxon::Result<void> OptimizedDrawMultipleHUDText(const maxon::BaseArray<HUDTextEntry>& texts, BaseDraw* bd)
                    {
                    	if (!bd || texts.IsEmpty())
                    		return maxon::IllegalArgumentError(MAXON_SOURCE_LOCATION);
                    
                    	AutoAlloc<GeClipMap> bgClipMap;
                    	if (!bgClipMap)
                    		return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
                    
                    	AutoAlloc<GeClipMap> clipMap;
                    	if (!clipMap)
                    		return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
                    	
                    	// get the current view region
                    	Int32 cr, cl, cb, ct;
                    	bd->GetFrame(&cl, &ct, &cr, &cb);
                    	
                    	// calculate view sizes
                    	const Int32 viewW = (cr - cl + 1);
                    	const Int32 viewH = (cb - ct + 1);
                    	
                    	// set the BaseDraw matrix and lighting method
                    	bd->SetMatrix_Screen();
                    	bd->SetLightList(BDRAW_SETLIGHTLIST_NOLIGHTS);
                    
                    	// Init HUD clipmap
                    	if (clipMap->Init(viewW, viewH, 32) != IMAGERESULT::OK)
                    		return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
                    
                    	clipMap->BeginDraw();
                    
                    	const Vector 	textColor = 255 * bd->GetParameterData(BASEDRAW_HUD_TEXTCOLOR).GetVector();
                    	const Vector 	bgColor = 255 * bd->GetParameterData(BASEDRAW_HUD_BACKCOLOR).GetVector();
                    	const Float 	bgTransparency = 255 * bd->GetParameterData(BASEDRAW_HUD_BACKOPACITY).GetFloat();
                    	
                    	const Int32 textH = clipMap->GetTextHeight();
                    	const Int32	drawH = textH + 10;
                    	const Int32 tX = 5;
                    	const Int32	tY = (drawH - textH) / 2;
                    
                    	// set the complete image transparent
                    	clipMap->SetColor((Int32)bgColor.x, (Int32)bgColor.y, (Int32)bgColor.z, 0);
                    	clipMap->FillRect(cl, ct, cr, cb);
                    
                    	for (const auto& it : texts)
                    	{
                    		// get text sizes
                    		const Int32 textW = clipMap->GetTextWidth(it._txt);
                    		const Int32 drawW = textW + 10;
                    
                    		// init BG clip
                    		if (bgClipMap->Init(drawW, drawH, 32) != IMAGERESULT::OK)
                    			return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
                    
                    		// create the BG
                    		bgClipMap->BeginDraw();
                    		bgClipMap->SetColor((Int32)bgColor.x, (Int32)bgColor.y, (Int32)bgColor.z, (Int32)bgTransparency);
                    		bgClipMap->FillRect(0, 0, drawW, drawH);
                    		bgClipMap->EndDraw();
                    		
                    		// blit BG
                    		clipMap->Blit((Int32)it._position.x, (Int32)it._position.y, *bgClipMap, 0, 0, drawW, drawH, GE_CM_BLIT::COL);
                    		
                    		// set text color
                    		clipMap->SetColor((Int32)textColor.x, (Int32)textColor.y, (Int32)textColor.z, 255);
                    		
                    		// draw Text
                    		clipMap->TextAt((Int32)it._position.x + tX, (Int32)it._position.y + tY, it._txt);
                    	}
                    
                    	clipMap->EndDraw();
                    	
                    	// set the points coordinates
                    	const Vector 	pvText[4] = {
                    		Vector((Float)cl, (Float)ct, 0),
                    		Vector((Float)cl, (Float)ct, 0) + Vector(viewW, 0.0, 0.0),
                    		Vector((Float)cl, (Float)ct, 0) + Vector(viewW, viewH, 0.0),
                    		Vector((Float)cl, (Float)ct, 0) + Vector(0.0, viewH, 0.0)};
                    	
                    	// set the UVs coordinates
                    	const Vector 	pvUV[4] = {
                    		Vector(0, 0, 0),
                    		Vector(1, 0, 0),
                    		Vector(1, 1, 0),
                    		Vector(0, 1, 0)};
                    
                    	// draw in Viewport
                    	bd->DrawTexture(clipMap->GetBitmap(), pvText, nullptr, nullptr, pvUV, 4, DRAW_ALPHA::NORMAL, DRAW_TEXTUREFLAGS::INTERPOLATION_NEAREST | DRAW_TEXTUREFLAGS::TEMPORARY);
                    
                    	return maxon::OK;
                    }
                    

                    Best, R

                    1 Reply Last reply Reply Quote 1
                    • fwilleke80F
                      fwilleke80
                      last edited by

                      Thank you Ricardo! This looks much simpler than the code we're currently using. I'll check it out!

                      www.frankwilleke.de
                      Only asking personal code questions here.

                      1 Reply Last reply Reply Quote 0
                      • fwilleke80F
                        fwilleke80
                        last edited by fwilleke80

                        Hm, not bad. In deed, it has the potential to look more like the "normal" HUD, without doing hacky stunts. And it is a bit faster than DrawMultipleHUDText().

                        However, even if I only draw 4 texts using this code, the framerate on my iMac is down to 24 fps (tested in R21). Using my own code, I get 127 fps. I'll see if it can be optimised more (e.g. by making the clip map a member of MyClass so it does not have to be allocated for every draw call.

                        Cheers,
                        Frank

                        EDIT: And it gets slower in a linear way. drawing 4 texts only gives me 12 fps. So, it looked promising, and I thank you very much for the code, as it gives me some new inspiration on how to do text drawing in the viewport), but for what I need to do (drawing > 30 texts on average), it is not suitable.

                        www.frankwilleke.de
                        Only asking personal code questions here.

                        1 Reply Last reply Reply Quote 0
                        • ferdinandF ferdinand referenced this topic on
                        • First post
                          Last post