dust3d/thirdparty/carve-1.4.0/examples/texture_example.cpp

355 lines
9.7 KiB
C++

// 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 <carve_config.h>
#endif
#include <carve/interpolator.hpp>
#include <carve/csg_triangulator.hpp>
#include <carve/csg.hpp>
#include "carve_texture.h"
#include "brick_texture.h"
#include "leaf_texture.h"
#include "scene.hpp"
#if defined(__APPLE__)
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#include <GLUT/glut.h>
#else
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#endif
#include <fstream>
#include <string>
#include <utility>
#include <set>
#include <time.h>
#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<tex_t> &fv_tex,
carve::interpolate::FaceAttr<GLuint> &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<vt_t> 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<tex_t> &fv_tex,
carve::interpolate::FaceAttr<GLuint> &f_tex_num,
GLuint tex,
const carve::math::Matrix &transform = carve::math::Matrix::IDENT()) {
std::vector<poly_t::vertex_t> 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<poly_t::face_t> 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<bool> 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<tex_t> fv_tex;
carve::interpolate::FaceAttr<GLuint> 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;
}