I am trying to create a tool that will draw a shape in openGL and then modify the values of the properties of that shape in a windows form. So if my shape is a rectangle, I will create a form that will allow the user to control the size, color etc of the rectangle. I have written the openGL code in managed c++ and the form in c#, and as some of these shapes got more complicated I decided to make display lists for them (for both performance and predictability purposes).
I define the display list in the constructor for the shape and I call the display lists in the render method.
My issue is that my display lists won't run at all. The parts that I render outside of a display list will be rendered, but the parts inside the display list will not be rendered.
Here's some sample code of my process:
//c# side
GLRectangle rect
public CSharpRectangle() {
rect = new GLRectangle();
}
//managed c++ side
public GLRectangle() {
width = 50;
height = 50;
//initialize more values
rectDL = glGenLists(1);
glNewList(rectDL, GL_COMPILE);
renderRect();
glEndList();
}
public render() {
//Draw border
glBegin(GL_LINE_LOOP);
glVertex2f(0, 0);
glVertex2f(width, 0);
glVertex2f(width, height);
glVertex2f(0, height);
glEnd();
//Draw interior
glCallList(rectDL);
}
private renderRect() {
glRectf(0,0,width,height);
}
In this example, the border of the rectangle would be rendered, but the rectangle itself won't be rendered... if I replace the display list with simply a method call, the rectangle is rendered fine. Does anyone know why this might be happening?
I want to give my 2 cents.
The code in your question seems correct to me, so probably there something else in your application that make your display list not runnable.
The only thing I can think is there's no current context when compiling the display list (indeed when executing GlRectangle constructor). So, is that routine executed in the same thread which have called glMakeCurrent? Is that routine called after glMakeCurrent?
Further, check with glGetError after each OpenGL routine in order to validate the operation. In the case it returns an error, you can know what's wrong in your code..
The reason you may not get what you want is simply because it isn't there anymore. In time I was reading openGL Red book, I've noticed that display lists were deprecated in openGL 3.1 and higher (means simply removed) and googling for that confirmed it. I don't remember reason anymore, but I believe because it was messing with VAOs and VBOs. So if you are using higher than opengl 3.1 you won't get display lists anymore.
Related
I am trying to make simple square where you could paint with mouse. Problem is, whenever draw signal is happens, cairo surface seems to be cleared entirely. I understand this because after first queue_draw() white background is gone and I see my GTK theme color (which is grey).
I thought I could save surface or context, but you can't just create empty surface in cairo, and I can't create it using this->get_window()->create_cairo_surface() (where this is object of class inherited from Gtk::DrawingArea) because when constructor is called, widget isn't attached to any window yet, so it is a null pointer. I mean, I could create some public function called you_are_added_to_window_create_cairo_surface() but I'd really like not to do this.
So I really don't know what to do and what I don't understand about cairo.
How do I preserve, or save 'canvas' current state, so whatever is actually being drawn is just applied on existing drawing?
Here is callback function of my class:
bool MyDrawingArea::on_draw(const Cairo::RefPtr<Cairo::Context> & cr) {
/* clear and fill background with white in the beginning */
if (first_draw) {
cr->save();
cr->set_source_rgb(255.0, 255.0, 255.0);
cr->paint();
cr->restore();
first_draw = false;
}
cr->save();
cr->set_source_rgb(0.0, 0.0, 0.0);
cr->begin_new_path();
while (!dots_queue.empty()) {
auto dot = dots_queue.front();
cr->line_to(dot.first, dot.second);
dots_queue.pop();
}
cr->close_path();
cr->stroke();
cr->restore();
return false;
}
Remove first_draw and instead of dots_queue.pop(), just iterate over the dots_queue and redraw all of them each time.
The draw function is not meant for "I want to add some drawing". Instead, it is "hey, the windowing system has no idea what should be drawn here, please fill this with content". That's why the cairo surface is cleared.
So while storing all actions works, it's really not ok if you are trying to have your program save your drawings, you will have to use second surface to save everything on.
My solution combines both answers of Uli Schlachter.
First, I have structure, in which I store last drawing action, since last Button Press, and until Button Release. This allows me to show things such as lines in real time, while keeping canvas clean of it.
Second, I store everything drawn on canvas on a surface, which is created like that:
// this - is object of class, derived from DrawingArea
auto allocation = this->get_allocation();
this->surface = Cairo::ImageSurface::create(
Cairo::Format::FORMAT_ARGB32,
allocation.get_width(),
allocation.get_height()
);
Then, on each draw signal, I restore it like that:
cr->save();
cr->set_source(surface, 0.0, 0.0);
cr->paint();
cr->restore();
Whenever I want to save surface, i.e. apply drawing on to canvas, I do the following:
Cairo::RefPtr<Cairo::Context> t_context = Cairo::Context::create(surface);
t_context->set_source(cr->get_target(), -allocation.get_x(), -allocation.get_y());
t_context->paint();
Here is the important moment. Without adjusting for the allocation coordinates, your canvas is going to slide away on each surface save and restore.
With that, I can easily keep my drawings on canvas, load canvas from file (because I am using ImageSurface), or save it to the file.
I'm stumped. I have a widget inside the mainwindow on a QT 4.6 application which has been configured as a openGL widget. It draws just fine except I am unable to clear the background between frames. I get a black background when he window opens and it never clears after that, so I get a jumbled mess of rendered objects as time goes along. I'm also having to call swapBuffers() at the end of the paintGL() function to get the widget to show the most recent frame which has me puzzled as I was under the impression that swapBuffers() was called automatically. I am set up for double buffering and the widget is not shared. Here is the relevant code:
void GLWidget::paintGL ( )
{
m_Input.Draw();
QGLWidget::swapBuffers();
}
void GLWidget::initializeGL ( )
{
qglClearColor(QColor(0,0,255,128));
glClear(GL_COLOR_BUFFER_BIT);
}
It does seem there's something not right with the double buffering. Clearing the screen to a background color is pretty basic. But it's driving me nuts as to why it's not working. The remainder of the drawing code is working fine. Any ideas? (This is on a Linux system.)
glClear is a drawing operation. It doesn't belong into initializeGL but into paintGL. The clearing color should be set right before calling glClear as well, so move that [q]glClearColor along.
Update
The paintGL method should look like this:
void GLWidget::paintGL()
{
qglClearColor(QColor(0,0,255,128));
glClear(GL_COLOR_BUFFER_BIT);
// you probably also want to clear the depth and stencil buffers
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
m_Input.Draw();
QGLWidget::swapBuffers();
}
Of course you must make sure that m_Input.Draw() doesn't mess things up again. You didn't show the code for that, so I'm in the blind here.
I am trying to rotate a 3d object but it doesnt update when applying transforms in a for loop.
The object jumps to the last position.
How does one update a 3d object's position in a sequence of updates if it wont update in a for loop?
Just calling glTranslate, glRotate or such won't change things on the screen. Why? Because OpenGL is a plain drawing API, not a scene graph. All it knows about are points, lines and triangles that draws to a pixel framebuffer. That's it. You want to change something on the screen, you must redraw it, i.e. clear the picture, and draw it again, with the changes.
BTW: You should not use a dedicated loop to implement animations (neither for, nor while, nor do while). Instead perform animation in the idle handler and issue a redraw event.
I reckon you have a wrong understanding what OpenGL does for you.
I'll try to outline:
- Send vertex data to the GPU (once)
(this does only specify the (standard) shape of the object)
- Create matrices to rotate, translate or transform the object (per update)
- Send the matrices to the shader (per update)
(The shader then calculates the screen position using the original
vertex position and the transformation matrix)
- Tell OpenGL to draw the bound vertices (per update)
Imagine programming with OpenGL like being a web client - only specifying the request (changing the matrix and binding stuff) is not enough, you need to explicitly send the request (send the transformation data and tell OpenGL to draw) to receive the answer (having objects on the screen.)
It is possible to draw an animation from a loop.
for ( ...) {
edit_transformation();
draw();
glFlush(); // maybe glutSwapBuffers() if you use GLUT
usleep(100); // not standard C, bad
}
You draw, you flush/swap to make sure that what you just drew is sent to the screen, and you sleep.
However, it is not recommended to do this in an interactive application. The main reason is that while you are in this loop, nothing else can run. Your application will be unresponsive.
That's why window systems are event-based. Every few miliseconds, the window system pings your app so you can update your state, for example do animation. This is the idle function. When the state of your program changed, you tell the window system that you would like to draw again. It is then up the the window system to call your display function. You do your OpenGL calls when the system tells you to.
If you use GLUT for communicating with the window system, this looks like the code below. Other libraries like GLFW have equivalent functions.
int main() {
... // Create window, set everything up.
glutIdleFunc(update); // Register idle function
glutDisplayFunc(display); // Register display function
glutMainLoop(); // The window system is in charge from here on.
}
void update() {
edit_transformation(); // Update your models
glutPostRedisplay(); // Tell the window system that something changed.
}
void display() {
draw(); // Your OpenGL code here.
glFlush(); // or glutSwapBuffers();
}
I'm using glScissor() in my application and it works properly, but I met a problem:
I have my Window object for which drawing area is specified by glScissor() and inside this area, I'm drawing my ListView object for which the drawing area should also be specified with glScissor() as I don't want to draw it all.
In a code I could represent it as:
Window::draw()
{
glEnable(GL_SCISSOR_TEST);
glScissor(x, y, width, height);
// Draw some components...
mListView.draw(); // mListView is an object of ListView type
glDisable(GL_SCISSOR_TEST);
}
ListView::draw()
{
glEnable(GL_SCISSOR_TEST);
glScissor(x, y, width, height);
// Draw a chosen part of ListView here
glDisable(GL_SCISSOR_TEST);
}
But of course in this situation enable/disable calls are wrong:
glEnable(GL_SCISSOR_TEST);
glEnable(GL_SCISSOR_TEST);
glDisable(GL_SCISSOR_TEST);
glDisable(GL_SCISSOR_TEST);
If I remove those internal glEnable/glDisable calls (the ones in ListView), I would anyway end up with two glScissor() calls which also seems to be wrong.
EDIT
I would like to somehow achieve both scissor effects, I mean - that Window should draw only in it's scissored area and internal ListView also only in it's scissored area.
As you can see in a picture, with red rectangle I have marked scissor area for Window which WORKS, and with a blue rectangle I marked an area on which I'd like to draw my ListView. That's why I was trying to use nested scissors, but I know it was useless. So basically my question is, what could be the best approach to achieve this?
Since OpenGL is a state machine and the scissor rect, like any other state, is overwritten when calling glScissor the next time, you have to properly restore the window's scissor rect after drawing the list view. This can either be done by just letting the window manage it:
Window::draw()
{
// draw some components with their own scissors
mListView.draw(); // mListView is an object of ListView type
glScissor(x, y, width, height);
glEnable(GL_SCISSOR_TEST);
// draw other stuff using window's scissor
glDisable(GL_SCISSOR_TEST);
}
But it might be more flexible to let the individual components restore the scissor state themselves, especially if used in such a hierarchical manner. For this you can either use the deprecated glPush/PopAttrib functions to save and restore the scissor rect:
ListView::draw()
{
glPushAttrib(GL_SCISSOR_BIT);
glEnable(GL_SCISSOR_TEST);
glScissor(x, y, width, height);
// Draw a chosen part of ListView here
glDisable(GL_SCISSOR_TEST);
glPopAttrib();
}
Or you save and restore the scissor state yourself:
ListView::draw()
{
// save
int rect[4];
bool on = glIsEnabled(GL_SCISSOR_TEST);
glGetIntegerv(GL_SCISSOR_BOX, rect);
glEnable(GL_SCISSOR_TEST);
glScissor(x, y, width, height);
// Draw a chosen part of ListView here
// restore
glScissor(rect[0], rect[1], rect[2], rect[3]);
if(!on)
glDisable(GL_SCISSOR_TEST);
}
This can of course be automated with a nice RAII wrapper, but that is free for you to excercise.
edited: General case.
Every time you set the scissor state with glScissor, you set the scissor state. It does not nest, and it does not stack, so you cannot "subscissor" with nested calls to glScissor. You'll have to manually compute the rectangular intersection of your ListView and your Window bounding rects, and then scissor to that when drawing ListView.
In the general case, you'll be manually maintaining a stack of scissor rectangles. As you draw each sub-element, you intersect the sub-element's bounding rect against the current top of the stack, and use that as the scissor for that sub-element. Push the new subrect onto the stack when painting children, and pop it when returning back up the hierarchy.
If you're painting other contents to Window, you'll also have to make sure to handle overdraw correctly; either by setting the Z ordering and enabling depth buffering, or by disabling depth buffering and painting your contents back-to-front. Scissoring won't help you mask the Window contents behind the ListView, since scissors can only be rectangular regions.
OpenGL is a state machine. You can call glScissor, glEnable and glDisable as often as you'd like to. They don't act like opening-closing braces that must be matched. If your calls "fold" like this, that's no problem. Just don't expect the one scissor to merge with the other one; it will merely change/overwrite the previous setting.
I was wondering whether the following can be easily implemented in OpenGL:
divide window into multiple panels
put each panel into place using normalized coordinates (0-1) so that if the window gets re-sized, the panel will stay in the correct position
draw directly into one of the previously defined panels
The result should look something like the following picture:
So far I've been drawing my objects directly into the window, offsetting the coordinates with the respective value for each panel. However this doesn't feel like the right way of doing things. Any suggestions and example code from experienced developers is highly appreciated!
EDIT: What I've read so far, using glScissor or glViewport might be two ways of accomplishing what I want, however I don't know what the pros and cons are for going either route (your insights are very welcome!). Additionally, I would really prefer to define some kind of panel, return its handle and just draw into that.
If you use glScissor() you just define the clipping rectangle (i.e. where to draw). This might be everything you need.
With glViewport() you essentially call glScissor() behind the scenes as well as changing how coordinates are mapped to screen space.
If you want to limit drawing to one of the panels (without using local coordinates), use glScissor(). Otherwise, use glViewport().
As for the panel, I'd probably use some abstract base class:
class Panel {
// ...
virtual void OnDraw(void) = 0;
void Draw(void) {
glViewport(x, y, w, h);
OnDraw();
glViewport(0, 0, parent_w, parent_h);
}
}