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:
parent
62e0ef5859
commit
818b8b7b86
9 changed files with 150 additions and 68 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue