// Begin License: // Copyright (C) 2006-2008 Tobias Sargeant (tobias.sargeant@gmail.com). // All rights reserved. // // This file is part of the Carve CSG Library (http://carve-csg.com/) // // This file may be used under the terms of the GNU General Public // License version 2.0 as published by the Free Software Foundation // and appearing in the file LICENSE.GPL2 included in the packaging of // this file. // // This file is provided "AS IS" with NO WARRANTY OF ANY KIND, // INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE. // End: #if defined(HAVE_CONFIG_H) # include #endif #include #include #include #include "carve_texture.h" #include "brick_texture.h" #include "leaf_texture.h" #include "scene.hpp" #if defined(__APPLE__) #include #include #include #else #include #include #include #endif #include #include #include #include #include #if defined(__GNUC__) #define __stdcall #endif #if defined(GLU_TESS_CALLBACK_VARARGS) typedef GLvoid (__stdcall *GLUTessCallback)(...); #else typedef void (__stdcall *GLUTessCallback)(); #endif typedef carve::poly::Polyhedron poly_t; carve::geom3d::Vector g_translation; double g_scale; static inline void glVertex(const carve::geom3d::Vector &v) { glVertex3f(g_scale * (v.x + g_translation.x), g_scale * (v.y + g_translation.y), g_scale * (v.z + g_translation.z)); } struct tex_t { float u; float v; tex_t() : u(0.0f), v(0.0f) { } tex_t(float _u, float _v) : u(_u), v(_v) { } }; tex_t operator*(double s, const tex_t &t) { return tex_t(t.u * s, t.v * s); } tex_t &operator+=(tex_t &t1, const tex_t &t2) { t1.u += t2.u; t1.v += t2.v; return t1; } struct vt_t { double x, y, z; float u, v; }; void __stdcall tess_vertex(vt_t *v, bool *is_textured) { if (*is_textured) { glTexCoord2f(v->u, v->v); } glVertex3d(v->x, v->y, v->z); } void drawTexturedPolyhedron(poly_t *poly, carve::interpolate::FaceVertexAttr &fv_tex, carve::interpolate::FaceAttr &f_tex_num) { glEnable(GL_TEXTURE_2D); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); GLUtesselator *tess = gluNewTess(); gluTessCallback(tess, GLU_TESS_BEGIN, (GLUTessCallback)glBegin); gluTessCallback(tess, GLU_TESS_VERTEX_DATA, (GLUTessCallback)tess_vertex); gluTessCallback(tess, GLU_TESS_END, (GLUTessCallback)glEnd); for (size_t i = 0, l = poly->faces.size(); i != l; ++i) { poly_t::face_t &f = poly->faces[i]; std::vector vc(f.nVertices()); bool textured = true; for (size_t j = 0; j < f.nVertices(); ++j) { vc[j].x = g_scale * (f.vertex(j)->v.x + g_translation.x); vc[j].y = g_scale * (f.vertex(j)->v.y + g_translation.y); vc[j].z = g_scale * (f.vertex(j)->v.z + g_translation.z); if (fv_tex.hasAttribute(&f, j)) { tex_t t = fv_tex.getAttribute(&f, j); vc[j].u = t.u; vc[j].v = t.v; } else { textured = false; } } if (textured) { GLuint tex_num = f_tex_num.getAttribute(&f, 0); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, tex_num); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); } else { glColor4f(0.5f, 0.6f, 0.7f, 1.0f); } glNormal3dv(f.plane_eqn.N.v); gluTessBeginPolygon(tess, (void *)&textured); gluTessBeginContour(tess); for (size_t j = 0; j != vc.size(); ++j) { gluTessVertex(tess, (GLdouble *)&vc[j], (GLvoid *)&vc[j]); } gluTessEndContour(tess); gluTessEndPolygon(tess); } gluDeleteTess(tess); glDisable(GL_TEXTURE_2D); } void drawWireframePolyhedron(poly_t *poly) { glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glDisable(GL_LIGHTING); for (size_t i = 0, l = poly->faces.size(); i != l; ++i) { poly_t::face_t &f = poly->faces[i]; glBegin(GL_LINE_LOOP); for (size_t j = 0; j < f.nVertices(); ++j) { double x = g_scale * (f.vertex(j)->v.x + g_translation.x); double y = g_scale * (f.vertex(j)->v.y + g_translation.y); double z = g_scale * (f.vertex(j)->v.z + g_translation.z); glVertex3d(x, y, z); } glEnd(); } glEnable(GL_LIGHTING); } poly_t *texturedCube( carve::interpolate::FaceVertexAttr &fv_tex, carve::interpolate::FaceAttr &f_tex_num, GLuint tex, const carve::math::Matrix &transform = carve::math::Matrix::IDENT()) { std::vector v; v.push_back(poly_t::vertex_t(transform * carve::geom::VECTOR(+1.0, +1.0, +1.0))); v.push_back(poly_t::vertex_t(transform * carve::geom::VECTOR(-1.0, +1.0, +1.0))); v.push_back(poly_t::vertex_t(transform * carve::geom::VECTOR(-1.0, -1.0, +1.0))); v.push_back(poly_t::vertex_t(transform * carve::geom::VECTOR(+1.0, -1.0, +1.0))); v.push_back(poly_t::vertex_t(transform * carve::geom::VECTOR(+1.0, +1.0, -1.0))); v.push_back(poly_t::vertex_t(transform * carve::geom::VECTOR(-1.0, +1.0, -1.0))); v.push_back(poly_t::vertex_t(transform * carve::geom::VECTOR(-1.0, -1.0, -1.0))); v.push_back(poly_t::vertex_t(transform * carve::geom::VECTOR(+1.0, -1.0, -1.0))); std::vector faces; faces.reserve(6); faces.push_back(poly_t::face_t(&v[0], &v[1], &v[2], &v[3])); faces.push_back(poly_t::face_t(&v[7], &v[6], &v[5], &v[4])); faces.push_back(poly_t::face_t(&v[0], &v[4], &v[5], &v[1])); faces.push_back(poly_t::face_t(&v[1], &v[5], &v[6], &v[2])); faces.push_back(poly_t::face_t(&v[2], &v[6], &v[7], &v[3])); faces.push_back(poly_t::face_t(&v[3], &v[7], &v[4], &v[0])); for (size_t i = 0; i < 6; ++i) { fv_tex.setAttribute(&faces[i], 0, tex_t(0.0f, 1.0f)); fv_tex.setAttribute(&faces[i], 1, tex_t(1.0f, 1.0f)); fv_tex.setAttribute(&faces[i], 2, tex_t(1.0f, 0.0f)); fv_tex.setAttribute(&faces[i], 3, tex_t(0.0f, 0.0f)); f_tex_num.setAttribute(&faces[i], tex); } poly_t *poly = new poly_t(faces); return poly; } struct TestScene : public Scene { GLuint draw_list_base; std::vector draw_flags; virtual bool key(unsigned char k, int x, int y) { const char *t; static const char *l = "1234567890!@#$%^&*()"; t = strchr(l, k); if (t != NULL) { int layer = t - l; if (layer < draw_flags.size()) { draw_flags[layer] = !draw_flags[layer]; } } return true; } virtual GLvoid draw() { for (size_t i = 0; i < draw_flags.size(); ++i) { if (draw_flags[i]) glCallList(draw_list_base + i); } } TestScene(int argc, char **argv, int n_dlist) : Scene(argc, argv) { draw_list_base = glGenLists(n_dlist); draw_flags.resize(n_dlist, false); } virtual ~TestScene() { glDeleteLists(draw_list_base, draw_flags.size()); } }; GLuint initTexture(GLuint w, GLuint h, const unsigned char *data) { GLuint tex; glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D, tex); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data); 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_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); return tex; } void destroyTexture(GLuint tex) { glDeleteTextures(1, &tex); } int main(int argc, char **argv) { TestScene *scene = new TestScene(argc, argv, 2); GLuint tex_1 = initTexture(128, 128, carve_texture); GLuint tex_2 = initTexture(128, 128, brick_texture); GLuint tex_3 = initTexture(128, 128, leaf_texture); g_scale = 10.0; carve::interpolate::FaceVertexAttr fv_tex; carve::interpolate::FaceAttr f_tex_num; poly_t *base = NULL; bool b = true; for (int x = -10; x <= +10; x += 5) { for (int y = -10; y <= +10; y += 5) { for (int z = -10; z <= +10; z += 5) { double rot = x * .17 + y * .06 + z * .09; poly_t *r = texturedCube(fv_tex, f_tex_num, b ? tex_2 : tex_3, carve::math::Matrix::TRANS(x/2.5, y/2.5, z/2.5) * carve::math::Matrix::ROT(rot, 1,2,3)); b = !b; if (base) { poly_t *temp = base; carve::csg::CSG csg; fv_tex.installHooks(csg); f_tex_num.installHooks(csg); base = csg.compute(temp, r, carve::csg::CSG::UNION); delete temp; delete r; } else { base = r; } } } } poly_t *r1 = texturedCube(fv_tex, f_tex_num, tex_1, carve::math::Matrix::TRANS(0,0,4) * carve::math::Matrix::SCALE(4,4,4)); poly_t *r2 = texturedCube(fv_tex, f_tex_num, tex_1, carve::math::Matrix::TRANS(0,0,5) * carve::math::Matrix::SCALE(2, 2, 2)); carve::csg::CSG csg; fv_tex.installHooks(csg); f_tex_num.installHooks(csg); poly_t *r3 = csg.compute(base, r1, carve::csg::CSG::INTERSECTION); poly_t *r4 = csg.compute(r3, r2, carve::csg::CSG::UNION); glNewList(scene->draw_list_base, GL_COMPILE); drawTexturedPolyhedron(r4, fv_tex, f_tex_num); glEndList(); glNewList(scene->draw_list_base+1, GL_COMPILE); drawWireframePolyhedron(r3); glEndList(); scene->draw_flags[0] = true; scene->draw_flags[1] = true; scene->run(); destroyTexture(tex_1); destroyTexture(tex_2); destroyTexture(tex_3); delete scene; return 0; }