paysages : Terrain canvas - Height map painting (WIP).

git-svn-id: https://subversion.assembla.com/svn/thunderk/paysages@392 b1fd45b6-86a6-48da-8261-f70d1f35bdcc
This commit is contained in:
Michaël Lemaire 2012-07-16 20:34:01 +00:00 committed by ThunderK
parent 62e0ef5859
commit 818b8b7b86
9 changed files with 150 additions and 68 deletions

View file

@ -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);
}

View file

@ -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;

View file

@ -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)
{
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;
if ((event->buttons() & Qt::LeftButton) || (event->buttons() & Qt::RightButton))
_angle_h -= (double)move_x * 0.008;
_angle_v += (double)move_y * 0.003;
}
_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();

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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;
/* 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;
}
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;
}

View file

@ -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;
}

View file

@ -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
}