paysages : Start of unit testing (WIP).

git-svn-id: https://subversion.assembla.com/svn/thunderk/paysages@555 b1fd45b6-86a6-48da-8261-f70d1f35bdcc
This commit is contained in:
Michaël Lemaire 2013-04-20 11:28:56 +00:00 committed by ThunderK
parent 541bfa1f00
commit 0e0b39f576
12 changed files with 181 additions and 71 deletions

View file

@ -6,24 +6,30 @@ all:
@+cd src/exploring && make BUILDMODE=${BUILDMODE} PROJECT_PATH=${CURDIR} @+cd src/exploring && make BUILDMODE=${BUILDMODE} PROJECT_PATH=${CURDIR}
@+cd src/controlling && make BUILDMODE=${BUILDMODE} PROJECT_PATH=${CURDIR} @+cd src/controlling && make BUILDMODE=${BUILDMODE} PROJECT_PATH=${CURDIR}
@+cd src/editing && qmake "BUILDMODE=${BUILDMODE}" "PROJECT_PATH=${CURDIR}" && make @+cd src/editing && qmake "BUILDMODE=${BUILDMODE}" "PROJECT_PATH=${CURDIR}" && make
@+cd src/testing && make BUILDMODE=${BUILDMODE} PROJECT_PATH=${CURDIR}
clean: clean:
cd src/rendering && make clean BUILDMODE=${BUILDMODE} PROJECT_PATH=${CURDIR} cd src/rendering && make clean BUILDMODE=${BUILDMODE} PROJECT_PATH=${CURDIR}
cd src/exploring && make clean BUILDMODE=${BUILDMODE} PROJECT_PATH=${CURDIR} cd src/exploring && make clean BUILDMODE=${BUILDMODE} PROJECT_PATH=${CURDIR}
cd src/controlling && make clean BUILDMODE=${BUILDMODE} PROJECT_PATH=${CURDIR} cd src/controlling && make clean BUILDMODE=${BUILDMODE} PROJECT_PATH=${CURDIR}
cd src/editing && qmake "BUILDMODE=${BUILDMODE}" "PROJECT_PATH=${CURDIR}" && make clean cd src/editing && qmake "BUILDMODE=${BUILDMODE}" "PROJECT_PATH=${CURDIR}" && make clean
cd src/testing && make clean BUILDMODE=${BUILDMODE} PROJECT_PATH=${CURDIR}
rm -f ${BUILDPATH}/paysages-cli rm -f ${BUILDPATH}/paysages-cli
rm -f ${BUILDPATH}/paysages-qt rm -f ${BUILDPATH}/paysages-qt
rm -f ${BUILDPATH}/paysages-tests
rm -f ${BUILDPATH}/libpaysages_exploring.so rm -f ${BUILDPATH}/libpaysages_exploring.so
rm -f ${BUILDPATH}/libpaysages_rendering.so rm -f ${BUILDPATH}/libpaysages_rendering.so
release: release:
make BUILDMODE=release all make BUILDMODE=release all
run_cli: tests: all
LD_LIBRARY_PATH=${BUILDPATH} ${BUILDPATH}/paysages-tests
run_cli: all
LD_LIBRARY_PATH=${BUILDPATH} ${BUILDPATH}/paysages-cli LD_LIBRARY_PATH=${BUILDPATH} ${BUILDPATH}/paysages-cli
run_qt: run_qt: all
LD_LIBRARY_PATH=${BUILDPATH} ${BUILDPATH}/paysages-qt LD_LIBRARY_PATH=${BUILDPATH} ${BUILDPATH}/paysages-qt
profile: profile:

View file

@ -18,8 +18,6 @@ DialogHeightMap::DialogHeightMap(QWidget* parent, TerrainDefinition* terrain) :
QWidget* mainarea; QWidget* mainarea;
QWidget* buttons; QWidget* buttons;
QWidget* panel; QWidget* panel;
QWidget* viewer;
QGridLayout* viewer_layout;
QLabel* label; QLabel* label;
QSlider* slider; QSlider* slider;
@ -42,30 +40,15 @@ DialogHeightMap::DialogHeightMap(QWidget* parent, TerrainDefinition* terrain) :
this->layout()->addWidget(buttons); this->layout()->addWidget(buttons);
// Main area layout (viewer + panel) // Main area layout (viewer + panel)
viewer = new QWidget(mainarea); _3dview = new WidgetHeightMap(mainarea, _value_modified);
viewer_layout = new QGridLayout(); connect(_3dview, SIGNAL(heightmapChanged()), this, SLOT(heightmapChanged()));
viewer->setLayout(viewer_layout); mainarea->layout()->addWidget(_3dview);
mainarea->layout()->addWidget(viewer);
panel = new QWidget(mainarea); panel = new QWidget(mainarea);
panel->setLayout(new QVBoxLayout()); panel->setLayout(new QVBoxLayout());
mainarea->layout()->addWidget(panel); mainarea->layout()->addWidget(panel);
mainarea->layout()->setAlignment(panel, Qt::AlignTop); mainarea->layout()->setAlignment(panel, Qt::AlignTop);
// Viewer layout (3d display + sliders)
_3dview = new WidgetHeightMap(viewer, _value_modified);
viewer_layout->addWidget(_3dview, 0, 0);
connect(_3dview, SIGNAL(heightmapChanged()), this, SLOT(heightmapChanged()));
slider = new QSlider(Qt::Horizontal, viewer);
slider->setRange(0, 1000);
connect(slider, SIGNAL(valueChanged(int)), this, SLOT(angleHChanged(int)));
viewer_layout->addWidget(slider, 1, 0);
slider = new QSlider(Qt::Vertical, viewer);
slider->setRange(-300, 700);
connect(slider, SIGNAL(valueChanged(int)), this, SLOT(angleVChanged(int)));
viewer_layout->addWidget(slider, 0, 1);
// Panel layout // Panel layout
_info_memory = new QLabel(panel); _info_memory = new QLabel(panel);
panel->layout()->addWidget(_info_memory); panel->layout()->addWidget(_info_memory);
@ -151,16 +134,6 @@ void DialogHeightMap::revert()
_3dview->revert(); _3dview->revert();
} }
void DialogHeightMap::angleHChanged(int value)
{
_3dview->setHorizontalViewAngle(M_PI * ((double)value) / 500.0);
}
void DialogHeightMap::angleVChanged(int value)
{
_3dview->setVerticalViewAngle(M_PI_2 * ((double)value) / 1000.0);
}
void DialogHeightMap::brushModeChanged(int value) void DialogHeightMap::brushModeChanged(int value)
{ {
_3dview->setBrushMode((HeightMapBrushMode)value); _3dview->setBrushMode((HeightMapBrushMode)value);

View file

@ -18,8 +18,6 @@ public slots:
void revert(); void revert();
private slots: private slots:
void angleHChanged(int value);
void angleVChanged(int value);
void brushModeChanged(int value); void brushModeChanged(int value);
void brushSizeChanged(int value); void brushSizeChanged(int value);
void brushSmoothingChanged(int value); void brushSmoothingChanged(int value);

View file

@ -35,11 +35,13 @@ WidgetHeightMap::WidgetHeightMap(QWidget *parent, TerrainDefinition* terrain):
_last_time = QDateTime::currentDateTime(); _last_time = QDateTime::currentDateTime();
_mouse_moved = false; _mouse_moved = false;
_position_x = 0; _current_camera = cameraCreateDefinition();
_position_z = 0; _top_camera = cameraCreateDefinition();
_angle_h = 0.0; _temp_camera = cameraCreateDefinition();
_angle_v = 1.4;
_distance = 100.0; cameraSetLocation(&_current_camera, 0.0, 80.0, 20.0);
cameraSetTarget(&_current_camera, 0.0, 0.0, 0.0);
cameraCopyDefinition(&_current_camera, &_top_camera);
_brush_x = 0.0; _brush_x = 0.0;
_brush_z = 0.0; _brush_z = 0.0;
@ -58,18 +60,6 @@ WidgetHeightMap::~WidgetHeightMap()
delete[] _vertices; delete[] _vertices;
} }
void WidgetHeightMap::setHorizontalViewAngle(double angle_h)
{
_angle_h = angle_h;
updateGL();
}
void WidgetHeightMap::setVerticalViewAngle(double angle_v)
{
_angle_v = angle_v;
updateGL();
}
void WidgetHeightMap::setBrushMode(HeightMapBrushMode mode) void WidgetHeightMap::setBrushMode(HeightMapBrushMode mode)
{ {
_brush_mode = mode; _brush_mode = mode;
@ -166,8 +156,9 @@ void WidgetHeightMap::mouseMoveEvent(QMouseEvent* event)
int move_x = event->x() - _last_mouse_x; int move_x = event->x() - _last_mouse_x;
int move_y = event->y() - _last_mouse_y; int move_y = event->y() - _last_mouse_y;
_angle_h -= (double)move_x * 0.008; // TODO
_angle_v += (double)move_y * 0.003; /*_angle_h -= (double)move_x * 0.008;
_angle_v += (double)move_y * 0.003;*/
} }
_last_mouse_x = event->x(); _last_mouse_x = event->x();
@ -193,8 +184,8 @@ void WidgetHeightMap::timerEvent(QTimerEvent*)
double brush_strength; double brush_strength;
TerrainBrush brush; TerrainBrush brush;
brush.relative_x = _brush_x + (double)_position_x; brush.relative_x = _brush_x + _current_camera.target.x;
brush.relative_z = _brush_z + (double)_position_z; brush.relative_z = _brush_z + _current_camera.target.z;
brush.hard_radius = _brush_size * (1.0 - _brush_smoothing); brush.hard_radius = _brush_size * (1.0 - _brush_smoothing);
brush.smoothed_size = _brush_size * _brush_smoothing; brush.smoothed_size = _brush_size * _brush_smoothing;
brush.total_radius = brush.hard_radius + brush.smoothed_size; brush.total_radius = brush.hard_radius + brush.smoothed_size;
@ -230,7 +221,7 @@ void WidgetHeightMap::timerEvent(QTimerEvent*)
// Edge scrolling // Edge scrolling
// TODO Apply scrolling to vertex info and dirty only needed area // TODO Apply scrolling to vertex info and dirty only needed area
double edge_length = 10.0; /*double edge_length = 10.0;
if (_brush_x > HEIGHTMAP_RESOLUTION / 2.0 - edge_length) if (_brush_x > HEIGHTMAP_RESOLUTION / 2.0 - edge_length)
{ {
double dx = HEIGHTMAP_RESOLUTION / 2.0 - edge_length - _brush_x; double dx = HEIGHTMAP_RESOLUTION / 2.0 - edge_length - _brush_x;
@ -262,7 +253,7 @@ void WidgetHeightMap::timerEvent(QTimerEvent*)
_dirty = true; _dirty = true;
updateGL(); updateGL();
} }*/
} }
void WidgetHeightMap::initializeGL() void WidgetHeightMap::initializeGL()
@ -365,7 +356,7 @@ void WidgetHeightMap::paintGL()
// Place camera // Place camera
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); glLoadIdentity();
gluLookAt(_distance * cos(_angle_h) * cos(_angle_v), _distance * sin(_angle_v), -_distance * sin(_angle_h) * cos(_angle_v), 0.0, 0.0, 0.0, -cos(_angle_h) * sin(_angle_v), cos(_angle_v), sin(_angle_h) * sin(_angle_v)); gluLookAt(_current_camera.location.x, _current_camera.location.y, _current_camera.location.z, _current_camera.target.x, _current_camera.target.y, _current_camera.target.z, _current_camera.up.x, _current_camera.up.y, _current_camera.up.z);
// Place lights // Place lights
GLfloat light_position[] = { 40.0, 40.0, 40.0, 0.0 }; GLfloat light_position[] = { 40.0, 40.0, 40.0, 0.0 };
@ -388,8 +379,8 @@ void WidgetHeightMap::paintGL()
_VertexInfo* vertex = _vertices + z * rx + x + dx; _VertexInfo* vertex = _vertices + z * rx + x + dx;
double diff_x, diff_z, diff; double diff_x, diff_z, diff;
diff_x = vertex->point.x - (double)_position_x - _brush_x; diff_x = vertex->point.x - _current_camera.target.x - _brush_x;
diff_z = vertex->point.z - (double)_position_z - _brush_z; diff_z = vertex->point.z - _current_camera.target.z - _brush_z;
diff = sqrt(diff_x * diff_x + diff_z * diff_z); diff = sqrt(diff_x * diff_x + diff_z * diff_z);
if (diff > _brush_size) if (diff > _brush_size)
{ {
@ -405,7 +396,7 @@ void WidgetHeightMap::paintGL()
} }
glColor3f(0.8 + diff, vertex->painted ? 1.0 : 0.8, 0.8); glColor3f(0.8 + diff, vertex->painted ? 1.0 : 0.8, 0.8);
glNormal3f(vertex->normal.x, vertex->normal.y, vertex->normal.z); glNormal3f(vertex->normal.x, vertex->normal.y, vertex->normal.z);
glVertex3f(vertex->point.x - (double)_position_x, vertex->point.y, vertex->point.z - (double)_position_z); glVertex3f(vertex->point.x - _current_camera.target.x, vertex->point.y, vertex->point.z - _current_camera.target.z);
} }
} }
glEnd(); glEnd();
@ -441,8 +432,8 @@ void WidgetHeightMap::updateVertexInfo()
{ {
_VertexInfo* vertex = _vertices + z * rx + x; _VertexInfo* vertex = _vertices + z * rx + x;
dx = _position_x + x - rx / 2; dx = _current_camera.target.x + x - rx / 2;
dz = _position_z + z - rz / 2; dz = _current_camera.target.z + z - rz / 2;
vertex->point.x = (double)dx; vertex->point.x = (double)dx;
vertex->point.z = (double)dz; vertex->point.z = (double)dz;

View file

@ -3,6 +3,7 @@
#include <QGLWidget> #include <QGLWidget>
#include <QDateTime> #include <QDateTime>
#include "rendering/camera.h"
#include "rendering/tools/euclid.h" #include "rendering/tools/euclid.h"
#include "rendering/renderer.h" #include "rendering/renderer.h"
#include "rendering/terrain/public.h" #include "rendering/terrain/public.h"
@ -28,8 +29,6 @@ public:
WidgetHeightMap(QWidget* parent, TerrainDefinition* terrain); WidgetHeightMap(QWidget* parent, TerrainDefinition* terrain);
~WidgetHeightMap(); ~WidgetHeightMap();
void setHorizontalViewAngle(double angle_h);
void setVerticalViewAngle(double angle_v);
void setBrushMode(HeightMapBrushMode mode); void setBrushMode(HeightMapBrushMode mode);
void setBrushSize(double size); void setBrushSize(double size);
void setBrushSmoothing(double smoothing); void setBrushSmoothing(double smoothing);
@ -73,11 +72,9 @@ private:
QDateTime _last_time; QDateTime _last_time;
bool _mouse_moved; bool _mouse_moved;
int _position_x; CameraDefinition _top_camera;
int _position_z; CameraDefinition _temp_camera;
double _angle_h; CameraDefinition _current_camera;
double _angle_v;
double _distance;
double _brush_x; double _brush_x;
double _brush_z; double _brush_z;

View file

@ -155,7 +155,8 @@ void cameraSetTarget(CameraDefinition* camera, double x, double y, double z)
} }
else else
{ {
/* TODO Guess angles */ /* Guess angles */
v3ToEuler(forward, &camera->yaw, &camera->pitch);
} }
cameraValidateDefinition(camera, 0); cameraValidateDefinition(camera, 0);

View file

@ -102,6 +102,12 @@ Vector3 v3Cross(Vector3 v1, Vector3 v2)
return result; return result;
} }
void v3ToEuler(Vector3 v, double* heading, double* attitude)
{
*heading = euclidGet2DAngle(v.x, v.z);
*attitude = euclidGet2DAngle(sqrt(v.x * v.x + v.z * v.z), v.y);
}
void m4Save(PackStream* stream, Matrix4* m) void m4Save(PackStream* stream, Matrix4* m)
{ {
packWriteDouble(stream, &m->a); packWriteDouble(stream, &m->a);
@ -405,6 +411,41 @@ Matrix4 m4Inverse(Matrix4 m)
} }
} }
double euclidGet2DAngle(double x, double y)
{
double nx, ny, d, ret;
if (x == 0.0)
{
if (y == 0.0)
{
return 0.0;
}
else
{
if (y < 0.0)
{
return 3.0 * M_PI_2;
}
else
{
return M_PI_2;
}
}
}
d = sqrt(x * x + y * y);
nx = x / d;
ny = y / d;
ret = asin(ny);
if (nx < 0.0)
{
ret = M_PI - ret;
}
return fmod(ret, 2.0 * M_PI);
}
Vector3 euclidGetNormalFromTriangle(Vector3 center, Vector3 bottom, Vector3 right) Vector3 euclidGetNormalFromTriangle(Vector3 center, Vector3 bottom, Vector3 right)
{ {
Vector3 dx = v3Sub(right, center); Vector3 dx = v3Sub(right, center);

View file

@ -53,6 +53,7 @@ double v3Norm(Vector3 v);
Vector3 v3Normalize(Vector3 v); Vector3 v3Normalize(Vector3 v);
double v3Dot(Vector3 v1, Vector3 v2); double v3Dot(Vector3 v1, Vector3 v2);
Vector3 v3Cross(Vector3 v1, Vector3 v2); Vector3 v3Cross(Vector3 v1, Vector3 v2);
void v3ToEuler(Vector3 v, double* heading, double* attitude);
void m4Save(PackStream* stream, Matrix4* m); void m4Save(PackStream* stream, Matrix4* m);
void m4Load(PackStream* stream, Matrix4* m); void m4Load(PackStream* stream, Matrix4* m);
@ -74,6 +75,7 @@ Matrix4 m4NewPerspective(double fov_y, double aspect, double near, double far);
double m4Determinant(Matrix4 m); double m4Determinant(Matrix4 m);
Matrix4 m4Inverse(Matrix4 m); Matrix4 m4Inverse(Matrix4 m);
double euclidGet2DAngle(double x, double y);
Vector3 euclidGetNormalFromTriangle(Vector3 center, Vector3 bottom, Vector3 right); Vector3 euclidGetNormalFromTriangle(Vector3 center, Vector3 bottom, Vector3 right);
double euclidGetDistance2D(double x1, double y1, double x2, double y2); double euclidGetDistance2D(double x1, double y1, double x2, double y2);
int euclidRayIntersectSphere(Vector3 ray_point, Vector3 ray_direction, Vector3 sphere_center, double sphere_radius, Vector3* hit1, Vector3* hit2); int euclidRayIntersectSphere(Vector3 ray_point, Vector3 ray_direction, Vector3 sphere_center, double sphere_radius, Vector3* hit1, Vector3* hit2);

11
src/testing/Makefile Normal file
View file

@ -0,0 +1,11 @@
include ../common_pre.mk
OBJPATH = ${BUILDPATH}/testing
RESULT = ${BUILDPATH}/paysages-tests
SOURCES += $(wildcard *.c)
HEADERS += $(wildcard *.h)
CC_LDFLAGS += -L${BUILDPATH} -lpaysages_rendering
LIBS += check
include ../common_post.mk

40
src/testing/common.h Normal file
View file

@ -0,0 +1,40 @@
#ifndef _PAYSAGES_TESTING_COMMON_H_
#define _PAYSAGES_TESTING_COMMON_H_
#include <check.h>
#include <stdarg.h>
#include <math.h>
static inline void _add_methods_to_case(TCase* tc, ...)
{
void* method;
va_list argp;
va_start(argp, tc);
while ((method = va_arg(argp, void*)) != NULL)
{
tcase_add_test(tc, method);
}
va_end(argp);
}
#define TEST_CASE(_name_,...) void test_ ## _name_ ## _case(Suite* s) { \
TCase *tc = tcase_create(#_name_); \
_add_methods_to_case(tc, __VA_ARGS__, NULL); \
suite_add_tcase(s, tc); \
}
static inline int _double_equals(double x, double y)
{
return fabs(x - y) < 0.00000000001;
}
static inline int _double_not_equals(double x, double y)
{
return fabs(x - y) >= 0.00000000001;
}
#define _ck_assert_double(F, X, O, Y) ck_assert_msg(F(X, Y), "Assertion '"#X#O#Y"' failed: "#X"==%f, "#Y"==%f", X, Y)
#define ck_assert_double_eq(X, Y) _ck_assert_double(_double_equals, X, ==, Y)
#define ck_assert_double_ne(X, Y) _ck_assert_double(_double_not_equals, X, !=, Y)
#endif

31
src/testing/euclid.c Normal file
View file

@ -0,0 +1,31 @@
#include "testing/common.h"
#include "rendering/tools/euclid.h"
START_TEST(test_euclid_angles)
{
ck_assert_double_eq(euclidGet2DAngle(0.0, 0.0), 0.0);
ck_assert_double_eq(euclidGet2DAngle(0.1, 0.0), 0.0);
ck_assert_double_eq(euclidGet2DAngle(1.0, 0.0), 0.0);
ck_assert_double_eq(euclidGet2DAngle(2.0, 0.0), 0.0);
ck_assert_double_eq(euclidGet2DAngle(0.0, 0.1), M_PI_2);
ck_assert_double_eq(euclidGet2DAngle(0.0, 1.0), M_PI_2);
ck_assert_double_eq(euclidGet2DAngle(0.0, 2.0), M_PI_2);
ck_assert_double_eq(euclidGet2DAngle(-0.1, 0.0), M_PI);
ck_assert_double_eq(euclidGet2DAngle(-1.0, 0.0), M_PI);
ck_assert_double_eq(euclidGet2DAngle(-2.0, 0.0), M_PI);
ck_assert_double_eq(euclidGet2DAngle(0.0, -0.1), 3.0 * M_PI_2);
ck_assert_double_eq(euclidGet2DAngle(0.0, -1.0), 3.0 * M_PI_2);
ck_assert_double_eq(euclidGet2DAngle(0.0, -2.0), 3.0 * M_PI_2);
ck_assert_double_eq(euclidGet2DAngle(0.5, 0.5), M_PI_4);
ck_assert_double_eq(euclidGet2DAngle(0.5, -0.5), 7.0 * M_PI_4);
ck_assert_double_eq(euclidGet2DAngle(-0.5, 0.5), 3.0 * M_PI_4);
ck_assert_double_eq(euclidGet2DAngle(-0.5, -0.5), 5.0 * M_PI_4);
}
END_TEST
TEST_CASE(euclid, test_euclid_angles)

19
src/testing/main.c Normal file
View file

@ -0,0 +1,19 @@
#include <check.h>
#include <stdlib.h>
extern void test_euclid_case(Suite* s);
int main(int argc, char** argv)
{
int number_failed;
Suite *s = suite_create("rendering");
/* TODO Find a way to automate this */
test_euclid_case(s);
SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}