229 lines
8.7 KiB
C++
229 lines
8.7 KiB
C++
/* ================================================================
|
|
RenderScene
|
|
----------------
|
|
This header file defines the RenderScene class.
|
|
================================================================ */
|
|
#include "RenderScene.hpp"
|
|
#include "RenderObject.hpp"
|
|
#include "Log.hpp"
|
|
#include <stdexcept> // for std::out_of_range
|
|
#include <iostream> // for std::cerr
|
|
#include <algorithm> // for std::find
|
|
|
|
/* ======== Constructors and Destructors ======== */
|
|
RenderScene::RenderScene() {
|
|
|
|
}
|
|
RenderScene::~RenderScene() {
|
|
}
|
|
|
|
/* renderTo
|
|
This function attempts to render the given scene to the target_view using the contained RenderCamera(s).
|
|
It iterates over all RenderSets and their RenderObjects and attempts to render to the RenderCamera's attached RenderViews.
|
|
*/
|
|
int RenderScene::renderTo(RenderView *target_view, Program *render_program) {
|
|
RenderCamera *camera;
|
|
RenderView *view;
|
|
RenderSet *set;
|
|
RenderObject *object;
|
|
std::vector<RenderCamera*>::iterator camera_it, camera_end;
|
|
for (camera_it = cameras.begin(), camera_end = cameras.end(); camera_it != camera_end; ++camera_it) {
|
|
camera = *camera_it;
|
|
if ((view = camera->getRenderView()) == NULL) continue;
|
|
glBindFramebuffer(GL_FRAMEBUFFER, view->fbo);
|
|
|
|
std::vector<RenderSet*>::iterator set_it, set_end;
|
|
for (set_it = sets.begin(), set_end = sets.end(); set_it != set_end; ++set_it) {
|
|
set = *set_it;
|
|
std::vector<RenderObject*>::iterator obj_it, obj_end;
|
|
for (obj_it = set->objects.begin(), obj_end = set->objects.end(); obj_it != obj_end; ++obj_it) {
|
|
object = *obj_it;
|
|
|
|
}
|
|
}
|
|
}
|
|
// Use this provided program for rendering. Should refer to a framebuffer shader
|
|
glUseProgram(render_program->getProgram());
|
|
// Bind to the provided target view's fbo
|
|
glBindFramebuffer(GL_FRAMEBUFFER, target_view->fbo);
|
|
// Render each of our camera's framebuffers with the appropriate changes
|
|
for (camera_it = cameras.begin(), camera_end = cameras.end(); camera_it != camera_end; ++camera_it) {
|
|
camera = *camera_it;
|
|
if ((view = camera->getRenderView()) == NULL) continue;
|
|
glBindFramebuffer(GL_FRAMEBUFFER, view->fbo);
|
|
}
|
|
return 0;
|
|
}
|
|
int RenderScene::doRender() {
|
|
RenderCamera *camera;
|
|
RenderView *view;
|
|
RenderSet *set;
|
|
RenderObject *object;
|
|
// Begin iteration over the scene's cameras
|
|
std::vector<RenderCamera*>::iterator camera_it, camera_end;
|
|
for (camera_it = cameras.begin(), camera_end = cameras.end(); camera_it != camera_end; ++camera_it) {
|
|
camera = *camera_it;
|
|
if ((view = camera->getRenderView()) == NULL) continue; // bail if camera has no rendering target
|
|
glBindFramebuffer(GL_FRAMEBUFFER, view->fbo);
|
|
glViewport(0, 0, view->w, view->h);
|
|
if (camera->render_flags & RenderCamera::CLEAR_DEPTH) glClear(GL_DEPTH_BUFFER_BIT);
|
|
if (camera->render_flags & RenderCamera::CLEAR_COLOR) glClear(GL_COLOR_BUFFER_BIT);
|
|
// Iterate over the scene's render sets
|
|
std::vector<RenderSet*>::iterator set_it, set_end;
|
|
for (set_it = sets.begin(), set_end = sets.end(); set_it != set_end; ++set_it) {
|
|
set = *set_it;
|
|
if (set->program == NULL) continue; // bail if set has no rendering program to use
|
|
GLuint glsl_program = set->program->getProgram();
|
|
//LOG(LOG_INFO) << "set program is: " << glsl_program;
|
|
glUseProgram(glsl_program);
|
|
// FIXME: We are temporarily getting the locations here - this needs to be moved elsewhere (Program?)
|
|
GLuint shader_projection = glGetUniformLocation(glsl_program, "proj_matrix");
|
|
GLuint shader_modelview = glGetUniformLocation(glsl_program, "mv_matrix");
|
|
GLuint shader_texture = glGetUniformLocation(glsl_program, "texture_sampler");
|
|
GLuint shader_vp = glGetAttribLocation(glsl_program, "vp");
|
|
GLuint shader_uv = glGetAttribLocation(glsl_program, "uv");
|
|
GLuint shader_normal = glGetAttribLocation(glsl_program, "normal");
|
|
// Send the camera's perspective
|
|
float pm[16];
|
|
glUniformMatrix4fv(shader_projection, 1, GL_FALSE, camera->p_matrix.toFloats(pm));
|
|
// enable attribs
|
|
glEnableVertexAttribArray(shader_vp);
|
|
glEnableVertexAttribArray(shader_uv);
|
|
glEnableVertexAttribArray(shader_normal);
|
|
// Iterate over the set's render objects
|
|
std::vector<RenderObject*>::iterator obj_it, obj_end;
|
|
for (obj_it = set->objects.begin(), obj_end = set->objects.end(); obj_it != obj_end; ++obj_it) {
|
|
object = *obj_it;
|
|
if (object->flags & RenderObject::HIDDEN) continue;
|
|
Mat4 mv_matrix; // modelview matrix
|
|
float mv[16]; // converted modelview to send to OpenGL
|
|
Mesh *mesh;
|
|
Texture *texture;
|
|
GLuint gl_texture = 0;
|
|
if ((mesh = object->mesh) == NULL) continue; // No mesh to render with, bail
|
|
if ((texture = object->texture) == NULL) {
|
|
// TODO: add a "missing texture" texture here
|
|
} else {
|
|
gl_texture = object->texture->texture;
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, gl_texture);
|
|
glUniform1i(shader_texture, 0);
|
|
}
|
|
// TODO: if object is not in camera's view, continue (probably reverse projection on each screen corner)
|
|
// send computed modelview to shader
|
|
mv_matrix = camera->mv_matrix * object->model;
|
|
glUniformMatrix4fv(shader_modelview, 1, GL_FALSE, mv_matrix.toFloats(mv));
|
|
// TODO: enable and attach texture
|
|
// bind vp
|
|
glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo);
|
|
glVertexAttribPointer(shader_vp, 3, GL_FLOAT, GL_FALSE, 0, NULL);
|
|
// bind uvs/texture coords
|
|
glBindBuffer(GL_ARRAY_BUFFER, mesh->uvbo);
|
|
glVertexAttribPointer(shader_uv, 2, GL_FLOAT, GL_FALSE, 0, 0);
|
|
// bind normals
|
|
glBindBuffer(GL_ARRAY_BUFFER, mesh->nbo);
|
|
glVertexAttribPointer(shader_normal, 3, GL_FLOAT, GL_FALSE, 0, NULL);
|
|
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->ibo);
|
|
//glDrawElements(GL_TRIANGLES, mesh->indices.size(), GL_UNSIGNED_INT, 0);
|
|
glDrawArrays(GL_TRIANGLES, 0, mesh->vertices.size());
|
|
// TODO: maybe other things? Should this be managed by Program somehow?
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
/* ======== Camera Functionality ======== */
|
|
// This function adds the ptr to Camera and returns its "id" which is simply its index+1
|
|
int RenderScene::addCamera(RenderCamera* camera) {
|
|
try {
|
|
cameras.push_back(camera);
|
|
} catch(...) {
|
|
LOG(LOG_ERROR) << FUNC_NAME << ": Could not add RenderCamera";
|
|
}
|
|
// return size regardless of success, likely The Wrong Thing
|
|
return cameras.size();
|
|
}
|
|
// Remove camera by ID
|
|
int RenderScene::remCamera(int id) {
|
|
RenderCamera *camera = getCamera(id);
|
|
if (camera) {
|
|
cameras.erase(cameras.begin()+(id-1));
|
|
return 0;
|
|
}
|
|
LOG(LOG_WARNING) << FUNC_NAME << ": Could not remove RenderCamera " << id;
|
|
return 1;
|
|
}
|
|
// Remove camera by pointer
|
|
int RenderScene::remCamera(RenderCamera *camera) {
|
|
std::vector<RenderCamera*>::iterator it;
|
|
if ((it = std::find(cameras.begin(), cameras.end(), camera)) != cameras.end()) {
|
|
cameras.erase(it);
|
|
return 0;
|
|
}
|
|
LOG(LOG_WARNING) << FUNC_NAME << ": Could not remove RenderCamera";
|
|
return 1;
|
|
}
|
|
// Get camera by ID
|
|
RenderCamera* RenderScene::getCamera(int id) {
|
|
try {
|
|
return cameras.at(id-1);
|
|
} catch (const std::out_of_range& oor) {
|
|
LOG(LOG_WARNING) << FUNC_NAME << ": RenderCamera index out of range: " << oor.what();
|
|
}
|
|
return NULL;
|
|
}
|
|
// Get cameras vector
|
|
std::vector<RenderCamera*> *RenderScene::getCameras() {
|
|
return &cameras;
|
|
}
|
|
/* ======== RenderSet Functionality ======== */
|
|
int RenderScene::addSet(RenderSet* set) {
|
|
try {
|
|
sets.push_back(set);
|
|
} catch(...) {
|
|
LOG(LOG_ERROR) << FUNC_NAME << ": Could not add RenderSet";
|
|
}
|
|
// return size regardless of success, likely The Wrong Thing
|
|
return sets.size();
|
|
}
|
|
int RenderScene::remSet(int id) {
|
|
RenderSet *set = getSet(id);
|
|
if (set) {
|
|
sets.erase(sets.begin()+(id-1));
|
|
return 0;
|
|
}
|
|
LOG(LOG_WARNING) << FUNC_NAME << ": Could not remove RenderSet " << id;
|
|
return 1;
|
|
}
|
|
int RenderScene::remSet(RenderSet *set) {
|
|
std::vector<RenderSet*>::iterator it;
|
|
if ((it = std::find(sets.begin(), sets.end(), set)) != sets.end()) {
|
|
sets.erase(it);
|
|
return 0;
|
|
}
|
|
LOG(LOG_WARNING) << FUNC_NAME << ": Could not remove RenderSet";
|
|
return 1;
|
|
}
|
|
int RenderScene::delSet(RenderSet *set) {
|
|
std::vector<RenderSet*>::iterator it;
|
|
if ((it = std::find(sets.begin(), sets.end(), set)) != sets.end()) {
|
|
sets.erase(it);
|
|
delete set;
|
|
return 0;
|
|
}
|
|
LOG(LOG_WARNING) << FUNC_NAME << ": Could not delete RenderSet";
|
|
return 1;
|
|
}
|
|
|
|
RenderSet* RenderScene::getSet(int id) {
|
|
try {
|
|
return sets.at(id-1);
|
|
} catch (const std::out_of_range& oor) {
|
|
LOG(LOG_ERROR) << FUNC_NAME << ": RenderSet index out of range: " << oor.what();
|
|
}
|
|
return NULL;
|
|
}
|
|
std::vector<RenderSet*> *RenderScene::getSets() {
|
|
return &sets;
|
|
}
|