I am using some simple code to render a mesh in a loop. In practice on each iteration I will change the viewpoint and save an image of the rendering. I have reduced this to a small compilable example below:
int main(int argc, char **argv) {
vtkSmartPointer<vtkPLYReader> fileReader = vtkSmartPointer<vtkPLYReader>::New();
fileReader->SetFileName("benchvise_mesh.ply");
fileReader->Update();
vtkSmartPointer<vtkPolyData> polydata_ = fileReader->GetOutput();
vtkSmartPointer<vtkRenderWindow> render_win = vtkSmartPointer<vtkRenderWindow>::New();
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkActor> actor_view = vtkSmartPointer<vtkActor>::New();
vtkSmartPointer<vtkCamera> cam = vtkSmartPointer<vtkCamera>::New();
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
for (int i = 0; i < 100; i++) {
mapper->SetInput(polydata_);
mapper->Update();
cam->SetViewAngle(58);
cam->SetClippingRange(0.00001, 10000);
//Invert view Up
cam->SetViewUp(0, -1, 0);
cam->SetPosition(0, 0, -500);
cam->SetFocalPoint(0, 0, 1);
cam->Modified();
actor_view->SetMapper(mapper);
actor_view->Modified();
renderer->SetActiveCamera(cam);
renderer->AddActor(actor_view);
renderer->SetBackground(1.0, 1.0, 1.0);
renderer->Modified();
render_win->AddRenderer(renderer);
render_win->SetSize(640, 480);
//white
render_win->Modified();
render_win->Start();
render_win->Render();
render_win->Finalize();
}
}
The problem is, when I run this many vtkWindow icons appear on my taskbar and eventually bring the pc to a halt. It appears as though on each loop the rendering window stays alive. However, when I click on an icon the window doesn't actually appear.
Is there something I am missing that will clean up the render windows on each iteration.
BTW, I am running under Ubntu with vtk 5.8
You do several things 'wrong' there. Remove everything wrong the loop, most importantly render_win->Start(), initialize at begin and just call render_win->Render() at each loop after the appreciated modifications to viewing has been made ( calls to mappers or cameras SetPosition and similars affect your view without reconnection, reconnection being call to Add????() -methods). Modified() calls should be implicit and not required manually.
Related
My goal is to create a simple video player QWidget that allows for some overlayed graphics (think subtitles or similar).
I started with the naive approach, which was to use QVideoWidget with another set of QWidget on top (my overlays). Unfortunately this does not work because Qt does not allow widgets with transparent background to render on top of video. The background shows as black instead of the actual video.
Next idea is to use QGraphicsScene et al. which is supposed to allow this kind of compositing, so I create a dead simple setup like this:
// The widget we will use as viewport
auto viewport= new QWidget();
//Set an easily recognizable bg color for debugging
palette.setColor(QPalette::Window, Qt::green);
viewport->setPalette(palette);
viewport->setAutoFillBackground(true);
// Our scene
auto mScene=new QGraphicsScene(this);
// The video
auto mVideoItem = new QGraphicsVideoItem();
mVideoItem->setPos(0,0);
myVideoSource.setVideoOutput(mVideoItem); // ... not shown: setting up of the video source
mScene->addItem(mVideoItem);
// Yellow line starting at 0,0 for debugging
auto line=new QGraphicsLineItem (0,0,100,100);
line->setPos(0,0);
line->setPen(QPen(Qt::yellow, 2));
mScene->addItem(line);
// A Text string
auto text=new QGraphicsTextItem("Its Wednesday my dudes", mVideoItem);
text->setPos(10, 10);
// Our view
mView=new QGraphicsView;
mView->setScene(mScene);
mView->setViewport(viewport);
viewport->show()
Now this looks promising because I can see compositing works; the line and text render flawlessly on top of the video. However the video is positioned in a seemingly random place in the widget. (see screensdhot)
At this point I have tried every conceivable and inconceivable combination of
mVideoItem->setSize();
mVideoItem->setOffset();
mScene->setSceneRect();
mView->fitInView();
mView->ensureVisible();
mView->centerOn()
Trying to fill the viewport widget with the video item but nothing seems logical at all. Instead of centering the content, it seems to fly around the screen in logic defying ways and I have given up. I put my code in the viewport widget's resizeEvent and use the viewport widget's size() as the base.
So my question is; How can I fill viewport widget with video item on resize?
I dont think QGraphicsVideoItem is good for this task.
You can implement QAbstractVideoSurface that receives QVideoFrames and feeds them to QWidget that converts them to QImage, scales and draws them in paintEvent. Since you control paintEvent you can draw anything over your video, and get "fill viewport" feature for free.
Gist:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Surface surface;
Widget widget(surface);
widget.show();
QMediaPlayer player;
player.setVideoOutput(&surface);
player.setMedia(QMediaContent(QUrl("path/to/media")));
player.play();
return a.exec();
}
bool Surface::present(const QVideoFrame &frame)
{
mFrame = frame;
emit frameReceived();
return true;
}
Widget::Widget(Surface &surface, QWidget *parent)
: QWidget{parent}, mSurface(surface)
{
connect(&mSurface,SIGNAL(frameReceived()),this,SLOT(update()));
}
void Widget::paintEvent(QPaintEvent *event)
{
QVideoFrame frame = mSurface.frame();
if (frame.map(QAbstractVideoBuffer::ReadOnly)) {
QPainter painter(this);
int imageWidth = mSurface.imageSize().width();
int imageHeight = mSurface.imageSize().height();
auto image = QImage(frame.bits(),
imageWidth,
imageHeight,
mSurface.imageFormat());
double scale1 = (double) width() / imageWidth;
double scale2 = (double) height() / imageHeight;
double scale = std::min(scale1, scale2);
QTransform transform;
transform.translate(width() / 2.0, height() / 2.0);
transform.scale(scale, scale);
transform.translate(-imageWidth / 2.0, -imageHeight / 2.0);
painter.setTransform(transform);
painter.drawImage(QPoint(0,0), image);
painter.setTransform(QTransform());
painter.setFont(QFont("Arial", 20));
int fontHeight = painter.fontMetrics().height();
int ypos = height() - (height() - imageHeight * scale) / 2 - fontHeight;
QRectF textRect(QPoint(0, ypos), QSize(width(), fontHeight));
QTextOption opt(Qt::AlignCenter);
painter.setPen(Qt::blue);
painter.drawText(textRect, "Subtitles sample", opt);
frame.unmap();
}
}
Full source: draw-over-video
Based on customvideosurface example from Qt.
I'm attempting to create a window using SDL2 and initialize BGFX to use it. My current test is just to set the window to purple using a clear color.
I tried creating a window using CreateWindowEx as well, and was also unable to update the window with the clear color I specified in my call to bgfx::setViewClear. I've been scouring open source projects as well as the docs and samples, and I can't figure out what step of bgfx initialization/update I could be missing. Please help! I've attached my current approach as a small test main.
int main(int, char**) {
SDL_InitSubSystem(SDL_INIT_VIDEO);
const int width = 800;
const int height = 600;
SDL_Window* window = nullptr;
HWND nativeWindow;
// sdl2
{
window = SDL_CreateWindow(
"test_window",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
width, height,
0
);
SDL_SysWMinfo windowManInfo;
SDL_VERSION(&windowManInfo.version);
if (SDL_GetWindowWMInfo(window, &windowManInfo)) {
nativeWindow = windowManInfo.info.win.window;
}
}
// bgfx
{
bgfx::PlatformData platformData;
platformData.ndt = nullptr;
platformData.nwh = nativeWindow;
bgfx::setPlatformData(platformData);
// prevent creation of a renderer thread
bgfx::renderFrame();
bgfx::Init init;
init.type = bgfx::RendererType::Count;
init.resolution.width = width;
init.resolution.height = height;
init.resolution.reset = BGFX_RESET_VSYNC;
bgfx::init(init);
bgfx::setViewClear(0, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x443355FF /*purple*/, 1.f, 0);
}
while (1) {
// sdl events
{
SDL_Event _event;
while (SDL_PollEvent(&_event) > 0);
}
bgfx::frame();
}
bgfx::shutdown();
SDL_Quit();
return 0;
}
After asking around work/etc.. I finally got a solution, and there were actually a couple of things that I was missing.
Because I wasn't adding any render work to the frame, bgfx is 'smart' and doesn't actually do anything. Adding a call to bgfx::touch will add an empty primitve for rendering. After I added this I could see a small dot in the top-left of my window, which leads to the other call I was missing.
I never set my view! I was also only rendering to one pixel of my window. By adding a call to bgfx::setViewRect I was able to set a size for my window view and the clear color finally took.
I've been working on a project in SDL on nights and weekends for the past few months. I'm currently trying to get a menu system working. At the moment, I'm working on drawing text using SDL_TTF. As for my question, I'm seeing some strange behavior when I try to draw some textures to another texture.
The weirdness is that when I draw it, on a destination texture created with SDL_TEXTUREACCESS_TARGET (like it says to do in the docs) draws nothing, but returns no error. However, if I use SDL_TEXTUREACCESS_STATIC or SDL_TEXTUREACCESS_STREAM, it returns an error when I set the render target because of the access attribute, but draws just fine. After doing some digging, I heard some things about a bug in the Intel drivers (I'm on a Macbook with Intel graphics), so I was wondering if this was something I messed up, and how I might fix it. Alternately, if it isn't my fault, I'd still like to know what's going on, and if it would perform differently on different platforms and how I could work around it.
Here's my code, after removing unnecessary parts and :
I create the renderer:
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
Later on, when I go to render onto a canvas:
TTF_Font *fnt = loadFont(fontName.c_str(), fontSize);
In here I parse out some attributes and set them using TTF_SetFontStyle() and the clr for text color.
SDL_Texture *canvas;
canvas = SDL_CreateTexture(rendy, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, contentRect.w, contentRect.h)
SDL_SetRenderTarget(rendy, canvas);
int pos = 0;
for (list<string>::iterator itr = lines.begin(); itr != lines.end(); itr++){
SDL_Surface *temp;
temp = TTF_RenderText_Blended(fnt, src.c_str(), clr);
SDL_Texture *line;
line = SDL_CreateTextureFromSurface(rendy, temp);
int w,h;
SDL_QueryTexture(line, NULL, NULL, &w, &h);
SDL_Rect destR;
//Assume that we're left justified
destR.x = 0;
destR.y = pos;
destR.w = w;
destR.h = h;
SDL_RenderCopy(rendy, line, NULL, &destR);
SDL_DestroyTexture(line);
SDL_FreeSurface(temp);
pos += TTF_FontLineSkip(fnt);
}
//Clean up
SDL_SetRenderTarget(rendy, NULL);
canvas gets returned to the calling function so it can be cached until this text box is modified. That function works by having a texture for the whole box, drawing a background texture onto it, and then drawing this image on top of that, and holding on to the whole thing.
That code looks like this:
(stuff to draw the background, which renders fine)
SDL_Texture *sum = SDL_CreateTexture(rendy, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, globalRect.w, globalRect.h);
SDL_SetTextureBlendMode(sum, SDL_BLENDMODE_BLEND);
SDL_SetRenderTarget(rendy, sum);
string lPad = getAttribute(EL_LEFT_PADDING);
string tPad = getAttribute(EL_TOP_PADDING);
int paddingL = strtol(lPad.c_str(), NULL, 10);
int paddingT = strtol(tPad.c_str(), NULL, 10);
SDL_Rect destR;
SDL_Rect srcR;
srcR.x = 0;
srcR.y = 0;
srcR.w = globalRect.w; //globalRect is the size size of the whole button
srcR.h = globalRect.h;
destR.x = 0;
destR.y = 0;
destR.w = globalRect.w;
destR.h = globalRect.h;
SDL_RenderCopy(rendy, bgTexture, NULL, &destR);
int maxX = contentRect.w;
fgTexture = getFGImage(rendy); //The call to the previous part
int w, h;
SDL_QueryTexture(fgTexture, NULL, NULL, &w, &h);
int width, height;
getTextSize(&width, &height, maxX);
srcR.x = 0;
srcR.y = 0;
srcR.w = width;
srcR.h = height;
destR.x = paddingL;
destR.y = paddingT;
destR.w = globalRect.w;
destR.h = globalRect.h;
SDL_RenderCopy(rendy, fgTexture, NULL, &destR);
SDL_DestroyTexture(fgTexture);
SDL_DestroyTexture(bgTexture);
return sum;
Sum is returned to another function which does the drawing.
Thanks in advance!
Update
So I've figured out that the reason it only drew when I had the incorrect access setting was that, since the function was returning an error value, the render target was never set to the texture, so it was just drawing on the screen. I've also checked all my textures by writing a function AuditTexture which checks to see that the texture format for a texture is supported by the renderer, prints a string description of the access attribute, and prints the dimensions. I now know that all of their texture formats are supported, the two lines are static, canvas and sum are render targets, and none of them have dimensions of zero.
As it turns out, I had set the render target to be the composite texture, then called my function which set the render target to the text texture before drawing text. Then when I returned from the function, the render target was still the text texture instead of the composite one, so I basically drew the text over itself instead of drawing over the background.
A word to the wise: Don't ever assume something is taken care of for you, especially in c or c++.
I'm trying to display a texture onto the screen but all I'm getting is a black window.
No SDL Errors are being reported. There's a good chance that I'm missing something stupid, but I can't see it. Hopefully another set of eyes will help. Feel free to ask for more code/info.
main.cpp
SDL_Window * window;
SDL_Renderer * renderer;
SDL_Texture * grass;
SDL_Rect g_dst;
SDL_Event event;
Game app;
SDL_Init(SDL_INIT_EVERYTHING);
window = SDL_CreateWindow("tmp", 100, 100, 640, 480, SDL_WINDOW_SHOWN);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
g_dst.x = g_dst.y = 0;
g_dst.w = 640;
g_dst.h = 480;
grass = IMG_LoadTexture(renderer, "grass.bmp");
while (app.isRunning()) {
app.pollEvents(&event);
app.render_init();
app.render(grass, NULL, &g_dst);
app.render_end();
}
//SDL_Quit() is handled by the Game class' destructor
Game.cpp
//Only functions used for rendering are shown
void render_init(Uint8 red=0, Uint8 green=0, Uint8 blue=0, Uint8 alpha=255)
{
SDL_SetRenderDrawColor(renderer, red, green, blue, alpha);
SDL_RenderClear(renderer);
}
void render(SDL_Texture * texture, SDL_Rect * src, SDL_Rect * dest) {
SDL_RenderCopy(renderer, texture, src, dest);
}
void render_end() { SDL_RenderPresent(renderer); }
First of all, you're initializing everything? please don't do that frequently, mind you that you're also initializing MANY unnecessary stuffs like for game controllers, etc. if the app gets bigger then the efficiency and the possibility of this app running at a smoot speed is at stake.
I also noticed that you are declaring variables in the .cpp file, do that in the header file and just recall the header to the cpp file that will be using it.
You want to render the grass right? and render it as much as the screens size.
(I'll just assume that you used this in the game.cpp part, which is the very first file, thus, not regarding any classes made)
int winWidth = 680; //The reason for this is just in case you make the window resizable
int winHeight = 480; //then the texture would also resize along with the window
SDL_Window *window = window = SDL_CreateWindow("The Space Project", 100, 100, winWidth, winHeight, SDL_WINDOW_SHOWN);
SDL_Renderer *renderer = NULL; //I've set this to NULL so that we can know if
the reason as to why your image is not rendering is because the renderer is not properly working.
renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED);
if(renderer == NULL)
{
cout >> "Renderer is not working" >> endl;
//This shows a line at the command prompt that your renderer doesn't have any output, thus, only having a NULL as an equivalent
}
SDL_Texture* grass= NULL;
grass= IMG_LoadTexture(renderer, "grass.bmp"); //As you can see, I've set the grass to Null again
if(grass == NULL)
{
cout >> "Grass have failed to initialize" >> endl;
/*I don't normally do this but it's very important if you really need trouble shooting guides
but this time, were here to check IF the grass.bmp entered the SDL_Texture grass, so if the system can't find the .bmp file then it would show this error
since the grass (SDL_Texture) still doesn't have anything inside it (NULL)*/
}
SDL_Rect grass_rect;
grass_rect.x = 0;
grass_rect.y = 0;
grass_rect.w = winWidth;
grass_rect.h = winHeight;
//Loop part, I'll skip some of it
while (!quit && mainEvent->type != SDL_QUIT) //!quit is just an imaginary Boolean I've typed)
{
SDL_PollEvent(mainEvent); //Let's say you created the event already
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, grass, NULL, &grass_rect);
//The NULL part is also similar to a rect but it's a limiting type, we didn't assign anything to it
since I assumed that you wanted the whole image to be rendered
SDL_RenderPresent(renderer);
}
I revised the code and made it more efficient since your code called for useless extras which might result in lower performance.
I also notice that you tried calling for color changes?
use this
SDL_SetTextureColorMod(texture, red-value, green-value, blue-value);
and put it in the loops part under the render present of the same texture.
SDL_SetTextureColorMod(grass, 250, 250, 250);
Doing this would set all color values to 250, thus, having a white color, this change your texture color to white.
You're also wasting space on making the app.is running(), you could easily replace it with a boolean, which consumes much less space or you could omit it if you don't have an exit button inside the application and just make your loop read the SDL_QUIT, this saves space for the file, mind the efficiency.
If this still doesn't work then try replacing the image your using, make a simple one on paint name it something like "grass.png" or anything then try it again.
Don't forget to put the file in the proper folder, in the DEBUG folder if you haven't specified a folder, and also put it in the app folder so it would also read it when it executes as an .exe file and not as part of the debug command.
EDIT: SOLVED
The problem was me using the renderstate functions I needed for alphablending outside of the Sprite->Begin() and Sprite->End() codeblock.
I am creating my own 2D engine within DirectX 9.0. I am using sprites with corresponding spritesheets to draw them. Now the problem is, if I set my blending to D3DSPR_SORT_TEXTURE, I'll be able to see the texture without any problems (including transformation matrices), however if I try and set it to D3DSPR_ALPHABLEND, the sprite won't display. I've tried several things; SetRenderState, change the image format from .png to .tga, add an alpha channel to the image with a black background, used another image used within an example of 2D blending, changed my D3DFMT_ parameter of my D3DManager, etc.
I'm tried searching for an answer here but didn't find any answers related to my question.
Here's some of my code which might be of importance;
D3DManager.cpp
parameters.BackBufferWidth = w; //Change Direct3D renderer size
parameters.BackBufferHeight = h;
parameters.BackBufferFormat = D3DFMT_UNKNOWN; //Colors
parameters.BackBufferCount = 1; //The amount of buffers to use
parameters.MultiSampleType = D3DMULTISAMPLE_NONE; //Anti-aliasing quality
parameters.MultiSampleQuality = 0;
parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
parameters.hDeviceWindow = window; //The window to tie the buffer to
parameters.Windowed = true; //Window mode, true or false
parameters.EnableAutoDepthStencil = NULL;
parameters.Flags = NULL; //Advanced flags
parameters.FullScreen_RefreshRateInHz = 0; //Fullscreen refresh rate, leave at 0 for auto and no risk
parameters.PresentationInterval = D3DPRESENT_INTERVAL_ONE; //How often to redraw
Sprite.cpp
void Sprite::draw(){
D3DXVECTOR2 center2D = D3DXVECTOR2(center.x,center.y);
D3DXMatrixTransformation2D(&matrix,¢er2D,NULL,&scale,¢er2D,angle,new D3DXVECTOR2(position.x,position.y));
sprite->SetTransform(&matrix);
sprite->Begin(D3DXSPRITE_ALPHABLEND);
if(!extended){
sprite->Draw(texture, NULL, NULL, &position, 0xFFFFFF);
}
else{
doAnimation();
sprite->Draw(texture, &src, ¢er, new D3DXVECTOR3(0,0,0), color);
}
sprite->End();
}
Main.cpp
//Clear the scene for drawing
void renderScene(){
d3dManager->getDevice().Clear(0,NULL,D3DCLEAR_TARGET,0x161616,1.0f,0); //Clear entire backbuffer
d3dManager->getDevice().BeginScene(); //Prepare scene for drawing
render(); //Render everything
d3dManager->getDevice().EndScene(); //Close off
d3dManager->getDevice().Present(NULL, NULL, NULL, NULL); //Present everything on-screen
}
//Render everything
void render(){
snake->draw();
}
I've got no clue at all. Any help would be appreciated.
The problem was me using the renderstate functions I needed for alphablending outside of the Sprite->Begin() and Sprite->End()
code block.