PDA

View Full Version : GLUT - Non-shared Idle Function?



DarkHeart
02-09-2014, 02:51 PM
Hello all, I'm looking into making an object oriented toolkit and have ran into a bit of a snag with glut's idle function callback. The problem is that I can't seem to attach a dedicated idle function callback on a per-window basis. Is there any way to make glut accept idle functions on a per-window basis? Thanks for any help.

Below is what I have mocked together so far (It's a bit long, but cannot be further compressed for a SSCCE, sorry):
(Note: The code is in C++11, only Clang is supported, though GCC *might* work)



#ifndef BOOTSTRAP_HPP
#define BOOTSTRAP_HPP

#include <iostream>
#include <map>

#include "Platform.hpp"

namespace detail
{
struct VirtualBootstrap
{
protected:
static thread_local bool glew_initialized;
public:
virtual void idle() = 0;
virtual void tick() = 0;
virtual void render() = 0;
virtual ~VirtualBootstrap() = default;
};

thread_local bool VirtualBootstrap::glew_initialized = false;

thread_local std::map<int, VirtualBootstrap*> bootstraps;

template<int N>
void register_this(VirtualBootstrap* bootstrap) noexcept
{
bootstraps.insert(std::make_pair(N, bootstrap));
}

template<int N>
void unregister_this() noexcept
{
bootstraps.erase(N);
}

template<int N>
void glutDisplayFuncDelegate()
{
std::cout << N << " rendering" << std::endl;
bootstraps[N]->render();
}

template<int N>
void glutIdleFuncDelegate()
{
std::cout << N << " idling" << std::endl;
bootstraps[N]->idle();
}
}

template<int N>
class Bootstrap : public detail::VirtualBootstrap
{
public:

Bootstrap(int windowWidth, int windowHeight)
{
glutInitWindowSize(windowWidth, windowHeight);
glutInitWindowPosition(100, 100);
glutCreateWindow((std::string("Bootstrap Test (") + std::to_string(N) + ")").c_str());
if(!glew_initialized)
{
glewInit();
glew_initialized = true;
}
glutDisplayFunc(detail::glutDisplayFuncDelegate<N>);
glutIdleFunc(detail::glutIdleFuncDelegate<N>);
detail::register_this<N>(this);
}

virtual ~Bootstrap()
{
detail::unregister_this<N>();
}
};

template<int N>
class TestBootstrap : public Bootstrap<N>
{
public:
TestBootstrap(int w, int h) : Bootstrap<N>(w, h) {}
virtual void idle() { /** update some uniforms... */ glutPostRedisplay();}
virtual void tick() {}
virtual void render() { /** Render something impressive */}
};

int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA);
TestBootstrap<0> bootstrap0(300, 300);
TestBootstrap<1> bootstrap1(300, 300);
glutMainLoop();
}

#endif

DarkHeart
02-09-2014, 04:04 PM
Do'H!

I think I just found a quick and dirty work-around...but would appreciate any peer reviews that might be offered!


#ifndef BOOTSTRAP_HPP
#define BOOTSTRAP_HPP

#include <map>

#include "Platform.hpp"

namespace detail
{
struct VirtualBootstrap
{
protected:
static thread_local bool glew_initialized;
public:
virtual void idle() = 0;
virtual void tick() = 0;
virtual void render() = 0;
virtual ~VirtualBootstrap() = default;
};

thread_local bool VirtualBootstrap::glew_initialized = false;

thread_local VirtualBootstrap* current = nullptr;

thread_local std::map<int, VirtualBootstrap*> bootstraps;

template<int N>
void register_this(VirtualBootstrap* bootstrap) noexcept
{
bootstraps.insert(std::make_pair(N, bootstrap));
}

template<int N>
void unregister_this() noexcept
{
bootstraps.erase(N);
}

template<int N>
void glutIdleFuncDelegate()
{
bootstraps[N]->idle();
}

template<int N>
void glutDisplayFuncDelegate()
{
if(bootstraps[N] != current)
{
current = bootstraps[N];

/// Invoke idle function one time
glutIdleFuncDelegate<N>();

/// Set subsequent idle function invocations
glutIdleFunc(glutIdleFuncDelegate<N>);
}
bootstraps[N]->render();
}
}

template<int N>
class Bootstrap : public detail::VirtualBootstrap
{
public:

Bootstrap(int windowWidth, int windowHeight)
{
glutInitWindowSize(windowWidth, windowHeight);
glutInitWindowPosition(100, 100);
glutCreateWindow((std::string("Bootstrap Test (") + std::to_string(N) + ")").c_str());
if(!glew_initialized)
{
glewInit();
glew_initialized = true;
}
glutDisplayFunc(detail::glutDisplayFuncDelegate<N>);
glutIdleFunc(detail::glutIdleFuncDelegate<N>);
detail::register_this<N>(this);
}

virtual ~Bootstrap()
{
detail::unregister_this<N>();
}
};

#endif