long time_msec;
int win_width, win_height;
+int vp_width, vp_height;
float win_aspect;
bool fb_srgb;
bool opt_gear_wireframe;
avatar.body_rot = rad_to_deg(acos(dot(dir, Vec3(0, 0, 1))));
exman = new ExhibitManager;
- /*
- if(!exman->load(mscn, "data/exhibits")) {
- //return false;
- }
- */
+ // exhibits are loaded in post_scene_init, because they need access to the scene graph
+
if(!exui_init()) {
error_log("failed to initialize exhibit ui system\n");
return false;
}
rend = new Renderer;
+ if(!rend->init()) {
+ return false;
+ }
rend->set_scene(mscn);
glUseProgram(0);
return true;
}
+// post_scene_init is called after the scene has completed loading
static void post_scene_init()
{
+ mscn->update(0); // update once to calculate node matrices
+
int num_mir = mscn->calc_mirror_planes();
info_log("found %d mirror planes\n", num_mir);
for(int i=0; i<2; i++) {
// for each eye
goatvr_draw_eye(i);
+ vp_width = goatvr_get_fb_eye_width(i);
+ vp_height = goatvr_get_fb_eye_height(i);
proj_matrix = goatvr_projection_matrix(i, NEAR_CLIP, FAR_CLIP);
glMatrixMode(GL_PROJECTION);
}
goatvr_draw_done();
+ vp_width = win_width;
+ vp_height = win_height;
+
if(should_swap) {
app_swap_buffers();
}
glViewport(0, 0, x, y);
goatvr_set_fb_size(x, y, 1.0f);
debug_gui_reshape(x, y);
+
+ vp_width = x;
+ vp_height = y;
}
void app_keyboard(int key, bool pressed)
extern long time_msec;
extern int win_width, win_height;
+extern int vp_width, vp_height; // viewport size differs from win size during VR eye rendering
extern float win_aspect;
extern bool opt_gear_wireframe;
extern bool fb_srgb;
int MetaScene::calc_mirror_planes()
{
+ std::vector<Vec4> world_planes;
+
int num_mirrors = 0;
while(mirrors) {
FlatMirror *m = mirrors;
FlatMirror *mir = new FlatMirror;
mir->reflect = obj->mtl.reflect;
+ mir->node = obj->node;
if(obj->mtl.flat_mirror == MTL_MIRROR_AUTO) {
// grab the first triangle and make a plane
mir->plane.normal = face.normal;
} else {
int plane_idx = obj->mtl.flat_mirror - MTL_MIRROR_AABB_PX;
- if(obj->node) {
- mir->plane = obj->node->get_bounds().get_plane(plane_idx);
- } else {
- mir->plane = obj->get_aabox().get_plane(plane_idx);
- }
+ mir->plane = obj->get_aabox().get_plane(plane_idx);
debug_log("mirror plane: p(%f %f %f) n(%f %f %f)\n", mir->plane.pt.x, mir->plane.pt.y,
mir->plane.pt.z, mir->plane.normal.x, mir->plane.normal.y, mir->plane.normal.z);
}
+ float pdist = dot(mir->plane.normal, mir->plane.pt);
+ Vec4 plane_eq = Vec4(mir->plane.normal.x, mir->plane.normal.y, mir->plane.normal.z, pdist);
+
+ if(obj->node) {
+ plane_eq = obj->node->get_matrix() * plane_eq;
+ }
+
// check to see if we have found this mirror plane already
bool found = false;
- FlatMirror *node = mirrors;
- while(node) {
- if(1.0f - dot(mir->plane.normal, node->plane.normal) < 1e-4f &&
- fabs(dot(mir->plane.normal, normalize(mir->plane.pt - node->plane.pt))) < 1e-4) {
+ int nplanes = world_planes.size();
+ for(int k=0; k<nplanes; k++) {
+ if(1.0f - dot(plane_eq.xyz(), world_planes[k].xyz()) < 1e-4f &&
+ fabs(plane_eq.w - world_planes[k].w) < 1e-4) {
found = true;
break;
}
- node = node->next;
}
if(!found) {
mir->next = mirrors;
mirrors = mir;
+ world_planes.push_back(plane_eq);
+
+ mir->objects.push_back(obj);
objmirror[obj] = mir; // associate with object
++num_mirrors;
} else {
switch(tolower(caxis)) {
case 'x':
- plane = caxis == '+' ? MTL_MIRROR_AABB_PX : MTL_MIRROR_AABB_NX;
+ plane = csign == '+' ? MTL_MIRROR_AABB_PX : MTL_MIRROR_AABB_NX;
break;
case 'y':
- plane = caxis == '+' ? MTL_MIRROR_AABB_PY : MTL_MIRROR_AABB_NY;
+ plane = csign == '+' ? MTL_MIRROR_AABB_PY : MTL_MIRROR_AABB_NY;
break;
case 'z':
- plane = caxis == '+' ? MTL_MIRROR_AABB_PZ : MTL_MIRROR_AABB_NZ;
+ plane = csign == '+' ? MTL_MIRROR_AABB_PZ : MTL_MIRROR_AABB_NZ;
break;
default:
error_log("invalid reflect plane specifier: %s\n", aplane->val.str);
struct FlatMirror {
Plane plane;
float reflect;
- //std::vector<Object*> objects;
+ std::vector<Object*> objects;
+ SceneNode *node;
FlatMirror *next;
};
std::map<Scene*, void*> scndata;
FlatMirror *mirrors;
- int num_mirrors;
std::map<Object*, FlatMirror*> objmirror;
AudioStream *music;
+#include <stdlib.h>
#include "opengl.h"
#include "logger.h"
return 0;
}
+void dump_gl_texture(unsigned int tex, const char *fname)
+{
+ FILE *fp;
+ int i, width, height;
+ unsigned char *pixels;
+
+ glBindTexture(GL_TEXTURE_2D, tex);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
+
+ if(!(pixels = malloc(width * height * 3))) {
+ return;
+ }
+ glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
+
+ if(!(fp = fopen(fname, "wb"))) {
+ free(pixels);
+ return;
+ }
+ fprintf(fp, "P6\n%d %d\n255\n", width, height);
+ for(i=0; i<width * height * 3; i++) {
+ fputc(pixels[i], fp);
+ }
+ fclose(fp);
+ free(pixels);
+}
+
static void GLAPIENTRY gldebug_logger(GLenum src, GLenum type, GLuint id, GLenum severity,
GLsizei len, const char *msg, const void *cls)
int init_opengl(void);
+void dump_gl_texture(unsigned int tex, const char *fname);
+
#ifdef __cplusplus
}
#endif
#include "renderer.h"
+#include "rtarg.h"
+#include "app.h"
+
+static RenderTarget *rtmirror;
Renderer::Renderer()
{
mscn = 0;
+ ropt = RENDER_ALL;
}
Renderer::~Renderer()
{
+ destroy();
}
bool Renderer::init()
{
+ static bool once;
+ if(!rtmirror && !once) {
+ once = true;
+ rtmirror = new RenderTarget;
+ if(!rtmirror->create(vp_width, vp_height, GL_SRGB)) {
+ error_log("failed to create mirror render target (%dx%d)\n", vp_width, vp_height);
+ }
+ }
+
return true;
}
return mscn;
}
+// render mirror reflections if ...
+#define DO_MIRRORS \
+ mscn->mirrors && /* scene contains mirrors */ \
+ (ropt & RENDER_MIRRORS) && /* mirror rendering is enabled */ \
+ rtmirror /* mirror render target succesfully created */
+
void Renderer::draw() const
{
if(!mscn) return;
+ if(DO_MIRRORS && current_render_target() != rtmirror) {
+ // check if the render target needs resizing
+ if(rtmirror->get_width() != vp_width || rtmirror->get_height() != vp_height) {
+ if(!rtmirror->resize(vp_width, vp_height)) {
+ error_log("failed to resize mirror render target (%dx%d)\n", vp_width, vp_height);
+ goto abort_mirrors;
+ }
+ }
+
+ FlatMirror *mir = mscn->mirrors;
+ while(mir) {
+ draw_mirror(mir);
+ mir = mir->next;
+ }
+ }
+abort_mirrors:
+
int num = (int)mscn->scenes.size();
for(int i=0; i<num; i++) {
Scene *scn = mscn->scenes[i];
int nobj = (int)scn->objects.size();
for(int j=0; j<nobj; j++) {
+ // don't draw mirrors, we already did that earlier (if mirror rendering enabled)
+ if((ropt & RENDER_MIRRORS) && scn->objects[j]->mtl.flat_mirror) {
+ continue;
+ }
draw_object(scn->objects[j]);
}
}
obj->draw();
}
}
+
+void Renderer::draw_mirror(FlatMirror *mir) const
+{
+ push_render_target(rtmirror);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+
+ float pdist = dot(mir->plane.normal, mir->plane.pt);
+ Vec4 peq = Vec4(mir->plane.normal.x, mir->plane.normal.y, mir->plane.normal.z, pdist);
+
+ if(mir->node) {
+ peq = mir->node->get_matrix() * peq;
+ }
+
+ Mat4 mirmat;
+ mirmat.mirror(peq.x, peq.y, peq.z, peq.w);
+ glMultMatrixf(mirmat[0]);
+
+ glFrontFace(GL_CW);
+ draw();
+ glFrontFace(GL_CCW);
+
+ glPopMatrix();
+ pop_render_target();
+
+ dump_gl_texture(rtmirror->texture()->get_id(), "mirror.ppm");
+
+ int nobj = mir->objects.size();
+ for(int i=0; i<nobj; i++) {
+ draw_object(mir->objects[i]);
+ }
+}
#include "metascene.h"
+enum {
+ RENDER_MIRRORS = 1,
+
+ RENDER_ALL = 0x7fffffff
+};
+
class Renderer {
private:
MetaScene *mscn;
public:
+ unsigned int ropt;
Renderer();
virtual ~Renderer();
virtual void draw() const;
virtual void draw_object(Object *obj) const;
+
+ virtual void draw_mirror(FlatMirror *mir) const;
};
#endif // RENDERER_H_