diff --git a/gui_qt/baseexplorerchunk.cpp b/gui_qt/baseexplorerchunk.cpp index 53cabce..9cf9b64 100644 --- a/gui_qt/baseexplorerchunk.cpp +++ b/gui_qt/baseexplorerchunk.cpp @@ -64,7 +64,7 @@ bool BaseExplorerChunk::maintain() _texture_changed = true; _lock_data.unlock(); - if (_texture_current_size < 8 && _texture_current_size < _texture_max_size) + if (_texture_current_size < 4 && _texture_current_size < _texture_max_size) { maintain(); } diff --git a/gui_qt/dialogrender.cpp b/gui_qt/dialogrender.cpp index b809f54..f818f29 100644 --- a/gui_qt/dialogrender.cpp +++ b/gui_qt/dialogrender.cpp @@ -6,6 +6,10 @@ #include #include #include +#include +#include +#include +#include #include "tools.h" #include "../lib_paysages/scenery.h" @@ -26,7 +30,6 @@ static void _renderStart(int width, int height, Color background) static void _renderDraw(int x, int y, Color col) { - col = colorProfileApply(_current_dialog->_hdr_profile, col); _current_dialog->pixbuf->setPixel(x, _current_dialog->pixbuf->height() - 1 - y, colorToQColor(col).rgb()); } @@ -80,8 +83,6 @@ DialogRender::DialogRender(QWidget *parent, Renderer* renderer): _render_thread = NULL; _renderer = renderer; - _hdr_profile = colorProfileCreate(); - setModal(true); setWindowTitle(tr("Paysages 3D - Render")); setLayout(new QVBoxLayout()); @@ -92,6 +93,7 @@ DialogRender::DialogRender(QWidget *parent, Renderer* renderer): _scroll->setWidget(area); layout()->addWidget(_scroll); + // Status bar _info = new QWidget(this); _info->setLayout(new QHBoxLayout()); layout()->addWidget(_info); @@ -106,8 +108,31 @@ DialogRender::DialogRender(QWidget *parent, Renderer* renderer): _progress->setValue(0); _info->layout()->addWidget(_progress); + // Action bar + _actions = new QWidget(this); + _actions->setLayout(new QHBoxLayout()); + layout()->addWidget(_actions); + + _actions->layout()->addWidget(new QLabel(tr("Tone-mapping: "), _actions)); + _tonemapping_control = new QComboBox(_actions); + _tonemapping_control->addItems(QStringList(tr("Uncharted")) << tr("Reinhard")); + _actions->layout()->addWidget(_tonemapping_control); + + _actions->layout()->addWidget(new QLabel(tr("Exposure: "), _actions)); + _exposure_control = new QSlider(Qt::Horizontal, _actions); + _exposure_control->setRange(0, 1000); + _exposure_control->setValue(200); + _actions->layout()->addWidget(_exposure_control); + + _save_button = new QPushButton(QIcon("images/save.png"), tr("Save picture"), _actions); + _actions->layout()->addWidget(_save_button); + + // Connections connect(this, SIGNAL(renderSizeChanged(int, int)), this, SLOT(applyRenderSize(int, int))); connect(this, SIGNAL(progressChanged(double)), this, SLOT(applyProgress(double))); + connect(_save_button, SIGNAL(clicked()), this, SLOT(saveRender())); + connect(_tonemapping_control, SIGNAL(currentIndexChanged(int)), this, SLOT(toneMappingChanged())); + connect(_exposure_control, SIGNAL(valueChanged(int)), this, SLOT(toneMappingChanged())); } DialogRender::~DialogRender() @@ -119,7 +144,6 @@ DialogRender::~DialogRender() delete _render_thread; } - colorProfileDelete(_hdr_profile); delete pixbuf; delete pixbuf_lock; } @@ -147,6 +171,33 @@ void DialogRender::startRender(RenderParams params) exec(); } +void DialogRender::saveRender() +{ + QString filepath; + + filepath = QFileDialog::getSaveFileName(this, tr("Paysages 3D - Choose a filename to save the last render"), QString(), tr("Images (*.png *.jpg)")); + if (!filepath.isNull()) + { + if (!filepath.toLower().endsWith(".jpg") && !filepath.toLower().endsWith(".jpeg") && !filepath.toLower().endsWith(".png")) + { + filepath = filepath.append(".png"); + } + if (renderSaveToFile(_renderer->render_area, (char*)filepath.toStdString().c_str())) + { + QMessageBox::information(this, "Message", QString(tr("The picture %1 has been saved.")).arg(filepath)); + } + else + { + QMessageBox::critical(this, "Message", QString(tr("Can't write to file : %1")).arg(filepath)); + } + } +} + +void DialogRender::toneMappingChanged() +{ + renderSetToneMapping(_renderer->render_area, (ToneMappingOperator)_tonemapping_control->currentIndex(), ((double)_exposure_control->value()) * 0.01); +} + void DialogRender::loadLastRender() { //applyRenderSize(_renderer->render_width, _renderer->render_height); diff --git a/gui_qt/dialogrender.h b/gui_qt/dialogrender.h index 6a33828..b8a81ce 100644 --- a/gui_qt/dialogrender.h +++ b/gui_qt/dialogrender.h @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include #include #include "../lib_paysages/renderer.h" @@ -26,11 +28,12 @@ public: QImage* pixbuf; QMutex* pixbuf_lock; QWidget* area; - ColorProfile* _hdr_profile; private slots: void applyRenderSize(int width, int height); void applyProgress(double value); + void saveRender(); + void toneMappingChanged(); signals: void renderSizeChanged(int width, int height); @@ -39,6 +42,10 @@ signals: private: QScrollArea* _scroll; QWidget* _info; + QWidget* _actions; + QComboBox* _tonemapping_control; + QSlider* _exposure_control; + QPushButton* _save_button; QThread* _render_thread; QLabel* _timer; Renderer* _renderer; diff --git a/gui_qt/explorerchunksky.cpp b/gui_qt/explorerchunksky.cpp index 1f079ac..84721e3 100644 --- a/gui_qt/explorerchunksky.cpp +++ b/gui_qt/explorerchunksky.cpp @@ -8,15 +8,21 @@ ExplorerChunkSky::ExplorerChunkSky(Renderer* renderer, double size, SkyboxOrient { _box_size = size; _orientation = orientation; + _center = VECTOR_ZERO; setMaxTextureSize(256); maintain(); } +void ExplorerChunkSky::onCameraEvent(CameraDefinition* camera) +{ + _center = camera->location; +} + void ExplorerChunkSky::onRenderEvent(QGLWidget*) { double size = _box_size; - Vector3 camera = renderer()->getCameraLocation(renderer(), VECTOR_ZERO); + Vector3 camera = _center; glBegin(GL_QUADS); switch(_orientation) @@ -72,14 +78,14 @@ void ExplorerChunkSky::onRenderEvent(QGLWidget*) glVertex3d(camera.x + size, camera.y + size, camera.z + size); break; case SKYBOX_BOTTOM: - glTexCoord2d(0.0, 0.0); + /*glTexCoord2d(0.0, 0.0); glVertex3d(camera.x - size, camera.y - size, camera.z - size); glTexCoord2d(0.0, 1.0); glVertex3d(camera.x - size, camera.y - size, camera.z + size); glTexCoord2d(1.0, 1.0); glVertex3d(camera.x + size, camera.y - size, camera.z + size); glTexCoord2d(1.0, 0.0); - glVertex3d(camera.x + size, camera.y - size, camera.z - size); + glVertex3d(camera.x + size, camera.y - size, camera.z - size);*/ break; } glEnd(); diff --git a/gui_qt/explorerchunksky.h b/gui_qt/explorerchunksky.h index 9eeb49d..732a6d5 100644 --- a/gui_qt/explorerchunksky.h +++ b/gui_qt/explorerchunksky.h @@ -20,6 +20,7 @@ class ExplorerChunkSky:public BaseExplorerChunk public: ExplorerChunkSky(Renderer* renderer, double size, SkyboxOrientation orientation); + void onCameraEvent(CameraDefinition* camera); void onRenderEvent(QGLWidget* widget); double getDisplayedSizeHint(CameraDefinition* camera); Color getTextureColor(double x, double y); @@ -27,7 +28,7 @@ public: private: SkyboxOrientation _orientation; double _box_size; - + Vector3 _center; }; #endif diff --git a/gui_qt/explorerchunkterrain.cpp b/gui_qt/explorerchunkterrain.cpp index 79c7c8e..f6af5c9 100644 --- a/gui_qt/explorerchunkterrain.cpp +++ b/gui_qt/explorerchunkterrain.cpp @@ -4,13 +4,18 @@ #include "baseexplorerchunk.h" #include "../lib_paysages/camera.h" -ExplorerChunkTerrain::ExplorerChunkTerrain(Renderer* renderer, double x, double z, double size, int nbchunks) : BaseExplorerChunk(renderer) +ExplorerChunkTerrain::ExplorerChunkTerrain(Renderer* renderer, double x, double z, double size, int nbchunks, double water_height) : BaseExplorerChunk(renderer) { _startx = x; _startz = z; _size = size; _overall_step = size * (double)nbchunks; + _distance_to_camera = 0.0; + + _water_height = water_height; + _overwater = false; + _tessellation_max_size = 32; _tessellation = new double[(_tessellation_max_size + 1) * (_tessellation_max_size + 1)]; _tessellation_current_size = 0; @@ -31,6 +36,7 @@ ExplorerChunkTerrain::~ExplorerChunkTerrain() void ExplorerChunkTerrain::onResetEvent() { _tessellation_current_size = 0; + _overwater = false; } bool ExplorerChunkTerrain::onMaintainEvent() @@ -50,6 +56,10 @@ bool ExplorerChunkTerrain::onMaintainEvent() if (_tessellation_current_size == 0 || i % old_tessellation_inc != 0 || j % old_tessellation_inc != 0) { double height = renderer->terrain->getHeight(renderer, _startx + _tessellation_step * (double)i, _startz + _tessellation_step * (double)j, 1); + if (height >= _water_height) + { + _overwater = true; + } _tessellation[j * (_tessellation_max_size + 1) + i] = height; } } @@ -59,7 +69,7 @@ bool ExplorerChunkTerrain::onMaintainEvent() _tessellation_current_size = new_tessellation_size; _lock_data.unlock(); - if (_tessellation_current_size < 8 && _tessellation_current_size < _tessellation_max_size) + if (_tessellation_current_size < 4 && _tessellation_current_size < _tessellation_max_size) { onMaintainEvent(); } @@ -96,6 +106,9 @@ void ExplorerChunkTerrain::onCameraEvent(CameraDefinition* camera) _startz -= _overall_step; askReset(); } + + _distance_to_camera = v3Norm(v3Sub(getCenter(), camera->location)); + _lock_data.unlock(); } @@ -106,7 +119,7 @@ void ExplorerChunkTerrain::onRenderEvent(QGLWidget*) double tsize = 1.0 / (double)_tessellation_max_size; _lock_data.unlock(); - if (tessellation_size <= 1) + if (tessellation_size <= 1 or not _overwater) { return; } @@ -131,11 +144,16 @@ double ExplorerChunkTerrain::getDisplayedSizeHint(CameraDefinition* camera) double distance; Vector3 center; + if (not _overwater) + { + return -1000.0; + } + center = getCenter(); if (cameraIsBoxInView(camera, center, _size, 40.0, _size)) { - distance = v3Norm(v3Sub(camera->location, center)); + distance = _distance_to_camera; distance = distance < 0.1 ? 0.1 : distance; return (int)ceil(120.0 - distance / 1.5); } diff --git a/gui_qt/explorerchunkterrain.h b/gui_qt/explorerchunkterrain.h index 83d8da1..bf47db4 100644 --- a/gui_qt/explorerchunkterrain.h +++ b/gui_qt/explorerchunkterrain.h @@ -8,7 +8,7 @@ class ExplorerChunkTerrain:public BaseExplorerChunk { public: - ExplorerChunkTerrain(Renderer* renderer, double x, double z, double size, int nbchunks); + ExplorerChunkTerrain(Renderer* renderer, double x, double z, double size, int nbchunks, double water_height); ~ExplorerChunkTerrain(); void onCameraEvent(CameraDefinition* camera); @@ -26,6 +26,10 @@ private: double _size; double _overall_step; + double _distance_to_camera; + double _water_height; + bool _overwater; + double* _tessellation; int _tessellation_max_size; int _tessellation_current_size; diff --git a/gui_qt/formrender.cpp b/gui_qt/formrender.cpp index aab4235..143481a 100644 --- a/gui_qt/formrender.cpp +++ b/gui_qt/formrender.cpp @@ -1,7 +1,5 @@ #include "formrender.h" -#include -#include #include "dialogrender.h" #include "inputcamera.h" #include "tools.h" @@ -120,8 +118,6 @@ FormRender::FormRender(QWidget *parent) : connect(button, SIGNAL(clicked()), this, SLOT(startRender())); button = addButton(tr("Show last render")); connect(button, SIGNAL(clicked()), this, SLOT(showRender())); - button = addButton(tr("Save last render")); - connect(button, SIGNAL(clicked()), this, SLOT(saveRender())); revertConfig(); } @@ -215,28 +211,3 @@ void FormRender::showRender() delete dialog; } } - -void FormRender::saveRender() -{ - if (_renderer_inited) - { - QString filepath; - - filepath = QFileDialog::getSaveFileName(this, tr("Paysages 3D - Choose a filename to save the last render"), QString(), tr("Images (*.png *.jpg)")); - if (!filepath.isNull()) - { - if (!filepath.toLower().endsWith(".jpg") && !filepath.toLower().endsWith(".jpeg") && !filepath.toLower().endsWith(".png")) - { - filepath = filepath.append(".png"); - } - if (renderSaveToFile(_renderer->render_area, (char*)filepath.toStdString().c_str())) - { - QMessageBox::information(this, "Message", QString(tr("The picture %1 has been saved.")).arg(filepath)); - } - else - { - QMessageBox::critical(this, "Message", QString(tr("Can't write to file : %1")).arg(filepath)); - } - } - } -} diff --git a/gui_qt/formrender.h b/gui_qt/formrender.h index a99ef0a..0eab0e6 100644 --- a/gui_qt/formrender.h +++ b/gui_qt/formrender.h @@ -28,7 +28,6 @@ protected slots: private slots: void startRender(); void showRender(); - void saveRender(); private: RenderParams _params; diff --git a/gui_qt/formwater.cpp b/gui_qt/formwater.cpp index 6241a1f..a33acd3 100644 --- a/gui_qt/formwater.cpp +++ b/gui_qt/formwater.cpp @@ -238,7 +238,7 @@ FormWater::FormWater(QWidget *parent): addPreview(previewCoverage, tr("Coverage preview")); addPreview(previewColor, tr("Rendered preview")); - addInputDouble(tr("Height"), &_definition.height, -10.0, 10.0, 0.1, 1.0); + addInputDouble(tr("Height"), &_definition.height, -15.0, 15.0, 0.1, 1.0); addInputMaterial(tr("Surface material"), &_definition.material); addInputColor(tr("Depth color"), &_definition.depth_color); addInputDouble(tr("Transparency"), &_definition.transparency, 0.0, 1.0, 0.001, 0.1); diff --git a/gui_qt/widgetexplorer.cpp b/gui_qt/widgetexplorer.cpp index b581b1e..4009b3d 100644 --- a/gui_qt/widgetexplorer.cpp +++ b/gui_qt/widgetexplorer.cpp @@ -53,6 +53,11 @@ static Color _applyTextures(Renderer* renderer, Vector3 location, double precisi return texturesGetColor((TexturesDefinition*)(renderer->customData[1]), renderer, location.x, location.z, precision); } +static Vector3 _getCameraLocation(Renderer* renderer, Vector3) +{ + return ((CameraDefinition*)renderer->customData[2])->location; +} + WidgetExplorer::WidgetExplorer(QWidget *parent, CameraDefinition* camera): QGLWidget(parent) { @@ -70,8 +75,10 @@ WidgetExplorer::WidgetExplorer(QWidget *parent, CameraDefinition* camera): _renderer = sceneryCreateStandardRenderer(); _renderer->render_quality = 3; _renderer->customData[1] = &_textures; + _renderer->customData[2] = _base_camera; _renderer->customData[3] = &_water; _renderer->applyTextures = _applyTextures; + _renderer->getCameraLocation = _getCameraLocation; _inited = false; _updated = false; @@ -100,14 +107,15 @@ void WidgetExplorer::startRendering() { // Add terrain int chunks = 20; - double size = 200.0; + double size = 400.0; double chunksize = size / (double)chunks; double start = -size / 2.0; + double water_height = _renderer->getWaterHeightInfo(_renderer).base_height; for (int i = 0; i < chunks; i++) { for (int j = 0; j < chunks; j++) { - ExplorerChunkTerrain* chunk = new ExplorerChunkTerrain(_renderer, start + chunksize * (double)i, start + chunksize * (double)j, chunksize, chunks); + ExplorerChunkTerrain* chunk = new ExplorerChunkTerrain(_renderer, start + chunksize * (double)i, start + chunksize * (double)j, chunksize, chunks, water_height); _chunks.append(chunk); _updateQueue.append(chunk); } @@ -326,7 +334,6 @@ void WidgetExplorer::wheelEvent(QWheelEvent* event) { cameraStrafeForward(&_current_camera, (double)event->delta() * factor); updateGL(); - } event->accept(); } @@ -396,6 +403,7 @@ void WidgetExplorer::paintGL() QTime start_time; double frame_time; + cameraCopyDefinition(&_current_camera, &_renderer->render_camera); cameraValidateDefinition(&_current_camera, 1); start_time = QTime::currentTime(); diff --git a/lib_paysages/clouds/definition.c b/lib_paysages/clouds/definition.c index 9b3c80f..9f60bdb 100644 --- a/lib_paysages/clouds/definition.c +++ b/lib_paysages/clouds/definition.c @@ -65,7 +65,8 @@ void cloudsLayerValidateDefinition(CloudsLayerDefinition* definition) noiseClearLevels(definition->_edge_noise); noiseClearLevels(definition->_coverage_noise); - noiseAddLevelsSimple(definition->_coverage_noise, 3, 1.0, 0.0, 1.0, 0.0); + noiseAddLevelsSimple(definition->_coverage_noise, 2, 10.0, 0.0, 1.0, 0.0); + noiseAddLevelsSimple(definition->_coverage_noise, 2, 1.0, 0.0, 1.0, 0.0); noiseSetFunctionParams(definition->_coverage_noise, NOISE_FUNCTION_NAIVE, 0.0, 0.0); switch (definition->type) { diff --git a/lib_paysages/render.c b/lib_paysages/render.c index 1aa1853..657f6b6 100644 --- a/lib_paysages/render.c +++ b/lib_paysages/render.c @@ -44,6 +44,7 @@ typedef struct struct RenderArea { + ColorProfile* hdr_mapping; RenderParams params; int pixel_count; RenderFragment* pixels; @@ -96,6 +97,7 @@ RenderArea* renderCreateArea() RenderArea* result; result = malloc(sizeof(RenderArea)); + result->hdr_mapping = colorProfileCreate(); result->params.width = 1; result->params.height = 1; result->params.antialias = 1; @@ -123,6 +125,7 @@ RenderArea* renderCreateArea() void renderDeleteArea(RenderArea* area) { + colorProfileDelete(area->hdr_mapping); mutexDestroy(area->lock); free(area->pixels); free(area->scanline_up); @@ -130,6 +133,14 @@ void renderDeleteArea(RenderArea* area) free(area); } +static void _setAllDirty(RenderArea* area) +{ + area->dirty_left = 0; + area->dirty_right = area->params.width * area->params.antialias - 1; + area->dirty_down = 0; + area->dirty_up = area->params.height * area->params.antialias - 1; +} + void renderSetParams(RenderArea* area, RenderParams params) { int width, height; @@ -155,6 +166,13 @@ void renderSetParams(RenderArea* area, RenderParams params) renderClear(area); } +void renderSetToneMapping(RenderArea* area, ToneMappingOperator tonemapper, double exposure) +{ + colorProfileSetToneMapping(area->hdr_mapping, tonemapper, exposure); + _setAllDirty(area); + renderUpdate(area); +} + void renderSetBackgroundColor(RenderArea* area, Color* col) { area->background_color = *col; @@ -264,6 +282,8 @@ static inline Color _getFinalPixel(RenderArea* area, int x, int y) result.r += col.r / (double)(area->params.antialias * area->params.antialias); result.g += col.g / (double)(area->params.antialias * area->params.antialias); result.b += col.b / (double)(area->params.antialias * area->params.antialias); + + result = colorProfileApply(area->hdr_mapping, result); } } @@ -304,14 +324,6 @@ void renderUpdate(RenderArea* area) mutexRelease(area->lock); } -static void _setAllDirty(RenderArea* area) -{ - area->dirty_left = 0; - area->dirty_right = area->params.width * area->params.antialias - 1; - area->dirty_down = 0; - area->dirty_up = area->params.height * area->params.antialias - 1; -} - static inline unsigned int _pushCallback(RenderArea* area, FragmentCallback callback) { int i; diff --git a/lib_paysages/render.h b/lib_paysages/render.h index d1885b6..b246c06 100644 --- a/lib_paysages/render.h +++ b/lib_paysages/render.h @@ -32,6 +32,7 @@ RenderArea* renderCreateArea(); void renderDeleteArea(RenderArea* area); void renderSetParams(RenderArea* area, RenderParams params); +void renderSetToneMapping(RenderArea* area, ToneMappingOperator tonemapper, double exposure); void renderSetBackgroundColor(RenderArea* area, Color* col); void renderClear(RenderArea* area); void renderUpdate(RenderArea* area); diff --git a/lib_paysages/system.c b/lib_paysages/system.c index 79d350a..1f87c1e 100644 --- a/lib_paysages/system.c +++ b/lib_paysages/system.c @@ -83,6 +83,7 @@ int systemSavePictureFile(const char* filepath, PictureCallbackSavePixel callbac for (x = 0; x < width; x++) { result = callback_pixel(data, x, y); + colorNormalize(&result); rgba = colorTo32BitRGBA(&result); pixels[y * width + x] = rgba; } diff --git a/lib_paysages/terrain/painting.c b/lib_paysages/terrain/painting.c index ed31f71..bc2a444 100644 --- a/lib_paysages/terrain/painting.c +++ b/lib_paysages/terrain/painting.c @@ -9,6 +9,7 @@ #include #include #include "../tools/memory.h" +#include "../tools.h" TerrainHeightMap* terrainHeightMapCreate(TerrainDefinition* terrain) { @@ -143,10 +144,35 @@ void terrainHeightmapLoad(PackStream* stream, TerrainHeightMap* heightmap) static inline int _checkDataHit(TerrainHeightMapChunk* chunk, double x, double z, double* result) { - if (x > (double)chunk->rect.xstart && x < (double)chunk->rect.xend && z > (double)chunk->rect.zstart && z < (double)chunk->rect.zend) + if (x >= (double)chunk->rect.xstart && x <= (double)chunk->rect.xend && z >= (double)chunk->rect.zstart && z <= (double)chunk->rect.zend) { - /* TODO Get interpolated value */ - *result = 0.0; + double stencil[16]; + int ix, iz, cx, cz; + int xmax = chunk->rect.xsize - 1; + int zmax = chunk->rect.zsize - 1; + int xlow; + int zlow; + + x -= chunk->rect.xstart; + z -= chunk->rect.zstart; + + xlow = floor(x); + zlow = floor(z); + + for (ix = xlow - 1; ix <= xlow + 2; ix++) + { + for (iz = zlow - 1; iz <= zlow + 2; iz++) + { + cx = ix < 0 ? 0 : ix; + cx = cx > xmax ? xmax : cx; + cz = iz < 0 ? 0 : iz; + cz = cz > zmax ? zmax : cz; + stencil[(iz - (zlow - 1)) * 4 + ix - (xlow - 1)] = chunk->data[cz * chunk->rect.xsize + cx]; + } + } + + *result = toolsBicubicInterpolate(stencil, x - (double)xlow, z - (double)zlow); + return 1; } else @@ -240,7 +266,7 @@ static void _prepareBrushStroke(TerrainHeightMap* heightmap, TerrainBrush* brush new_size = sizeof(double) * heightmap->floating_data.rect.xsize * heightmap->floating_data.rect.zsize; heightmap->floating_data.data = realloc(heightmap->floating_data.data, new_size); - _resetRect(heightmap, 0, 0, heightmap->floating_data.rect.xsize - 1, heightmap->floating_data.rect.zsize - 1); + _resetRect(heightmap, 0, heightmap->floating_data.rect.xsize - 1, 0, heightmap->floating_data.rect.zsize - 1); heightmap->floating_used = 1; } diff --git a/lib_paysages/terrain/presets.c b/lib_paysages/terrain/presets.c index bc95d50..54f8ed5 100644 --- a/lib_paysages/terrain/presets.c +++ b/lib_paysages/terrain/presets.c @@ -14,7 +14,9 @@ void terrainAutoPreset(TerrainDefinition* definition, TerrainPreset preset) case TERRAIN_PRESET_STANDARD: noiseRandomizeOffsets(definition->_height_noise); noiseClearLevels(definition->_height_noise); - noiseAddLevelsSimple(definition->_height_noise, resolution, pow(2.0, resolution - 1), -12.5, 12.5, 0.5); + noiseAddLevelSimple(definition->_height_noise, pow(2.0, resolution + 1), -15.0, 15.0); + noiseAddLevelsSimple(definition->_height_noise, resolution - 2, pow(2.0, resolution - 1), -10.0, 10.0, 0.5); + noiseNormalizeAmplitude(definition->_height_noise, -15.0, 15.0, 0); noiseSetFunctionParams(definition->_height_noise, NOISE_FUNCTION_SIMPLEX, 0.0, 0.0); definition->scaling = 1.0; definition->height = 1.0; diff --git a/lib_paysages/tools/color.c b/lib_paysages/tools/color.c index ba6c688..8144135 100644 --- a/lib_paysages/tools/color.c +++ b/lib_paysages/tools/color.c @@ -184,6 +184,8 @@ struct ColorProfile { double minvalue; double maxvalue; + Color (*mapper)(Color col, double exposure); + double exposure; }; ColorProfile* colorProfileCreate() @@ -192,6 +194,7 @@ ColorProfile* colorProfileCreate() profile = malloc(sizeof(ColorProfile)); + colorProfileSetToneMapping(profile, TONE_MAPPING_UNCHARTED, 2.0); colorProfileClear(profile); return profile; @@ -202,6 +205,52 @@ void colorProfileDelete(ColorProfile* profile) free(profile); } +static inline double _uncharted2Tonemap(double x) +{ + double A = 0.15; + double B = 0.50; + double C = 0.10; + double D = 0.20; + double E = 0.02; + double F = 0.30; + + return ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F; +} + +static Color _toneMappingUncharted(Color pixel, double exposure) +{ + double W = 11.2; + double white_scale = 1.0 / _uncharted2Tonemap(W); + + pixel.r = pow(_uncharted2Tonemap(pixel.r * exposure) * white_scale, 1.0 / 2.2); + pixel.g = pow(_uncharted2Tonemap(pixel.g * exposure) * white_scale, 1.0 / 2.2); + pixel.b = pow(_uncharted2Tonemap(pixel.b * exposure) * white_scale, 1.0 / 2.2); + + return pixel; +} + +static Color _toneMappingReinhard(Color pixel, double exposure) +{ + pixel.r = (pixel.r * exposure) / (1.0 + pixel.r * exposure); + pixel.g = (pixel.g * exposure) / (1.0 + pixel.g * exposure); + pixel.b = (pixel.b * exposure) / (1.0 + pixel.b * exposure); + + return pixel; +} + +void colorProfileSetToneMapping(ColorProfile* profile, ToneMappingOperator tonemapper, double exposure) +{ + if (tonemapper == TONE_MAPPING_REIHNARD) + { + profile->mapper = _toneMappingReinhard; + } + else + { + profile->mapper = _toneMappingUncharted; + } + profile->exposure = exposure; +} + void colorProfileSave(PackStream* stream, ColorProfile* profile) { /* TODO */ @@ -236,37 +285,9 @@ int colorProfileCollect(ColorProfile* profile, Color pixel) return changed; } -static double _uncharted2Tonemap(double x) -{ - double A = 0.15; - double B = 0.50; - double C = 0.10; - double D = 0.20; - double E = 0.02; - double F = 0.30; - - return ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F; -} - Color colorProfileApply(ColorProfile* profile, Color pixel) { - /*pixel.r *= 0.4; - pixel.g *= 0.4; - pixel.b *= 0.4; - pixel.r = pixel.r < 1.413 ? pow(pixel.r * 0.38317, 1.0 / 2.2) : 1.0 - exp(-pixel.r); - pixel.g = pixel.g < 1.413 ? pow(pixel.g * 0.38317, 1.0 / 2.2) : 1.0 - exp(-pixel.g); - pixel.b = pixel.b < 1.413 ? pow(pixel.b * 0.38317, 1.0 / 2.2) : 1.0 - exp(-pixel.b); - return pixel;*/ - - double exposure_bias = 2.0; - double W = 11.2; - double white_scale = 1.0 / _uncharted2Tonemap(W); - - pixel.r = pow(_uncharted2Tonemap(pixel.r * exposure_bias) * white_scale, 1.0 / 2.2); - pixel.g = pow(_uncharted2Tonemap(pixel.g * exposure_bias) * white_scale, 1.0 / 2.2); - pixel.b = pow(_uncharted2Tonemap(pixel.b * exposure_bias) * white_scale, 1.0 / 2.2); - - return pixel; + return profile->mapper(pixel, profile->exposure); } /******************************** ColorGradation ********************************/ diff --git a/lib_paysages/tools/color.h b/lib_paysages/tools/color.h index 53f6acc..31f52a5 100644 --- a/lib_paysages/tools/color.h +++ b/lib_paysages/tools/color.h @@ -44,10 +44,17 @@ double colorGetValue(Color* col); /* HDR profile for tone-mapping */ typedef struct ColorProfile ColorProfile; +typedef enum +{ + TONE_MAPPING_UNCHARTED, + TONE_MAPPING_REIHNARD +} ToneMappingOperator; ColorProfile* colorProfileCreate(); void colorProfileDelete(ColorProfile* profile); +void colorProfileSetToneMapping(ColorProfile* profile, ToneMappingOperator tonemapper, double exposure); + void colorProfileSave(PackStream* stream, ColorProfile* profile); void colorProfileLoad(PackStream* stream, ColorProfile* profile); diff --git a/lib_paysages/tools/memory.c b/lib_paysages/tools/memory.c index 874f772..d8d7616 100644 --- a/lib_paysages/tools/memory.c +++ b/lib_paysages/tools/memory.c @@ -1,11 +1,54 @@ #include "memory.h" #include +#include void* memory2dRealloc(void* data, int datasize, int oldxsize, int oldysize, int newxsize, int newysize, int xoffset, int yoffset) { - /* TODO Move remaining part*/ - return realloc(data, datasize * newxsize * newysize); + int xstart, xend, xlen; + int ystart, yend, y; + void* result = malloc(datasize * newxsize * newysize); + + /* Move remaining part*/ + ystart = yoffset; + yend = yoffset + oldysize; + if (yend >= 0 && ystart < newysize) + { + if (ystart < 0) + { + ystart = 0; + } + if (yend > newysize - 1) + { + yend = newysize - 1; + } + + xstart = xoffset; + xend = xoffset + oldxsize; + if (xend >= 0 && xstart < newxsize) + { + if (xstart < 0) + { + xstart = 0; + } + if (xend > newxsize - 1) + { + xend = newxsize - 1; + } + + xlen = xend - xstart + 1; + if (xlen > 0) + { + for (y = ystart; y <= yend; y++) + { + memcpy(result + (y * newxsize + xstart) * datasize, data + ((y - ystart) * oldxsize) * datasize, xlen * datasize); + } + } + } + } + + free(data); + return result; } void memory2dScrolling(void* data, int datasize, int xsize, int ysize, int xoffset, int yoffset)