Created
August 16, 2014 05:19
-
-
Save jwatte/73e5e0e9f5bf0de5eadb to your computer and use it in GitHub Desktop.
Problem C++ file for Raspberry Pi
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "All.h" | |
#include <VG/openvg.h> | |
#include <VG/vgu.h> | |
#include <EGL/egl.h> | |
#include <GLES2/gl2.h> | |
#include <bcm_host.h> | |
#include <assert.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <map> | |
#include <string> | |
struct EGLState { | |
EGLState() { | |
width = 0; | |
height = 0; | |
display = 0; | |
surface = 0; | |
context = 0; | |
startTime = 0; | |
nFrames = 0; | |
prevFps = 0; | |
} | |
uint32_t width; | |
uint32_t height; | |
EGL_DISPMANX_WINDOW_T window; | |
EGLDisplay display; | |
EGLSurface surface; | |
EGLContext context; | |
double startTime; | |
float prevFps; | |
int nFrames; | |
GLuint program; | |
GLuint uMatrix; | |
GLuint uTexture; | |
}; | |
static void InitWindow(EGLState *state) { | |
int32_t success = 0; | |
EGLBoolean result; | |
EGLint num_config; | |
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; | |
static const EGLint attribute_list[] = { | |
EGL_RED_SIZE, 8, | |
EGL_GREEN_SIZE, 8, | |
EGL_BLUE_SIZE, 8, | |
// No depth needed for OpenVG | |
EGL_SURFACE_TYPE, EGL_WINDOW_BIT, | |
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, | |
EGL_NONE | |
}; | |
EGLConfig config = 0; | |
// get an EGL display connection | |
state->display = eglGetDisplay(EGL_DEFAULT_DISPLAY); | |
assert(state->display != EGL_NO_DISPLAY); | |
// initialize the EGL display connection | |
result = eglInitialize(state->display, NULL, NULL); | |
assert(EGL_FALSE != result); | |
// bind GLES2 API | |
eglBindAPI(EGL_OPENGL_ES_API); | |
// get an appropriate EGL frame buffer configuration | |
result = eglChooseConfig(state->display, attribute_list, &config, 1, &num_config); | |
assert(EGL_FALSE != result); | |
// create an EGL rendering context | |
state->context = eglCreateContext(state->display, config, EGL_NO_CONTEXT, NULL); | |
assert(state->context != EGL_NO_CONTEXT); | |
// create an EGL window surface | |
success = graphics_get_display_size(0, &state->width, &state->height); | |
assert(success >= 0); | |
dst_rect.x = 0; | |
dst_rect.y = 0; | |
dst_rect.width = state->width; | |
dst_rect.height = state->height; | |
src_rect.x = 0; | |
src_rect.y = 0; | |
src_rect.width = state->width << 16; | |
src_rect.height = state->height << 16; | |
dispman_display = vc_dispmanx_display_open(0); | |
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_NO_ROTATE /*transform */ ); | |
state->window.element = dispman_element; | |
state->window.width = state->width; | |
state->window.height = state->height; | |
vc_dispmanx_update_submit_sync(dispman_update); | |
state->surface = eglCreateWindowSurface(state->display, config, &state->window, NULL); | |
assert(state->surface != EGL_NO_SURFACE); | |
// connect the context to the surface | |
result = eglMakeCurrent(state->display, state->surface, state->surface, state->context); | |
assert(EGL_FALSE != result); | |
glClearColor(0, 0, 0, 0); | |
glClear(GL_COLOR_BUFFER_BIT); | |
GLCHECK(); | |
fprintf(stderr, "Created display surface.\n"); | |
} | |
Display::Display() { | |
state = new EGLState(); | |
bcm_host_init(); | |
InitWindow(state); | |
LoadShaders(); | |
state->startTime = Time(); | |
state->prevFps = 0.0; | |
} | |
Display::~Display() { | |
eglMakeCurrent(state->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); | |
eglDestroySurface(state->display, state->surface); | |
eglDestroyContext(state->display, state->context); | |
eglTerminate(state->display); | |
delete state; | |
state = NULL; | |
} | |
static GLuint load_shader(char const *name, GLuint type) { | |
GLuint shader = glCreateShader(type); | |
fprintf(stderr, "%s (0x%x) = 0x%x\n", name, type, shader); | |
GLCHECK(); | |
assert(shader != 0); | |
FILE *f = fopen(name, "rb"); | |
if (!f) { | |
fprintf(stderr, "could not find required shader %s\n", name); | |
exit(1); | |
} | |
fseek(f, 0, 2); | |
long l = ftell(f); | |
fseek(f, 0, 0); | |
char *data = new char[l+1]; | |
fread(data, 1, l, f); | |
data[l] = 0; | |
fclose(f); | |
glShaderSource(shader, 1, const_cast<char const **>(&data), nullptr); | |
delete[] data; | |
glCompileShader(shader); | |
GLint compiled = 0; | |
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); | |
if (!compiled) { | |
GLint infolen = 0; | |
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infolen); | |
if (infolen > 1) { | |
char *info = new char[infolen+1]; | |
glGetShaderInfoLog(shader, infolen, nullptr, info); | |
info[infolen] = 0; | |
fprintf(stderr, "%s:1: compile error:\n%s\n", name, info); | |
delete[] info; | |
} else { | |
fprintf(stderr, "%s:1: unknown compile error\n", name); | |
} | |
exit(1); | |
} | |
return shader; | |
} | |
void Display::LoadShaders() { | |
GLuint vShader = load_shader("vertex.glsl", GL_VERTEX_SHADER); | |
GLuint fShader = load_shader("fragment.glsl", GL_FRAGMENT_SHADER); | |
state->program = glCreateProgram(); | |
GLCHECK(); | |
assert(state->program != 0); | |
glAttachShader(state->program, vShader); | |
glAttachShader(state->program, fShader); | |
glBindAttribLocation(state->program, 0, "attrPos"); | |
glBindAttribLocation(state->program, 1, "attrUV"); | |
glLinkProgram(state->program); | |
GLint linked = 0; | |
glGetProgramiv(state->program, GL_LINK_STATUS, &linked); | |
if (!linked) { | |
GLint infolen = 0; | |
glGetProgramiv(state->program, GL_INFO_LOG_LENGTH, &infolen); | |
if (infolen > 1) { | |
char *info = new char[infolen+1]; | |
glGetProgramInfoLog(state->program, infolen, nullptr, info); | |
info[infolen] = 0; | |
fprintf(stderr, "GLES program link error:\n%s\n", info); | |
delete[] info; | |
} else { | |
fprintf(stderr, "GLES unknown program link error.\n"); | |
} | |
exit(1); | |
} | |
state->uMatrix = glGetUniformLocation(state->program, "uMatrix"); | |
state->uTexture = glGetUniformLocation(state->program, "uTexture"); | |
glUniform1i(state->uTexture, 0); // texture unit 0 | |
GLCHECK(); | |
} | |
int Display::Width() { | |
return (int)state->width; | |
} | |
int Display::Height() { | |
return (int)state->height; | |
} | |
void Display::Begin() { | |
GLCHECK(); | |
glDisable(GL_BLEND); | |
glViewport(0, 0, Width(), Height()); | |
glClearColor(0, 0, 0, 1); | |
glClear(GL_COLOR_BUFFER_BIT); | |
float mat[16] = { | |
2.0f / Width(), 0, 0, -1, | |
0, -2.0f / Height(), 0, -1, | |
0, 0, 1, 0, | |
0, 0, 0, 1, | |
}; | |
glUniformMatrix4fv(state->uMatrix, 1, GL_FALSE, mat); | |
GLCHECK(); | |
} | |
void Display::Flip() { | |
GLCHECK(); | |
eglSwapBuffers(state->display, state->surface); | |
++state->nFrames; | |
} | |
double Display::Time() { | |
struct timespec tv; | |
clock_gettime(CLOCK_MONOTONIC, &tv); | |
return tv.tv_sec + 1e-9*tv.tv_nsec; | |
} | |
float Display::Fps() { | |
double now = Time(); | |
if (now - state->startTime >= 1.25) { | |
state->prevFps = state->nFrames / (now - state->startTime); | |
state->nFrames = 0; | |
state->startTime = now; | |
} | |
return state->prevFps; | |
} | |
void gl_check(char const *file, int line, char const *func) { | |
GLuint err = glGetError(); | |
if (err) { | |
fprintf(stderr, "%s:%d: gl error 0x%x in %s\n", file, line, err, func); | |
abort(); | |
} | |
} | |
static std::map<std::string, GLuint> textures; | |
static bool bgraKnown = false; | |
static bool hasBgra = false; | |
#if !defined(GL_BGRA_EXT) | |
#define GL_BGRA_EXT ((GLenum)0x80E1) | |
#endif | |
unsigned int Display::LoadTexture(char const *name) { | |
auto ptr(textures.find(name)); | |
if (ptr != textures.end()) { | |
return (*ptr).second; | |
} | |
if (!bgraKnown) { | |
bgraKnown = true; | |
hasBgra = strstr((char const *)glGetString(GL_EXTENSIONS), "GL_EXT_texture_format_BGRA8888") != NULL; | |
if (hasBgra) { | |
fprintf(stderr, "has GL_EXT_texture_format_BGRA8888\n"); | |
} | |
} | |
FILE *f = fopen(name, "rb"); | |
if (!f) { | |
fprintf(stderr, "Could not load texture: %s\n", name); | |
exit(1); | |
} | |
unsigned char hdr[18]; | |
fread(hdr, 1, 18, f); | |
size_t bpp = 0; | |
if (hdr[2] == 2) { | |
bpp = 4; | |
} else if (hdr[2] == 3) { | |
bpp = 1; | |
} | |
fseek(f, hdr[0], 1); | |
unsigned int width = hdr[12] + (hdr[13] << 8); | |
unsigned int height = hdr[14] + (hdr[15] << 8); | |
if (bpp == 4 && hdr[16] == 24) { | |
bpp = 3; | |
} | |
fprintf(stderr, "%s: %dx%d@%d\n", name, width, height, bpp*8); | |
unsigned char *data = new unsigned char[width * height * bpp]; | |
fread(data, 1, width*height*bpp, f); | |
fclose(f); | |
GLuint tex = 0; | |
GLCHECK(); | |
glGenTextures(1, &tex); | |
glBindTexture(GL_TEXTURE_2D, tex); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); | |
GLCHECK(); | |
GLuint fmt = (bpp == 1) ? GL_LUMINANCE : (bpp == 3) ? GL_RGB : GL_RGBA; | |
if (bpp == 4 && hasBgra) { | |
fmt = GL_BGRA_EXT; | |
} else if (bpp > 1) { | |
unsigned char *ptr = data; | |
size_t n = width * height; | |
while (n-- > 0) { | |
unsigned char sw = ptr[0]; | |
ptr[0] = ptr[2]; | |
ptr[2] = sw; | |
ptr += bpp; | |
} | |
} | |
glTexImage2D(GL_TEXTURE_2D, 0, fmt, width, height, 0, fmt, GL_UNSIGNED_BYTE, data); | |
GLCHECK(); | |
glGenerateMipmap(GL_TEXTURE_2D); | |
GLCHECK(); | |
textures[name] = tex; | |
glBindTexture(GL_TEXTURE_2D, 0); | |
delete[] data; | |
return tex; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment