Skip to content

Instantly share code, notes, and snippets.

@IanusInferus
Created July 22, 2019 03:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save IanusInferus/95fdf0aa085a31caf887090cabc20e10 to your computer and use it in GitHub Desktop.
Save IanusInferus/95fdf0aa085a31caf887090cabc20e10 to your computer and use it in GitHub Desktop.
patch for Objective-C sample BGRenderer.m
//================================================================================================================================
//
// Copyright (c) 2015-2019 VisionStar Information Technology (Shanghai) Co., Ltd. All Rights Reserved.
// EasyAR is the registered trademark or trademark of VisionStar Information Technology (Shanghai) Co., Ltd in China
// and other countries for the augmented reality technology developed by VisionStar Information Technology (Shanghai) Co., Ltd.
//
//================================================================================================================================
#import "BGRenderer.h"
#import <easyar/vector.oc.h>
#define GLES_SILENCE_DEPRECATION
#include <OpenGLES/ES2/gl.h>
const char* videobackground_vert="attribute vec4 coord;\n"
"attribute vec2 texCoord;\n"
"varying vec2 texc;\n"
"\n"
"void main(void)\n"
"{\n"
" gl_Position = coord;\n"
" texc = texCoord;\n"
"}\n"
"\n"
;
const char* videobackground_bgr_frag="#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"uniform sampler2D texture;\n"
"varying vec2 texc;\n"
"\n"
"void main(void)\n"
"{\n"
" gl_FragColor = texture2D(texture, texc).bgra;\n"
"}\n"
"\n"
;
const char* videobackground_rgb_frag="#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"uniform sampler2D texture;\n"
"varying vec2 texc;\n"
"\n"
"void main(void)\n"
"{\n"
" gl_FragColor = texture2D(texture, texc);\n"
"}\n"
"\n"
;
const char* videobackground_yuv_i420_yv12_frag="#ifdef GL_ES\n"
"precision highp float;\n"
"#endif\n"
"uniform sampler2D texture;\n"
"uniform sampler2D u_texture;\n"
"uniform sampler2D v_texture;\n"
"varying vec2 texc;\n"
"\n"
"void main(void)\n"
"{\n"
" float cb = texture2D(u_texture, texc).r - 0.5;\n"
" float cr = texture2D(v_texture, texc).r - 0.5;\n"
" vec3 ycbcr = vec3(texture2D(texture, texc).r, cb, cr);\n"
" vec3 rgb = mat3(1, 1, 1,\n"
" 0, -0.344, 1.772,\n"
" 1.402, -0.714, 0) * ycbcr;\n"
" gl_FragColor = vec4(rgb, 1.0);\n"
"}\n"
"\n"
;
const char* videobackground_yuv_nv12_frag="#ifdef GL_ES\n"
"precision highp float;\n"
"#endif\n"
"uniform sampler2D texture;\n"
"uniform sampler2D uv_texture;\n"
"varying vec2 texc;\n"
"\n"
"void main(void)\n"
"{\n"
" vec2 cbcr = texture2D(uv_texture, texc).ra - vec2(0.5, 0.5);\n"
" vec3 ycbcr = vec3(texture2D(texture, texc).r, cbcr);\n"
" vec3 rgb = mat3(1.0, 1.0, 1.0,\n"
" 0.0, -0.344, 1.772,\n"
" 1.402, -0.714, 0) * ycbcr;\n"
" gl_FragColor = vec4(rgb, 1.0);\n"
"}\n"
"\n"
;
const char* videobackground_yuv_nv21_frag="#ifdef GL_ES\n"
"precision highp float;\n"
"#endif\n"
"uniform sampler2D texture;\n"
"uniform sampler2D uv_texture;\n"
"varying vec2 texc;\n"
"\n"
"void main(void)\n"
"{\n"
" vec2 cbcr = texture2D(uv_texture, texc).ar - vec2(0.5, 0.5);\n"
" vec3 ycbcr = vec3(texture2D(texture, texc).r, cbcr);\n"
" vec3 rgb = mat3(1, 1, 1,\n"
" 0, -0.344, 1.772,\n"
" 1.402, -0.714, 0) * ycbcr;\n"
" gl_FragColor = vec4(rgb, 1.0);\n"
"}\n"
"\n"
;
static unsigned char yuv_black[24] = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
127, 127,
127, 127,
127, 127,
127, 127
};
enum FrameShader
{
FrameShader_RGB,
FrameShader_YUV,
};
enum RetrieveStatus {
Unset,
Upload,
Clear,
};
@interface BGRenderer ()
- (easyar_Vec4F *)mul:(easyar_Matrix44F *)mat vec:(easyar_Vec4F *)vec;
- (void) retrieveFrame:(easyar_PixelFormat)format width:(int)width height:(int)height bufferData:(void *)bufferData retrieve_count:(int)retrieve_count;
- (BOOL) initialize:(easyar_PixelFormat)format;
- (void) finalize:(easyar_PixelFormat)format;
@end
@implementation BGRenderer {
enum FrameShader background_shader_;
BOOL initialized_;
unsigned int background_program_;
unsigned int background_texture_id_;
unsigned int background_texture_uv_id_;
unsigned int background_texture_u_id_;
unsigned int background_texture_v_id_;
int background_coord_location_;
int background_texture_location_;
unsigned int background_coord_vbo_;
unsigned int background_texture_vbo_;
unsigned int background_texture_fbo_;
enum easyar_PixelFormat current_format_;
easyar_Vec2I * current_image_size_;
}
+ (instancetype)create
{
return [[BGRenderer alloc] init];
}
- (instancetype)init
{
background_shader_ = FrameShader_RGB;
initialized_ = NO;
background_program_ = 0;
background_texture_id_ = 0;
background_texture_uv_id_ = 0;
background_texture_u_id_ = 0;
background_texture_v_id_ = 0;
background_coord_location_ = -1;
background_texture_location_ = -1;
background_coord_vbo_ = 0;
background_texture_vbo_ = 0;
background_texture_fbo_ = 0;
current_format_ = easyar_PixelFormat_Unknown;
current_image_size_ = [easyar_Vec2I create:@[@0, @0]];
return self;
}
- (void)dealloc
{
[self finalize:current_format_];
}
- (easyar_Vec4F *)mul:(easyar_Matrix44F *)mat vec:(easyar_Vec4F *)vec
{
NSMutableArray<NSNumber*>* val = [NSMutableArray arrayWithObjects:@(0),@(0),@(0),@(0), nil];
for (int i = 0; i < 4; ++i) {
for (int k = 0; k < 4; ++k) {
NSNumber* left = [mat data][i*4 + k];
NSNumber* right = [vec data][k];
NSNumber* value = [NSNumber numberWithFloat:[left floatValue] * [right floatValue]];
val[i] = [NSNumber numberWithFloat:val[i].floatValue + value.floatValue];
}
}
vec = [easyar_Vec4F create:@[val[0], val[1], val[2], val[3]]];
return vec;
}
- (void)upload:(easyar_PixelFormat)format width:(int)width height:(int)height bufferData:(void *)bufferData
{
GLint bak_tex, bak_program, bak_active_tex, bak_tex_1, bak_tex_2;
glGetIntegerv(GL_CURRENT_PROGRAM, &bak_program);
glGetIntegerv(GL_ACTIVE_TEXTURE, &bak_active_tex);
glActiveTexture(GL_TEXTURE0);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &bak_tex);
glActiveTexture(GL_TEXTURE1);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &bak_tex_1);
glActiveTexture(GL_TEXTURE2);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &bak_tex_2);
do {
if (current_format_ != format) {
[self finalize:current_format_];
if (![self initialize:format]) { break; }
current_format_ = format;
}
current_image_size_ = [easyar_Vec2I create:@[@(width), @(height)]];
switch (background_shader_) {
case FrameShader_RGB:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, background_texture_id_);
[self retrieveFrame:format width:width height:height bufferData:bufferData retrieve_count:0];
break;
case FrameShader_YUV:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, background_texture_id_);
[self retrieveFrame:format width:width height:height bufferData:bufferData retrieve_count:0];
if (format == easyar_PixelFormat_YUV_NV21 || format == easyar_PixelFormat_YUV_NV12) {
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, background_texture_uv_id_);
[self retrieveFrame:format width:width height:height bufferData:bufferData retrieve_count:1];
} else {
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, background_texture_u_id_);
[self retrieveFrame:format width:width height:height bufferData:bufferData retrieve_count:1];
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, background_texture_v_id_);
[self retrieveFrame:format width:width height:height bufferData:bufferData retrieve_count:2];
}
break;
}
break;
} while (0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, bak_tex);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, bak_tex_1);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, bak_tex_2);
glActiveTexture(bak_active_tex);
glUseProgram(bak_program);
}
- (void)render:(easyar_Matrix44F *)imageProjection
{
GLint bak_blend, bak_depth, bak_fbo, bak_tex, bak_arr_buf, bak_ele_arr_buf, bak_cull, bak_program, bak_active_tex, bak_tex_1, bak_tex_2;
GLint bak_viewport[4];
glGetIntegerv(GL_BLEND, &bak_blend);
glGetIntegerv(GL_DEPTH_TEST, &bak_depth);
glGetIntegerv(GL_CULL_FACE, &bak_cull);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &bak_arr_buf);
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &bak_ele_arr_buf);
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &bak_fbo);
glGetIntegerv(GL_VIEWPORT, &bak_viewport[0]);
glGetIntegerv(GL_CURRENT_PROGRAM, &bak_program);
glGetIntegerv(GL_ACTIVE_TEXTURE, &bak_active_tex);
glActiveTexture(GL_TEXTURE0);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &bak_tex);
glActiveTexture(GL_TEXTURE1);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &bak_tex_1);
glActiveTexture(GL_TEXTURE2);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &bak_tex_2);
int va[2] = {-1, -1};
int bak_va_binding[2] = {0, 0};
int bak_va_enable[2], bak_va_size[2], bak_va_stride[2], bak_va_type[2], bak_va_norm[2];
void* bak_va_pointer[2];
glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glDisable(GL_CULL_FACE);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
va[0] = background_coord_location_;
va[1] = background_texture_location_;
for (int i = 0; i < 2; ++i) {
if (va[i] == -1)
continue;
glGetVertexAttribiv(va[i], GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &bak_va_binding[i]);
glGetVertexAttribiv(va[i], GL_VERTEX_ATTRIB_ARRAY_ENABLED, &bak_va_enable[i]);
glGetVertexAttribiv(va[i], GL_VERTEX_ATTRIB_ARRAY_SIZE, &bak_va_size[i]);
glGetVertexAttribiv(va[i], GL_VERTEX_ATTRIB_ARRAY_STRIDE, &bak_va_stride[i]);
glGetVertexAttribiv(va[i], GL_VERTEX_ATTRIB_ARRAY_TYPE, &bak_va_type[i]);
glGetVertexAttribiv(va[i], GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &bak_va_norm[i]);
glGetVertexAttribPointerv(va[i], GL_VERTEX_ATTRIB_ARRAY_POINTER, &bak_va_pointer[i]);
}
BOOL result = NO;
do {
glUseProgram(background_program_);
glBindBuffer(GL_ARRAY_BUFFER, background_coord_vbo_);
glEnableVertexAttribArray(background_coord_location_);
glVertexAttribPointer(background_coord_location_, 3, GL_FLOAT, GL_FALSE, 0, 0);
GLfloat vertices[] = {
-1.0f, -1.0f, 0.f,
1.0f, -1.0f, 0.f,
1.0f, 1.0f, 0.f,
-1.0f, 1.0f, 0.f,
};
easyar_Vec4F* v0_v4f = [easyar_Vec4F create:@[@(vertices[0]), @(vertices[1]), @(vertices[2]), @(1.0f)]];
easyar_Vec4F* v1_v4f = [easyar_Vec4F create:@[@(vertices[3]), @(vertices[4]), @(vertices[5]), @(1.0f)]];
easyar_Vec4F* v2_v4f = [easyar_Vec4F create:@[@(vertices[6]), @(vertices[7]), @(vertices[8]), @(1.0f)]];
easyar_Vec4F* v3_v4f = [easyar_Vec4F create:@[@(vertices[9]), @(vertices[10]), @(vertices[11]), @(1.0f)]];
v0_v4f = [self mul:imageProjection vec:v0_v4f];
v1_v4f = [self mul:imageProjection vec:v1_v4f];
v2_v4f = [self mul:imageProjection vec:v2_v4f];
v3_v4f = [self mul:imageProjection vec:v3_v4f];
NSArray<easyar_Vec4F*>* v4f_array = @[v0_v4f, v1_v4f, v2_v4f, v3_v4f];
for (int i = 0; i < 4; i += 1) {
for (int k = 0; k < 3; k += 1) {
vertices[i * 3 + k] = [[v4f_array[i] data][k] floatValue];
}
}
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 12, vertices, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, background_texture_vbo_);
glEnableVertexAttribArray(background_texture_location_);
glVertexAttribPointer(background_texture_location_, 2, GL_FLOAT, GL_FALSE, 0, 0);
switch (background_shader_) {
case FrameShader_RGB:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, background_texture_id_);
break;
case FrameShader_YUV:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, background_texture_id_);
if (current_format_ == easyar_PixelFormat_YUV_NV21 || current_format_ == easyar_PixelFormat_YUV_NV12) {
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, background_texture_uv_id_);
} else {
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, background_texture_u_id_);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, background_texture_v_id_);
}
break;
}
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
result = YES;
} while (0);
if (bak_blend) glEnable(GL_BLEND);
if (bak_depth) glEnable(GL_DEPTH_TEST);
if (bak_cull) glEnable(GL_CULL_FACE);
for (int i = 0; i < 2; ++i) {
if (!bak_va_binding[i])
continue;
glBindBuffer(GL_ARRAY_BUFFER, bak_va_binding[i]);
if (bak_va_enable[i])
glEnableVertexAttribArray(va[i]);
else
glDisableVertexAttribArray(va[i]);
glVertexAttribPointer(va[i], bak_va_size[i], bak_va_type[i], (GLboolean)bak_va_norm[i], bak_va_stride[i], bak_va_pointer[i]);
}
glBindBuffer(GL_ARRAY_BUFFER, bak_arr_buf);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bak_ele_arr_buf);
glBindFramebuffer(GL_FRAMEBUFFER, bak_fbo);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, bak_tex);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, bak_tex_1);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, bak_tex_2);
glActiveTexture(bak_active_tex);
glViewport(bak_viewport[0], bak_viewport[1], bak_viewport[2], bak_viewport[3]);
glUseProgram(bak_program);
}
-(void)retrieveFrame:(easyar_PixelFormat)format width:(int)width height:(int)height bufferData:(void *)bufferData retrieve_count:(int)retrieve_count
{
if (retrieve_count == 0) {
if (width & 0x3) {
if (width & 0x1)
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
else
glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
}
switch (background_shader_) {
case FrameShader_RGB:
{
switch (format) {
case easyar_PixelFormat_Unknown:
glBindTexture(GL_TEXTURE_2D, 0);
break;
case easyar_PixelFormat_Gray:
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, bufferData);
break;
case easyar_PixelFormat_BGR888:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, bufferData);
break;
case easyar_PixelFormat_RGB888:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, bufferData);
break;
case easyar_PixelFormat_RGBA8888:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bufferData);
break;
case easyar_PixelFormat_BGRA8888:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bufferData);
break;
default:
glBindTexture(GL_TEXTURE_2D, 0);
}
}
break;
case FrameShader_YUV:
if (format == easyar_PixelFormat_YUV_NV21 || format == easyar_PixelFormat_YUV_NV12 || format == easyar_PixelFormat_YUV_I420 || format == easyar_PixelFormat_YUV_YV12) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, bufferData);
} else {
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 4, 4, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, yuv_black);
}
break;
default:
break;
}
}
else if (retrieve_count == 1 || retrieve_count == 2) {
if (background_shader_ != FrameShader_YUV) { return; }
if (width & 0x7) {
if (width & 0x3)
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
else
glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
}
unsigned char* data = NULL;
GLint type = GL_LUMINANCE_ALPHA;
if (format == easyar_PixelFormat_YUV_NV21 || format == easyar_PixelFormat_YUV_NV12) {
data = (unsigned char *)bufferData + width * height;
} else if (format == easyar_PixelFormat_YUV_I420) {
type = GL_LUMINANCE;
if (retrieve_count == 1) { //U
data = (unsigned char *)bufferData + width * height;
} else if (retrieve_count == 2) { //V
data = (unsigned char *)bufferData + width * height * 5 / 4;
}
} else if (format == easyar_PixelFormat_YUV_YV12) {
type = GL_LUMINANCE;
if (retrieve_count == 1) { //U
data = (unsigned char *)bufferData + width * height * 5 / 4;
} else if (retrieve_count == 2) { //V
data = (unsigned char *)bufferData + width * height;
}
}
glTexImage2D(GL_TEXTURE_2D, 0, type, width / 2, height / 2, 0, type, GL_UNSIGNED_BYTE, data);
}
}
- (BOOL)initialize:(easyar_PixelFormat)format
{
if (format == easyar_PixelFormat_Unknown)
return NO;
background_program_ = glCreateProgram();
GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertShader, 1, &videobackground_vert, NULL);
glCompileShader(vertShader);
GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);
switch (format) {
case easyar_PixelFormat_Gray:
case easyar_PixelFormat_RGB888:
case easyar_PixelFormat_RGBA8888:
background_shader_ = FrameShader_RGB;
glShaderSource(fragShader, 1, &videobackground_rgb_frag, NULL);
break;
case easyar_PixelFormat_BGR888:
case easyar_PixelFormat_BGRA8888:
background_shader_ = FrameShader_RGB;
glShaderSource(fragShader, 1, &videobackground_bgr_frag, NULL);
break;
case easyar_PixelFormat_YUV_NV21:
background_shader_ = FrameShader_YUV;
glShaderSource(fragShader, 1, &videobackground_yuv_nv21_frag, NULL);
break;
case easyar_PixelFormat_YUV_NV12:
background_shader_ = FrameShader_YUV;
glShaderSource(fragShader, 1, &videobackground_yuv_nv12_frag, NULL);
break;
case easyar_PixelFormat_YUV_I420:
case easyar_PixelFormat_YUV_YV12:
background_shader_ = FrameShader_YUV;
glShaderSource(fragShader, 1, &videobackground_yuv_i420_yv12_frag, NULL);
break;
default:
break;
}
glCompileShader(fragShader);
glAttachShader(background_program_, vertShader);
glAttachShader(background_program_, fragShader);
GLint compileSuccess;
glGetShaderiv(vertShader, GL_COMPILE_STATUS, &compileSuccess);
if (compileSuccess == GL_FALSE) {
GLchar messages[256];
glGetShaderInfoLog(vertShader, sizeof(messages), 0, &messages[0]);
}
glGetShaderiv(fragShader, GL_COMPILE_STATUS, &compileSuccess);
if (compileSuccess == GL_FALSE) {
GLchar messages[256];
glGetShaderInfoLog(fragShader, sizeof(messages), 0, &messages[0]);
}
glLinkProgram(background_program_);
glDeleteShader(vertShader);
glDeleteShader(fragShader);
GLint linkstatus = 0;
glGetProgramiv(background_program_, GL_LINK_STATUS, &linkstatus);
glUseProgram(background_program_);
background_coord_location_ = glGetAttribLocation(background_program_, "coord");
background_texture_location_ = glGetAttribLocation(background_program_, "texCoord");
glGenBuffers(1, &background_coord_vbo_);
glBindBuffer(GL_ARRAY_BUFFER, background_coord_vbo_);
const GLfloat coord[] = { -1.0f, -1.0f, 0.f, 1.0f, -1.0f, 0.f, 1.0f, 1.0f, 0.f, -1.0f, 1.0f, 0.f };
glBufferData(GL_ARRAY_BUFFER, sizeof(coord), coord, GL_DYNAMIC_DRAW);
glGenBuffers(1, &background_texture_vbo_);
glBindBuffer(GL_ARRAY_BUFFER, background_texture_vbo_);
static const GLfloat texcoord[] = { 0.f, 1.f, 1.f, 1.f, 1.f, 0.f, 0.f, 0.f }; //input texture data is Y-inverted
glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), texcoord, GL_STATIC_DRAW);
glUniform1i(glGetUniformLocation(background_program_, "texture"), 0);
glGenTextures(1, &background_texture_id_);
glBindTexture(GL_TEXTURE_2D, background_texture_id_);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
switch (background_shader_) {
case FrameShader_RGB:
break;
case FrameShader_YUV:
if (format == easyar_PixelFormat_YUV_NV21 || format == easyar_PixelFormat_YUV_NV12) {
glUniform1i(glGetUniformLocation(background_program_, "uv_texture"), 1);
glGenTextures(1, &background_texture_uv_id_);
glBindTexture(GL_TEXTURE_2D, background_texture_uv_id_);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
} else {
glUniform1i(glGetUniformLocation(background_program_, "u_texture"), 1);
glGenTextures(1, &background_texture_u_id_);
glBindTexture(GL_TEXTURE_2D, background_texture_u_id_);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glUniform1i(glGetUniformLocation(background_program_, "v_texture"), 2);
glGenTextures(1, &background_texture_v_id_);
glBindTexture(GL_TEXTURE_2D, background_texture_v_id_);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
break;
default:
break;
}
glGenFramebuffers(1, &background_texture_fbo_);
initialized_ = YES;
return YES;
}
- (void)finalize:(easyar_PixelFormat)format
{
if (!initialized_) { return; }
glDeleteProgram(background_program_);
glDeleteBuffers(1, &background_coord_vbo_);
glDeleteBuffers(1, &background_texture_vbo_);
glDeleteFramebuffers(1, &background_texture_fbo_);
glDeleteTextures(1, &background_texture_id_);
switch (background_shader_) {
case FrameShader_RGB:
break;
case FrameShader_YUV:
if (format == easyar_PixelFormat_YUV_NV21 || format == easyar_PixelFormat_YUV_NV12) {
glDeleteTextures(1, &background_texture_uv_id_);
} else {
glDeleteTextures(1, &background_texture_u_id_);
glDeleteTextures(1, &background_texture_v_id_);
}
break;
default:
break;
}
initialized_ = NO;
}
@end
//================================================================================================================================
//
// Copyright (c) 2015-2019 VisionStar Information Technology (Shanghai) Co., Ltd. All Rights Reserved.
// EasyAR is the registered trademark or trademark of VisionStar Information Technology (Shanghai) Co., Ltd in China
// and other countries for the augmented reality technology developed by VisionStar Information Technology (Shanghai) Co., Ltd.
//
//================================================================================================================================
#import "BGRenderer.h"
#import <easyar/vector.oc.h>
#define GLES_SILENCE_DEPRECATION
#include <OpenGLES/ES2/gl.h>
const char* videobackground_vert="attribute vec4 coord;\n"
"attribute vec2 texCoord;\n"
"varying vec2 texc;\n"
"\n"
"void main(void)\n"
"{\n"
" gl_Position = coord;\n"
" texc = texCoord;\n"
"}\n"
"\n"
;
const char* videobackground_bgr_frag="#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"uniform sampler2D texture;\n"
"varying vec2 texc;\n"
"\n"
"void main(void)\n"
"{\n"
" gl_FragColor = texture2D(texture, texc).bgra;\n"
"}\n"
"\n"
;
const char* videobackground_rgb_frag="#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"uniform sampler2D texture;\n"
"varying vec2 texc;\n"
"\n"
"void main(void)\n"
"{\n"
" gl_FragColor = texture2D(texture, texc);\n"
"}\n"
"\n"
;
const char* videobackground_yuv_i420_yv12_frag="#ifdef GL_ES\n"
"precision highp float;\n"
"#endif\n"
"uniform sampler2D texture;\n"
"uniform sampler2D u_texture;\n"
"uniform sampler2D v_texture;\n"
"varying vec2 texc;\n"
"\n"
"void main(void)\n"
"{\n"
" float cb = texture2D(u_texture, texc).r - 0.5;\n"
" float cr = texture2D(v_texture, texc).r - 0.5;\n"
" vec3 ycbcr = vec3(texture2D(texture, texc).r, cb, cr);\n"
" vec3 rgb = mat3(1, 1, 1,\n"
" 0, -0.344, 1.772,\n"
" 1.402, -0.714, 0) * ycbcr;\n"
" gl_FragColor = vec4(rgb, 1.0);\n"
"}\n"
"\n"
;
const char* videobackground_yuv_nv12_frag="#ifdef GL_ES\n"
"precision highp float;\n"
"#endif\n"
"uniform sampler2D texture;\n"
"uniform sampler2D uv_texture;\n"
"varying vec2 texc;\n"
"\n"
"void main(void)\n"
"{\n"
" vec2 cbcr = texture2D(uv_texture, texc).ra - vec2(0.5, 0.5);\n"
" vec3 ycbcr = vec3(texture2D(texture, texc).r, cbcr);\n"
" vec3 rgb = mat3(1.0, 1.0, 1.0,\n"
" 0.0, -0.344, 1.772,\n"
" 1.402, -0.714, 0) * ycbcr;\n"
" gl_FragColor = vec4(rgb, 1.0);\n"
"}\n"
"\n"
;
const char* videobackground_yuv_nv21_frag="#ifdef GL_ES\n"
"precision highp float;\n"
"#endif\n"
"uniform sampler2D texture;\n"
"uniform sampler2D uv_texture;\n"
"varying vec2 texc;\n"
"\n"
"void main(void)\n"
"{\n"
" vec2 cbcr = texture2D(uv_texture, texc).ar - vec2(0.5, 0.5);\n"
" vec3 ycbcr = vec3(texture2D(texture, texc).r, cbcr);\n"
" vec3 rgb = mat3(1, 1, 1,\n"
" 0, -0.344, 1.772,\n"
" 1.402, -0.714, 0) * ycbcr;\n"
" gl_FragColor = vec4(rgb, 1.0);\n"
"}\n"
"\n"
;
static unsigned char yuv_black[24] = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
127, 127,
127, 127,
127, 127,
127, 127
};
enum FrameShader
{
FrameShader_RGB,
FrameShader_YUV,
};
enum RetrieveStatus {
Unset,
Upload,
Clear,
};
@interface BGRenderer ()
- (easyar_Vec4F *)mul:(easyar_Matrix44F *)mat vec:(easyar_Vec4F *)vec;
- (void) retrieveFrame:(easyar_PixelFormat)format width:(int)width height:(int)height bufferData:(void *)bufferData retrieve_count:(int)retrieve_count;
- (BOOL) initialize:(easyar_PixelFormat)format;
- (void) finalize:(easyar_PixelFormat)format;
@end
@implementation BGRenderer {
enum FrameShader background_shader_;
BOOL initialized_;
unsigned int background_program_;
unsigned int background_texture_id_;
unsigned int background_texture_uv_id_;
unsigned int background_texture_u_id_;
unsigned int background_texture_v_id_;
int background_coord_location_;
int background_texture_location_;
unsigned int background_coord_vbo_;
unsigned int background_texture_vbo_;
unsigned int background_texture_fbo_;
enum easyar_PixelFormat current_format_;
easyar_Vec2I * current_image_size_;
}
+ (instancetype)create
{
return [[BGRenderer alloc] init];
}
- (instancetype)init
{
background_shader_ = FrameShader_RGB;
initialized_ = NO;
background_program_ = 0;
background_texture_id_ = 0;
background_texture_uv_id_ = 0;
background_texture_u_id_ = 0;
background_texture_v_id_ = 0;
background_coord_location_ = -1;
background_texture_location_ = -1;
background_coord_vbo_ = 0;
background_texture_vbo_ = 0;
background_texture_fbo_ = 0;
current_format_ = easyar_PixelFormat_Unknown;
current_image_size_ = [easyar_Vec2I create:@[@0, @0]];
return self;
}
- (void)dealloc
{
[self finalize:current_format_];
}
- (easyar_Vec4F *)mul:(easyar_Matrix44F *)mat vec:(easyar_Vec4F *)vec
{
NSMutableArray<NSNumber*>* val = [NSMutableArray arrayWithObjects:@(0),@(0),@(0),@(0), nil];
for (int i = 0; i < 4; ++i) {
for (int k = 0; k < 4; ++k) {
NSNumber* left = [mat data][i*4 + k];
NSNumber* right = [vec data][k];
NSNumber* value = [NSNumber numberWithFloat:[left floatValue] * [right floatValue]];
val[i] = [NSNumber numberWithFloat:val[i].floatValue + value.floatValue];
}
}
vec = [easyar_Vec4F create:@[val[0], val[1], val[2], val[3]]];
return vec;
}
- (void)upload:(easyar_PixelFormat)format width:(int)width height:(int)height bufferData:(void *)bufferData
{
GLint bak_tex, bak_program, bak_active_tex, bak_tex_1, bak_tex_2;
glGetIntegerv(GL_CURRENT_PROGRAM, &bak_program);
glGetIntegerv(GL_ACTIVE_TEXTURE, &bak_active_tex);
glActiveTexture(GL_TEXTURE0);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &bak_tex);
glActiveTexture(GL_TEXTURE1);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &bak_tex_1);
glActiveTexture(GL_TEXTURE2);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &bak_tex_2);
do {
if (current_format_ != format) {
[self finalize:current_format_];
if (![self initialize:format]) { break; }
current_format_ = format;
}
current_image_size_ = [easyar_Vec2I create:@[@(width), @(height)]];
switch (background_shader_) {
case FrameShader_RGB:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, background_texture_id_);
[self retrieveFrame:format width:width height:height bufferData:bufferData retrieve_count:0];
break;
case FrameShader_YUV:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, background_texture_id_);
[self retrieveFrame:format width:width height:height bufferData:bufferData retrieve_count:0];
if (format == easyar_PixelFormat_YUV_NV21 || format == easyar_PixelFormat_YUV_NV12) {
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, background_texture_uv_id_);
[self retrieveFrame:format width:width height:height bufferData:bufferData retrieve_count:1];
} else {
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, background_texture_u_id_);
[self retrieveFrame:format width:width height:height bufferData:bufferData retrieve_count:1];
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, background_texture_v_id_);
[self retrieveFrame:format width:width height:height bufferData:bufferData retrieve_count:2];
}
break;
}
break;
} while (0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, bak_tex);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, bak_tex_1);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, bak_tex_2);
glActiveTexture(bak_active_tex);
glUseProgram(bak_program);
}
- (void)render:(easyar_Matrix44F *)imageProjection
{
GLint bak_blend, bak_depth, bak_fbo, bak_tex, bak_arr_buf, bak_ele_arr_buf, bak_cull, bak_program, bak_active_tex, bak_tex_1, bak_tex_2;
GLint bak_viewport[4];
glGetIntegerv(GL_BLEND, &bak_blend);
glGetIntegerv(GL_DEPTH_TEST, &bak_depth);
glGetIntegerv(GL_CULL_FACE, &bak_cull);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &bak_arr_buf);
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &bak_ele_arr_buf);
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &bak_fbo);
glGetIntegerv(GL_VIEWPORT, &bak_viewport[0]);
glGetIntegerv(GL_CURRENT_PROGRAM, &bak_program);
glGetIntegerv(GL_ACTIVE_TEXTURE, &bak_active_tex);
glActiveTexture(GL_TEXTURE0);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &bak_tex);
glActiveTexture(GL_TEXTURE1);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &bak_tex_1);
glActiveTexture(GL_TEXTURE2);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &bak_tex_2);
int va[2] = {-1, -1};
int bak_va_binding[2] = {0, 0};
int bak_va_enable[2], bak_va_size[2], bak_va_stride[2], bak_va_type[2], bak_va_norm[2];
void* bak_va_pointer[2];
glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glDisable(GL_CULL_FACE);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
va[0] = background_coord_location_;
va[1] = background_texture_location_;
for (int i = 0; i < 2; ++i) {
if (va[i] == -1)
continue;
glGetVertexAttribiv(va[i], GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &bak_va_binding[i]);
glGetVertexAttribiv(va[i], GL_VERTEX_ATTRIB_ARRAY_ENABLED, &bak_va_enable[i]);
glGetVertexAttribiv(va[i], GL_VERTEX_ATTRIB_ARRAY_SIZE, &bak_va_size[i]);
glGetVertexAttribiv(va[i], GL_VERTEX_ATTRIB_ARRAY_STRIDE, &bak_va_stride[i]);
glGetVertexAttribiv(va[i], GL_VERTEX_ATTRIB_ARRAY_TYPE, &bak_va_type[i]);
glGetVertexAttribiv(va[i], GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &bak_va_norm[i]);
glGetVertexAttribPointerv(va[i], GL_VERTEX_ATTRIB_ARRAY_POINTER, &bak_va_pointer[i]);
}
BOOL result = NO;
do {
glUseProgram(background_program_);
glBindBuffer(GL_ARRAY_BUFFER, background_coord_vbo_);
glEnableVertexAttribArray(background_coord_location_);
glVertexAttribPointer(background_coord_location_, 3, GL_FLOAT, GL_FALSE, 0, 0);
GLfloat vertices[] = {
-1.0f, -1.0f, 0.f,
1.0f, -1.0f, 0.f,
1.0f, 1.0f, 0.f,
-1.0f, 1.0f, 0.f,
};
easyar_Vec4F* v0_v4f = [easyar_Vec4F create:@[@(vertices[0]), @(vertices[1]), @(vertices[2]), @(1.0f)]];
easyar_Vec4F* v1_v4f = [easyar_Vec4F create:@[@(vertices[3]), @(vertices[4]), @(vertices[5]), @(1.0f)]];
easyar_Vec4F* v2_v4f = [easyar_Vec4F create:@[@(vertices[6]), @(vertices[7]), @(vertices[8]), @(1.0f)]];
easyar_Vec4F* v3_v4f = [easyar_Vec4F create:@[@(vertices[9]), @(vertices[10]), @(vertices[11]), @(1.0f)]];
v0_v4f = [self mul:imageProjection vec:v0_v4f];
v1_v4f = [self mul:imageProjection vec:v1_v4f];
v2_v4f = [self mul:imageProjection vec:v2_v4f];
v3_v4f = [self mul:imageProjection vec:v3_v4f];
NSArray<easyar_Vec4F*>* v4f_array = @[v0_v4f, v1_v4f, v2_v4f, v3_v4f];
for (int i = 0; i < 4; i += 1) {
for (int k = 0; k < 3; k += 1) {
vertices[i * 3 + k] = [[v4f_array[i] data][k] floatValue];
}
}
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 12, vertices, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, background_texture_vbo_);
glEnableVertexAttribArray(background_texture_location_);
glVertexAttribPointer(background_texture_location_, 2, GL_FLOAT, GL_FALSE, 0, 0);
switch (background_shader_) {
case FrameShader_RGB:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, background_texture_id_);
break;
case FrameShader_YUV:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, background_texture_id_);
if (current_format_ == easyar_PixelFormat_YUV_NV21 || current_format_ == easyar_PixelFormat_YUV_NV12) {
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, background_texture_uv_id_);
} else {
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, background_texture_u_id_);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, background_texture_v_id_);
}
break;
}
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
result = YES;
} while (0);
if (bak_blend) glEnable(GL_BLEND);
if (bak_depth) glEnable(GL_DEPTH_TEST);
if (bak_cull) glEnable(GL_CULL_FACE);
for (int i = 0; i < 2; ++i) {
if (!bak_va_binding[i])
continue;
glBindBuffer(GL_ARRAY_BUFFER, bak_va_binding[i]);
if (bak_va_enable[i])
glEnableVertexAttribArray(va[i]);
else
glDisableVertexAttribArray(va[i]);
glVertexAttribPointer(va[i], bak_va_size[i], bak_va_type[i], (GLboolean)bak_va_norm[i], bak_va_stride[i], bak_va_pointer[i]);
}
glBindBuffer(GL_ARRAY_BUFFER, bak_arr_buf);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bak_ele_arr_buf);
glBindFramebuffer(GL_FRAMEBUFFER, bak_fbo);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, bak_tex);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, bak_tex_1);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, bak_tex_2);
glActiveTexture(bak_active_tex);
glViewport(bak_viewport[0], bak_viewport[1], bak_viewport[2], bak_viewport[3]);
glUseProgram(bak_program);
}
-(void)retrieveFrame:(easyar_PixelFormat)format width:(int)width height:(int)height bufferData:(void *)bufferData retrieve_count:(int)retrieve_count
{
if (retrieve_count == 0) {
if (width & 0x3) {
if (width & 0x1)
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
else
glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
}
switch (background_shader_) {
case FrameShader_RGB:
{
switch (format) {
case easyar_PixelFormat_Unknown:
glBindTexture(GL_TEXTURE_2D, 0);
break;
case easyar_PixelFormat_Gray:
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, bufferData);
break;
case easyar_PixelFormat_BGR888:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, bufferData);
break;
case easyar_PixelFormat_RGB888:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, bufferData);
break;
case easyar_PixelFormat_RGBA8888:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bufferData);
break;
case easyar_PixelFormat_BGRA8888:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bufferData);
break;
default:
glBindTexture(GL_TEXTURE_2D, 0);
}
}
break;
case FrameShader_YUV:
if (format == easyar_PixelFormat_YUV_NV21 || format == easyar_PixelFormat_YUV_NV12 || format == easyar_PixelFormat_YUV_I420 || format == easyar_PixelFormat_YUV_YV12) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, bufferData);
} else {
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 4, 4, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, yuv_black);
}
break;
default:
break;
}
}
else if (retrieve_count == 1 || retrieve_count == 2) {
if (background_shader_ != FrameShader_YUV) { return; }
if (width & 0x7) {
if (width & 0x3)
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
else
glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
}
unsigned char* data = NULL;
GLint type = GL_LUMINANCE_ALPHA;
if (format == easyar_PixelFormat_YUV_NV21 || format == easyar_PixelFormat_YUV_NV12) {
data = (unsigned char *)bufferData + width * height;
} else if (format == easyar_PixelFormat_YUV_I420) {
type = GL_LUMINANCE;
if (retrieve_count == 1) { //U
data = (unsigned char *)bufferData + width * height;
} else if (retrieve_count == 2) { //V
data = (unsigned char *)bufferData + width * height * 5 / 4;
}
} else if (format == easyar_PixelFormat_YUV_YV12) {
type = GL_LUMINANCE;
if (retrieve_count == 1) { //U
data = (unsigned char *)bufferData + width * height * 5 / 4;
} else if (retrieve_count == 2) { //V
data = (unsigned char *)bufferData + width * height;
}
}
glTexImage2D(GL_TEXTURE_2D, 0, type, width / 2, height / 2, 0, type, GL_UNSIGNED_BYTE, data);
}
}
- (BOOL)initialize:(easyar_PixelFormat)format
{
if (format == easyar_PixelFormat_Unknown)
return NO;
background_program_ = glCreateProgram();
GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertShader, 1, &videobackground_vert, NULL);
glCompileShader(vertShader);
GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);
switch (format) {
case easyar_PixelFormat_Gray:
case easyar_PixelFormat_RGB888:
case easyar_PixelFormat_RGBA8888:
background_shader_ = FrameShader_RGB;
glShaderSource(fragShader, 1, &videobackground_rgb_frag, NULL);
break;
case easyar_PixelFormat_BGR888:
case easyar_PixelFormat_BGRA8888:
background_shader_ = FrameShader_RGB;
glShaderSource(fragShader, 1, &videobackground_bgr_frag, NULL);
break;
case easyar_PixelFormat_YUV_NV21:
background_shader_ = FrameShader_YUV;
glShaderSource(fragShader, 1, &videobackground_yuv_nv21_frag, NULL);
break;
case easyar_PixelFormat_YUV_NV12:
background_shader_ = FrameShader_YUV;
glShaderSource(fragShader, 1, &videobackground_yuv_nv12_frag, NULL);
break;
case easyar_PixelFormat_YUV_I420:
case easyar_PixelFormat_YUV_YV12:
background_shader_ = FrameShader_YUV;
glShaderSource(fragShader, 1, &videobackground_yuv_i420_yv12_frag, NULL);
break;
default:
break;
}
glCompileShader(fragShader);
glAttachShader(background_program_, vertShader);
glAttachShader(background_program_, fragShader);
GLint compileSuccess;
glGetShaderiv(vertShader, GL_COMPILE_STATUS, &compileSuccess);
if (compileSuccess == GL_FALSE) {
GLchar messages[256];
glGetShaderInfoLog(vertShader, sizeof(messages), 0, &messages[0]);
}
glGetShaderiv(fragShader, GL_COMPILE_STATUS, &compileSuccess);
if (compileSuccess == GL_FALSE) {
GLchar messages[256];
glGetShaderInfoLog(fragShader, sizeof(messages), 0, &messages[0]);
}
glLinkProgram(background_program_);
glDeleteShader(vertShader);
glDeleteShader(fragShader);
GLint linkstatus = 0;
glGetProgramiv(background_program_, GL_LINK_STATUS, &linkstatus);
glUseProgram(background_program_);
background_coord_location_ = glGetAttribLocation(background_program_, "coord");
background_texture_location_ = glGetAttribLocation(background_program_, "texCoord");
glGenBuffers(1, &background_coord_vbo_);
glBindBuffer(GL_ARRAY_BUFFER, background_coord_vbo_);
const GLfloat coord[] = { -1.0f, -1.0f, 0.f, 1.0f, -1.0f, 0.f, 1.0f, 1.0f, 0.f, -1.0f, 1.0f, 0.f };
glBufferData(GL_ARRAY_BUFFER, sizeof(coord), coord, GL_DYNAMIC_DRAW);
glGenBuffers(1, &background_texture_vbo_);
glBindBuffer(GL_ARRAY_BUFFER, background_texture_vbo_);
static const GLfloat texcoord[] = { 0.f, 1.f, 1.f, 1.f, 1.f, 0.f, 0.f, 0.f }; //input texture data is Y-inverted
glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), texcoord, GL_STATIC_DRAW);
glUniform1i(glGetUniformLocation(background_program_, "texture"), 0);
glGenTextures(1, &background_texture_id_);
glBindTexture(GL_TEXTURE_2D, background_texture_id_);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
switch (background_shader_) {
case FrameShader_RGB:
break;
case FrameShader_YUV:
if (format == easyar_PixelFormat_YUV_NV21 || format == easyar_PixelFormat_YUV_NV12) {
glUniform1i(glGetUniformLocation(background_program_, "uv_texture"), 1);
glGenTextures(1, &background_texture_uv_id_);
glBindTexture(GL_TEXTURE_2D, background_texture_uv_id_);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
} else {
glUniform1i(glGetUniformLocation(background_program_, "u_texture"), 1);
glGenTextures(1, &background_texture_u_id_);
glBindTexture(GL_TEXTURE_2D, background_texture_u_id_);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glUniform1i(glGetUniformLocation(background_program_, "v_texture"), 2);
glGenTextures(1, &background_texture_v_id_);
glBindTexture(GL_TEXTURE_2D, background_texture_v_id_);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
break;
default:
break;
}
glGenFramebuffers(1, &background_texture_fbo_);
initialized_ = YES;
return YES;
}
- (void)finalize:(easyar_PixelFormat)format
{
if (!initialized_) { return; }
glDeleteProgram(background_program_);
glDeleteBuffers(1, &background_coord_vbo_);
glDeleteBuffers(1, &background_texture_vbo_);
glDeleteFramebuffers(1, &background_texture_fbo_);
glDeleteTextures(1, &background_texture_id_);
switch (background_shader_) {
case FrameShader_RGB:
break;
case FrameShader_YUV:
if (format == easyar_PixelFormat_YUV_NV21 || format == easyar_PixelFormat_YUV_NV12) {
glDeleteTextures(1, &background_texture_uv_id_);
} else {
glDeleteTextures(1, &background_texture_u_id_);
glDeleteTextures(1, &background_texture_v_id_);
}
break;
default:
break;
}
initialized_ = NO;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment