first commit
This commit is contained in:
@@ -0,0 +1,385 @@
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifdef _RPI
|
||||
#include <bcm_host.h>
|
||||
#else
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xutil.h>
|
||||
#endif
|
||||
|
||||
#include "GLES_utils.hxx"
|
||||
|
||||
/// esCreateWindow flag - RGB color buffer
|
||||
#define GLES_UTILS_WINDOW_RGB 0
|
||||
/// esCreateWindow flag - ALPHA color buffer
|
||||
#define GLES_UTILS_WINDOW_ALPHA 1
|
||||
/// esCreateWindow flag - depth buffer
|
||||
#define GLES_UTILS_WINDOW_DEPTH 2
|
||||
/// esCreateWindow flag - stencil buffer
|
||||
#define GLES_UTILS_WINDOW_STENCIL 4
|
||||
/// esCreateWindow flat - multi-sample buffer
|
||||
#define GLES_UTILS_WINDOW_MULTISAMPLE 8
|
||||
|
||||
GLES_utils::GLES_utils () :
|
||||
m_State (),
|
||||
display_func (NULL),
|
||||
idle_func (NULL),
|
||||
keyboard_func (NULL),
|
||||
reshape_func (NULL) {}
|
||||
|
||||
GLES_utils::~GLES_utils () {}
|
||||
|
||||
GLES_utils&
|
||||
GLES_utils::instance () {
|
||||
static GLES_utils* const The_Instance (new GLES_utils);
|
||||
return *The_Instance;
|
||||
}
|
||||
|
||||
void
|
||||
GLES_utils::init (const string &title) {
|
||||
#ifdef _RPI
|
||||
bcm_host_init ();
|
||||
init_dispmanx (m_State.native_window);
|
||||
#else
|
||||
init_display (m_State, title);
|
||||
#endif
|
||||
init_egl (m_State, GLES_UTILS_WINDOW_RGB);
|
||||
}
|
||||
|
||||
void
|
||||
GLES_utils::print_config_info (const int n, const EGLDisplay &display, EGLConfig &config) {
|
||||
int size;
|
||||
|
||||
cout << "EGL Configuration " << n << " is" << endl;
|
||||
|
||||
eglGetConfigAttrib (display, config, EGL_RED_SIZE, &size);
|
||||
cout << "EGL Red size is " << size << endl;
|
||||
|
||||
eglGetConfigAttrib (display, config, EGL_BLUE_SIZE, &size);
|
||||
cout << "EGL Blue size is " << size << endl;
|
||||
|
||||
eglGetConfigAttrib (display, config, EGL_GREEN_SIZE, &size);
|
||||
cout << "EGL Green size is " << size << endl;
|
||||
|
||||
eglGetConfigAttrib (display, config, EGL_BUFFER_SIZE, &size);
|
||||
cout << "EGL Buffer size is " << size << endl;
|
||||
|
||||
eglGetConfigAttrib (display, config, EGL_BIND_TO_TEXTURE_RGB , &size);
|
||||
if (size == EGL_TRUE) {
|
||||
cout << "EGL Can be bound to RGB texture" << endl;
|
||||
} else {
|
||||
cout << "EGL Can't be bound to RGB texture" << endl;
|
||||
}
|
||||
|
||||
eglGetConfigAttrib (display, config, EGL_BIND_TO_TEXTURE_RGBA , &size);
|
||||
if (size == EGL_TRUE) {
|
||||
cout << "EGL Can be bound to RGBA texture" << endl;
|
||||
} else {
|
||||
cout << "EGL Can't be bound to RGBA texture" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GLES_utils::init_egl (EGL_STATE_T &state, const GLuint flags) {
|
||||
EGLBoolean result;
|
||||
|
||||
static const EGLint attribute_list[] = {
|
||||
EGL_RED_SIZE, 5,
|
||||
EGL_GREEN_SIZE, 6,
|
||||
EGL_BLUE_SIZE, 5,
|
||||
EGL_ALPHA_SIZE, (flags & GLES_UTILS_WINDOW_ALPHA) ? 8 : EGL_DONT_CARE,
|
||||
EGL_DEPTH_SIZE, (flags & GLES_UTILS_WINDOW_DEPTH) ? 8 : EGL_DONT_CARE,
|
||||
EGL_STENCIL_SIZE, (flags & GLES_UTILS_WINDOW_STENCIL) ? 8 : EGL_DONT_CARE,
|
||||
EGL_SAMPLE_BUFFERS, (flags & GLES_UTILS_WINDOW_MULTISAMPLE) ? 1 : 0,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
static const EGLint context_attributes[] = {
|
||||
EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||
EGL_NONE
|
||||
#ifndef _RPI
|
||||
, EGL_NONE
|
||||
#endif
|
||||
};
|
||||
|
||||
EGLConfig *configs;
|
||||
|
||||
// get an EGL display connection
|
||||
#ifdef _RPI
|
||||
state.display = eglGetDisplay (EGL_DEFAULT_DISPLAY);
|
||||
#else
|
||||
state.display = eglGetDisplay ((EGLNativeDisplayType) state.x_display);
|
||||
#endif
|
||||
assert (state.display != EGL_NO_DISPLAY);
|
||||
|
||||
// initialize the EGL display connection
|
||||
result = eglInitialize (state.display, &(state.major_version), &(state.minor_version));
|
||||
assert (result != EGL_FALSE);
|
||||
|
||||
result = eglGetConfigs (state.display, NULL, 0, &(state.num_configs));
|
||||
assert (result != EGL_FALSE);
|
||||
|
||||
configs = (EGLConfig *) calloc (state.num_configs, sizeof (*configs));
|
||||
result = eglGetConfigs (state.display, configs, state.num_configs, &(state.num_configs));
|
||||
assert (result != EGL_FALSE);
|
||||
|
||||
cout << "EGL version = " << state.major_version << "." << state.minor_version << endl;
|
||||
cout << "EGL has " << state.num_configs << " configs" << endl;
|
||||
for (int i = 0; i < state.num_configs; ++i) {
|
||||
print_config_info (i, state.display, configs[i]);
|
||||
}
|
||||
|
||||
// get an appropriate EGL frame buffer configuration
|
||||
result = eglChooseConfig (state.display, attribute_list, &(state.config), 1, &(state.num_configs));
|
||||
assert (result != EGL_FALSE);
|
||||
|
||||
// Choose the OpenGL ES API
|
||||
result = eglBindAPI (EGL_OPENGL_ES_API);
|
||||
assert (result != EGL_FALSE);
|
||||
|
||||
#ifdef _RPI
|
||||
state.surface = eglCreateWindowSurface (state.display,
|
||||
state.config,
|
||||
(EGLNativeWindowType) &(state.native_window),
|
||||
NULL);
|
||||
#else
|
||||
state.surface = eglCreateWindowSurface (state.display,
|
||||
state.config,
|
||||
state.native_window,
|
||||
NULL);
|
||||
#endif
|
||||
assert (state.surface != EGL_NO_SURFACE);
|
||||
|
||||
// create an EGL rendering context
|
||||
state.context = eglCreateContext (state.display, state.config, EGL_NO_CONTEXT, context_attributes);
|
||||
assert (state.context != EGL_NO_CONTEXT);
|
||||
|
||||
// connect the context to the surface
|
||||
result = eglMakeCurrent (state.display, state.surface, state.surface, state.context);
|
||||
assert (result != EGL_FALSE);
|
||||
}
|
||||
|
||||
#ifdef _RPI
|
||||
void
|
||||
GLES_utils::init_dispmanx (EGL_DISPMANX_WINDOW_T &native_window) {
|
||||
int32_t success = 0;
|
||||
uint32_t screen_width;
|
||||
uint32_t screen_height;
|
||||
|
||||
DISPMANX_ELEMENT_HANDLE_T dispman_element;
|
||||
DISPMANX_DISPLAY_HANDLE_T dispman_display;
|
||||
DISPMANX_UPDATE_HANDLE_T dispman_update;
|
||||
VC_RECT_T dst_rect;
|
||||
VC_RECT_T src_rect;
|
||||
|
||||
// create an EGL window surface
|
||||
success = graphics_get_display_size (0 /* LCD */,
|
||||
&screen_width,
|
||||
&screen_height);
|
||||
assert (success >= 0);
|
||||
|
||||
dst_rect.x = 0;
|
||||
dst_rect.y = 0;
|
||||
dst_rect.width = screen_width;
|
||||
dst_rect.height = screen_height;
|
||||
|
||||
src_rect.x = 0;
|
||||
src_rect.y = 0;
|
||||
src_rect.width = screen_width << 16;
|
||||
src_rect.height = screen_height << 16;
|
||||
|
||||
dispman_display = vc_dispmanx_display_open (0 /* LCD */);
|
||||
dispman_update = vc_dispmanx_update_start (0);
|
||||
|
||||
dispman_element = vc_dispmanx_element_add (dispman_update,
|
||||
dispman_display,
|
||||
0 /*layer*/,
|
||||
&dst_rect,
|
||||
0 /*src*/,
|
||||
&src_rect,
|
||||
DISPMANX_PROTECTION_NONE,
|
||||
0 /*alpha*/,
|
||||
0 /*clamp*/,
|
||||
DISPMANX_TRANSFORM_T (0) /*transform*/);
|
||||
|
||||
// Build an EGL_DISPMANX_WINDOW_T from the Dispmanx window
|
||||
native_window.element = dispman_element;
|
||||
native_window.width = screen_width;
|
||||
native_window.height = screen_height;
|
||||
vc_dispmanx_update_submit_sync (dispman_update);
|
||||
|
||||
cout << "Got a Dispmanx window" << endl;
|
||||
}
|
||||
|
||||
GLboolean
|
||||
GLES_utils::user_interrupt () {
|
||||
return GL_FALSE;
|
||||
}
|
||||
#else
|
||||
void
|
||||
GLES_utils::init_display (EGL_STATE_T &state, const string &title) {
|
||||
Window root;
|
||||
XSetWindowAttributes swa;
|
||||
XSetWindowAttributes xattr;
|
||||
Atom wm_state;
|
||||
XWMHints hints;
|
||||
XEvent xev;
|
||||
Window win;
|
||||
|
||||
state.width = 1024;
|
||||
state.height = 768;
|
||||
|
||||
/*
|
||||
* X11 native display initialization
|
||||
*/
|
||||
|
||||
state.x_display = XOpenDisplay (NULL);
|
||||
assert (state.x_display != NULL);
|
||||
|
||||
root = DefaultRootWindow (state.x_display);
|
||||
|
||||
swa.event_mask = ExposureMask | PointerMotionMask | KeyPressMask;
|
||||
win = XCreateWindow (state.x_display,
|
||||
root,
|
||||
0,
|
||||
0,
|
||||
state.width,
|
||||
state.height,
|
||||
0,
|
||||
CopyFromParent,
|
||||
InputOutput,
|
||||
CopyFromParent,
|
||||
CWEventMask,
|
||||
&swa);
|
||||
|
||||
xattr.override_redirect = false;
|
||||
XChangeWindowAttributes (state.x_display, win, CWOverrideRedirect, &xattr);
|
||||
|
||||
hints.input = true;
|
||||
hints.flags = InputHint;
|
||||
XSetWMHints (state.x_display, win, &hints);
|
||||
|
||||
// make the window visible on the screen
|
||||
XMapWindow (state.x_display, win);
|
||||
XStoreName (state.x_display, win, title.c_str ());
|
||||
|
||||
// get identifiers for the provided atom name strings
|
||||
wm_state = XInternAtom (state.x_display, "_NET_WM_STATE", false);
|
||||
|
||||
memset (&xev, 0, sizeof (xev));
|
||||
xev.type = ClientMessage;
|
||||
xev.xclient.window = win;
|
||||
xev.xclient.message_type = wm_state;
|
||||
xev.xclient.format = 32;
|
||||
xev.xclient.data.l[0] = 1;
|
||||
xev.xclient.data.l[1] = false;
|
||||
XSendEvent (state.x_display, DefaultRootWindow (state.x_display), false, SubstructureNotifyMask, &xev);
|
||||
|
||||
state.native_window = (EGLNativeWindowType) win;
|
||||
}
|
||||
|
||||
GLboolean
|
||||
GLES_utils::user_interrupt () {
|
||||
XEvent xev;
|
||||
KeySym key;
|
||||
GLboolean user_interrupt = GL_FALSE;
|
||||
char text;
|
||||
|
||||
// Pump all messages from X server. Keypresses are directed to keyfunc (if defined)
|
||||
while (XPending (m_State.x_display)) {
|
||||
XNextEvent (m_State.x_display, &xev);
|
||||
if (xev.type == KeyPress) {
|
||||
if (XLookupString (&xev.xkey, &text, 1, &key, 0) == 1) {
|
||||
if (keyboard_func != NULL) {
|
||||
keyboard_func (text, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (xev.type == DestroyNotify) {
|
||||
user_interrupt = GL_TRUE;
|
||||
}
|
||||
}
|
||||
return user_interrupt;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
GLES_utils::register_display_func (void (*display_func) ()) {
|
||||
this->display_func = display_func;
|
||||
}
|
||||
|
||||
void
|
||||
GLES_utils::register_idle_func (void (*idle_func) ()) {
|
||||
this->idle_func = idle_func;
|
||||
}
|
||||
|
||||
void
|
||||
GLES_utils::register_keyboard_func (void (*keyboard_func) (unsigned char, int, int)) {
|
||||
this->keyboard_func = keyboard_func;
|
||||
}
|
||||
|
||||
void
|
||||
GLES_utils::register_reshape_func (void (*reshape_func) (int, int)) {
|
||||
this->reshape_func = reshape_func;
|
||||
}
|
||||
|
||||
void
|
||||
GLES_utils::main_loop () {
|
||||
struct timeval t1, t2;
|
||||
struct timezone tz;
|
||||
float delta_time;
|
||||
float total_time = 0.0f;
|
||||
unsigned int frames = 0;
|
||||
|
||||
gettimeofday (&t1 , &tz);
|
||||
|
||||
while (user_interrupt () == GL_FALSE) {
|
||||
gettimeofday (&t2, &tz);
|
||||
delta_time = (float) (t2.tv_sec - t1.tv_sec + (t2.tv_usec - t1.tv_usec) * 1e-6);
|
||||
t1 = t2;
|
||||
|
||||
if (reshape_func != NULL) {
|
||||
#ifdef _RPI
|
||||
reshape_func (m_State.native_window.width, m_State.native_window.height);
|
||||
#else
|
||||
reshape_func (m_State.width, m_State.height);
|
||||
#endif
|
||||
}
|
||||
if (idle_func != NULL) {
|
||||
idle_func ();
|
||||
}
|
||||
if (display_func != NULL) {
|
||||
display_func ();
|
||||
}
|
||||
|
||||
eglSwapBuffers (m_State.display, m_State.surface);
|
||||
|
||||
total_time += delta_time;
|
||||
++frames;
|
||||
if (total_time > 2.0f) {
|
||||
cout << frames << " frames rendered in " << total_time << " seconds -> FPS = " << (frames / total_time) << endl;
|
||||
total_time -= 2.0f;
|
||||
frames = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user