Disabled external gits
This commit is contained in:
13
cs440-acg/ext/eigen/demos/CMakeLists.txt
Normal file
13
cs440-acg/ext/eigen/demos/CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
project(EigenDemos)
|
||||
|
||||
add_custom_target(demos)
|
||||
|
||||
if(NOT EIGEN_TEST_NOQT)
|
||||
find_package(Qt4)
|
||||
if(QT4_FOUND)
|
||||
add_subdirectory(mandelbrot)
|
||||
add_subdirectory(opengl)
|
||||
else(QT4_FOUND)
|
||||
message(STATUS "Qt4 not found, so disabling the mandelbrot and opengl demos")
|
||||
endif(QT4_FOUND)
|
||||
endif()
|
21
cs440-acg/ext/eigen/demos/mandelbrot/CMakeLists.txt
Normal file
21
cs440-acg/ext/eigen/demos/mandelbrot/CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
find_package(Qt4 REQUIRED)
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
|
||||
add_definitions ( "-DNDEBUG" )
|
||||
endif (CMAKE_COMPILER_IS_GNUCXX)
|
||||
|
||||
include_directories( ${QT_INCLUDE_DIR} )
|
||||
|
||||
set(mandelbrot_SRCS
|
||||
mandelbrot.cpp
|
||||
)
|
||||
|
||||
qt4_automoc(${mandelbrot_SRCS})
|
||||
|
||||
add_executable(mandelbrot ${mandelbrot_SRCS})
|
||||
add_dependencies(demos mandelbrot)
|
||||
|
||||
target_link_libraries(mandelbrot ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY})
|
10
cs440-acg/ext/eigen/demos/mandelbrot/README
Normal file
10
cs440-acg/ext/eigen/demos/mandelbrot/README
Normal file
@@ -0,0 +1,10 @@
|
||||
*** Mandelbrot demo ***
|
||||
|
||||
Controls:
|
||||
* Left mouse button to center view at a point.
|
||||
* Drag vertically with left mouse button to zoom in and out.
|
||||
|
||||
Be sure to enable SSE2 or AltiVec to improve performance.
|
||||
|
||||
The number of iterations, and the choice between single and double precision, are
|
||||
determined at runtime depending on the zoom level.
|
213
cs440-acg/ext/eigen/demos/mandelbrot/mandelbrot.cpp
Normal file
213
cs440-acg/ext/eigen/demos/mandelbrot/mandelbrot.cpp
Normal file
@@ -0,0 +1,213 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "mandelbrot.h"
|
||||
#include <iostream>
|
||||
#include<QtGui/QPainter>
|
||||
#include<QtGui/QImage>
|
||||
#include<QtGui/QMouseEvent>
|
||||
#include<QtCore/QTime>
|
||||
|
||||
void MandelbrotWidget::resizeEvent(QResizeEvent *)
|
||||
{
|
||||
if(size < width() * height())
|
||||
{
|
||||
std::cout << "reallocate buffer" << std::endl;
|
||||
size = width() * height();
|
||||
if(buffer) delete[]buffer;
|
||||
buffer = new unsigned char[4*size];
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> struct iters_before_test { enum { ret = 8 }; };
|
||||
template<> struct iters_before_test<double> { enum { ret = 16 }; };
|
||||
|
||||
template<typename Real> void MandelbrotThread::render(int img_width, int img_height)
|
||||
{
|
||||
enum { packetSize = Eigen::internal::packet_traits<Real>::size }; // number of reals in a Packet
|
||||
typedef Eigen::Array<Real, packetSize, 1> Packet; // wrap a Packet as a vector
|
||||
|
||||
enum { iters_before_test = iters_before_test<Real>::ret };
|
||||
max_iter = (max_iter / iters_before_test) * iters_before_test;
|
||||
const int alignedWidth = (img_width/packetSize)*packetSize;
|
||||
unsigned char *const buffer = widget->buffer;
|
||||
const double xradius = widget->xradius;
|
||||
const double yradius = xradius * img_height / img_width;
|
||||
const int threadcount = widget->threadcount;
|
||||
typedef Eigen::Array<Real, 2, 1> Vector2;
|
||||
Vector2 start(widget->center.x() - widget->xradius, widget->center.y() - yradius);
|
||||
Vector2 step(2*widget->xradius/img_width, 2*yradius/img_height);
|
||||
total_iter = 0;
|
||||
|
||||
for(int y = id; y < img_height; y += threadcount)
|
||||
{
|
||||
int pix = y * img_width;
|
||||
|
||||
// for each pixel, we're going to do the iteration z := z^2 + c where z and c are complex numbers,
|
||||
// starting with z = c = complex coord of the pixel. pzi and pzr denote the real and imaginary parts of z.
|
||||
// pci and pcr denote the real and imaginary parts of c.
|
||||
|
||||
Packet pzi_start, pci_start;
|
||||
for(int i = 0; i < packetSize; i++) pzi_start[i] = pci_start[i] = start.y() + y * step.y();
|
||||
|
||||
for(int x = 0; x < alignedWidth; x += packetSize, pix += packetSize)
|
||||
{
|
||||
Packet pcr, pci = pci_start, pzr, pzi = pzi_start, pzr_buf;
|
||||
for(int i = 0; i < packetSize; i++) pzr[i] = pcr[i] = start.x() + (x+i) * step.x();
|
||||
|
||||
// do the iterations. Every iters_before_test iterations we check for divergence,
|
||||
// in which case we can stop iterating.
|
||||
int j = 0;
|
||||
typedef Eigen::Matrix<int, packetSize, 1> Packeti;
|
||||
Packeti pix_iter = Packeti::Zero(), // number of iteration per pixel in the packet
|
||||
pix_dont_diverge; // whether or not each pixel has already diverged
|
||||
do
|
||||
{
|
||||
for(int i = 0; i < iters_before_test/4; i++) // peel the inner loop by 4
|
||||
{
|
||||
# define ITERATE \
|
||||
pzr_buf = pzr; \
|
||||
pzr = pzr.square(); \
|
||||
pzr -= pzi.square(); \
|
||||
pzr += pcr; \
|
||||
pzi = (2*pzr_buf)*pzi; \
|
||||
pzi += pci;
|
||||
ITERATE ITERATE ITERATE ITERATE
|
||||
}
|
||||
pix_dont_diverge = ((pzr.square() + pzi.square())
|
||||
.eval() // temporary fix as what follows is not yet vectorized by Eigen
|
||||
<= Packet::Constant(4))
|
||||
// the 4 here is not a magic value, it's a math fact that if
|
||||
// the square modulus is >4 then divergence is inevitable.
|
||||
.template cast<int>();
|
||||
pix_iter += iters_before_test * pix_dont_diverge;
|
||||
j++;
|
||||
total_iter += iters_before_test * packetSize;
|
||||
}
|
||||
while(j < max_iter/iters_before_test && pix_dont_diverge.any()); // any() is not yet vectorized by Eigen
|
||||
|
||||
// compute pixel colors
|
||||
for(int i = 0; i < packetSize; i++)
|
||||
{
|
||||
buffer[4*(pix+i)] = 255*pix_iter[i]/max_iter;
|
||||
buffer[4*(pix+i)+1] = 0;
|
||||
buffer[4*(pix+i)+2] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// if the width is not a multiple of packetSize, fill the remainder in black
|
||||
for(int x = alignedWidth; x < img_width; x++, pix++)
|
||||
buffer[4*pix] = buffer[4*pix+1] = buffer[4*pix+2] = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void MandelbrotThread::run()
|
||||
{
|
||||
setTerminationEnabled(true);
|
||||
double resolution = widget->xradius*2/widget->width();
|
||||
max_iter = 128;
|
||||
if(resolution < 1e-4f) max_iter += 128 * ( - 4 - std::log10(resolution));
|
||||
int img_width = widget->width()/widget->draft;
|
||||
int img_height = widget->height()/widget->draft;
|
||||
single_precision = resolution > 1e-7f;
|
||||
|
||||
if(single_precision)
|
||||
render<float>(img_width, img_height);
|
||||
else
|
||||
render<double>(img_width, img_height);
|
||||
}
|
||||
|
||||
void MandelbrotWidget::paintEvent(QPaintEvent *)
|
||||
{
|
||||
static float max_speed = 0;
|
||||
long long total_iter = 0;
|
||||
|
||||
QTime time;
|
||||
time.start();
|
||||
for(int th = 0; th < threadcount; th++)
|
||||
threads[th]->start(QThread::LowPriority);
|
||||
for(int th = 0; th < threadcount; th++)
|
||||
{
|
||||
threads[th]->wait();
|
||||
total_iter += threads[th]->total_iter;
|
||||
}
|
||||
int elapsed = time.elapsed();
|
||||
|
||||
if(draft == 1)
|
||||
{
|
||||
float speed = elapsed ? float(total_iter)*1000/elapsed : 0;
|
||||
max_speed = std::max(max_speed, speed);
|
||||
std::cout << threadcount << " threads, "
|
||||
<< elapsed << " ms, "
|
||||
<< speed << " iters/s (max " << max_speed << ")" << std::endl;
|
||||
int packetSize = threads[0]->single_precision
|
||||
? int(Eigen::internal::packet_traits<float>::size)
|
||||
: int(Eigen::internal::packet_traits<double>::size);
|
||||
setWindowTitle(QString("resolution ")+QString::number(xradius*2/width(), 'e', 2)
|
||||
+QString(", %1 iterations per pixel, ").arg(threads[0]->max_iter)
|
||||
+(threads[0]->single_precision ? QString("single ") : QString("double "))
|
||||
+QString("precision, ")
|
||||
+(packetSize==1 ? QString("no vectorization")
|
||||
: QString("vectorized (%1 per packet)").arg(packetSize)));
|
||||
}
|
||||
|
||||
QImage image(buffer, width()/draft, height()/draft, QImage::Format_RGB32);
|
||||
QPainter painter(this);
|
||||
painter.drawImage(QPoint(0, 0), image.scaled(width(), height()));
|
||||
|
||||
if(draft>1)
|
||||
{
|
||||
draft /= 2;
|
||||
setWindowTitle(QString("recomputing at 1/%1 resolution...").arg(draft));
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void MandelbrotWidget::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if( event->buttons() & Qt::LeftButton )
|
||||
{
|
||||
lastpos = event->pos();
|
||||
double yradius = xradius * height() / width();
|
||||
center = Eigen::Vector2d(center.x() + (event->pos().x() - width()/2) * xradius * 2 / width(),
|
||||
center.y() + (event->pos().y() - height()/2) * yradius * 2 / height());
|
||||
draft = 16;
|
||||
for(int th = 0; th < threadcount; th++)
|
||||
threads[th]->terminate();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void MandelbrotWidget::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
QPoint delta = event->pos() - lastpos;
|
||||
lastpos = event->pos();
|
||||
if( event->buttons() & Qt::LeftButton )
|
||||
{
|
||||
double t = 1 + 5 * double(delta.y()) / height();
|
||||
if(t < 0.5) t = 0.5;
|
||||
if(t > 2) t = 2;
|
||||
xradius *= t;
|
||||
draft = 16;
|
||||
for(int th = 0; th < threadcount; th++)
|
||||
threads[th]->terminate();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
MandelbrotWidget w;
|
||||
w.show();
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
#include "mandelbrot.moc"
|
71
cs440-acg/ext/eigen/demos/mandelbrot/mandelbrot.h
Normal file
71
cs440-acg/ext/eigen/demos/mandelbrot/mandelbrot.h
Normal file
@@ -0,0 +1,71 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef MANDELBROT_H
|
||||
#define MANDELBROT_H
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <QtGui/QApplication>
|
||||
#include <QtGui/QWidget>
|
||||
#include <QtCore/QThread>
|
||||
|
||||
class MandelbrotWidget;
|
||||
|
||||
class MandelbrotThread : public QThread
|
||||
{
|
||||
friend class MandelbrotWidget;
|
||||
MandelbrotWidget *widget;
|
||||
long long total_iter;
|
||||
int id, max_iter;
|
||||
bool single_precision;
|
||||
|
||||
public:
|
||||
MandelbrotThread(MandelbrotWidget *w, int i) : widget(w), id(i) {}
|
||||
void run();
|
||||
template<typename Real> void render(int img_width, int img_height);
|
||||
};
|
||||
|
||||
class MandelbrotWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class MandelbrotThread;
|
||||
Eigen::Vector2d center;
|
||||
double xradius;
|
||||
int size;
|
||||
unsigned char *buffer;
|
||||
QPoint lastpos;
|
||||
int draft;
|
||||
MandelbrotThread **threads;
|
||||
int threadcount;
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *);
|
||||
void paintEvent(QPaintEvent *);
|
||||
void mousePressEvent(QMouseEvent *event);
|
||||
void mouseMoveEvent(QMouseEvent *event);
|
||||
|
||||
public:
|
||||
MandelbrotWidget() : QWidget(), center(0,0), xradius(2),
|
||||
size(0), buffer(0), draft(16)
|
||||
{
|
||||
setAutoFillBackground(false);
|
||||
threadcount = QThread::idealThreadCount();
|
||||
threads = new MandelbrotThread*[threadcount];
|
||||
for(int th = 0; th < threadcount; th++) threads[th] = new MandelbrotThread(this, th);
|
||||
}
|
||||
~MandelbrotWidget()
|
||||
{
|
||||
if(buffer) delete[]buffer;
|
||||
for(int th = 0; th < threadcount; th++) delete threads[th];
|
||||
delete[] threads;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // MANDELBROT_H
|
9
cs440-acg/ext/eigen/demos/mix_eigen_and_c/README
Normal file
9
cs440-acg/ext/eigen/demos/mix_eigen_and_c/README
Normal file
@@ -0,0 +1,9 @@
|
||||
This is an example of how one can wrap some of Eigen into a C library.
|
||||
|
||||
To try this with GCC, do:
|
||||
|
||||
g++ -c binary_library.cpp -O2 -msse2 -I ../..
|
||||
gcc example.c binary_library.o -o example -lstdc++
|
||||
./example
|
||||
|
||||
TODO: add CMakeLists, add more explanations here
|
185
cs440-acg/ext/eigen/demos/mix_eigen_and_c/binary_library.cpp
Normal file
185
cs440-acg/ext/eigen/demos/mix_eigen_and_c/binary_library.cpp
Normal file
@@ -0,0 +1,185 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
// This C++ file compiles to binary code that can be linked to by your C program,
|
||||
// thanks to the extern "C" syntax used in the declarations in binary_library.h.
|
||||
|
||||
#include "binary_library.h"
|
||||
|
||||
#include <Eigen/Core>
|
||||
|
||||
using namespace Eigen;
|
||||
|
||||
/************************* pointer conversion methods **********************************************/
|
||||
|
||||
////// class MatrixXd //////
|
||||
|
||||
inline MatrixXd& c_to_eigen(C_MatrixXd* ptr)
|
||||
{
|
||||
return *reinterpret_cast<MatrixXd*>(ptr);
|
||||
}
|
||||
|
||||
inline const MatrixXd& c_to_eigen(const C_MatrixXd* ptr)
|
||||
{
|
||||
return *reinterpret_cast<const MatrixXd*>(ptr);
|
||||
}
|
||||
|
||||
inline C_MatrixXd* eigen_to_c(MatrixXd& ref)
|
||||
{
|
||||
return reinterpret_cast<C_MatrixXd*>(&ref);
|
||||
}
|
||||
|
||||
inline const C_MatrixXd* eigen_to_c(const MatrixXd& ref)
|
||||
{
|
||||
return reinterpret_cast<const C_MatrixXd*>(&ref);
|
||||
}
|
||||
|
||||
////// class Map<MatrixXd> //////
|
||||
|
||||
inline Map<MatrixXd>& c_to_eigen(C_Map_MatrixXd* ptr)
|
||||
{
|
||||
return *reinterpret_cast<Map<MatrixXd>*>(ptr);
|
||||
}
|
||||
|
||||
inline const Map<MatrixXd>& c_to_eigen(const C_Map_MatrixXd* ptr)
|
||||
{
|
||||
return *reinterpret_cast<const Map<MatrixXd>*>(ptr);
|
||||
}
|
||||
|
||||
inline C_Map_MatrixXd* eigen_to_c(Map<MatrixXd>& ref)
|
||||
{
|
||||
return reinterpret_cast<C_Map_MatrixXd*>(&ref);
|
||||
}
|
||||
|
||||
inline const C_Map_MatrixXd* eigen_to_c(const Map<MatrixXd>& ref)
|
||||
{
|
||||
return reinterpret_cast<const C_Map_MatrixXd*>(&ref);
|
||||
}
|
||||
|
||||
|
||||
/************************* implementation of classes **********************************************/
|
||||
|
||||
|
||||
////// class MatrixXd //////
|
||||
|
||||
|
||||
C_MatrixXd* MatrixXd_new(int rows, int cols)
|
||||
{
|
||||
return eigen_to_c(*new MatrixXd(rows,cols));
|
||||
}
|
||||
|
||||
void MatrixXd_delete(C_MatrixXd *m)
|
||||
{
|
||||
delete &c_to_eigen(m);
|
||||
}
|
||||
|
||||
double* MatrixXd_data(C_MatrixXd *m)
|
||||
{
|
||||
return c_to_eigen(m).data();
|
||||
}
|
||||
|
||||
void MatrixXd_set_zero(C_MatrixXd *m)
|
||||
{
|
||||
c_to_eigen(m).setZero();
|
||||
}
|
||||
|
||||
void MatrixXd_resize(C_MatrixXd *m, int rows, int cols)
|
||||
{
|
||||
c_to_eigen(m).resize(rows,cols);
|
||||
}
|
||||
|
||||
void MatrixXd_copy(C_MatrixXd *dst, const C_MatrixXd *src)
|
||||
{
|
||||
c_to_eigen(dst) = c_to_eigen(src);
|
||||
}
|
||||
|
||||
void MatrixXd_copy_map(C_MatrixXd *dst, const C_Map_MatrixXd *src)
|
||||
{
|
||||
c_to_eigen(dst) = c_to_eigen(src);
|
||||
}
|
||||
|
||||
void MatrixXd_set_coeff(C_MatrixXd *m, int i, int j, double coeff)
|
||||
{
|
||||
c_to_eigen(m)(i,j) = coeff;
|
||||
}
|
||||
|
||||
double MatrixXd_get_coeff(const C_MatrixXd *m, int i, int j)
|
||||
{
|
||||
return c_to_eigen(m)(i,j);
|
||||
}
|
||||
|
||||
void MatrixXd_print(const C_MatrixXd *m)
|
||||
{
|
||||
std::cout << c_to_eigen(m) << std::endl;
|
||||
}
|
||||
|
||||
void MatrixXd_multiply(const C_MatrixXd *m1, const C_MatrixXd *m2, C_MatrixXd *result)
|
||||
{
|
||||
c_to_eigen(result) = c_to_eigen(m1) * c_to_eigen(m2);
|
||||
}
|
||||
|
||||
void MatrixXd_add(const C_MatrixXd *m1, const C_MatrixXd *m2, C_MatrixXd *result)
|
||||
{
|
||||
c_to_eigen(result) = c_to_eigen(m1) + c_to_eigen(m2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
////// class Map_MatrixXd //////
|
||||
|
||||
|
||||
C_Map_MatrixXd* Map_MatrixXd_new(double *array, int rows, int cols)
|
||||
{
|
||||
return eigen_to_c(*new Map<MatrixXd>(array,rows,cols));
|
||||
}
|
||||
|
||||
void Map_MatrixXd_delete(C_Map_MatrixXd *m)
|
||||
{
|
||||
delete &c_to_eigen(m);
|
||||
}
|
||||
|
||||
void Map_MatrixXd_set_zero(C_Map_MatrixXd *m)
|
||||
{
|
||||
c_to_eigen(m).setZero();
|
||||
}
|
||||
|
||||
void Map_MatrixXd_copy(C_Map_MatrixXd *dst, const C_Map_MatrixXd *src)
|
||||
{
|
||||
c_to_eigen(dst) = c_to_eigen(src);
|
||||
}
|
||||
|
||||
void Map_MatrixXd_copy_matrix(C_Map_MatrixXd *dst, const C_MatrixXd *src)
|
||||
{
|
||||
c_to_eigen(dst) = c_to_eigen(src);
|
||||
}
|
||||
|
||||
void Map_MatrixXd_set_coeff(C_Map_MatrixXd *m, int i, int j, double coeff)
|
||||
{
|
||||
c_to_eigen(m)(i,j) = coeff;
|
||||
}
|
||||
|
||||
double Map_MatrixXd_get_coeff(const C_Map_MatrixXd *m, int i, int j)
|
||||
{
|
||||
return c_to_eigen(m)(i,j);
|
||||
}
|
||||
|
||||
void Map_MatrixXd_print(const C_Map_MatrixXd *m)
|
||||
{
|
||||
std::cout << c_to_eigen(m) << std::endl;
|
||||
}
|
||||
|
||||
void Map_MatrixXd_multiply(const C_Map_MatrixXd *m1, const C_Map_MatrixXd *m2, C_Map_MatrixXd *result)
|
||||
{
|
||||
c_to_eigen(result) = c_to_eigen(m1) * c_to_eigen(m2);
|
||||
}
|
||||
|
||||
void Map_MatrixXd_add(const C_Map_MatrixXd *m1, const C_Map_MatrixXd *m2, C_Map_MatrixXd *result)
|
||||
{
|
||||
c_to_eigen(result) = c_to_eigen(m1) + c_to_eigen(m2);
|
||||
}
|
71
cs440-acg/ext/eigen/demos/mix_eigen_and_c/binary_library.h
Normal file
71
cs440-acg/ext/eigen/demos/mix_eigen_and_c/binary_library.h
Normal file
@@ -0,0 +1,71 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
// This is a pure C header, no C++ here.
|
||||
// The functions declared here will be implemented in C++ but
|
||||
// we don't have to know, because thanks to the extern "C" syntax,
|
||||
// they will be compiled to C object code.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
// just dummy empty structs to give different pointer types,
|
||||
// instead of using void* which would be type unsafe
|
||||
struct C_MatrixXd {};
|
||||
struct C_Map_MatrixXd {};
|
||||
|
||||
// the C_MatrixXd class, wraps some of the functionality
|
||||
// of Eigen::MatrixXd.
|
||||
struct C_MatrixXd* MatrixXd_new(int rows, int cols);
|
||||
void MatrixXd_delete (struct C_MatrixXd *m);
|
||||
double* MatrixXd_data (struct C_MatrixXd *m);
|
||||
void MatrixXd_set_zero (struct C_MatrixXd *m);
|
||||
void MatrixXd_resize (struct C_MatrixXd *m, int rows, int cols);
|
||||
void MatrixXd_copy (struct C_MatrixXd *dst,
|
||||
const struct C_MatrixXd *src);
|
||||
void MatrixXd_copy_map (struct C_MatrixXd *dst,
|
||||
const struct C_Map_MatrixXd *src);
|
||||
void MatrixXd_set_coeff (struct C_MatrixXd *m,
|
||||
int i, int j, double coeff);
|
||||
double MatrixXd_get_coeff (const struct C_MatrixXd *m,
|
||||
int i, int j);
|
||||
void MatrixXd_print (const struct C_MatrixXd *m);
|
||||
void MatrixXd_add (const struct C_MatrixXd *m1,
|
||||
const struct C_MatrixXd *m2,
|
||||
struct C_MatrixXd *result);
|
||||
void MatrixXd_multiply (const struct C_MatrixXd *m1,
|
||||
const struct C_MatrixXd *m2,
|
||||
struct C_MatrixXd *result);
|
||||
|
||||
// the C_Map_MatrixXd class, wraps some of the functionality
|
||||
// of Eigen::Map<MatrixXd>
|
||||
struct C_Map_MatrixXd* Map_MatrixXd_new(double *array, int rows, int cols);
|
||||
void Map_MatrixXd_delete (struct C_Map_MatrixXd *m);
|
||||
void Map_MatrixXd_set_zero (struct C_Map_MatrixXd *m);
|
||||
void Map_MatrixXd_copy (struct C_Map_MatrixXd *dst,
|
||||
const struct C_Map_MatrixXd *src);
|
||||
void Map_MatrixXd_copy_matrix(struct C_Map_MatrixXd *dst,
|
||||
const struct C_MatrixXd *src);
|
||||
void Map_MatrixXd_set_coeff (struct C_Map_MatrixXd *m,
|
||||
int i, int j, double coeff);
|
||||
double Map_MatrixXd_get_coeff (const struct C_Map_MatrixXd *m,
|
||||
int i, int j);
|
||||
void Map_MatrixXd_print (const struct C_Map_MatrixXd *m);
|
||||
void Map_MatrixXd_add (const struct C_Map_MatrixXd *m1,
|
||||
const struct C_Map_MatrixXd *m2,
|
||||
struct C_Map_MatrixXd *result);
|
||||
void Map_MatrixXd_multiply (const struct C_Map_MatrixXd *m1,
|
||||
const struct C_Map_MatrixXd *m2,
|
||||
struct C_Map_MatrixXd *result);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // end extern "C"
|
||||
#endif
|
65
cs440-acg/ext/eigen/demos/mix_eigen_and_c/example.c
Normal file
65
cs440-acg/ext/eigen/demos/mix_eigen_and_c/example.c
Normal file
@@ -0,0 +1,65 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "binary_library.h"
|
||||
#include "stdio.h"
|
||||
|
||||
void demo_MatrixXd()
|
||||
{
|
||||
struct C_MatrixXd *matrix1, *matrix2, *result;
|
||||
printf("*** demo_MatrixXd ***\n");
|
||||
|
||||
matrix1 = MatrixXd_new(3, 3);
|
||||
MatrixXd_set_zero(matrix1);
|
||||
MatrixXd_set_coeff(matrix1, 0, 1, 2.5);
|
||||
MatrixXd_set_coeff(matrix1, 1, 0, 1.4);
|
||||
printf("Here is matrix1:\n");
|
||||
MatrixXd_print(matrix1);
|
||||
|
||||
matrix2 = MatrixXd_new(3, 3);
|
||||
MatrixXd_multiply(matrix1, matrix1, matrix2);
|
||||
printf("Here is matrix1*matrix1:\n");
|
||||
MatrixXd_print(matrix2);
|
||||
|
||||
MatrixXd_delete(matrix1);
|
||||
MatrixXd_delete(matrix2);
|
||||
}
|
||||
|
||||
// this helper function takes a plain C array and prints it in one line
|
||||
void print_array(double *array, int n)
|
||||
{
|
||||
struct C_Map_MatrixXd *m = Map_MatrixXd_new(array, 1, n);
|
||||
Map_MatrixXd_print(m);
|
||||
Map_MatrixXd_delete(m);
|
||||
}
|
||||
|
||||
void demo_Map_MatrixXd()
|
||||
{
|
||||
struct C_Map_MatrixXd *map;
|
||||
double array[5];
|
||||
int i;
|
||||
printf("*** demo_Map_MatrixXd ***\n");
|
||||
|
||||
for(i = 0; i < 5; ++i) array[i] = i;
|
||||
printf("Initially, the array is:\n");
|
||||
print_array(array, 5);
|
||||
|
||||
map = Map_MatrixXd_new(array, 5, 1);
|
||||
Map_MatrixXd_add(map, map, map);
|
||||
Map_MatrixXd_delete(map);
|
||||
|
||||
printf("Now the array is:\n");
|
||||
print_array(array, 5);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
demo_MatrixXd();
|
||||
demo_Map_MatrixXd();
|
||||
}
|
28
cs440-acg/ext/eigen/demos/opengl/CMakeLists.txt
Normal file
28
cs440-acg/ext/eigen/demos/opengl/CMakeLists.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
find_package(Qt4)
|
||||
find_package(OpenGL)
|
||||
|
||||
if(QT4_FOUND AND OPENGL_FOUND)
|
||||
|
||||
set(QT_USE_QTOPENGL TRUE)
|
||||
include(${QT_USE_FILE})
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
include_directories( ${QT_INCLUDE_DIR} )
|
||||
|
||||
set(quaternion_demo_SRCS gpuhelper.cpp icosphere.cpp camera.cpp trackball.cpp quaternion_demo.cpp)
|
||||
|
||||
qt4_automoc(${quaternion_demo_SRCS})
|
||||
|
||||
add_executable(quaternion_demo ${quaternion_demo_SRCS})
|
||||
add_dependencies(demos quaternion_demo)
|
||||
|
||||
target_link_libraries(quaternion_demo
|
||||
${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY}
|
||||
${QT_QTOPENGL_LIBRARY} ${OPENGL_LIBRARIES} )
|
||||
|
||||
else()
|
||||
|
||||
message(STATUS "OpenGL demo disabled because Qt4 and/or OpenGL have not been found.")
|
||||
|
||||
endif()
|
13
cs440-acg/ext/eigen/demos/opengl/README
Normal file
13
cs440-acg/ext/eigen/demos/opengl/README
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
Navigation:
|
||||
left button: rotate around the target
|
||||
middle button: zoom
|
||||
left button + ctrl quake rotate (rotate around camera position)
|
||||
middle button + ctrl walk (progress along camera's z direction)
|
||||
left button: pan (translate in the XY camera's plane)
|
||||
|
||||
R : move the camera to initial position
|
||||
A : start/stop animation
|
||||
C : clear the animation
|
||||
G : add a key frame
|
||||
|
264
cs440-acg/ext/eigen/demos/opengl/camera.cpp
Normal file
264
cs440-acg/ext/eigen/demos/opengl/camera.cpp
Normal file
@@ -0,0 +1,264 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "camera.h"
|
||||
|
||||
#include "gpuhelper.h"
|
||||
#include <GL/glu.h>
|
||||
|
||||
#include "Eigen/LU"
|
||||
using namespace Eigen;
|
||||
|
||||
Camera::Camera()
|
||||
: mViewIsUptodate(false), mProjIsUptodate(false)
|
||||
{
|
||||
mViewMatrix.setIdentity();
|
||||
|
||||
mFovY = M_PI/3.;
|
||||
mNearDist = 1.;
|
||||
mFarDist = 50000.;
|
||||
|
||||
mVpX = 0;
|
||||
mVpY = 0;
|
||||
|
||||
setPosition(Vector3f::Constant(100.));
|
||||
setTarget(Vector3f::Zero());
|
||||
}
|
||||
|
||||
Camera& Camera::operator=(const Camera& other)
|
||||
{
|
||||
mViewIsUptodate = false;
|
||||
mProjIsUptodate = false;
|
||||
|
||||
mVpX = other.mVpX;
|
||||
mVpY = other.mVpY;
|
||||
mVpWidth = other.mVpWidth;
|
||||
mVpHeight = other.mVpHeight;
|
||||
|
||||
mTarget = other.mTarget;
|
||||
mFovY = other.mFovY;
|
||||
mNearDist = other.mNearDist;
|
||||
mFarDist = other.mFarDist;
|
||||
|
||||
mViewMatrix = other.mViewMatrix;
|
||||
mProjectionMatrix = other.mProjectionMatrix;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Camera::Camera(const Camera& other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
Camera::~Camera()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void Camera::setViewport(uint offsetx, uint offsety, uint width, uint height)
|
||||
{
|
||||
mVpX = offsetx;
|
||||
mVpY = offsety;
|
||||
mVpWidth = width;
|
||||
mVpHeight = height;
|
||||
|
||||
mProjIsUptodate = false;
|
||||
}
|
||||
|
||||
void Camera::setViewport(uint width, uint height)
|
||||
{
|
||||
mVpWidth = width;
|
||||
mVpHeight = height;
|
||||
|
||||
mProjIsUptodate = false;
|
||||
}
|
||||
|
||||
void Camera::setFovY(float value)
|
||||
{
|
||||
mFovY = value;
|
||||
mProjIsUptodate = false;
|
||||
}
|
||||
|
||||
Vector3f Camera::direction(void) const
|
||||
{
|
||||
return - (orientation() * Vector3f::UnitZ());
|
||||
}
|
||||
Vector3f Camera::up(void) const
|
||||
{
|
||||
return orientation() * Vector3f::UnitY();
|
||||
}
|
||||
Vector3f Camera::right(void) const
|
||||
{
|
||||
return orientation() * Vector3f::UnitX();
|
||||
}
|
||||
|
||||
void Camera::setDirection(const Vector3f& newDirection)
|
||||
{
|
||||
// TODO implement it computing the rotation between newDirection and current dir ?
|
||||
Vector3f up = this->up();
|
||||
|
||||
Matrix3f camAxes;
|
||||
|
||||
camAxes.col(2) = (-newDirection).normalized();
|
||||
camAxes.col(0) = up.cross( camAxes.col(2) ).normalized();
|
||||
camAxes.col(1) = camAxes.col(2).cross( camAxes.col(0) ).normalized();
|
||||
setOrientation(Quaternionf(camAxes));
|
||||
|
||||
mViewIsUptodate = false;
|
||||
}
|
||||
|
||||
void Camera::setTarget(const Vector3f& target)
|
||||
{
|
||||
mTarget = target;
|
||||
if (!mTarget.isApprox(position()))
|
||||
{
|
||||
Vector3f newDirection = mTarget - position();
|
||||
setDirection(newDirection.normalized());
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::setPosition(const Vector3f& p)
|
||||
{
|
||||
mFrame.position = p;
|
||||
mViewIsUptodate = false;
|
||||
}
|
||||
|
||||
void Camera::setOrientation(const Quaternionf& q)
|
||||
{
|
||||
mFrame.orientation = q;
|
||||
mViewIsUptodate = false;
|
||||
}
|
||||
|
||||
void Camera::setFrame(const Frame& f)
|
||||
{
|
||||
mFrame = f;
|
||||
mViewIsUptodate = false;
|
||||
}
|
||||
|
||||
void Camera::rotateAroundTarget(const Quaternionf& q)
|
||||
{
|
||||
Matrix4f mrot, mt, mtm;
|
||||
|
||||
// update the transform matrix
|
||||
updateViewMatrix();
|
||||
Vector3f t = mViewMatrix * mTarget;
|
||||
|
||||
mViewMatrix = Translation3f(t)
|
||||
* q
|
||||
* Translation3f(-t)
|
||||
* mViewMatrix;
|
||||
|
||||
Quaternionf qa(mViewMatrix.linear());
|
||||
qa = qa.conjugate();
|
||||
setOrientation(qa);
|
||||
setPosition(- (qa * mViewMatrix.translation()) );
|
||||
|
||||
mViewIsUptodate = true;
|
||||
}
|
||||
|
||||
void Camera::localRotate(const Quaternionf& q)
|
||||
{
|
||||
float dist = (position() - mTarget).norm();
|
||||
setOrientation(orientation() * q);
|
||||
mTarget = position() + dist * direction();
|
||||
mViewIsUptodate = false;
|
||||
}
|
||||
|
||||
void Camera::zoom(float d)
|
||||
{
|
||||
float dist = (position() - mTarget).norm();
|
||||
if(dist > d)
|
||||
{
|
||||
setPosition(position() + direction() * d);
|
||||
mViewIsUptodate = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::localTranslate(const Vector3f& t)
|
||||
{
|
||||
Vector3f trans = orientation() * t;
|
||||
setPosition( position() + trans );
|
||||
setTarget( mTarget + trans );
|
||||
|
||||
mViewIsUptodate = false;
|
||||
}
|
||||
|
||||
void Camera::updateViewMatrix(void) const
|
||||
{
|
||||
if(!mViewIsUptodate)
|
||||
{
|
||||
Quaternionf q = orientation().conjugate();
|
||||
mViewMatrix.linear() = q.toRotationMatrix();
|
||||
mViewMatrix.translation() = - (mViewMatrix.linear() * position());
|
||||
|
||||
mViewIsUptodate = true;
|
||||
}
|
||||
}
|
||||
|
||||
const Affine3f& Camera::viewMatrix(void) const
|
||||
{
|
||||
updateViewMatrix();
|
||||
return mViewMatrix;
|
||||
}
|
||||
|
||||
void Camera::updateProjectionMatrix(void) const
|
||||
{
|
||||
if(!mProjIsUptodate)
|
||||
{
|
||||
mProjectionMatrix.setIdentity();
|
||||
float aspect = float(mVpWidth)/float(mVpHeight);
|
||||
float theta = mFovY*0.5;
|
||||
float range = mFarDist - mNearDist;
|
||||
float invtan = 1./tan(theta);
|
||||
|
||||
mProjectionMatrix(0,0) = invtan / aspect;
|
||||
mProjectionMatrix(1,1) = invtan;
|
||||
mProjectionMatrix(2,2) = -(mNearDist + mFarDist) / range;
|
||||
mProjectionMatrix(3,2) = -1;
|
||||
mProjectionMatrix(2,3) = -2 * mNearDist * mFarDist / range;
|
||||
mProjectionMatrix(3,3) = 0;
|
||||
|
||||
mProjIsUptodate = true;
|
||||
}
|
||||
}
|
||||
|
||||
const Matrix4f& Camera::projectionMatrix(void) const
|
||||
{
|
||||
updateProjectionMatrix();
|
||||
return mProjectionMatrix;
|
||||
}
|
||||
|
||||
void Camera::activateGL(void)
|
||||
{
|
||||
glViewport(vpX(), vpY(), vpWidth(), vpHeight());
|
||||
gpu.loadMatrix(projectionMatrix(),GL_PROJECTION);
|
||||
gpu.loadMatrix(viewMatrix().matrix(),GL_MODELVIEW);
|
||||
}
|
||||
|
||||
|
||||
Vector3f Camera::unProject(const Vector2f& uv, float depth) const
|
||||
{
|
||||
Matrix4f inv = mViewMatrix.inverse().matrix();
|
||||
return unProject(uv, depth, inv);
|
||||
}
|
||||
|
||||
Vector3f Camera::unProject(const Vector2f& uv, float depth, const Matrix4f& invModelview) const
|
||||
{
|
||||
updateViewMatrix();
|
||||
updateProjectionMatrix();
|
||||
|
||||
Vector3f a(2.*uv.x()/float(mVpWidth)-1., 2.*uv.y()/float(mVpHeight)-1., 1.);
|
||||
a.x() *= depth/mProjectionMatrix(0,0);
|
||||
a.y() *= depth/mProjectionMatrix(1,1);
|
||||
a.z() = -depth;
|
||||
// FIXME /\/|
|
||||
Vector4f b = invModelview * Vector4f(a.x(), a.y(), a.z(), 1.);
|
||||
return Vector3f(b.x(), b.y(), b.z());
|
||||
}
|
118
cs440-acg/ext/eigen/demos/opengl/camera.h
Normal file
118
cs440-acg/ext/eigen/demos/opengl/camera.h
Normal file
@@ -0,0 +1,118 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_CAMERA_H
|
||||
#define EIGEN_CAMERA_H
|
||||
|
||||
#include <Eigen/Geometry>
|
||||
#include <QObject>
|
||||
// #include <frame.h>
|
||||
|
||||
class Frame
|
||||
{
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
|
||||
inline Frame(const Eigen::Vector3f& pos = Eigen::Vector3f::Zero(),
|
||||
const Eigen::Quaternionf& o = Eigen::Quaternionf())
|
||||
: orientation(o), position(pos)
|
||||
{}
|
||||
Frame lerp(float alpha, const Frame& other) const
|
||||
{
|
||||
return Frame((1.f-alpha)*position + alpha * other.position,
|
||||
orientation.slerp(alpha,other.orientation));
|
||||
}
|
||||
|
||||
Eigen::Quaternionf orientation;
|
||||
Eigen::Vector3f position;
|
||||
};
|
||||
|
||||
class Camera
|
||||
{
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
|
||||
Camera(void);
|
||||
|
||||
Camera(const Camera& other);
|
||||
|
||||
virtual ~Camera();
|
||||
|
||||
Camera& operator=(const Camera& other);
|
||||
|
||||
void setViewport(uint offsetx, uint offsety, uint width, uint height);
|
||||
void setViewport(uint width, uint height);
|
||||
|
||||
inline uint vpX(void) const { return mVpX; }
|
||||
inline uint vpY(void) const { return mVpY; }
|
||||
inline uint vpWidth(void) const { return mVpWidth; }
|
||||
inline uint vpHeight(void) const { return mVpHeight; }
|
||||
|
||||
inline float fovY(void) const { return mFovY; }
|
||||
void setFovY(float value);
|
||||
|
||||
void setPosition(const Eigen::Vector3f& pos);
|
||||
inline const Eigen::Vector3f& position(void) const { return mFrame.position; }
|
||||
|
||||
void setOrientation(const Eigen::Quaternionf& q);
|
||||
inline const Eigen::Quaternionf& orientation(void) const { return mFrame.orientation; }
|
||||
|
||||
void setFrame(const Frame& f);
|
||||
const Frame& frame(void) const { return mFrame; }
|
||||
|
||||
void setDirection(const Eigen::Vector3f& newDirection);
|
||||
Eigen::Vector3f direction(void) const;
|
||||
void setUp(const Eigen::Vector3f& vectorUp);
|
||||
Eigen::Vector3f up(void) const;
|
||||
Eigen::Vector3f right(void) const;
|
||||
|
||||
void setTarget(const Eigen::Vector3f& target);
|
||||
inline const Eigen::Vector3f& target(void) { return mTarget; }
|
||||
|
||||
const Eigen::Affine3f& viewMatrix(void) const;
|
||||
const Eigen::Matrix4f& projectionMatrix(void) const;
|
||||
|
||||
void rotateAroundTarget(const Eigen::Quaternionf& q);
|
||||
void localRotate(const Eigen::Quaternionf& q);
|
||||
void zoom(float d);
|
||||
|
||||
void localTranslate(const Eigen::Vector3f& t);
|
||||
|
||||
/** Setup OpenGL matrices and viewport */
|
||||
void activateGL(void);
|
||||
|
||||
Eigen::Vector3f unProject(const Eigen::Vector2f& uv, float depth, const Eigen::Matrix4f& invModelview) const;
|
||||
Eigen::Vector3f unProject(const Eigen::Vector2f& uv, float depth) const;
|
||||
|
||||
protected:
|
||||
void updateViewMatrix(void) const;
|
||||
void updateProjectionMatrix(void) const;
|
||||
|
||||
protected:
|
||||
|
||||
uint mVpX, mVpY;
|
||||
uint mVpWidth, mVpHeight;
|
||||
|
||||
Frame mFrame;
|
||||
|
||||
mutable Eigen::Affine3f mViewMatrix;
|
||||
mutable Eigen::Matrix4f mProjectionMatrix;
|
||||
|
||||
mutable bool mViewIsUptodate;
|
||||
mutable bool mProjIsUptodate;
|
||||
|
||||
// used by rotateAroundTarget
|
||||
Eigen::Vector3f mTarget;
|
||||
|
||||
float mFovY;
|
||||
float mNearDist;
|
||||
float mFarDist;
|
||||
};
|
||||
|
||||
#endif // EIGEN_CAMERA_H
|
126
cs440-acg/ext/eigen/demos/opengl/gpuhelper.cpp
Normal file
126
cs440-acg/ext/eigen/demos/opengl/gpuhelper.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "gpuhelper.h"
|
||||
#include "icosphere.h"
|
||||
#include <GL/glu.h>
|
||||
// PLEASE don't look at this old code... ;)
|
||||
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
|
||||
GpuHelper gpu;
|
||||
|
||||
GpuHelper::GpuHelper()
|
||||
{
|
||||
mVpWidth = mVpHeight = 0;
|
||||
mCurrentMatrixTarget = 0;
|
||||
mInitialized = false;
|
||||
}
|
||||
|
||||
GpuHelper::~GpuHelper()
|
||||
{
|
||||
}
|
||||
|
||||
void GpuHelper::pushProjectionMode2D(ProjectionMode2D pm)
|
||||
{
|
||||
// switch to 2D projection
|
||||
pushMatrix(Matrix4f::Identity(),GL_PROJECTION);
|
||||
|
||||
if(pm==PM_Normalized)
|
||||
{
|
||||
//glOrtho(-1., 1., -1., 1., 0., 1.);
|
||||
}
|
||||
else if(pm==PM_Viewport)
|
||||
{
|
||||
GLint vp[4];
|
||||
glGetIntegerv(GL_VIEWPORT, vp);
|
||||
glOrtho(0., vp[2], 0., vp[3], -1., 1.);
|
||||
}
|
||||
|
||||
pushMatrix(Matrix4f::Identity(),GL_MODELVIEW);
|
||||
}
|
||||
|
||||
void GpuHelper::popProjectionMode2D(void)
|
||||
{
|
||||
popMatrix(GL_PROJECTION);
|
||||
popMatrix(GL_MODELVIEW);
|
||||
}
|
||||
|
||||
void GpuHelper::drawVector(const Vector3f& position, const Vector3f& vec, const Color& color, float aspect /* = 50.*/)
|
||||
{
|
||||
static GLUquadricObj *cylindre = gluNewQuadric();
|
||||
glColor4fv(color.data());
|
||||
float length = vec.norm();
|
||||
pushMatrix(GL_MODELVIEW);
|
||||
glTranslatef(position.x(), position.y(), position.z());
|
||||
Vector3f ax = Matrix3f::Identity().col(2).cross(vec);
|
||||
ax.normalize();
|
||||
Vector3f tmp = vec;
|
||||
tmp.normalize();
|
||||
float angle = 180.f/M_PI * acos(tmp.z());
|
||||
if (angle>1e-3)
|
||||
glRotatef(angle, ax.x(), ax.y(), ax.z());
|
||||
gluCylinder(cylindre, length/aspect, length/aspect, 0.8*length, 10, 10);
|
||||
glTranslatef(0.0,0.0,0.8*length);
|
||||
gluCylinder(cylindre, 2.0*length/aspect, 0.0, 0.2*length, 10, 10);
|
||||
|
||||
popMatrix(GL_MODELVIEW);
|
||||
}
|
||||
|
||||
void GpuHelper::drawVectorBox(const Vector3f& position, const Vector3f& vec, const Color& color, float aspect)
|
||||
{
|
||||
static GLUquadricObj *cylindre = gluNewQuadric();
|
||||
glColor4fv(color.data());
|
||||
float length = vec.norm();
|
||||
pushMatrix(GL_MODELVIEW);
|
||||
glTranslatef(position.x(), position.y(), position.z());
|
||||
Vector3f ax = Matrix3f::Identity().col(2).cross(vec);
|
||||
ax.normalize();
|
||||
Vector3f tmp = vec;
|
||||
tmp.normalize();
|
||||
float angle = 180.f/M_PI * acos(tmp.z());
|
||||
if (angle>1e-3)
|
||||
glRotatef(angle, ax.x(), ax.y(), ax.z());
|
||||
gluCylinder(cylindre, length/aspect, length/aspect, 0.8*length, 10, 10);
|
||||
glTranslatef(0.0,0.0,0.8*length);
|
||||
glScalef(4.0*length/aspect,4.0*length/aspect,4.0*length/aspect);
|
||||
drawUnitCube();
|
||||
popMatrix(GL_MODELVIEW);
|
||||
}
|
||||
|
||||
void GpuHelper::drawUnitCube(void)
|
||||
{
|
||||
static float vertices[][3] = {
|
||||
{-0.5,-0.5,-0.5},
|
||||
{ 0.5,-0.5,-0.5},
|
||||
{-0.5, 0.5,-0.5},
|
||||
{ 0.5, 0.5,-0.5},
|
||||
{-0.5,-0.5, 0.5},
|
||||
{ 0.5,-0.5, 0.5},
|
||||
{-0.5, 0.5, 0.5},
|
||||
{ 0.5, 0.5, 0.5}};
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glNormal3f(0,0,-1); glVertex3fv(vertices[0]); glVertex3fv(vertices[2]); glVertex3fv(vertices[3]); glVertex3fv(vertices[1]);
|
||||
glNormal3f(0,0, 1); glVertex3fv(vertices[4]); glVertex3fv(vertices[5]); glVertex3fv(vertices[7]); glVertex3fv(vertices[6]);
|
||||
glNormal3f(0,-1,0); glVertex3fv(vertices[0]); glVertex3fv(vertices[1]); glVertex3fv(vertices[5]); glVertex3fv(vertices[4]);
|
||||
glNormal3f(0, 1,0); glVertex3fv(vertices[2]); glVertex3fv(vertices[6]); glVertex3fv(vertices[7]); glVertex3fv(vertices[3]);
|
||||
glNormal3f(-1,0,0); glVertex3fv(vertices[0]); glVertex3fv(vertices[4]); glVertex3fv(vertices[6]); glVertex3fv(vertices[2]);
|
||||
glNormal3f( 1,0,0); glVertex3fv(vertices[1]); glVertex3fv(vertices[3]); glVertex3fv(vertices[7]); glVertex3fv(vertices[5]);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void GpuHelper::drawUnitSphere(int level)
|
||||
{
|
||||
static IcoSphere sphere;
|
||||
sphere.draw(level);
|
||||
}
|
||||
|
||||
|
207
cs440-acg/ext/eigen/demos/opengl/gpuhelper.h
Normal file
207
cs440-acg/ext/eigen/demos/opengl/gpuhelper.h
Normal file
@@ -0,0 +1,207 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_GPUHELPER_H
|
||||
#define EIGEN_GPUHELPER_H
|
||||
|
||||
#include <Eigen/Geometry>
|
||||
#include <GL/gl.h>
|
||||
#include <vector>
|
||||
|
||||
using namespace Eigen;
|
||||
|
||||
typedef Vector4f Color;
|
||||
|
||||
class GpuHelper
|
||||
{
|
||||
public:
|
||||
|
||||
GpuHelper();
|
||||
|
||||
~GpuHelper();
|
||||
|
||||
enum ProjectionMode2D { PM_Normalized = 1, PM_Viewport = 2 };
|
||||
void pushProjectionMode2D(ProjectionMode2D pm);
|
||||
void popProjectionMode2D();
|
||||
|
||||
/** Multiply the OpenGL matrix \a matrixTarget by the matrix \a mat.
|
||||
Essentially, this helper function automatically calls glMatrixMode(matrixTarget) if required
|
||||
and does a proper call to the right glMultMatrix*() function according to the scalar type
|
||||
and storage order.
|
||||
\warning glMatrixMode() must never be called directly. If your're unsure, use forceMatrixMode().
|
||||
\sa Matrix, loadMatrix(), forceMatrixMode()
|
||||
*/
|
||||
template<typename Scalar, int _Flags>
|
||||
void multMatrix(const Matrix<Scalar,4,4, _Flags, 4,4>& mat, GLenum matrixTarget);
|
||||
|
||||
/** Load the matrix \a mat to the OpenGL matrix \a matrixTarget.
|
||||
Essentially, this helper function automatically calls glMatrixMode(matrixTarget) if required
|
||||
and does a proper call to the right glLoadMatrix*() or glLoadIdentity() function according to the scalar type
|
||||
and storage order.
|
||||
\warning glMatrixMode() must never be called directly. If your're unsure, use forceMatrixMode().
|
||||
\sa Matrix, multMatrix(), forceMatrixMode()
|
||||
*/
|
||||
template<typename Scalar, int _Flags>
|
||||
void loadMatrix(const Eigen::Matrix<Scalar,4,4, _Flags, 4,4>& mat, GLenum matrixTarget);
|
||||
|
||||
template<typename Scalar, typename Derived>
|
||||
void loadMatrix(
|
||||
const Eigen::CwiseNullaryOp<Eigen::internal::scalar_identity_op<Scalar>,Derived>&,
|
||||
GLenum matrixTarget);
|
||||
|
||||
/** Make the matrix \a matrixTarget the current OpenGL matrix target.
|
||||
Call this function before loadMatrix() or multMatrix() if you cannot guarantee that glMatrixMode()
|
||||
has never been called after the last loadMatrix() or multMatrix() calls.
|
||||
\todo provides a debug mode checking the sanity of the cached matrix mode.
|
||||
*/
|
||||
inline void forceMatrixTarget(GLenum matrixTarget) {glMatrixMode(mCurrentMatrixTarget=matrixTarget);}
|
||||
|
||||
inline void setMatrixTarget(GLenum matrixTarget);
|
||||
|
||||
/** Push the OpenGL matrix \a matrixTarget and load \a mat.
|
||||
*/
|
||||
template<typename Scalar, int _Flags>
|
||||
inline void pushMatrix(const Matrix<Scalar,4,4, _Flags, 4,4>& mat, GLenum matrixTarget);
|
||||
|
||||
template<typename Scalar, typename Derived>
|
||||
void pushMatrix(
|
||||
const Eigen::CwiseNullaryOp<Eigen::internal::scalar_identity_op<Scalar>,Derived>&,
|
||||
GLenum matrixTarget);
|
||||
|
||||
/** Push and clone the OpenGL matrix \a matrixTarget
|
||||
*/
|
||||
inline void pushMatrix(GLenum matrixTarget);
|
||||
|
||||
/** Pop the OpenGL matrix \a matrixTarget
|
||||
*/
|
||||
inline void popMatrix(GLenum matrixTarget);
|
||||
|
||||
void drawVector(const Vector3f& position, const Vector3f& vec, const Color& color, float aspect = 50.);
|
||||
void drawVectorBox(const Vector3f& position, const Vector3f& vec, const Color& color, float aspect = 50.);
|
||||
void drawUnitCube(void);
|
||||
void drawUnitSphere(int level=0);
|
||||
|
||||
/// draw the \a nofElement first elements
|
||||
inline void draw(GLenum mode, uint nofElement);
|
||||
|
||||
/// draw a range of elements
|
||||
inline void draw(GLenum mode, uint start, uint end);
|
||||
|
||||
/// draw an indexed subset
|
||||
inline void draw(GLenum mode, const std::vector<uint>* pIndexes);
|
||||
|
||||
protected:
|
||||
|
||||
void update(void);
|
||||
|
||||
GLuint mColorBufferId;
|
||||
int mVpWidth, mVpHeight;
|
||||
GLenum mCurrentMatrixTarget;
|
||||
bool mInitialized;
|
||||
};
|
||||
|
||||
/** Singleton shortcut
|
||||
*/
|
||||
extern GpuHelper gpu;
|
||||
|
||||
|
||||
/** \internal
|
||||
*/
|
||||
template<bool RowMajor, int _Flags> struct GlMatrixHelper;
|
||||
|
||||
template<int _Flags> struct GlMatrixHelper<false,_Flags>
|
||||
{
|
||||
static void loadMatrix(const Matrix<float, 4,4, _Flags, 4,4>& mat) { glLoadMatrixf(mat.data()); }
|
||||
static void loadMatrix(const Matrix<double,4,4, _Flags, 4,4>& mat) { glLoadMatrixd(mat.data()); }
|
||||
static void multMatrix(const Matrix<float, 4,4, _Flags, 4,4>& mat) { glMultMatrixf(mat.data()); }
|
||||
static void multMatrix(const Matrix<double,4,4, _Flags, 4,4>& mat) { glMultMatrixd(mat.data()); }
|
||||
};
|
||||
|
||||
template<int _Flags> struct GlMatrixHelper<true,_Flags>
|
||||
{
|
||||
static void loadMatrix(const Matrix<float, 4,4, _Flags, 4,4>& mat) { glLoadMatrixf(mat.transpose().eval().data()); }
|
||||
static void loadMatrix(const Matrix<double,4,4, _Flags, 4,4>& mat) { glLoadMatrixd(mat.transpose().eval().data()); }
|
||||
static void multMatrix(const Matrix<float, 4,4, _Flags, 4,4>& mat) { glMultMatrixf(mat.transpose().eval().data()); }
|
||||
static void multMatrix(const Matrix<double,4,4, _Flags, 4,4>& mat) { glMultMatrixd(mat.transpose().eval().data()); }
|
||||
};
|
||||
|
||||
inline void GpuHelper::setMatrixTarget(GLenum matrixTarget)
|
||||
{
|
||||
if (matrixTarget != mCurrentMatrixTarget)
|
||||
glMatrixMode(mCurrentMatrixTarget=matrixTarget);
|
||||
}
|
||||
|
||||
template<typename Scalar, int _Flags>
|
||||
void GpuHelper::multMatrix(const Matrix<Scalar,4,4, _Flags, 4,4>& mat, GLenum matrixTarget)
|
||||
{
|
||||
setMatrixTarget(matrixTarget);
|
||||
GlMatrixHelper<_Flags&Eigen::RowMajorBit, _Flags>::multMatrix(mat);
|
||||
}
|
||||
|
||||
template<typename Scalar, typename Derived>
|
||||
void GpuHelper::loadMatrix(
|
||||
const Eigen::CwiseNullaryOp<Eigen::internal::scalar_identity_op<Scalar>,Derived>&,
|
||||
GLenum matrixTarget)
|
||||
{
|
||||
setMatrixTarget(matrixTarget);
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
template<typename Scalar, int _Flags>
|
||||
void GpuHelper::loadMatrix(const Eigen::Matrix<Scalar,4,4, _Flags, 4,4>& mat, GLenum matrixTarget)
|
||||
{
|
||||
setMatrixTarget(matrixTarget);
|
||||
GlMatrixHelper<(_Flags&Eigen::RowMajorBit)!=0, _Flags>::loadMatrix(mat);
|
||||
}
|
||||
|
||||
inline void GpuHelper::pushMatrix(GLenum matrixTarget)
|
||||
{
|
||||
setMatrixTarget(matrixTarget);
|
||||
glPushMatrix();
|
||||
}
|
||||
|
||||
template<typename Scalar, int _Flags>
|
||||
inline void GpuHelper::pushMatrix(const Matrix<Scalar,4,4, _Flags, 4,4>& mat, GLenum matrixTarget)
|
||||
{
|
||||
pushMatrix(matrixTarget);
|
||||
GlMatrixHelper<_Flags&Eigen::RowMajorBit,_Flags>::loadMatrix(mat);
|
||||
}
|
||||
|
||||
template<typename Scalar, typename Derived>
|
||||
void GpuHelper::pushMatrix(
|
||||
const Eigen::CwiseNullaryOp<Eigen::internal::scalar_identity_op<Scalar>,Derived>&,
|
||||
GLenum matrixTarget)
|
||||
{
|
||||
pushMatrix(matrixTarget);
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
inline void GpuHelper::popMatrix(GLenum matrixTarget)
|
||||
{
|
||||
setMatrixTarget(matrixTarget);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
inline void GpuHelper::draw(GLenum mode, uint nofElement)
|
||||
{
|
||||
glDrawArrays(mode, 0, nofElement);
|
||||
}
|
||||
|
||||
|
||||
inline void GpuHelper::draw(GLenum mode, const std::vector<uint>* pIndexes)
|
||||
{
|
||||
glDrawElements(mode, pIndexes->size(), GL_UNSIGNED_INT, &(pIndexes->front()));
|
||||
}
|
||||
|
||||
inline void GpuHelper::draw(GLenum mode, uint start, uint end)
|
||||
{
|
||||
glDrawArrays(mode, start, end-start);
|
||||
}
|
||||
|
||||
#endif // EIGEN_GPUHELPER_H
|
120
cs440-acg/ext/eigen/demos/opengl/icosphere.cpp
Normal file
120
cs440-acg/ext/eigen/demos/opengl/icosphere.cpp
Normal file
@@ -0,0 +1,120 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "icosphere.h"
|
||||
|
||||
#include <GL/gl.h>
|
||||
#include <map>
|
||||
|
||||
using namespace Eigen;
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// icosahedron data
|
||||
//--------------------------------------------------------------------------------
|
||||
#define X .525731112119133606
|
||||
#define Z .850650808352039932
|
||||
|
||||
static GLfloat vdata[12][3] = {
|
||||
{-X, 0.0, Z}, {X, 0.0, Z}, {-X, 0.0, -Z}, {X, 0.0, -Z},
|
||||
{0.0, Z, X}, {0.0, Z, -X}, {0.0, -Z, X}, {0.0, -Z, -X},
|
||||
{Z, X, 0.0}, {-Z, X, 0.0}, {Z, -X, 0.0}, {-Z, -X, 0.0}
|
||||
};
|
||||
|
||||
static GLint tindices[20][3] = {
|
||||
{0,4,1}, {0,9,4}, {9,5,4}, {4,5,8}, {4,8,1},
|
||||
{8,10,1}, {8,3,10}, {5,3,8}, {5,2,3}, {2,7,3},
|
||||
{7,10,3}, {7,6,10}, {7,11,6}, {11,0,6}, {0,1,6},
|
||||
{6,1,10}, {9,0,11}, {9,11,2}, {9,2,5}, {7,2,11} };
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
IcoSphere::IcoSphere(unsigned int levels)
|
||||
{
|
||||
// init with an icosahedron
|
||||
for (int i = 0; i < 12; i++)
|
||||
mVertices.push_back(Map<Vector3f>(vdata[i]));
|
||||
mIndices.push_back(new std::vector<int>);
|
||||
std::vector<int>& indices = *mIndices.back();
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
for (int k = 0; k < 3; k++)
|
||||
indices.push_back(tindices[i][k]);
|
||||
}
|
||||
mListIds.push_back(0);
|
||||
|
||||
while(mIndices.size()<levels)
|
||||
_subdivide();
|
||||
}
|
||||
|
||||
const std::vector<int>& IcoSphere::indices(int level) const
|
||||
{
|
||||
while (level>=int(mIndices.size()))
|
||||
const_cast<IcoSphere*>(this)->_subdivide();
|
||||
return *mIndices[level];
|
||||
}
|
||||
|
||||
void IcoSphere::_subdivide(void)
|
||||
{
|
||||
typedef unsigned long long Key;
|
||||
std::map<Key,int> edgeMap;
|
||||
const std::vector<int>& indices = *mIndices.back();
|
||||
mIndices.push_back(new std::vector<int>);
|
||||
std::vector<int>& refinedIndices = *mIndices.back();
|
||||
int end = indices.size();
|
||||
for (int i=0; i<end; i+=3)
|
||||
{
|
||||
int ids0[3], // indices of outer vertices
|
||||
ids1[3]; // indices of edge vertices
|
||||
for (int k=0; k<3; ++k)
|
||||
{
|
||||
int k1 = (k+1)%3;
|
||||
int e0 = indices[i+k];
|
||||
int e1 = indices[i+k1];
|
||||
ids0[k] = e0;
|
||||
if (e1>e0)
|
||||
std::swap(e0,e1);
|
||||
Key edgeKey = Key(e0) | (Key(e1)<<32);
|
||||
std::map<Key,int>::iterator it = edgeMap.find(edgeKey);
|
||||
if (it==edgeMap.end())
|
||||
{
|
||||
ids1[k] = mVertices.size();
|
||||
edgeMap[edgeKey] = ids1[k];
|
||||
mVertices.push_back( (mVertices[e0]+mVertices[e1]).normalized() );
|
||||
}
|
||||
else
|
||||
ids1[k] = it->second;
|
||||
}
|
||||
refinedIndices.push_back(ids0[0]); refinedIndices.push_back(ids1[0]); refinedIndices.push_back(ids1[2]);
|
||||
refinedIndices.push_back(ids0[1]); refinedIndices.push_back(ids1[1]); refinedIndices.push_back(ids1[0]);
|
||||
refinedIndices.push_back(ids0[2]); refinedIndices.push_back(ids1[2]); refinedIndices.push_back(ids1[1]);
|
||||
refinedIndices.push_back(ids1[0]); refinedIndices.push_back(ids1[1]); refinedIndices.push_back(ids1[2]);
|
||||
}
|
||||
mListIds.push_back(0);
|
||||
}
|
||||
|
||||
void IcoSphere::draw(int level)
|
||||
{
|
||||
while (level>=int(mIndices.size()))
|
||||
const_cast<IcoSphere*>(this)->_subdivide();
|
||||
if (mListIds[level]==0)
|
||||
{
|
||||
mListIds[level] = glGenLists(1);
|
||||
glNewList(mListIds[level], GL_COMPILE);
|
||||
glVertexPointer(3, GL_FLOAT, 0, mVertices[0].data());
|
||||
glNormalPointer(GL_FLOAT, 0, mVertices[0].data());
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glDrawElements(GL_TRIANGLES, mIndices[level]->size(), GL_UNSIGNED_INT, &(mIndices[level]->at(0)));
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
glEndList();
|
||||
}
|
||||
glCallList(mListIds[level]);
|
||||
}
|
||||
|
||||
|
30
cs440-acg/ext/eigen/demos/opengl/icosphere.h
Normal file
30
cs440-acg/ext/eigen/demos/opengl/icosphere.h
Normal file
@@ -0,0 +1,30 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_ICOSPHERE_H
|
||||
#define EIGEN_ICOSPHERE_H
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
|
||||
class IcoSphere
|
||||
{
|
||||
public:
|
||||
IcoSphere(unsigned int levels=1);
|
||||
const std::vector<Eigen::Vector3f>& vertices() const { return mVertices; }
|
||||
const std::vector<int>& indices(int level) const;
|
||||
void draw(int level);
|
||||
protected:
|
||||
void _subdivide();
|
||||
std::vector<Eigen::Vector3f> mVertices;
|
||||
std::vector<std::vector<int>*> mIndices;
|
||||
std::vector<int> mListIds;
|
||||
};
|
||||
|
||||
#endif // EIGEN_ICOSPHERE_H
|
656
cs440-acg/ext/eigen/demos/opengl/quaternion_demo.cpp
Normal file
656
cs440-acg/ext/eigen/demos/opengl/quaternion_demo.cpp
Normal file
@@ -0,0 +1,656 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "quaternion_demo.h"
|
||||
#include "icosphere.h"
|
||||
|
||||
#include <Eigen/Geometry>
|
||||
#include <Eigen/QR>
|
||||
#include <Eigen/LU>
|
||||
|
||||
#include <iostream>
|
||||
#include <QEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QInputDialog>
|
||||
#include <QGridLayout>
|
||||
#include <QButtonGroup>
|
||||
#include <QRadioButton>
|
||||
#include <QDockWidget>
|
||||
#include <QPushButton>
|
||||
#include <QGroupBox>
|
||||
|
||||
using namespace Eigen;
|
||||
|
||||
class FancySpheres
|
||||
{
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
|
||||
FancySpheres()
|
||||
{
|
||||
const int levels = 4;
|
||||
const float scale = 0.33;
|
||||
float radius = 100;
|
||||
std::vector<int> parents;
|
||||
|
||||
// leval 0
|
||||
mCenters.push_back(Vector3f::Zero());
|
||||
parents.push_back(-1);
|
||||
mRadii.push_back(radius);
|
||||
|
||||
// generate level 1 using icosphere vertices
|
||||
radius *= 0.45;
|
||||
{
|
||||
float dist = mRadii[0]*0.9;
|
||||
for (int i=0; i<12; ++i)
|
||||
{
|
||||
mCenters.push_back(mIcoSphere.vertices()[i] * dist);
|
||||
mRadii.push_back(radius);
|
||||
parents.push_back(0);
|
||||
}
|
||||
}
|
||||
|
||||
static const float angles [10] = {
|
||||
0, 0,
|
||||
M_PI, 0.*M_PI,
|
||||
M_PI, 0.5*M_PI,
|
||||
M_PI, 1.*M_PI,
|
||||
M_PI, 1.5*M_PI
|
||||
};
|
||||
|
||||
// generate other levels
|
||||
int start = 1;
|
||||
for (int l=1; l<levels; l++)
|
||||
{
|
||||
radius *= scale;
|
||||
int end = mCenters.size();
|
||||
for (int i=start; i<end; ++i)
|
||||
{
|
||||
Vector3f c = mCenters[i];
|
||||
Vector3f ax0 = (c - mCenters[parents[i]]).normalized();
|
||||
Vector3f ax1 = ax0.unitOrthogonal();
|
||||
Quaternionf q;
|
||||
q.setFromTwoVectors(Vector3f::UnitZ(), ax0);
|
||||
Affine3f t = Translation3f(c) * q * Scaling(mRadii[i]+radius);
|
||||
for (int j=0; j<5; ++j)
|
||||
{
|
||||
Vector3f newC = c + ( (AngleAxisf(angles[j*2+1], ax0)
|
||||
* AngleAxisf(angles[j*2+0] * (l==1 ? 0.35 : 0.5), ax1)) * ax0)
|
||||
* (mRadii[i] + radius*0.8);
|
||||
mCenters.push_back(newC);
|
||||
mRadii.push_back(radius);
|
||||
parents.push_back(i);
|
||||
}
|
||||
}
|
||||
start = end;
|
||||
}
|
||||
}
|
||||
|
||||
void draw()
|
||||
{
|
||||
int end = mCenters.size();
|
||||
glEnable(GL_NORMALIZE);
|
||||
for (int i=0; i<end; ++i)
|
||||
{
|
||||
Affine3f t = Translation3f(mCenters[i]) * Scaling(mRadii[i]);
|
||||
gpu.pushMatrix(GL_MODELVIEW);
|
||||
gpu.multMatrix(t.matrix(),GL_MODELVIEW);
|
||||
mIcoSphere.draw(2);
|
||||
gpu.popMatrix(GL_MODELVIEW);
|
||||
}
|
||||
glDisable(GL_NORMALIZE);
|
||||
}
|
||||
protected:
|
||||
std::vector<Vector3f> mCenters;
|
||||
std::vector<float> mRadii;
|
||||
IcoSphere mIcoSphere;
|
||||
};
|
||||
|
||||
|
||||
// generic linear interpolation method
|
||||
template<typename T> T lerp(float t, const T& a, const T& b)
|
||||
{
|
||||
return a*(1-t) + b*t;
|
||||
}
|
||||
|
||||
// quaternion slerp
|
||||
template<> Quaternionf lerp(float t, const Quaternionf& a, const Quaternionf& b)
|
||||
{ return a.slerp(t,b); }
|
||||
|
||||
// linear interpolation of a frame using the type OrientationType
|
||||
// to perform the interpolation of the orientations
|
||||
template<typename OrientationType>
|
||||
inline static Frame lerpFrame(float alpha, const Frame& a, const Frame& b)
|
||||
{
|
||||
return Frame(lerp(alpha,a.position,b.position),
|
||||
Quaternionf(lerp(alpha,OrientationType(a.orientation),OrientationType(b.orientation))));
|
||||
}
|
||||
|
||||
template<typename _Scalar> class EulerAngles
|
||||
{
|
||||
public:
|
||||
enum { Dim = 3 };
|
||||
typedef _Scalar Scalar;
|
||||
typedef Matrix<Scalar,3,3> Matrix3;
|
||||
typedef Matrix<Scalar,3,1> Vector3;
|
||||
typedef Quaternion<Scalar> QuaternionType;
|
||||
|
||||
protected:
|
||||
|
||||
Vector3 m_angles;
|
||||
|
||||
public:
|
||||
|
||||
EulerAngles() {}
|
||||
inline EulerAngles(Scalar a0, Scalar a1, Scalar a2) : m_angles(a0, a1, a2) {}
|
||||
inline EulerAngles(const QuaternionType& q) { *this = q; }
|
||||
|
||||
const Vector3& coeffs() const { return m_angles; }
|
||||
Vector3& coeffs() { return m_angles; }
|
||||
|
||||
EulerAngles& operator=(const QuaternionType& q)
|
||||
{
|
||||
Matrix3 m = q.toRotationMatrix();
|
||||
return *this = m;
|
||||
}
|
||||
|
||||
EulerAngles& operator=(const Matrix3& m)
|
||||
{
|
||||
// mat = cy*cz -cy*sz sy
|
||||
// cz*sx*sy+cx*sz cx*cz-sx*sy*sz -cy*sx
|
||||
// -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy
|
||||
m_angles.coeffRef(1) = std::asin(m.coeff(0,2));
|
||||
m_angles.coeffRef(0) = std::atan2(-m.coeff(1,2),m.coeff(2,2));
|
||||
m_angles.coeffRef(2) = std::atan2(-m.coeff(0,1),m.coeff(0,0));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Matrix3 toRotationMatrix(void) const
|
||||
{
|
||||
Vector3 c = m_angles.array().cos();
|
||||
Vector3 s = m_angles.array().sin();
|
||||
Matrix3 res;
|
||||
res << c.y()*c.z(), -c.y()*s.z(), s.y(),
|
||||
c.z()*s.x()*s.y()+c.x()*s.z(), c.x()*c.z()-s.x()*s.y()*s.z(), -c.y()*s.x(),
|
||||
-c.x()*c.z()*s.y()+s.x()*s.z(), c.z()*s.x()+c.x()*s.y()*s.z(), c.x()*c.y();
|
||||
return res;
|
||||
}
|
||||
|
||||
operator QuaternionType() { return QuaternionType(toRotationMatrix()); }
|
||||
};
|
||||
|
||||
// Euler angles slerp
|
||||
template<> EulerAngles<float> lerp(float t, const EulerAngles<float>& a, const EulerAngles<float>& b)
|
||||
{
|
||||
EulerAngles<float> res;
|
||||
res.coeffs() = lerp(t, a.coeffs(), b.coeffs());
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
RenderingWidget::RenderingWidget()
|
||||
{
|
||||
mAnimate = false;
|
||||
mCurrentTrackingMode = TM_NO_TRACK;
|
||||
mNavMode = NavTurnAround;
|
||||
mLerpMode = LerpQuaternion;
|
||||
mRotationMode = RotationStable;
|
||||
mTrackball.setCamera(&mCamera);
|
||||
|
||||
// required to capture key press events
|
||||
setFocusPolicy(Qt::ClickFocus);
|
||||
}
|
||||
|
||||
void RenderingWidget::grabFrame(void)
|
||||
{
|
||||
// ask user for a time
|
||||
bool ok = false;
|
||||
double t = 0;
|
||||
if (!m_timeline.empty())
|
||||
t = (--m_timeline.end())->first + 1.;
|
||||
t = QInputDialog::getDouble(this, "Eigen's RenderingWidget", "time value: ",
|
||||
t, 0, 1e3, 1, &ok);
|
||||
if (ok)
|
||||
{
|
||||
Frame aux;
|
||||
aux.orientation = mCamera.viewMatrix().linear();
|
||||
aux.position = mCamera.viewMatrix().translation();
|
||||
m_timeline[t] = aux;
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingWidget::drawScene()
|
||||
{
|
||||
static FancySpheres sFancySpheres;
|
||||
float length = 50;
|
||||
gpu.drawVector(Vector3f::Zero(), length*Vector3f::UnitX(), Color(1,0,0,1));
|
||||
gpu.drawVector(Vector3f::Zero(), length*Vector3f::UnitY(), Color(0,1,0,1));
|
||||
gpu.drawVector(Vector3f::Zero(), length*Vector3f::UnitZ(), Color(0,0,1,1));
|
||||
|
||||
// draw the fractal object
|
||||
float sqrt3 = std::sqrt(3.);
|
||||
glLightfv(GL_LIGHT0, GL_AMBIENT, Vector4f(0.5,0.5,0.5,1).data());
|
||||
glLightfv(GL_LIGHT0, GL_DIFFUSE, Vector4f(0.5,1,0.5,1).data());
|
||||
glLightfv(GL_LIGHT0, GL_SPECULAR, Vector4f(1,1,1,1).data());
|
||||
glLightfv(GL_LIGHT0, GL_POSITION, Vector4f(-sqrt3,-sqrt3,sqrt3,0).data());
|
||||
|
||||
glLightfv(GL_LIGHT1, GL_AMBIENT, Vector4f(0,0,0,1).data());
|
||||
glLightfv(GL_LIGHT1, GL_DIFFUSE, Vector4f(1,0.5,0.5,1).data());
|
||||
glLightfv(GL_LIGHT1, GL_SPECULAR, Vector4f(1,1,1,1).data());
|
||||
glLightfv(GL_LIGHT1, GL_POSITION, Vector4f(-sqrt3,sqrt3,-sqrt3,0).data());
|
||||
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, Vector4f(0.7, 0.7, 0.7, 1).data());
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Vector4f(0.8, 0.75, 0.6, 1).data());
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, Vector4f(1, 1, 1, 1).data());
|
||||
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 64);
|
||||
|
||||
glEnable(GL_LIGHTING);
|
||||
glEnable(GL_LIGHT0);
|
||||
glEnable(GL_LIGHT1);
|
||||
|
||||
sFancySpheres.draw();
|
||||
glVertexPointer(3, GL_FLOAT, 0, mVertices[0].data());
|
||||
glNormalPointer(GL_FLOAT, 0, mNormals[0].data());
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glDrawArrays(GL_TRIANGLES, 0, mVertices.size());
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
}
|
||||
|
||||
void RenderingWidget::animate()
|
||||
{
|
||||
m_alpha += double(m_timer.interval()) * 1e-3;
|
||||
|
||||
TimeLine::const_iterator hi = m_timeline.upper_bound(m_alpha);
|
||||
TimeLine::const_iterator lo = hi;
|
||||
--lo;
|
||||
|
||||
Frame currentFrame;
|
||||
|
||||
if(hi==m_timeline.end())
|
||||
{
|
||||
// end
|
||||
currentFrame = lo->second;
|
||||
stopAnimation();
|
||||
}
|
||||
else if(hi==m_timeline.begin())
|
||||
{
|
||||
// start
|
||||
currentFrame = hi->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
float s = (m_alpha - lo->first)/(hi->first - lo->first);
|
||||
if (mLerpMode==LerpEulerAngles)
|
||||
currentFrame = ::lerpFrame<EulerAngles<float> >(s, lo->second, hi->second);
|
||||
else if (mLerpMode==LerpQuaternion)
|
||||
currentFrame = ::lerpFrame<Eigen::Quaternionf>(s, lo->second, hi->second);
|
||||
else
|
||||
{
|
||||
std::cerr << "Invalid rotation interpolation mode (abort)\n";
|
||||
exit(2);
|
||||
}
|
||||
currentFrame.orientation.coeffs().normalize();
|
||||
}
|
||||
|
||||
currentFrame.orientation = currentFrame.orientation.inverse();
|
||||
currentFrame.position = - (currentFrame.orientation * currentFrame.position);
|
||||
mCamera.setFrame(currentFrame);
|
||||
|
||||
updateGL();
|
||||
}
|
||||
|
||||
void RenderingWidget::keyPressEvent(QKeyEvent * e)
|
||||
{
|
||||
switch(e->key())
|
||||
{
|
||||
case Qt::Key_Up:
|
||||
mCamera.zoom(2);
|
||||
break;
|
||||
case Qt::Key_Down:
|
||||
mCamera.zoom(-2);
|
||||
break;
|
||||
// add a frame
|
||||
case Qt::Key_G:
|
||||
grabFrame();
|
||||
break;
|
||||
// clear the time line
|
||||
case Qt::Key_C:
|
||||
m_timeline.clear();
|
||||
break;
|
||||
// move the camera to initial pos
|
||||
case Qt::Key_R:
|
||||
resetCamera();
|
||||
break;
|
||||
// start/stop the animation
|
||||
case Qt::Key_A:
|
||||
if (mAnimate)
|
||||
{
|
||||
stopAnimation();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_alpha = 0;
|
||||
connect(&m_timer, SIGNAL(timeout()), this, SLOT(animate()));
|
||||
m_timer.start(1000/30);
|
||||
mAnimate = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
updateGL();
|
||||
}
|
||||
|
||||
void RenderingWidget::stopAnimation()
|
||||
{
|
||||
disconnect(&m_timer, SIGNAL(timeout()), this, SLOT(animate()));
|
||||
m_timer.stop();
|
||||
mAnimate = false;
|
||||
m_alpha = 0;
|
||||
}
|
||||
|
||||
void RenderingWidget::mousePressEvent(QMouseEvent* e)
|
||||
{
|
||||
mMouseCoords = Vector2i(e->pos().x(), e->pos().y());
|
||||
bool fly = (mNavMode==NavFly) || (e->modifiers()&Qt::ControlModifier);
|
||||
switch(e->button())
|
||||
{
|
||||
case Qt::LeftButton:
|
||||
if(fly)
|
||||
{
|
||||
mCurrentTrackingMode = TM_LOCAL_ROTATE;
|
||||
mTrackball.start(Trackball::Local);
|
||||
}
|
||||
else
|
||||
{
|
||||
mCurrentTrackingMode = TM_ROTATE_AROUND;
|
||||
mTrackball.start(Trackball::Around);
|
||||
}
|
||||
mTrackball.track(mMouseCoords);
|
||||
break;
|
||||
case Qt::MidButton:
|
||||
if(fly)
|
||||
mCurrentTrackingMode = TM_FLY_Z;
|
||||
else
|
||||
mCurrentTrackingMode = TM_ZOOM;
|
||||
break;
|
||||
case Qt::RightButton:
|
||||
mCurrentTrackingMode = TM_FLY_PAN;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
void RenderingWidget::mouseReleaseEvent(QMouseEvent*)
|
||||
{
|
||||
mCurrentTrackingMode = TM_NO_TRACK;
|
||||
updateGL();
|
||||
}
|
||||
|
||||
void RenderingWidget::mouseMoveEvent(QMouseEvent* e)
|
||||
{
|
||||
// tracking
|
||||
if(mCurrentTrackingMode != TM_NO_TRACK)
|
||||
{
|
||||
float dx = float(e->x() - mMouseCoords.x()) / float(mCamera.vpWidth());
|
||||
float dy = - float(e->y() - mMouseCoords.y()) / float(mCamera.vpHeight());
|
||||
|
||||
// speedup the transformations
|
||||
if(e->modifiers() & Qt::ShiftModifier)
|
||||
{
|
||||
dx *= 10.;
|
||||
dy *= 10.;
|
||||
}
|
||||
|
||||
switch(mCurrentTrackingMode)
|
||||
{
|
||||
case TM_ROTATE_AROUND:
|
||||
case TM_LOCAL_ROTATE:
|
||||
if (mRotationMode==RotationStable)
|
||||
{
|
||||
// use the stable trackball implementation mapping
|
||||
// the 2D coordinates to 3D points on a sphere.
|
||||
mTrackball.track(Vector2i(e->pos().x(), e->pos().y()));
|
||||
}
|
||||
else
|
||||
{
|
||||
// standard approach mapping the x and y displacements as rotations
|
||||
// around the camera's X and Y axes.
|
||||
Quaternionf q = AngleAxisf( dx*M_PI, Vector3f::UnitY())
|
||||
* AngleAxisf(-dy*M_PI, Vector3f::UnitX());
|
||||
if (mCurrentTrackingMode==TM_LOCAL_ROTATE)
|
||||
mCamera.localRotate(q);
|
||||
else
|
||||
mCamera.rotateAroundTarget(q);
|
||||
}
|
||||
break;
|
||||
case TM_ZOOM :
|
||||
mCamera.zoom(dy*100);
|
||||
break;
|
||||
case TM_FLY_Z :
|
||||
mCamera.localTranslate(Vector3f(0, 0, -dy*200));
|
||||
break;
|
||||
case TM_FLY_PAN :
|
||||
mCamera.localTranslate(Vector3f(dx*200, dy*200, 0));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
updateGL();
|
||||
}
|
||||
|
||||
mMouseCoords = Vector2i(e->pos().x(), e->pos().y());
|
||||
}
|
||||
|
||||
void RenderingWidget::paintGL()
|
||||
{
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
|
||||
glDisable(GL_COLOR_MATERIAL);
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
glDisable(GL_TEXTURE_1D);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_TEXTURE_3D);
|
||||
|
||||
// Clear buffers
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
mCamera.activateGL();
|
||||
|
||||
drawScene();
|
||||
}
|
||||
|
||||
void RenderingWidget::initializeGL()
|
||||
{
|
||||
glClearColor(1., 1., 1., 0.);
|
||||
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
|
||||
glDepthMask(GL_TRUE);
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
|
||||
mCamera.setPosition(Vector3f(-200, -200, -200));
|
||||
mCamera.setTarget(Vector3f(0, 0, 0));
|
||||
mInitFrame.orientation = mCamera.orientation().inverse();
|
||||
mInitFrame.position = mCamera.viewMatrix().translation();
|
||||
}
|
||||
|
||||
void RenderingWidget::resizeGL(int width, int height)
|
||||
{
|
||||
mCamera.setViewport(width,height);
|
||||
}
|
||||
|
||||
void RenderingWidget::setNavMode(int m)
|
||||
{
|
||||
mNavMode = NavMode(m);
|
||||
}
|
||||
|
||||
void RenderingWidget::setLerpMode(int m)
|
||||
{
|
||||
mLerpMode = LerpMode(m);
|
||||
}
|
||||
|
||||
void RenderingWidget::setRotationMode(int m)
|
||||
{
|
||||
mRotationMode = RotationMode(m);
|
||||
}
|
||||
|
||||
void RenderingWidget::resetCamera()
|
||||
{
|
||||
if (mAnimate)
|
||||
stopAnimation();
|
||||
m_timeline.clear();
|
||||
Frame aux0 = mCamera.frame();
|
||||
aux0.orientation = aux0.orientation.inverse();
|
||||
aux0.position = mCamera.viewMatrix().translation();
|
||||
m_timeline[0] = aux0;
|
||||
|
||||
Vector3f currentTarget = mCamera.target();
|
||||
mCamera.setTarget(Vector3f::Zero());
|
||||
|
||||
// compute the rotation duration to move the camera to the target
|
||||
Frame aux1 = mCamera.frame();
|
||||
aux1.orientation = aux1.orientation.inverse();
|
||||
aux1.position = mCamera.viewMatrix().translation();
|
||||
float duration = aux0.orientation.angularDistance(aux1.orientation) * 0.9;
|
||||
if (duration<0.1) duration = 0.1;
|
||||
|
||||
// put the camera at that time step:
|
||||
aux1 = aux0.lerp(duration/2,mInitFrame);
|
||||
// and make it look at the target again
|
||||
aux1.orientation = aux1.orientation.inverse();
|
||||
aux1.position = - (aux1.orientation * aux1.position);
|
||||
mCamera.setFrame(aux1);
|
||||
mCamera.setTarget(Vector3f::Zero());
|
||||
|
||||
// add this camera keyframe
|
||||
aux1.orientation = aux1.orientation.inverse();
|
||||
aux1.position = mCamera.viewMatrix().translation();
|
||||
m_timeline[duration] = aux1;
|
||||
|
||||
m_timeline[2] = mInitFrame;
|
||||
m_alpha = 0;
|
||||
animate();
|
||||
connect(&m_timer, SIGNAL(timeout()), this, SLOT(animate()));
|
||||
m_timer.start(1000/30);
|
||||
mAnimate = true;
|
||||
}
|
||||
|
||||
QWidget* RenderingWidget::createNavigationControlWidget()
|
||||
{
|
||||
QWidget* panel = new QWidget();
|
||||
QVBoxLayout* layout = new QVBoxLayout();
|
||||
|
||||
{
|
||||
QPushButton* but = new QPushButton("reset");
|
||||
but->setToolTip("move the camera to initial position (with animation)");
|
||||
layout->addWidget(but);
|
||||
connect(but, SIGNAL(clicked()), this, SLOT(resetCamera()));
|
||||
}
|
||||
{
|
||||
// navigation mode
|
||||
QGroupBox* box = new QGroupBox("navigation mode");
|
||||
QVBoxLayout* boxLayout = new QVBoxLayout;
|
||||
QButtonGroup* group = new QButtonGroup(panel);
|
||||
QRadioButton* but;
|
||||
but = new QRadioButton("turn around");
|
||||
but->setToolTip("look around an object");
|
||||
group->addButton(but, NavTurnAround);
|
||||
boxLayout->addWidget(but);
|
||||
but = new QRadioButton("fly");
|
||||
but->setToolTip("free navigation like a spaceship\n(this mode can also be enabled pressing the \"shift\" key)");
|
||||
group->addButton(but, NavFly);
|
||||
boxLayout->addWidget(but);
|
||||
group->button(mNavMode)->setChecked(true);
|
||||
connect(group, SIGNAL(buttonClicked(int)), this, SLOT(setNavMode(int)));
|
||||
box->setLayout(boxLayout);
|
||||
layout->addWidget(box);
|
||||
}
|
||||
{
|
||||
// track ball, rotation mode
|
||||
QGroupBox* box = new QGroupBox("rotation mode");
|
||||
QVBoxLayout* boxLayout = new QVBoxLayout;
|
||||
QButtonGroup* group = new QButtonGroup(panel);
|
||||
QRadioButton* but;
|
||||
but = new QRadioButton("stable trackball");
|
||||
group->addButton(but, RotationStable);
|
||||
boxLayout->addWidget(but);
|
||||
but->setToolTip("use the stable trackball implementation mapping\nthe 2D coordinates to 3D points on a sphere");
|
||||
but = new QRadioButton("standard rotation");
|
||||
group->addButton(but, RotationStandard);
|
||||
boxLayout->addWidget(but);
|
||||
but->setToolTip("standard approach mapping the x and y displacements\nas rotations around the camera's X and Y axes");
|
||||
group->button(mRotationMode)->setChecked(true);
|
||||
connect(group, SIGNAL(buttonClicked(int)), this, SLOT(setRotationMode(int)));
|
||||
box->setLayout(boxLayout);
|
||||
layout->addWidget(box);
|
||||
}
|
||||
{
|
||||
// interpolation mode
|
||||
QGroupBox* box = new QGroupBox("spherical interpolation");
|
||||
QVBoxLayout* boxLayout = new QVBoxLayout;
|
||||
QButtonGroup* group = new QButtonGroup(panel);
|
||||
QRadioButton* but;
|
||||
but = new QRadioButton("quaternion slerp");
|
||||
group->addButton(but, LerpQuaternion);
|
||||
boxLayout->addWidget(but);
|
||||
but->setToolTip("use quaternion spherical interpolation\nto interpolate orientations");
|
||||
but = new QRadioButton("euler angles");
|
||||
group->addButton(but, LerpEulerAngles);
|
||||
boxLayout->addWidget(but);
|
||||
but->setToolTip("use Euler angles to interpolate orientations");
|
||||
group->button(mNavMode)->setChecked(true);
|
||||
connect(group, SIGNAL(buttonClicked(int)), this, SLOT(setLerpMode(int)));
|
||||
box->setLayout(boxLayout);
|
||||
layout->addWidget(box);
|
||||
}
|
||||
layout->addItem(new QSpacerItem(0,0,QSizePolicy::Minimum,QSizePolicy::Expanding));
|
||||
panel->setLayout(layout);
|
||||
return panel;
|
||||
}
|
||||
|
||||
QuaternionDemo::QuaternionDemo()
|
||||
{
|
||||
mRenderingWidget = new RenderingWidget();
|
||||
setCentralWidget(mRenderingWidget);
|
||||
|
||||
QDockWidget* panel = new QDockWidget("navigation", this);
|
||||
panel->setAllowedAreas((QFlags<Qt::DockWidgetArea>)(Qt::RightDockWidgetArea | Qt::LeftDockWidgetArea));
|
||||
addDockWidget(Qt::RightDockWidgetArea, panel);
|
||||
panel->setWidget(mRenderingWidget->createNavigationControlWidget());
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
std::cout << "Navigation:\n";
|
||||
std::cout << " left button: rotate around the target\n";
|
||||
std::cout << " middle button: zoom\n";
|
||||
std::cout << " left button + ctrl quake rotate (rotate around camera position)\n";
|
||||
std::cout << " middle button + ctrl walk (progress along camera's z direction)\n";
|
||||
std::cout << " left button: pan (translate in the XY camera's plane)\n\n";
|
||||
std::cout << "R : move the camera to initial position\n";
|
||||
std::cout << "A : start/stop animation\n";
|
||||
std::cout << "C : clear the animation\n";
|
||||
std::cout << "G : add a key frame\n";
|
||||
|
||||
QApplication app(argc, argv);
|
||||
QuaternionDemo demo;
|
||||
demo.resize(600,500);
|
||||
demo.show();
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
#include "quaternion_demo.moc"
|
||||
|
114
cs440-acg/ext/eigen/demos/opengl/quaternion_demo.h
Normal file
114
cs440-acg/ext/eigen/demos/opengl/quaternion_demo.h
Normal file
@@ -0,0 +1,114 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_QUATERNION_DEMO_H
|
||||
#define EIGEN_QUATERNION_DEMO_H
|
||||
|
||||
#include "gpuhelper.h"
|
||||
#include "camera.h"
|
||||
#include "trackball.h"
|
||||
#include <map>
|
||||
#include <QTimer>
|
||||
#include <QtGui/QApplication>
|
||||
#include <QtOpenGL/QGLWidget>
|
||||
#include <QtGui/QMainWindow>
|
||||
|
||||
class RenderingWidget : public QGLWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
typedef std::map<float,Frame> TimeLine;
|
||||
TimeLine m_timeline;
|
||||
Frame lerpFrame(float t);
|
||||
|
||||
Frame mInitFrame;
|
||||
bool mAnimate;
|
||||
float m_alpha;
|
||||
|
||||
enum TrackMode {
|
||||
TM_NO_TRACK=0, TM_ROTATE_AROUND, TM_ZOOM,
|
||||
TM_LOCAL_ROTATE, TM_FLY_Z, TM_FLY_PAN
|
||||
};
|
||||
|
||||
enum NavMode {
|
||||
NavTurnAround,
|
||||
NavFly
|
||||
};
|
||||
|
||||
enum LerpMode {
|
||||
LerpQuaternion,
|
||||
LerpEulerAngles
|
||||
};
|
||||
|
||||
enum RotationMode {
|
||||
RotationStable,
|
||||
RotationStandard
|
||||
};
|
||||
|
||||
Camera mCamera;
|
||||
TrackMode mCurrentTrackingMode;
|
||||
NavMode mNavMode;
|
||||
LerpMode mLerpMode;
|
||||
RotationMode mRotationMode;
|
||||
Vector2i mMouseCoords;
|
||||
Trackball mTrackball;
|
||||
|
||||
QTimer m_timer;
|
||||
|
||||
void setupCamera();
|
||||
|
||||
std::vector<Vector3f> mVertices;
|
||||
std::vector<Vector3f> mNormals;
|
||||
std::vector<int> mIndices;
|
||||
|
||||
protected slots:
|
||||
|
||||
virtual void animate(void);
|
||||
virtual void drawScene(void);
|
||||
|
||||
virtual void grabFrame(void);
|
||||
virtual void stopAnimation();
|
||||
|
||||
virtual void setNavMode(int);
|
||||
virtual void setLerpMode(int);
|
||||
virtual void setRotationMode(int);
|
||||
virtual void resetCamera();
|
||||
|
||||
protected:
|
||||
|
||||
virtual void initializeGL();
|
||||
virtual void resizeGL(int width, int height);
|
||||
virtual void paintGL();
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
virtual void mousePressEvent(QMouseEvent * e);
|
||||
virtual void mouseReleaseEvent(QMouseEvent * e);
|
||||
virtual void mouseMoveEvent(QMouseEvent * e);
|
||||
virtual void keyPressEvent(QKeyEvent * e);
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
|
||||
RenderingWidget();
|
||||
~RenderingWidget() { }
|
||||
|
||||
QWidget* createNavigationControlWidget();
|
||||
};
|
||||
|
||||
class QuaternionDemo : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QuaternionDemo();
|
||||
protected:
|
||||
RenderingWidget* mRenderingWidget;
|
||||
};
|
||||
|
||||
#endif // EIGEN_QUATERNION_DEMO_H
|
59
cs440-acg/ext/eigen/demos/opengl/trackball.cpp
Normal file
59
cs440-acg/ext/eigen/demos/opengl/trackball.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "trackball.h"
|
||||
#include "camera.h"
|
||||
|
||||
using namespace Eigen;
|
||||
|
||||
void Trackball::track(const Vector2i& point2D)
|
||||
{
|
||||
if (mpCamera==0)
|
||||
return;
|
||||
Vector3f newPoint3D;
|
||||
bool newPointOk = mapToSphere(point2D, newPoint3D);
|
||||
|
||||
if (mLastPointOk && newPointOk)
|
||||
{
|
||||
Vector3f axis = mLastPoint3D.cross(newPoint3D).normalized();
|
||||
float cos_angle = mLastPoint3D.dot(newPoint3D);
|
||||
if ( std::abs(cos_angle) < 1.0 )
|
||||
{
|
||||
float angle = 2. * acos(cos_angle);
|
||||
if (mMode==Around)
|
||||
mpCamera->rotateAroundTarget(Quaternionf(AngleAxisf(angle, axis)));
|
||||
else
|
||||
mpCamera->localRotate(Quaternionf(AngleAxisf(-angle, axis)));
|
||||
}
|
||||
}
|
||||
|
||||
mLastPoint3D = newPoint3D;
|
||||
mLastPointOk = newPointOk;
|
||||
}
|
||||
|
||||
bool Trackball::mapToSphere(const Vector2i& p2, Vector3f& v3)
|
||||
{
|
||||
if ((p2.x() >= 0) && (p2.x() <= int(mpCamera->vpWidth())) &&
|
||||
(p2.y() >= 0) && (p2.y() <= int(mpCamera->vpHeight())) )
|
||||
{
|
||||
double x = (double)(p2.x() - 0.5*mpCamera->vpWidth()) / (double)mpCamera->vpWidth();
|
||||
double y = (double)(0.5*mpCamera->vpHeight() - p2.y()) / (double)mpCamera->vpHeight();
|
||||
double sinx = sin(M_PI * x * 0.5);
|
||||
double siny = sin(M_PI * y * 0.5);
|
||||
double sinx2siny2 = sinx * sinx + siny * siny;
|
||||
|
||||
v3.x() = sinx;
|
||||
v3.y() = siny;
|
||||
v3.z() = sinx2siny2 < 1.0 ? sqrt(1.0 - sinx2siny2) : 0.0;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
42
cs440-acg/ext/eigen/demos/opengl/trackball.h
Normal file
42
cs440-acg/ext/eigen/demos/opengl/trackball.h
Normal file
@@ -0,0 +1,42 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_TRACKBALL_H
|
||||
#define EIGEN_TRACKBALL_H
|
||||
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
class Camera;
|
||||
|
||||
class Trackball
|
||||
{
|
||||
public:
|
||||
|
||||
enum Mode {Around, Local};
|
||||
|
||||
Trackball() : mpCamera(0) {}
|
||||
|
||||
void start(Mode m = Around) { mMode = m; mLastPointOk = false; }
|
||||
|
||||
void setCamera(Camera* pCam) { mpCamera = pCam; }
|
||||
|
||||
void track(const Eigen::Vector2i& newPoint2D);
|
||||
|
||||
protected:
|
||||
|
||||
bool mapToSphere( const Eigen::Vector2i& p2, Eigen::Vector3f& v3);
|
||||
|
||||
Camera* mpCamera;
|
||||
Eigen::Vector3f mLastPoint3D;
|
||||
Mode mMode;
|
||||
bool mLastPointOk;
|
||||
|
||||
};
|
||||
|
||||
#endif // EIGEN_TRACKBALL_H
|
Reference in New Issue
Block a user