The rate at which a wxMouseEvent occurs in wxWidgets is a bit too low for my liking. I have the same logic setup, but using another window/event system (SFML), and the rate of mouse events is about twice as fast. I like SFML, but I really want to use wxWidgets due to its superior native menu/widget usability.
I am measuring the number of wxMouseEvents that occur in 10 seconds while my mouse is dragging, and I visually put a small square red dot each drag event to visually compare.
Measuring on wxWIdgets;
I get about 611 events, or about 60 events per second. The dots are farther apart and the less smooth (less dots = sharper angles between dots when dragging the mouse in a circle).
Measuring on SFML:
I get about 1611 events, or about 160 events per second. So, about twice that of wxWidgets. The dots are a lot more smooth!
I will post what I hope is the relevant parts of my program. Posting the whole program would be a bit cumbersome because of all the OpenGL setup, but I could if there is interest...
wxWidgets src:
Code: Select all
wxBEGIN_EVENT_TABLE(MyGLCanvas, wxGLCanvas)
EVT_PAINT(MyGLCanvas::OnPaint)
EVT_SIZE(MyGLCanvas::OnSize)
EVT_MOUSE_EVENTS(MyGLCanvas::OnMouse)
//EVT_IDLE(MyGLCanvas::OnIdle)
wxEND_EVENT_TABLE()
Code: Select all
void MyGLCanvas::OnMouse(wxMouseEvent& event)
{
static int i = 0;
if (i++ % 10 == 0) std::cout << i << "\n";
event.Skip();
// GL 0 Y-coordinate is at bottom of the window
int oglwinY = m_winHeight - event.GetY();
if (event.LeftUp())
{
}
if (event.LeftDown())
{
//std::cout << "(" << i << ") " << "Click at " << "(" << event.GetX() << ", " << event.GetY() << ")\n";
size_t index = 4 * m_width * event.GetY() + 4 * event.GetX();
m_pixels[index+0] = 255;
m_pixels[index+1] = 0;
m_pixels[index+2] = 0;
}
if (event.LeftIsDown())
{
//std::cout << "...\n";
if (!event.Dragging())
{
}
else
{
//std::cout << "(" << i << ") " << "dragging\n";
static const std::vector<unsigned char> red_data {
255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255,
255, 0, 0, 255
};
// Update the image to OpenGL
// by sending a red box
glTexSubImage2D(
GL_TEXTURE_2D, // target
0, // level
event.GetX(), // xoffset
event.GetY(), // yoffset
// note: no internal format can be changed for Sub
m_width/100, // width
m_height/100, // height
//GL_BGRA, // format (of the pixel data)
GL_RGBA,
GL_UNSIGNED_BYTE, // type
red_data.data() //dat
);
// Generate paint event without erasing the background.
Refresh(false);
}
}
}
Code: Select all
void MyGLCanvas::OnPaint( wxPaintEvent& WXUNUSED(event) )
{
// This is a dummy, to avoid an endless succession of paint messages.
// OnPaint handlers must always create a wxPaintDC.
wxPaintDC dc(this);
// Avoid painting when we have not yet a size
if (m_winHeight < 1)
return;
// This should not be needed, while we have only one canvas
SetCurrent(*m_oglContext);
// Do the magic
//m_oglManager->Render();
glClearColor(0.0, 0.2, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shader.getProgram());
// Bind our texture in Texture Unit 0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureID);
// Set our "myTextureSampler" sampler to use Texture Unit 0
glUniform1i(uniformTextureID, 0);
// 1st attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
0, // attribute 0. Matches layout of shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// 2nd attribute buffer : UVs
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glVertexAttribPointer(
1, // attribute. No particular reason for 1, but must match the layout in the shader.
2, // size : U+V => 2
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glDrawArrays(GL_TRIANGLES, 0, 3 * 2); // 3 * num_triangles_to_draw
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
SwapBuffers();
}
Code: Select all
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::MouseButtonPressed)
{
if (event.mouseButton.button == sf::Mouse::Left)
{
std::cout << "the left button was pressed" << std::endl;
std::cout << "mouse x: " << event.mouseButton.x << std::endl;
std::cout << "mouse y: " << event.mouseButton.y << std::endl;
size_t index = 4 * m_width * event.mouseButton.y + 4 * event.mouseButton.x;
m_pixels[index+0] = 255;
m_pixels[index+1] = 0;
m_pixels[index+2] = 0;
dragging = true;
}
}
else if (event.type == sf::Event::MouseButtonReleased)
{
dragging = false;
}
else if (event.type == sf::Event::MouseMoved)
{
static int i = 0;
if (i++ % 10 == 0) std::cout << i << "\n";
if (dragging)
{
//std::cout << "dragging at (" << event.mouseMove.x << ", " << event.mouseMove.y << "\n";
static const std::vector<unsigned char> red_data {
255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255
};
// Update the image to OpenGL
// by sending a red box
glTexSubImage2D(
GL_TEXTURE_2D, // target
0, // level
event.mouseMove.x, // xoffset
event.mouseMove.y, // yoffset
// note: no internal format can be changed for Sub
m_width/100, // width
m_height/100, // height
GL_BGRA, // format (of the pixel data)
GL_UNSIGNED_BYTE, // type
red_data.data() //dat
);
}
}
else if (event.type == sf::Event::Closed)
window.close();
}
sf::Time t = sf::milliseconds(1);
sf::sleep(t);
glClearColor(0.0, 0.2, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shader.getProgram());
// Bind our texture in Texture Unit 0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureID);
// Set our "myTextureSampler" sampler to use Texture Unit 0
glUniform1i(uniformTextureID, 0);
// 1st attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
0, // attribute 0. Matches layout of shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// 2nd attribute buffer : UVs
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glVertexAttribPointer(
1, // attribute. No particular reason for 1, but must match the layout in the shader.
2, // size : U+V => 2
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glDrawArrays(GL_TRIANGLES, 0, 3 * 2); // 3 * num_triangles_to_draw
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
window.display();
}
Thank you.