X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;ds=sidebyside;f=src%2F3dengfx%2Fsrc%2F3dengfx%2Fobject.cpp;fp=src%2F3dengfx%2Fsrc%2F3dengfx%2Fobject.cpp;h=7fd4772d2eee3e4c6194bda270e48089ad6a32fc;hb=6e23259dbabaeb1711a2a5ca25b9cb421f693759;hp=0000000000000000000000000000000000000000;hpb=fe068fa879814784c45e0cb2e65dac489e8f5594;p=summerhack diff --git a/src/3dengfx/src/3dengfx/object.cpp b/src/3dengfx/src/3dengfx/object.cpp new file mode 100644 index 0000000..7fd4772 --- /dev/null +++ b/src/3dengfx/src/3dengfx/object.cpp @@ -0,0 +1,630 @@ +/* +This file is part of the 3dengfx, realtime visualization system. + +Copyright (c) 2004, 2005 John Tsiombikas + +3dengfx is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +3dengfx is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with 3dengfx; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* higher level 3d object abstraction + * + * Author: John Tsiombikas 2004 + * Modified: John Tsiombikas 2005, 2006 + */ + +#include "3dengfx_config.h" + +#include "opengl.h" +#include "object.hpp" +#include "3denginefx.hpp" +#include "camera.hpp" +#include "gfxprog.hpp" +#include "texman.hpp" +#include "ggen.hpp" +#include "common/err_msg.h" + +RenderParams::RenderParams() { + billboarded = false; + zwrite = true; + blending = false; + src_blend = BLEND_SRC_ALPHA; + dest_blend = BLEND_ONE_MINUS_SRC_ALPHA; + handle_blending = true; + gfxprog = 0; + auto_cube_maps = false; + hidden = false; + show_normals = false; + show_normals_scale = 0.5; + highlight = false; + highlight_color = Color(1.0, 1.0, 1.0, 1.0); + highlight_line_width = 1.0; + use_vertex_color = false; + taddr = TEXADDR_WRAP; + auto_normalize = false; + cast_shadows = true; +} + + +unsigned long master_render_mode = RMODE_ALL; + + +Object::Object() { + bvol_valid = false; + bvol = 0; + set_dynamic(false); +} + +Object::Object(const TriMesh &mesh) { + bvol = 0; + set_mesh(mesh); + set_dynamic(false); +} + +Object::~Object() { + if(bvol) delete bvol; +} + +void Object::set_mesh(const TriMesh &mesh) { + this->mesh = mesh; + update_bounding_volume(); +} + +TriMesh *Object::get_mesh_ptr() { + bvol_valid = false; + return &mesh; +} + +TriMesh &Object::get_mesh() { + return mesh; +} + +const TriMesh &Object::get_mesh() const { + return mesh; +} + +unsigned long Object::get_vertex_count() const { + return mesh.get_vertex_array()->get_count(); +} + +const Vertex *Object::get_vertex_data() const { + return mesh.get_vertex_array()->get_data(); +} + +Vertex *Object::get_mod_vertex_data() { + return mesh.get_mod_vertex_array()->get_mod_data(); +} + +unsigned long Object::get_triangle_count() const { + return mesh.get_triangle_array()->get_count(); +} + +const Triangle *Object::get_triangle_data() const { + return mesh.get_triangle_array()->get_data(); +} + +Triangle *Object::get_mod_triangle_data() { + return mesh.get_mod_triangle_array()->get_mod_data(); +} + +void Object::set_dynamic(bool enable) { + const_cast(mesh.get_vertex_array())->set_dynamic(enable); + const_cast(mesh.get_triangle_array())->set_dynamic(enable); + //const_cast(mesh.get_index_array())->set_dynamic(enable); +} + +bool Object::get_dynamic() const { + return mesh.get_vertex_array()->get_dynamic(); +} + +void Object::set_material(const Material &mat) { + this->mat = mat; +} + +Material *Object::get_material_ptr() { + return &mat; +} + +Material Object::get_material() const { + return mat; +} + +void Object::set_render_params(const RenderParams &rp) { + render_params = rp; +} + +RenderParams Object::get_render_params() const { + return render_params; +} + +void Object::set_shading(ShadeMode shading_mode) { + mat.shading = shading_mode; +} + +void Object::set_billboarding(bool enable) { + render_params.billboarded = enable; +} + +void Object::set_zwrite(bool enable) { + render_params.zwrite = enable; +} + +void Object::set_blending(bool enable) { + render_params.blending = enable; +} + +void Object::set_blending_mode(BlendingFactor sblend, BlendingFactor dblend) { + render_params.src_blend = sblend; + render_params.dest_blend = dblend; +} + +void Object::set_handle_blending(bool enable) { + render_params.handle_blending = enable; +} + +void Object::set_wireframe(bool enable) { + mat.wireframe = enable; +} + +void Object::set_gfx_program(GfxProg *prog) { + render_params.gfxprog = prog; +} + +void Object::set_auto_cube_maps(bool enable) { + render_params.auto_cube_maps = enable; +} + +void Object::set_hidden(bool enable) { + render_params.hidden = enable; +} + +void Object::set_show_normals(bool enable) { + render_params.show_normals = enable; +} + +void Object::set_show_normals_scale(scalar_t scale) { + render_params.show_normals_scale = scale; +} + +void Object::set_highlight(bool enable) +{ + render_params.highlight = enable; +} + +void Object::set_highlight_color(const Color &color) +{ + render_params.highlight_color = color; +} + +void Object::set_highlight_line_width(scalar_t width) +{ + render_params.highlight_line_width = width; +} + +void Object::set_auto_global(bool enable) { + mat.auto_refl = enable; +} + +void Object::set_use_vertex_color(bool enable) { + render_params.use_vertex_color = enable; +} + +void Object::set_texture_addressing(TextureAddressing taddr) { + render_params.taddr = taddr; +} + +void Object::set_auto_normalize(bool enable) { + render_params.auto_normalize = enable; +} + +void Object::set_shadow_casting(bool enable) +{ + render_params.cast_shadows = enable; +} + +void Object::apply_xform(unsigned long time) { + world_mat = get_prs(time).get_xform_matrix(); + mesh.apply_xform(world_mat); + reset_xform(time); +} + +void Object::calculate_normals() { + mesh.calculate_normals(); +} + +void Object::normalize_normals() { + mesh.normalize_normals(); +} + +bool Object::render(unsigned long time) { + world_mat = get_prs(time).get_xform_matrix(); + + if(!bvol_valid) update_bounding_volume(); + + // set the active world-space transformation for the bounding volume ... + bvol->set_transform(world_mat); + + /* if we have the camera that generated the active view matrix available + * chances are it already has the view frustum, so use it directly to test + * the object, otherwise generate one. + */ + if(engfx_state::view_mat_camera) { + if(!bvol->visible(engfx_state::view_mat_camera->get_frustum())) return false; + } else { + Matrix4x4 view_proj = engfx_state::proj_matrix * engfx_state::view_matrix; + + FrustumPlane frustum[6]; + for(int i=0; i<6; i++) { + frustum[i] = FrustumPlane(view_proj, i); + } + + if(!bvol->visible(frustum)) return false; + } + + + set_matrix(XFORM_WORLD, world_mat); + mat.set_glmaterial(); + + ::set_auto_normalize(render_params.auto_normalize); + + //render8tex_units(); + render_hack(time); + + if(render_params.auto_normalize) ::set_auto_normalize(false); + + return true; +} + +void Object::render_hack(unsigned long time) { + //::set_material(mat); + int tex_unit = 0; + + if(master_render_mode & RMODE_TEXTURES) { + if(mat.tex[TEXTYPE_BUMPMAP]) { + setup_bump_light(time); // sets the light vector into texcoord[1] + + set_texture(tex_unit, mat.tex[TEXTYPE_BUMPMAP]); + enable_texture_unit(tex_unit); + set_texture_coord_index(tex_unit, 0); + set_texture_unit_color(tex_unit, TOP_REPLACE, TARG_TEXTURE, TARG_TEXTURE); + set_texture_unit_alpha(tex_unit, TOP_REPLACE, TARG_PREV, TARG_PREV); + tex_unit++; + + select_texture_unit(tex_unit); + set_texture(tex_unit, get_normal_cube()); + enable_texture_unit(tex_unit); +// ::set_texture_filtering(tex_unit, render_params.tfilter); + set_texture_coord_index(tex_unit, 1); // tex coord with the light vector (UVW) + set_texture_unit_color(tex_unit, TOP_DOT3, TARG_TEXTURE, TARG_PREV); + set_texture_unit_alpha(tex_unit, TOP_REPLACE, TARG_PREV, TARG_PREV); + tex_unit++; + } + + if(mat.tex[TEXTYPE_DIFFUSE]) { + set_texture(tex_unit, mat.tex[TEXTYPE_DIFFUSE]); + enable_texture_unit(tex_unit); + set_texture_coord_index(tex_unit, 0); + set_texture_unit_color(tex_unit, TOP_MODULATE, TARG_TEXTURE, TARG_PREV); + set_texture_unit_alpha(tex_unit, TOP_MODULATE, TARG_TEXTURE, TARG_PREV); + //tex_id = mat.tex[TEXTYPE_DIFFUSE]->tex_id; + ::set_texture_addressing(tex_unit, render_params.taddr, render_params.taddr); +// ::set_texture_filtering(tex_unit, render_params.tfilter); + set_matrix(XFORM_TEXTURE, mat.tmat[TEXTYPE_DIFFUSE], 0); + tex_unit++; + } + + if(mat.tex[TEXTYPE_DETAIL]) { + set_texture(tex_unit, mat.tex[TEXTYPE_DETAIL]); + enable_texture_unit(tex_unit); + set_texture_coord_index(tex_unit, 1); + set_texture_unit_color(tex_unit, TOP_ADD, TARG_TEXTURE, TARG_PREV); + set_texture_unit_color(tex_unit, TOP_MODULATE, TARG_PREV, TARG_TEXTURE); + ::set_texture_addressing(tex_unit, render_params.taddr, render_params.taddr); +// ::set_texture_filtering(tex_unit, render_params.tfilter); + set_matrix(XFORM_TEXTURE, mat.tmat[TEXTYPE_DIFFUSE], 1); + tex_unit++; + } + + if(mat.tex[TEXTYPE_ENVMAP]) { + set_texture(tex_unit, mat.tex[TEXTYPE_ENVMAP]); +// ::set_texture_filtering(tex_unit, render_params.tfilter); + enable_texture_unit(tex_unit); + set_texture_unit_color(tex_unit, TOP_ADD, TARG_TEXTURE, TARG_PREV); + set_texture_unit_alpha(tex_unit, TOP_REPLACE, TARG_PREV, TARG_TEXTURE); + + if(mat.tex[TEXTYPE_ENVMAP]->get_type() == TEX_CUBE) { + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); + glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); + glEnable(GL_TEXTURE_GEN_S); + glEnable(GL_TEXTURE_GEN_T); + glEnable(GL_TEXTURE_GEN_R); + + Matrix4x4 inv_view = engfx_state::view_matrix; + inv_view[0][3] = inv_view[1][3] = inv_view[2][3] = 0.0; + inv_view.transpose(); + + set_matrix(XFORM_TEXTURE, inv_view, tex_unit); + + ::set_texture_addressing(tex_unit, TEXADDR_CLAMP, TEXADDR_CLAMP); + } else { + ::set_texture_addressing(tex_unit, render_params.taddr, render_params.taddr); + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); + glEnable(GL_TEXTURE_GEN_S); + glEnable(GL_TEXTURE_GEN_T); + + // TODO: fix this to produce the correct orientation + /*glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + glRotatef(180.0, 0.0, 1.0, 0.0);*/ + } + //tex_id = mat.tex[TEXTYPE_ENVMAP]->tex_id; + tex_unit++; + } + } + + ::set_zwrite(render_params.zwrite); + set_shading_mode(mat.shading); + + if(master_render_mode & RMODE_BLENDING) { + if(render_params.handle_blending) { + if(mat.alpha < 1.0 - small_number) { + set_alpha_blending(true); + set_blend_func(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA); + } + } else { + set_alpha_blending(render_params.blending); + set_blend_func(render_params.src_blend, render_params.dest_blend); + } + } + + if(mat.wireframe) ::set_wireframe(true); + + if(render_params.gfxprog && (master_render_mode & RMODE_SHADERS)) { + ::set_gfx_program(render_params.gfxprog); + } + // XXX: cont. here + + if(mat.two_sided) set_backface_culling(false); + if(render_params.use_vertex_color) ::use_vertex_colors(true); + + draw(*mesh.get_vertex_array(), *mesh.get_index_array()); + + if(render_params.use_vertex_color) ::use_vertex_colors(false); + if(mat.two_sided) set_backface_culling(true); + + if(mat.wireframe) ::set_wireframe(false); + if((master_render_mode & RMODE_BLENDING) && + (render_params.handle_blending && mat.alpha < 1.0 - small_number) || + (!render_params.handle_blending && render_params.blending)) { + set_alpha_blending(false); + } + if(!render_params.zwrite) ::set_zwrite(true); + if(mat.shading == SHADING_FLAT) set_shading_mode(SHADING_GOURAUD); + + + if(master_render_mode & RMODE_TEXTURES) { + for(int i=0; iget_count(); + const Vertex *vptr = mesh.get_vertex_array()->get_data(); + + set_lighting(false); + + glBegin(GL_LINES); + glColor4f(1.0, 1.0, 1.0, 1.0); + for(int i=0; ipos; + Vector3 normal = vptr->normal * normal_scale; + + glVertex3f(pos.x, pos.y, pos.z); + glVertex3f(pos.x + normal.x, pos.y + normal.y, pos.z + normal.z); + vptr++; + } + glEnd(); + + set_lighting(true); +} + +void Object::draw_highlight() +{ + const Vertex *vptr = mesh.get_vertex_array()->get_data(); + + // get contour edges relative to viewer + Vector3 pov = Vector3(0, 0, 0); + Matrix4x4 model = get_matrix(XFORM_WORLD); + Matrix4x4 view = get_matrix(XFORM_VIEW); + pov.transform(view.inverse()); + pov.transform(model.inverse()); + std::vector *edges = mesh.get_contour_edges(pov, false); + + set_lighting(false); + ::set_gfx_program(0); + + glEnable(GL_LINE_SMOOTH); + glLineWidth(render_params.highlight_line_width); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + Color clr = render_params.highlight_color; + glBegin(GL_LINES); + glColor4f(clr.r, clr.g, clr.b, clr.a); + for (unsigned int i=0; isize(); i++) + { + Vector3 p1, p2; + p1 = vptr[(*edges)[i].vertices[0]].pos; + p2 = vptr[(*edges)[i].vertices[1]].pos; + glVertex3f(p1.x, p1.y, p1.z); + glVertex3f(p2.x, p2.y, p2.z); + } + glEnd(); + + glLineWidth(1); + + glDisable(GL_BLEND); + + set_lighting(true); + +} + +void Object::setup_bump_light(unsigned long time) { + Vector3 lpos = engfx_state::bump_light->get_prs(time).position; + + Matrix4x4 inv_world = world_mat.inverse(); + lpos.transform(inv_world); + + VertexArray *va = mesh.get_mod_vertex_array(); + int vcount = va->get_count(); + Vertex *varray = va->get_mod_data(); + int tcount = mesh.get_triangle_array()->get_count(); + const Triangle *tptr = mesh.get_triangle_array()->get_data(); + + + Vector3 *utan = new Vector3[vcount]; + memset(utan, 0, vcount * sizeof(Vector3)); + + Vector3 *vtan = new Vector3[vcount]; + memset(vtan, 0, vcount * sizeof(Vector3)); + + for(int i=0; ivertices[0]]; + Vertex *v2 = &varray[tptr->vertices[1]]; + Vertex *v3 = &varray[tptr->vertices[2]]; + + Vector3 vec1 = v2->pos - v1->pos; + Vector3 vec2 = v3->pos - v1->pos; + + TexCoord tc1(v2->tex[0].u - v1->tex[0].u, v2->tex[0].v - v1->tex[0].v); + TexCoord tc2(v3->tex[0].u - v1->tex[0].u, v3->tex[0].v - v1->tex[0].v); + + scalar_t r = 1.0 / (tc1.u * tc2.v - tc2.u * tc1.v); + Vector3 udir( (tc2.v * vec1.x - tc1.v * vec2.x) * r, + (tc2.v * vec1.y - tc1.v * vec2.y) * r, + (tc2.v * vec1.z - tc1.v * vec2.z) * r); + + Vector3 vdir( (tc1.u * vec2.x - tc2.u * vec1.x) * r, + (tc1.u * vec2.y - tc2.u * vec1.y) * r, + (tc1.u * vec2.z - tc2.u * vec1.z) * r); + + utan[tptr->vertices[0]] += udir; + utan[tptr->vertices[1]] += udir; + utan[tptr->vertices[2]] += udir; + + vtan[tptr->vertices[0]] += vdir; + vtan[tptr->vertices[1]] += vdir; + vtan[tptr->vertices[2]] += vdir; + + tptr++; + } + + Vertex *vptr = varray; + for(int i=0; ipos; + + Vector3 normal = -vptr->normal; + Vector3 tan = utan[i]; + tan = (tan - normal * dot_product(normal, tan)).normalized(); + Vector3 bitan = cross_product(normal, tan); + + Basis tbn(tan, bitan, normal); + lvec.transform(tbn.create_rotation_matrix()); + //lvec.normalize(); + + vptr->tex[1].u = -lvec.z; + vptr->tex[1].v = -lvec.y; + vptr->tex[1].w = lvec.x; + vptr++; + } + + delete [] utan; + delete [] vtan; +} + + +void Object::update_bounding_volume() { + VertexStatistics vstat = mesh.get_vertex_stats(); + + if(!bvol) { + bvol = new BoundingSphere(vstat.centroid, vstat.max_dist); + bvol_valid = true; + } else { + BoundingSphere *bsph; + + if((bsph = dynamic_cast(bvol))) { + bsph->set_position(vstat.centroid); + bsph->set_radius(vstat.max_dist); + bvol_valid = true; + } else { + static int dbg; + if(!dbg++) error("obj \"%s\": only bounding spheres are supported at this point", name.c_str()); + } + } +} + + +// Convenience classes to deal with generated geometry + +ObjCube::ObjCube(scalar_t sz, int subdiv) { + create_cube(get_mesh_ptr(), sz, subdiv); +} + +ObjPlane::ObjPlane(const Vector3 &normal, const Vector2 &size, int subdiv) { + create_plane(get_mesh_ptr(), normal, size, subdiv); +} + +ObjCylinder::ObjCylinder(scalar_t rad, scalar_t len, bool caps, int udiv, int vdiv) { + create_cylinder(get_mesh_ptr(), rad, len, caps, udiv, vdiv); +} + +ObjSphere::ObjSphere(scalar_t radius, int subdiv) { + create_sphere(get_mesh_ptr(), radius, subdiv); +} + +ObjTorus::ObjTorus(scalar_t circle_rad, scalar_t revolv_rad, int subdiv) { + create_torus(get_mesh_ptr(), circle_rad, revolv_rad, subdiv); +} + +ObjTeapot::ObjTeapot(scalar_t size, int subdiv) { + create_teapot(get_mesh_ptr(), size, subdiv); +}