blob: c701dbd9010f6d003fe30e892ae508ac097c8460 [file] [log] [blame]
/*
* Copyright 2017 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// This modules handles drawing the passthrough camera image into the OpenGL
// scene.
#include <type_traits>
#include "platform_tools/android/apps/arcore/src/main/cpp/background_renderer.h"
namespace hello_ar {
namespace {
// Positions of the quad vertices in clip space (X, Y, Z).
const GLfloat kVertices[] = {
-1.0f, -1.0f, 0.0f, +1.0f, -1.0f, 0.0f,
-1.0f, +1.0f, 0.0f, +1.0f, +1.0f, 0.0f,
};
// UVs of the quad vertices (S, T)
const GLfloat kUvs[] = {
0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
};
constexpr char kVertexShader[] = R"(
attribute vec4 vertex;
attribute vec2 textureCoords;
varying vec2 v_textureCoords;
void main() {
v_textureCoords = textureCoords;
gl_Position = vertex;
})";
constexpr char kFragmentShader[] = R"(
#extension GL_OES_EGL_image_external : require
precision mediump float;
uniform samplerExternalOES texture;
varying vec2 v_textureCoords;
void main() {
gl_FragColor = texture2D(texture, v_textureCoords);
})";
} // namespace
void BackgroundRenderer::InitializeGlContent() {
shader_program_ = util::CreateProgram(kVertexShader, kFragmentShader);
if (!shader_program_) {
LOGE("Could not create program.");
}
glGenTextures(1, &texture_id_);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id_);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
uniform_texture_ = glGetUniformLocation(shader_program_, "texture");
attribute_vertices_ = glGetAttribLocation(shader_program_, "vertex");
attribute_uvs_ = glGetAttribLocation(shader_program_, "textureCoords");
}
void BackgroundRenderer::Draw(const ArSession *session, const ArFrame *frame) {
static_assert(std::extent<decltype(kUvs)>::value == kNumVertices * 2,
"Incorrect kUvs length");
static_assert(std::extent<decltype(kVertices)>::value == kNumVertices * 3,
"Incorrect kVertices length");
// If display rotation changed (also includes view size change), we need to
// re-query the uv coordinates for the on-screen portion of the camera image.
int32_t geometry_changed = 0;
ArFrame_getDisplayGeometryChanged(session, frame, &geometry_changed);
if (geometry_changed != 0 || !uvs_initialized_) {
ArFrame_transformDisplayUvCoords(session, frame, kNumVertices * 2, kUvs,
transformed_uvs_);
uvs_initialized_ = true;
}
glUseProgram(shader_program_);
glDepthMask(GL_FALSE);
glUniform1i(uniform_texture_, 1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id_);
glEnableVertexAttribArray(attribute_vertices_);
glVertexAttribPointer(attribute_vertices_, 3, GL_FLOAT, GL_FALSE, 0,
kVertices);
glEnableVertexAttribArray(attribute_uvs_);
glVertexAttribPointer(attribute_uvs_, 2, GL_FLOAT, GL_FALSE, 0,
transformed_uvs_);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glUseProgram(0);
glDepthMask(GL_TRUE);
util::CheckGlError("BackgroundRenderer::Draw() error");
}
GLuint BackgroundRenderer::GetTextureId() const { return texture_id_; }
} // namespace hello_ar