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.
    • C4DSC
      C4DS
      last edited by C4DS

      Hi,
      This is what I use to copy the alpha over and I do get transparency. But I only use filled colored areas, no text, still I think this should provide the same result.

      	UInt16 r, g, b, a;
      	Int32 destX, destY;
      	for (Int32 y = 0; y < sourceBmp->GetBh(); ++y)
      	{
      		for (Int32 x = 0; x < sourceBmp->GetBw(); ++x)
      		{
      			sourceBmp->GetAlphaPixel(alphaSource, x, y, &a);
      			if (a)
      			{
      				sourceBmp->GetPixel(x, y, &r, &g, &b);
      				destBmp->SetPixel(destX, destY, r, g, b);
      				destBmp->SetAlphaPixel(alphaDest, destX, destY, a);
      			}
      		}
      	}
      
      

      EDIT: however, I don't see any alpha values different from 255 in your clipmap, or am I missing something?

      1 Reply Last reply Reply Quote 0
      • 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