Amerio.Stephane Posted June 20, 2023 Share Posted June 20, 2023 Hi, I want to create a GUI where available point of views are presented each in a button. The button image has to be generated at runtime, but only on request (not every frame!). The number of viewpoints is not fixed (depends on the scene). Ideally, the buttons should be round (mask?) I tried to use this kind of code, but the texture don't show up (the button is invisible, but still clickable). for (auto p: players) { ViewportPtr viewport = Viewport::create(); viewport->setSkipFlags(Viewport::SKIP_VELOCITY_BUFFER | Viewport::SKIP_VISUALIZER); viewport->setRenderMode(Viewport::RENDER_DEPTH_GBUFFER_FINAL); viewport->setNodeLightUsage(Viewport::USAGE_AUX_LIGHT); TexturePtr texture = Texture::create(); texture->create2D(128, 128, Unigine::Texture::FORMAT_RGBA8, Texture::SAMPLER_FILTER_LINEAR | Texture::SAMPLER_ANISOTROPY_16 | Texture::FORMAT_USAGE_RENDER); int streaming_mode = Render::getStreamingMode(); Render::setStreamingMode(Render::STREAMING_FORCE); // force load texture viewport->renderTexture2D(p->getCamera(),texture); Render::setStreamingMode(streaming_mode); // restore streaming mode ImagePtr image = Image::create(); texture->getImage(image); String filename = String::format("__%s.png", p->getName()); // unique name per camera image->save(filename); // the image on disk is correct! FileSystem::addVirtualFile(filename); // Not sure if necessary? auto button = WidgetButton::create(gui, p->getName()); button->setTexture(String("asset://")+filename); // ideally, I'd rather set directly the texture instead of saving a file // the button is here, but invisible? (displayed correctly if commented) onScreenCameras->addChild(button, Gui::ALIGN_EXPAND); } How should I do that? What am I doing wrong? Link to comment
karpych11 Posted June 21, 2023 Share Posted June 21, 2023 Hello. For round buttons I would recommend using WidgetSprite. This widget allows you to set up a mask for finding intersections. This mask is converted to R8 format. We can also use this mask to create a round sprite. grid_box.deleteLater(); grid_box = WidgetGridBox::create(); WindowManager::getMainWindow()->addChild(grid_box, Gui::ALIGN_CENTER); ImagePtr mask = Image::create("button_mask.png"); mask->convertToFormat(Image::FORMAT_R8); mask->resize(128, 128); for (auto p : players) { ViewportPtr viewport = Viewport::create(); viewport->setSkipFlags(Viewport::SKIP_VELOCITY_BUFFER | Viewport::SKIP_VISUALIZER); viewport->setRenderMode(Viewport::RENDER_DEPTH_GBUFFER_FINAL); viewport->setNodeLightUsage(Viewport::USAGE_AUX_LIGHT); TexturePtr texture = Texture::create(); texture->create2D(128, 128, Unigine::Texture::FORMAT_RGBA8, Texture::SAMPLER_FILTER_LINEAR | Texture::SAMPLER_ANISOTROPY_16 | Texture::FORMAT_USAGE_RENDER); int streaming_mode = Render::getStreamingMode(); Render::setStreamingMode(Render::STREAMING_FORCE); // force load texture viewport->renderTexture2D(p->getCamera(), texture); Render::setStreamingMode(streaming_mode); // restore streaming mode ImagePtr image = Image::create(); texture->getImage(image); // apply mask int width = image->getWidth(); int height = image->getHeight(); for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { Image::Pixel image_pixel = image->get2D(i, j); Image::Pixel mask_pixel = mask->get2D(i, j); image_pixel.i.a = mask_pixel.i.r; image->set2D(i, j, image_pixel); } } WidgetSpritePtr sprite = WidgetSprite::create(); sprite->setImage(image); sprite->addCallback(Gui::CLICKED, MakeCallback(this, &AppWorldLogic::on_click)); // set intersection mask sprite->setIntersectionImageEnabled(true); sprite->setIntersectionImage(mask); grid_box->addChild(sprite); } Here's what the result look like: 1 Link to comment
Amerio.Stephane Posted June 21, 2023 Author Share Posted June 21, 2023 Oooh I see, so WidgetButton is not necessary. So, last bit missing would be the mouse-hover effect. My Idea would have been to overlay a bright circle around the image. But I can't find a way to overlay something in a grid. Any idea? Link to comment
karpych11 Posted June 21, 2023 Share Posted June 21, 2023 You can use multiple layers in the WidgetSprite for this. Place the background on the zero layer, and the button sprite on the first one. Then you need to turn the backroung on and off on mouse callbacks. For the test I just used the mask as a background. WidgetSpritePtr sprite = WidgetSprite::create(); sprite->addLayer(); sprite->setLayerEnabled(0, false); sprite->setLayerImage(0, mask); sprite->setLayerImage(1, image); sprite->addCallback(Gui::ENTER, MakeCallback(on_enter)); sprite->addCallback(Gui::LEAVE, MakeCallback(on_leave)); void on_enter(WidgetPtr w) { WidgetSpritePtr sprite = checked_ptr_cast<WidgetSprite>(w); if (sprite == nullptr) return; sprite->setLayerEnabled(0, true); } void on_leave(WidgetPtr w) { WidgetSpritePtr sprite = checked_ptr_cast<WidgetSprite>(w); if (sprite == nullptr) return; sprite->setLayerEnabled(0, false); } 1 Link to comment
Recommended Posts