diff --git a/gui_qt/dialogheightmap.cpp b/gui_qt/dialogheightmap.cpp index 88f40ff..e69ee7a 100644 --- a/gui_qt/dialogheightmap.cpp +++ b/gui_qt/dialogheightmap.cpp @@ -88,6 +88,15 @@ DialogHeightMap::DialogHeightMap(QWidget* parent, HeightMap* heightmap) : Dialog slider->setRange(0, 1000); connect(slider, SIGNAL(valueChanged(int)), this, SLOT(brushSmoothingChanged(int))); panel->layout()->addWidget(slider); + slider->setValue(600); + + label = new QLabel(tr("Brush strength"), panel); + panel->layout()->addWidget(label); + + slider = new QSlider(Qt::Horizontal, panel); + slider->setRange(0, 1000); + connect(slider, SIGNAL(valueChanged(int)), this, SLOT(brushStrengthChanged(int))); + panel->layout()->addWidget(slider); slider->setValue(200); // Buttons layout @@ -120,11 +129,14 @@ bool DialogHeightMap::editHeightMap(QWidget* parent, HeightMap* heightmap) void DialogHeightMap::accept() { + heightmapCopy(&_value_modified, _value_original); QDialog::accept(); } void DialogHeightMap::revert() { + heightmapCopy(_value_original, &_value_modified); + _3dview->revert(); } void DialogHeightMap::angleHChanged(int value) @@ -151,3 +163,8 @@ void DialogHeightMap::brushSmoothingChanged(int value) { _3dview->setBrushSmoothing((double)value / 1000.0); } + +void DialogHeightMap::brushStrengthChanged(int value) +{ + _3dview->setBrushStrength((double)value / 2000.0); +} diff --git a/gui_qt/dialogheightmap.h b/gui_qt/dialogheightmap.h index 099d5f5..b87ac34 100644 --- a/gui_qt/dialogheightmap.h +++ b/gui_qt/dialogheightmap.h @@ -22,6 +22,7 @@ private slots: void brushModeChanged(int value); void brushSizeChanged(int value); void brushSmoothingChanged(int value); + void brushStrengthChanged(int value); private: HeightMap* _value_original; diff --git a/gui_qt/widgetheightmap.cpp b/gui_qt/widgetheightmap.cpp index 1aa9cbb..0737b98 100644 --- a/gui_qt/widgetheightmap.cpp +++ b/gui_qt/widgetheightmap.cpp @@ -14,6 +14,8 @@ WidgetHeightMap::WidgetHeightMap(QWidget *parent, HeightMap* heightmap): setMinimumSize(500, 500); setFocusPolicy(Qt::StrongFocus); setMouseTracking(true); + setCursor(Qt::CrossCursor); + startTimer(100); _heightmap = heightmap; _vertexes = new _VertexInfo[heightmap->resolution_x * heightmap->resolution_z]; @@ -22,6 +24,7 @@ WidgetHeightMap::WidgetHeightMap(QWidget *parent, HeightMap* heightmap): _average_frame_time = 0.0; + _last_brush_action = 0; _last_mouse_x = 0; _last_mouse_y = 0; @@ -33,6 +36,7 @@ WidgetHeightMap::WidgetHeightMap(QWidget *parent, HeightMap* heightmap): _brush_mode = HEIGHTMAP_BRUSH_RAISE; _brush_size = 10.0; _brush_smoothing = 0.5; + _brush_strength = 1.0; } WidgetHeightMap::~WidgetHeightMap() @@ -55,6 +59,9 @@ void WidgetHeightMap::setVerticalViewAngle(double angle_v) void WidgetHeightMap::setBrushMode(HeightMapBrushMode mode) { _brush_mode = mode; + _brush_x = 0.0; + _brush_z = 0.0; + updateGL(); } void WidgetHeightMap::setBrushSize(double size) @@ -73,6 +80,20 @@ void WidgetHeightMap::setBrushSmoothing(double smoothing) updateGL(); } +void WidgetHeightMap::setBrushStrength(double strength) +{ + _brush_strength = strength; + _brush_x = 0.0; + _brush_z = 0.0; + updateGL(); +} + +void WidgetHeightMap::revert() +{ + _dirty = true; + updateGL(); +} + void WidgetHeightMap::resetToTerrain() { TerrainDefinition terrain; @@ -92,83 +113,69 @@ void WidgetHeightMap::resetToTerrain() } terrainDeleteDefinition(&terrain); - _dirty = true; - updateGL(); -} - -void WidgetHeightMap::keyPressEvent(QKeyEvent* event) -{ + revert(); } void WidgetHeightMap::mousePressEvent(QMouseEvent* event) { - mouseMoveEvent(event); + _last_mouse_x = event->x(); + _last_mouse_y = event->y(); + if (event->buttons() & Qt::LeftButton) + { + _last_brush_action = 1; + } + else if (event->buttons() & Qt::RightButton) + { + _last_brush_action = -1; + } +} + +void WidgetHeightMap::mouseReleaseEvent(QMouseEvent* event) +{ + _last_brush_action = 0; } void WidgetHeightMap::mouseMoveEvent(QMouseEvent* event) { - int move_x = event->x() - _last_mouse_x; - int move_y = event->y() - _last_mouse_y; + if (event->buttons() & Qt::MiddleButton) + { + // Rotate around the turntable + int move_x = event->x() - _last_mouse_x; + int move_y = event->y() - _last_mouse_y; + + _angle_h -= (double)move_x * 0.008; + _angle_v += (double)move_y * 0.003; + } - if ((event->buttons() & Qt::LeftButton) || (event->buttons() & Qt::RightButton)) + _last_mouse_x = event->x(); + _last_mouse_y = event->y(); + + updateGL(); +} + +void WidgetHeightMap::timerEvent(QTimerEvent* event) +{ + if (_last_brush_action) { HeightMapBrush brush; brush.relative_x = (_brush_x + 40.0) / 80.0; brush.relative_z = (_brush_z + 40.0) / 80.0; - brush.hard_radius = _brush_size / 80.0 - _brush_smoothing; - brush.smoothed_size = (_brush_size / 80.0) * _brush_smoothing; + brush.hard_radius = _brush_size * (1.0 - _brush_smoothing) / 80.0; + brush.smoothed_size = _brush_size * _brush_smoothing / 80.0; switch (_brush_mode) { case HEIGHTMAP_BRUSH_RAISE: - heightmapBrushElevation(_heightmap, &brush, (event->buttons() & Qt::RightButton) ? -0.01 : 0.01); - _dirty = true; - updateGL(); + heightmapBrushElevation(_heightmap, &brush, _brush_strength * _last_brush_action); break; default: - ; + return; } - } - else if (event->buttons() & Qt::MiddleButton) - { - // Rotate around the turntable - _angle_h -= (double)move_x * 0.008; - _angle_v += (double)move_y * 0.003; + _dirty = true; updateGL(); } - else - { - // OpenGL picking using z-buffer - GLint viewport[4]; - GLdouble modelview[16]; - GLdouble projection[16]; - GLfloat winX, winY, winZ; - Vector3 point; - - glGetDoublev(GL_MODELVIEW_MATRIX, modelview); - glGetDoublev(GL_PROJECTION_MATRIX, projection); - glGetIntegerv(GL_VIEWPORT, viewport); - - winX = (float)event->x(); - winY = (float)height() - (float)event->y(); - glReadPixels(event->x(), (int)winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ); - - gluUnProject(winX, winY, winZ, modelview, projection, viewport, &point.x, &point.y, &point.z); - - _brush_x = point.x; - _brush_z = point.z; - - updateGL(); - } - - _last_mouse_x = event->x(); - _last_mouse_y = event->y(); -} - -void WidgetHeightMap::wheelEvent(QWheelEvent* event) -{ } void WidgetHeightMap::initializeGL() @@ -230,6 +237,26 @@ void WidgetHeightMap::paintGL() _dirty = false; } + // Picking mouse position using z-buffer (for brush) + GLint viewport[4]; + GLdouble modelview[16]; + GLdouble projection[16]; + GLfloat winX, winY, winZ; + Vector3 point; + + glGetDoublev(GL_MODELVIEW_MATRIX, modelview); + glGetDoublev(GL_PROJECTION_MATRIX, projection); + glGetIntegerv(GL_VIEWPORT, viewport); + + winX = (float)_last_mouse_x; + winY = (float)height() - (float)_last_mouse_y; + glReadPixels(_last_mouse_x, (int)winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ); + + gluUnProject(winX, winY, winZ, modelview, projection, viewport, &point.x, &point.y, &point.z); + + _brush_x = point.x; + _brush_z = point.z; + // Place camera glMatrixMode(GL_MODELVIEW); glLoadIdentity(); diff --git a/gui_qt/widgetheightmap.h b/gui_qt/widgetheightmap.h index e3d0f8e..3bddf33 100644 --- a/gui_qt/widgetheightmap.h +++ b/gui_qt/widgetheightmap.h @@ -29,15 +29,18 @@ public: void setBrushMode(HeightMapBrushMode mode); void setBrushSize(double size); void setBrushSmoothing(double smoothing); + void setBrushStrength(double smoothing); public slots: + void revert(); void resetToTerrain(); protected: - void keyPressEvent(QKeyEvent* event); void mousePressEvent(QMouseEvent* event); + void mouseReleaseEvent(QMouseEvent* event); void mouseMoveEvent(QMouseEvent* event); - void wheelEvent(QWheelEvent* event); + + void timerEvent(QTimerEvent* event); void initializeGL(); void resizeGL(int w, int h); @@ -54,6 +57,7 @@ private: double _average_frame_time; + int _last_brush_action; int _last_mouse_x; int _last_mouse_y; @@ -65,6 +69,7 @@ private: HeightMapBrushMode _brush_mode; double _brush_size; double _brush_smoothing; + double _brush_strength; }; #endif diff --git a/lib_paysages/heightmap.c b/lib_paysages/heightmap.c index 7371da6..24bd555 100644 --- a/lib_paysages/heightmap.c +++ b/lib_paysages/heightmap.c @@ -50,6 +50,7 @@ void heightmapLoad(PackStream* stream, HeightMap* heightmap) packReadInt(stream, &heightmap->resolution_x); packReadInt(stream, &heightmap->resolution_z); + heightmap->data = realloc(heightmap->data, sizeof(double) * heightmap->resolution_x * heightmap->resolution_z); for (i = 0; i < heightmap->resolution_x * heightmap->resolution_z; i++) { packReadDouble(stream, &heightmap->data[i]); @@ -70,6 +71,12 @@ void heightmapChangeResolution(HeightMap* heightmap, int resolution_x, int resol } } +double heightmapGetValue(HeightMap* heightmap, double x, double z) +{ + // TODO Bicubic interpolation + return heightmap->data[lround(z * (heightmap->resolution_z - 1)) * heightmap->resolution_x + lround(x * (heightmap->resolution_x - 1))]; +} + void heightmapBrushElevation(HeightMap* heightmap, HeightMapBrush* brush, double value) { int x, z; @@ -89,7 +96,7 @@ void heightmapBrushElevation(HeightMap* heightmap, HeightMapBrush* brush, double { if (distance <= brush->hard_radius + brush->smoothed_size) { - heightmap->data[z * heightmap->resolution_x +x] += value * (distance - brush->hard_radius) / brush->smoothed_size; + heightmap->data[z * heightmap->resolution_x +x] += value * (1.0 - (distance - brush->hard_radius) / brush->smoothed_size); } } else diff --git a/lib_paysages/heightmap.h b/lib_paysages/heightmap.h index 0ef3d77..e2cb222 100644 --- a/lib_paysages/heightmap.h +++ b/lib_paysages/heightmap.h @@ -33,6 +33,7 @@ void heightmapSave(PackStream* stream, HeightMap* heightmap); void heightmapLoad(PackStream* stream, HeightMap* heightmap); void heightmapChangeResolution(HeightMap* heightmap, int resolution_x, int resolution_z); +double heightmapGetValue(HeightMap* heightmap, double x, double z); void heightmapBrushElevation(HeightMap* heightmap, HeightMapBrush* brush, double value); diff --git a/lib_paysages/terrain.c b/lib_paysages/terrain.c index db169c4..5485a83 100644 --- a/lib_paysages/terrain.c +++ b/lib_paysages/terrain.c @@ -19,7 +19,7 @@ void terrainSave(PackStream* stream, TerrainDefinition* definition) noiseSaveGenerator(stream, definition->height_noise); packWriteDouble(stream, &definition->height_factor); packWriteDouble(stream, &definition->scaling); - layersSave(stream, &definition->canvases); + layersSave(stream, definition->canvases); packWriteDouble(stream, &definition->shadow_smoothing); } @@ -28,7 +28,7 @@ void terrainLoad(PackStream* stream, TerrainDefinition* definition) noiseLoadGenerator(stream, definition->height_noise); packReadDouble(stream, &definition->height_factor); packReadDouble(stream, &definition->scaling); - layersLoad(stream, &definition->canvases); + layersLoad(stream, definition->canvases); packReadDouble(stream, &definition->shadow_smoothing); terrainValidateDefinition(definition); @@ -81,28 +81,44 @@ void terrainValidateDefinition(TerrainDefinition* definition) static inline double _getHeight(TerrainDefinition* definition, double x, double z) { + TerrainCanvas* canvas; Vector3 location; - int i; + int i, n; location.x = x; location.y = noiseGet2DTotal(definition->height_noise, x / definition->scaling, z / definition->scaling) * definition->height_factor; location.z = z; + + n = layersCount(definition->canvases); + for (i = 0; i < n; i++) + { + canvas = layersGetLayer(definition->canvases, i); + location = terrainCanvasApply(canvas, location); + } - /* TODO Apply canvases and modifiers */ + /* TODO Apply modifiers */ return location.y; } static inline double _getHeightDetail(TerrainDefinition* definition, double x, double z, double detail) { + TerrainCanvas* canvas; Vector3 location; - int i; + int i, n; location.x = x; location.y = noiseGet2DDetail(definition->height_noise, x / definition->scaling, z / definition->scaling, detail / definition->height_factor) * definition->height_factor; location.z = z; - /* TODO Apply canvases and modifiers */ + n = layersCount(definition->canvases); + for (i = 0; i < n; i++) + { + canvas = layersGetLayer(definition->canvases, i); + location = terrainCanvasApply(canvas, location); + } + + /* TODO Apply modifiers */ return location.y; } diff --git a/lib_paysages/terraincanvas.c b/lib_paysages/terraincanvas.c index 708894e..47f5528 100644 --- a/lib_paysages/terraincanvas.c +++ b/lib_paysages/terraincanvas.c @@ -8,10 +8,10 @@ TerrainCanvas* terrainCanvasCreate() TerrainCanvas* result = malloc(sizeof(TerrainCanvas)); result->area.bounded = 1; - result->area.location_x = 0.0; - result->area.location_z = 0.0; - result->area.size_x = 1.0; - result->area.size_z = 1.0; + result->area.location_x = -40.0; + result->area.location_z = -40.0; + result->area.size_x = 80.0; + result->area.size_z = 80.0; result->offset_z = 0.0; result->height_map = heightmapCreate(); heightmapChangeResolution(&result->height_map, 256, 256); @@ -107,6 +107,14 @@ void terrainCanvasRevertToTerrain(TerrainCanvas* canvas, TerrainDefinition* terr { } -Vector3 terrainCanvasApply(TerrainCanvas* canvas, Vector3 position) +Vector3 terrainCanvasApply(TerrainCanvas* canvas, Vector3 location) { + if (location.x >= canvas->area.location_x && + location.z >= canvas->area.location_z && + location.x <= canvas->area.location_x + canvas->area.size_x && + location.z <= canvas->area.location_z + canvas->area.size_z) + { + location.y = heightmapGetValue(&canvas->height_map, (location.x - canvas->area.location_x) / canvas->area.size_x, (location.z - canvas->area.location_z) / canvas->area.size_z); + } + return location; } diff --git a/lib_paysages/terraincanvas.h b/lib_paysages/terraincanvas.h index 273b70a..8435827 100644 --- a/lib_paysages/terraincanvas.h +++ b/lib_paysages/terraincanvas.h @@ -48,7 +48,7 @@ void terrainCanvasSave(PackStream* stream, TerrainCanvas* canvas); void terrainCanvasLoad(PackStream* stream, TerrainCanvas* canvas); void terrainCanvasRevertToTerrain(TerrainCanvas* canvas, TerrainDefinition* terrain, int only_masked); -Vector3 terrainCanvasApply(TerrainCanvas* canvas, Vector3 position); +Vector3 terrainCanvasApply(TerrainCanvas* canvas, Vector3 location); #ifdef __cplusplus }